101 bool newAssistantAllowed =
true;
124 QPointF mousePos =
m_canvas->viewConverter()->documentToView(canvasDecoration->
snapToGuide(event, QPointF(),
false));
134 if (assistant->isLocked()) {
143 allAssistantHandles.append(assistant->handles());
144 allAssistantHandles.append(assistant->sideHandles());
149 if (dist < minDist) {
154 m_canvas->paintingAssistantsDecoration()->raiseAssistant(assistant);
168 if (dist < minDist) {
171 m_dragStart = QPointF(assistant->topRight().data()->x(),assistant->topRight().data()->y());
175 if (dist < minDist) {
179 m_dragStart = QPointF(assistant->topLeft().data()->x(),assistant->topLeft().data()->y());
182 if (dist < minDist) {
186 m_dragStart = QPointF(assistant->bottomRight().data()->x(),assistant->bottomRight().data()->y());
189 if (dist < minDist) {
193 m_dragStart = QPointF(assistant->bottomLeft().data()->x(),assistant->bottomLeft().data()->y());
196 m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->topLeft().data()->x())*0.5,
197 (assistant->bottomLeft().data()->y()+assistant->topLeft().data()->y())*0.5);
210 m_dragStart = QPointF((assistant->topRight().data()->x()+assistant->bottomRight().data()->x())*0.5,
211 (assistant->topRight().data()->y()+assistant->bottomRight().data()->y())*0.5);
225 m_dragStart = QPointF((assistant->topLeft().data()->x()+assistant->topRight().data()->x())*0.5,
226 (assistant->topLeft().data()->y()+assistant->topRight().data()->y())*0.5);
240 m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->bottomRight().data()->x())*0.5,
241 (assistant->bottomLeft().data()->y()+assistant->bottomRight().data()->y())*0.5);
257 else if (
m_handleDrag && assistant->handles().size()>1 && (assistant->id() ==
"ruler" ||
258 assistant->id() ==
"parallel ruler" ||
259 assistant->id() ==
"infinite ruler" ||
260 assistant->id() ==
"spline" ||
261 assistant->id() ==
"curvilinear-perspective")){
266 }
else if(assistant->handles().size()==4){
274 }
else if (
m_handleDrag && assistant->handles().size()>2 && (assistant->id() ==
"ellipse" ||
275 assistant->id() ==
"concentric ellipse" ||
276 assistant->id() ==
"fisheye-point")){
289 }
else if (
m_handleDrag && assistant->handles().size()>2 && assistant->id() ==
"two point") {
297 const QPointF
p1 = *assistant->handles()[0];
298 const QPointF
p2 = *assistant->handles()[1];
299 const QPointF
p3 = *assistant->handles()[2];
302 QTransform t = qSharedPointerCast<TwoPointAssistant>(
m_newAssistant)->localTransform(
p1,
p2,
p3,&size);
303 QTransform inv = t.inverted();
304 if (t.map(
p1).x() * t.map(
p2).x() > 0) {
308 const QPointF safe_start = QPointF(-1.0*t.map(
p1).x(),t.map(
p1).y());
311 const QPointF safe_start = QPointF(-1.0*t.map(
p2).x(),t.map(
p1).y());
321 }
else if (
m_handleDrag && assistant->id() ==
"vanishing point" &&
352 QPointF uiMousePosition = initialTransform.map(canvasDecoration->
snapToGuide(event, QPointF(),
false));
357 QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.
boundingSize));
364 QPointF actionsBGRectangle(actionsPosition + QPointF(globalEditorWidgetData.
widgetOffset,globalEditorWidgetData.
widgetOffset));
365 QRectF editorWidget = QRectF(actionsBGRectangle.x(), actionsBGRectangle.y(), globalEditorWidgetData.
boundingSize.width(), globalEditorWidgetData.
boundingSize.height());
367 if (editorWidget.contains(uiMousePosition)) {
368 assistantsPressed.push_back(assistant);
374 if (!assistantsPressed.isEmpty()) {
378 m_canvas->paintingAssistantsDecoration()->raiseAssistant(assistant);
382 QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.
boundingSize));
386 QPointF iconMovePosition(actionsPosition + globalEditorWidgetData.
moveIconPosition);
387 QRectF moveRect(iconMovePosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
389 if (moveRect.contains(uiMousePosition) && !assistant->isLocked()) {
400 QPointF iconSnapPosition(actionsPosition + globalEditorWidgetData.
snapIconPosition);
401 QRectF visibleRect(iconSnapPosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
402 if (visibleRect.contains(uiMousePosition)) {
403 newAssistantAllowed =
false;
404 assistant->setSnappingActive(!assistant->isSnappingActive());
405 assistant->uncache();
411 QPointF iconLockPosition(actionsPosition + globalEditorWidgetData.
lockedIconPosition);
412 QRectF lockRect(iconLockPosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
413 if (lockRect.contains(uiMousePosition)) {
415 assistant->setLocked(!assistant->isLocked());
424 QRectF duplicateRect(iconDuplicatePosition,QSizeF(globalEditorWidgetData.
buttonSize,globalEditorWidgetData.
buttonSize));
426 if (duplicateRect.contains(uiMousePosition)) {
428 QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> handleMap;
436 m_canvas->viewManager()->undoAdapter()->addCommand(addAssistantCmd);
443 if(assistant->isLocked()) {
444 newAssistantAllowed =
false;
465 QPointF iconDeletePosition(actionsPosition + globalEditorWidgetData.
deleteIconPosition);
466 QRectF deleteRect(iconDeletePosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
467 if (deleteRect.contains(uiMousePosition) && !assistant->isLocked()) {
469 if(
m_canvas->paintingAssistantsDecoration()->assistants().isEmpty()) {
478 if((QRectF(actionsPosition + QPointF(10, 10), globalEditorWidgetData.
boundingSize).adjusted(-2, -2, 2, 2).contains(uiMousePosition))) {
479 newAssistantAllowed =
false;
490 if (newAssistantAllowed==
true) {
491 QString key =
m_options.availableAssistantsComboBox->model()->index(
m_options.availableAssistantsComboBox->currentIndex(), 0 ).data(Qt::UserRole).toString();
492 KConfigGroup cfg = KSharedConfig::openConfig()->group(
toolId());
493 cfg.writeEntry(
"AssistantType", key);
508 m_newAssistant->setAssistantGlobalColorCache(
m_canvas->paintingAssistantsDecoration()->globalAssistantsColor());
530 if (!(event->
modifiers() & Qt::ShiftModifier)) {
531 double minDist = 49.0;
532 QPointF mousePos =
m_canvas->viewConverter()->documentToView(event->
point);
539 if (dist < minDist) {
548 if (event->
modifiers() & Qt::ShiftModifier ) {
567 QPointF currentOffset = selectedAssistant->editorWidgetOffset();
568 selectedAssistant->setEditorWidgetOffset(currentOffset + (event->
point -
m_dragEnd));
576 QPointF mousep =
m_canvas->viewConverter()->documentToView(event->
point);
577 QList <KisPaintingAssistantSP> pAssistant=
m_canvas->paintingAssistantsDecoration()->assistants();
580 if(assistant->id() ==
"perspective") {
592 if(
m_handleDrag && assistant->id() ==
"vanishing point" && assistant->sideHandles().size()==4) {
595 QLineF perspectiveline = QLineF(*assistant->handles()[0],
596 *assistant->sideHandles()[0]);
598 qreal
length = QLineF(*assistant->sideHandles()[0],
599 *assistant->sideHandles()[1]).length();
605 length += perspectiveline.length();
606 perspectiveline.setLength(
length);
607 *assistant->sideHandles()[1] = perspectiveline.p2();
610 QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]);
611 qreal
length = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length();
617 length += perspectiveline.length();
618 perspectiveline.setLength(
length);
619 *assistant->sideHandles()[3] = perspectiveline.p2();
622 QPointF vanishingpoint(0,0);
623 QLineF perspectiveline = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]);
624 QLineF perspectiveline2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]);
626 if (QLineF(perspectiveline2).intersects(QLineF(perspectiveline), &vanishingpoint) != QLineF::NoIntersection){
627 *assistant->handles()[0] = vanishingpoint;
631 QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[0]);
632 QLineF perspectiveline2 = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]);
633 qreal
length = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]).length();
634 qreal length2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length();
644 length += perspectiveline.length();
645 length2 += perspectiveline2.length();
646 perspectiveline.setLength(
length);
647 perspectiveline2.setLength(length2);
648 *assistant->sideHandles()[1] = perspectiveline.p2();
649 *assistant->sideHandles()[3] = perspectiveline2.p2();
653 if (
m_handleDrag && assistant->id() ==
"two point" && assistant->handles().size() >= 3 &&
654 assistant->sideHandles().size() == 8) {
659 const bool far_handle_is_dragged =
663 if (far_handle_is_dragged) {
664 QLineF perspective_line_a, perspective_line_b;
665 QPointF vp_new_pos(0,0);
669 perspective_line_a = QLineF(*side_hndl[0],*side_hndl[1]);
670 perspective_line_b = QLineF(*side_hndl[4],*side_hndl[5]);
673 perspective_line_a = QLineF(*side_hndl[3],*side_hndl[2]);
674 perspective_line_b = QLineF(*side_hndl[6],*side_hndl[7]);
676 if (perspective_line_a.intersects(perspective_line_b, &vp_new_pos) != QLineF::NoIntersection) {
677 *vp_moved = vp_new_pos;
680 QLineF perspective_line_a1;
681 QLineF perspective_line_b1;
682 QLineF perspective_line_a2;
683 QLineF perspective_line_b2;
685 perspective_line_a1 = QLineF(*hndl[0], *side_hndl[0]);
686 perspective_line_a1.setLength(QLineF(*side_hndl[0],*side_hndl[1]).
length());
687 perspective_line_a1.translate(*side_hndl[0] - perspective_line_a1.p1());
688 *side_hndl[1] = perspective_line_a1.p2();
690 perspective_line_b1 = QLineF(*hndl[0], *side_hndl[4]);
691 perspective_line_b1.setLength(QLineF(*side_hndl[4],*side_hndl[5]).
length());
692 perspective_line_b1.translate(*side_hndl[4] - perspective_line_b1.p1());
693 *side_hndl[5] = perspective_line_b1.p2();
695 perspective_line_a2 = QLineF(*hndl[1], *side_hndl[2]);
696 perspective_line_a2.setLength(QLineF(*side_hndl[2],*side_hndl[3]).
length());
697 perspective_line_a2.translate(*side_hndl[2] - perspective_line_a2.p1());
698 *side_hndl[3] = perspective_line_a2.p2();
700 perspective_line_b2 = QLineF(*hndl[1], *side_hndl[6]);
701 perspective_line_b2.setLength(QLineF(*side_hndl[6],*side_hndl[7]).
length());
702 perspective_line_b2.translate(*side_hndl[6] - perspective_line_b2.p1());
703 *side_hndl[7] = perspective_line_b2.p2();
708 if (
m_handleDrag && (assistant->id() ==
"ruler" || assistant->id() ==
"infinite ruler")
709 && qSharedPointerCast<RulerAssistant>(assistant)->hasFixedLength()
710 && assistant->isAssistantComplete()) {
720 QPointF center = *ruler->handles()[0];
721 QPointF handle = *ruler->handles()[1];
723 QPointF direction = handle - center;
725 QPointF delta = direction /
distance * ruler->fixedLength();
727 *ruler->handles()[1] = center + delta;
863 int horizontalButtonCount = 0;
871 horizontalButtonCount++;
872 if(horizontalButtonCount > horizontalButtonLimit)
874 horizontalButtonCount = 1;
886 horizontalButtonCount++;
887 if(horizontalButtonCount > horizontalButtonLimit)
889 horizontalButtonCount = 1;
899 horizontalButtonCount++;
900 if(horizontalButtonCount > horizontalButtonLimit)
902 horizontalButtonCount = 1;
912 horizontalButtonCount++;
913 if(horizontalButtonCount > horizontalButtonLimit)
915 horizontalButtonCount = 0;
925 horizontalButtonCount++;
926 if(horizontalButtonCount > horizontalButtonLimit)
928 horizontalButtonCount = 1;
938 int boundingWidgetWidth = (buttonCount < horizontalButtonLimit) ? buttonCount*buttonSection:horizontalButtonLimit*buttonSection;
939 boundingWidgetWidth += 5;
942 int buttonToWidthRatio = (buttonCount/horizontalButtonLimit);
943 if(buttonCount%horizontalButtonLimit != 0) {
944 buttonToWidthRatio++;
947 int boundingWidgetHeight = buttonToWidthRatio*buttonSection;
948 boundingWidgetHeight += 5;
949 globalEditorWidgetData.
boundingSize.setHeight(boundingWidgetHeight);
952 m_canvas->updateCanvasDecorations();
979 bool hasActiveAssistant = m_selectedAssistant ? true :
false;
992 m_options.showDuplicate->setChecked(
true);
998 if (m_selectedAssistant) {
999 bool isVanishingPointAssistant = m_selectedAssistant->id() ==
"vanishing point";
1000 bool isTwoPointAssistant = m_selectedAssistant->id() ==
"two point";
1001 bool isRulerAssistant = m_selectedAssistant->id() ==
"ruler"
1002 || m_selectedAssistant->id() ==
"infinite ruler";
1003 bool isPerspectiveAssistant = m_selectedAssistant->id() ==
"perspective";
1005 m_options.vanishingPointAngleSpinbox->setVisible(isVanishingPointAssistant);
1006 m_options.twoPointDensitySpinbox->setVisible(isTwoPointAssistant);
1007 m_options.twoPointUseVerticalCheckbox->setVisible(isTwoPointAssistant);
1008 m_options.subdivisionsSpinbox->setVisible(isRulerAssistant || isPerspectiveAssistant);
1009 m_options.minorSubdivisionsSpinbox->setVisible(isRulerAssistant);
1010 m_options.fixedLengthCheckbox->setVisible(isRulerAssistant);
1015 m_options.showDuplicate->setVisible(
true);
1020 if (isVanishingPointAssistant) {
1021 QSharedPointer <VanishingPointAssistant> assis = qSharedPointerCast<VanishingPointAssistant>(m_selectedAssistant);
1022 m_options.vanishingPointAngleSpinbox->setValue(assis->referenceLineDensity());
1025 if (isTwoPointAssistant) {
1026 QSharedPointer <TwoPointAssistant> assis = qSharedPointerCast<TwoPointAssistant>(m_selectedAssistant);
1027 m_options.twoPointDensitySpinbox->setValue(assis->gridDensity());
1028 m_options.twoPointUseVerticalCheckbox->setChecked(assis->useVertical());
1031 if (isRulerAssistant) {
1032 QSharedPointer <RulerAssistant> assis = qSharedPointerCast<RulerAssistant>(m_selectedAssistant);
1033 m_options.subdivisionsSpinbox->setValue(assis->subdivisions());
1034 m_options.minorSubdivisionsSpinbox->setValue(assis->minorSubdivisions());
1035 m_options.fixedLengthCheckbox->setChecked(assis->hasFixedLength());
1037 m_options.fixedLengthSpinbox->setVisible(assis->hasFixedLength());
1038 m_options.fixedLengthUnit->setVisible(assis->hasFixedLength());
1041 QSignalBlocker b(
m_options.fixedLengthSpinbox);
1044 m_options.fixedLengthSpinbox->changeValue(assis->fixedLength());
1046 m_options.fixedLengthSpinbox->setPrefix(
"");
1048 m_options.fixedLengthSpinbox->setVisible(
false);
1049 m_options.fixedLengthUnit->setVisible(
false);
1052 if (isPerspectiveAssistant) {
1053 QSharedPointer <PerspectiveAssistant> assis = qSharedPointerCast<PerspectiveAssistant>(m_selectedAssistant);
1054 m_options.subdivisionsSpinbox->setValue(assis->subdivisions());
1058 m_options.useCustomAssistantColor->setChecked(m_selectedAssistant->useCustomColor());
1059 m_options.customAssistantColorButton->setColor(m_selectedAssistant->assistantCustomColor());
1062 double opacity = (double)m_selectedAssistant->assistantCustomColor().alpha()/(double)255.00 * (
double)100.00 ;
1063 opacity = ceil(opacity);
1065 m_options.customColorOpacitySlider->blockSignals(
true);
1066 m_options.customColorOpacitySlider->setValue((
double)opacity);
1067 m_options.customColorOpacitySlider->blockSignals(
false);
1070 m_options.vanishingPointAngleSpinbox->setVisible(
false);
1071 m_options.twoPointDensitySpinbox->setVisible(
false);
1072 m_options.twoPointUseVerticalCheckbox->setVisible(
false);
1073 m_options.subdivisionsSpinbox->setVisible(
false);
1074 m_options.minorSubdivisionsSpinbox->setVisible(
false);
1075 m_options.fixedLengthCheckbox->setVisible(
false);
1076 m_options.fixedLengthSpinbox->setVisible(
false);
1077 m_options.fixedLengthUnit->setVisible(
false);
1081 m_options.useCustomAssistantColor->setVisible(hasActiveAssistant);
1084 bool showCustomColorSettings =
m_options.useCustomAssistantColor->isChecked() && hasActiveAssistant;
1085 m_options.customColorOpacitySlider->setVisible(showCustomColorSettings);
1086 m_options.customAssistantColorButton->setVisible(showCustomColorSettings);
1089 m_options.assistantsGlobalOpacitySlider->setEnabled(!showCustomColorSettings);
1090 m_options.assistantsColor->setEnabled(!showCustomColorSettings);
1091 m_options.globalColorLabel->setEnabled(!showCustomColorSettings);
1093 QString key =
m_options.availableAssistantsComboBox->model()->index(
m_options.availableAssistantsComboBox->currentIndex(), 0 ).data(Qt::UserRole).toString();
1094 m_options.localAssistantCheckbox->setVisible(key ==
"two point" || key ==
"vanishing point" || key ==
"parallel ruler");
1437 dialog.setCaption(i18n(
"Select an Assistant"));
1438 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1439 dialog.setMimeTypeFilters(
QStringList() <<
"application/x-krita-assistant",
"application/x-krita-assistant");
1440 QString filename = dialog.filename();
1441 if (filename.isEmpty())
return;
1442 if (!QFileInfo(filename).exists())
return;
1444 QFile file(filename);
1445 file.open(QIODevice::ReadOnly);
1447 QByteArray data = file.readAll();
1448 QXmlStreamReader xml(data);
1449 QMap<int, KisPaintingAssistantHandleSP> handleMap;
1450 QMap<int, KisPaintingAssistantHandleSP> sideHandleMap;
1452 bool errors =
false;
1457 while (!xml.atEnd()) {
1458 switch (xml.readNext()) {
1459 case QXmlStreamReader::StartElement:
1460 if (xml.name() ==
"handle") {
1461 if (assistant && !xml.attributes().value(
"ref").isEmpty()) {
1469 QString strId = xml.attributes().value(
"id").toString(),
1470 strX = xml.attributes().value(
"x").toString(),
1471 strY = xml.attributes().value(
"y").toString();
1475 if (!strId.isEmpty() && !strX.isEmpty() && !strY.isEmpty()) {
1476 int id = strId.toInt();
1477 double x = strX.toDouble(),
1478 y = strY.toDouble();
1479 if (!handleMap.contains(
id)) {
1489 }
else if (xml.name() ==
"sidehandle"){
1492 if (!xml.attributes().value(
"id").isEmpty()) {
1493 QString strId = xml.attributes().value(
"id").toString(),
1494 strX = xml.attributes().value(
"x").toString(),
1495 strY = xml.attributes().value(
"y").toString();
1496 if (!strId.isEmpty() && !strX.isEmpty() && !strY.isEmpty()) {
1497 int id = strId.toInt();
1498 double x = strX.toDouble();
1499 double y = strY.toDouble();
1500 if (!sideHandleMap.contains(
id)) {
1505 if (!xml.attributes().value(
"ref").isEmpty() && assistant) {
1512 }
else if (xml.name() ==
"assistant") {
1527 if (xml.attributes().hasAttribute(
"useCustomColor")) {
1528 auto useCustomColor = xml.attributes().value(
"useCustomColor");
1530 bool usingColor =
false;
1531 if (useCustomColor.toString() ==
"1") {
1534 assistant->setUseCustomColor(usingColor);
1537 if ( xml.attributes().hasAttribute(
"useCustomColor")) {
1538 auto customColor = xml.attributes().value(
"customColor");
1546 assistant->loadCustomXml(&xml);
1551 case QXmlStreamReader::EndElement:
1552 if (xml.name() ==
"assistant") {
1554 if (assistant->handles().size() == assistant->numHandles()) {
1555 if (assistant->id() ==
"vanishing point" && sideHandleMap.empty()){
1557 QPointF pos = *assistant->handles()[0];
1563 m_canvas->paintingAssistantsDecoration()->addAssistant(assistant);
1581 if (xml.hasError()) {
1582 QMessageBox::warning(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), xml.errorString());
1585 QMessageBox::warning(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Errors were encountered. Not all assistants were successfully loaded."));
1589 m_canvas->viewManager()->undoAdapter()->addCommand(command);
1601 QXmlStreamWriter xml(&data);
1602 xml.writeStartDocument();
1603 xml.writeStartElement(
"paintingassistant");
1604 xml.writeAttribute(
"color",
1606 m_canvas->paintingAssistantsDecoration()->globalAssistantsColor()));
1609 xml.writeStartElement(
"handles");
1610 QMap<KisPaintingAssistantHandleSP, int> handleMap;
1612 int id = handleMap.size();
1613 handleMap.insert(handle,
id);
1614 xml.writeStartElement(
"handle");
1616 xml.writeAttribute(
"id", QString::number(
id));
1617 xml.writeAttribute(
"x", QString::number(
double(handle->x()),
'f', 3));
1618 xml.writeAttribute(
"y", QString::number(
double(handle->y()),
'f', 3));
1619 xml.writeEndElement();
1621 xml.writeEndElement();
1622 xml.writeStartElement(
"sidehandles");
1623 QMap<KisPaintingAssistantHandleSP, int> sideHandleMap;
1626 int id = sideHandleMap.size();
1627 sideHandleMap.insert(handle,
id);
1628 xml.writeStartElement(
"sidehandle");
1629 xml.writeAttribute(
"id", QString::number(
id));
1630 xml.writeAttribute(
"x", QString::number(
double(handle->x()),
'f', 3));
1631 xml.writeAttribute(
"y", QString::number(
double(handle->y()),
'f', 3));
1632 xml.writeEndElement();
1635 xml.writeStartElement(
"assistants");
1639 xml.writeStartElement(
"assistant");
1640 xml.writeAttribute(
"type", assistant->id());
1641 xml.writeAttribute(
"useCustomColor", QString::number(assistant->useCustomColor()));
1647 assistant->saveCustomXml(&xml);
1650 xml.writeStartElement(
"handles");
1652 xml.writeStartElement(
"handle");
1653 xml.writeAttribute(
"ref", QString::number(handleMap.value(handle)));
1654 xml.writeEndElement();
1656 xml.writeEndElement();
1657 if (!sideHandleMap.empty()) {
1658 xml.writeStartElement(
"sidehandles");
1660 xml.writeStartElement(
"sidehandle");
1661 xml.writeAttribute(
"ref", QString::number(sideHandleMap.value(handle)));
1662 xml.writeEndElement();
1664 xml.writeEndElement();
1666 xml.writeEndElement();
1668 xml.writeEndElement();
1669 xml.writeEndElement();
1670 xml.writeEndDocument();
1673 dialog.setCaption(i18n(
"Save Assistant"));
1674 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1675 dialog.setMimeTypeFilters(
QStringList() <<
"application/x-krita-assistant",
"application/x-krita-assistant");
1676 QString filename = dialog.filename();
1677 if (filename.isEmpty())
return;
1679 QFile file(filename);
1680 file.open(QIODevice::WriteOnly);
1690 KConfigGroup cfg = KSharedConfig::openConfig()->group(
toolId());
1694 specialSpacer->setObjectName(
"SpecialSpacer");
1695 specialSpacer->setFixedSize(0, 0);
1699 m_options.loadAssistantButton->setIconSize(QSize(16, 16));
1701 m_options.saveAssistantButton->setIconSize(QSize(16, 16));
1703 m_options.deleteAllAssistantsButton->setIconSize(QSize(16, 16));
1706 m_options.showDockerOptionsButton->setIconSize(QSize(16, 16));
1711 assistants <<
KoID(key, name);
1715 QString currentAssistantType = cfg.readEntry(
"AssistantType",
"two point");
1717 int currentAssistantIndex = 0;
1718 Q_FOREACH(
const KoID &
id, assistants) {
1719 m_options.availableAssistantsComboBox->addItem(
id.name(),
id.
id());
1720 if (
id.
id() == currentAssistantType) {
1721 currentAssistantIndex = i;
1725 m_options.availableAssistantsComboBox->setCurrentIndex(currentAssistantIndex);
1754 const QColor color =
m_canvas->paintingAssistantsDecoration()->globalAssistantsColor();
1756 QColor opaqueColor = color;
1757 opaqueColor.setAlpha(255);
1759 m_options.assistantsColor->setColor(opaqueColor);
1760 m_options.customAssistantColorButton->setColor(opaqueColor);
1761 m_options.assistantsGlobalOpacitySlider->setValue(color.alphaF() * 100.0);
1764 m_options.assistantsColor->setColor(QColor(176, 176, 176, 255));
1765 m_options.assistantsGlobalOpacitySlider->setValue(100);
1768 m_options.assistantsGlobalOpacitySlider->setPrefix(i18n(
"Opacity: "));
1769 m_options.assistantsGlobalOpacitySlider->setSuffix(
" %");
1773 m_options.customColorOpacitySlider->setValue(100);
1774 m_options.customColorOpacitySlider->setPrefix(i18n(
"Opacity: "));
1775 m_options.customColorOpacitySlider->setSuffix(
" %");
1781 m_options.twoPointDensitySpinbox->setPrefix(i18n(
"Density: "));
1782 m_options.twoPointDensitySpinbox->setRange(0.1, 4.0, 2);
1783 m_options.twoPointDensitySpinbox->setSingleStep(0.1);
1785 m_options.vanishingPointAngleSpinbox->setPrefix(i18n(
"Density: "));
1786 m_options.vanishingPointAngleSpinbox->setSuffix(QStringLiteral(
"°"));
1787 m_options.vanishingPointAngleSpinbox->setRange(1.0, 180.0);
1788 m_options.vanishingPointAngleSpinbox->setSingleStep(1.0);
1790 m_options.subdivisionsSpinbox->setPrefix(i18n(
"Subdivisions: "));
1791 m_options.subdivisionsSpinbox->setRange(0, 100);
1792 m_options.subdivisionsSpinbox->setSoftRange(0, 20);
1794 m_options.minorSubdivisionsSpinbox->setPrefix(i18n(
"Minor Subdivisions: "));
1795 m_options.minorSubdivisionsSpinbox->setRange(1, 5);
1799 m_options.fixedLengthSpinbox->setDisplayUnit(
false);
1800 m_options.fixedLengthSpinbox->setMinimum(0);
1806 m_options.vanishingPointAngleSpinbox->setVisible(
false);
1807 m_options.twoPointDensitySpinbox->setVisible(
false);
1808 m_options.subdivisionsSpinbox->setVisible(
false);
1809 m_options.minorSubdivisionsSpinbox->setVisible(
false);
1810 m_options.fixedLengthCheckbox->setVisible(
false);
1811 m_options.fixedLengthSpinbox->setVisible(
false);
1812 m_options.fixedLengthUnit->setVisible(
false);
1815 m_options.localAssistantCheckbox->setChecked(cfg.readEntry(
"LimitAssistantToArea",
false));
1835 m_options.showDuplicate->setChecked(
true);
1998 if (event->
modifiers() == Qt::NoModifier) {
2007 if (selectedAssistant->id() ==
"two point" &&
m_handleDrag != handles[2] &&
2008 event->
modifiers() != Qt::ShiftModifier) {
2018 const QTransform t = assis->localTransform(prevPoint,*handleOpp,*handles[2],&size);
2019 const QTransform inv = t.inverted();
2024 const QLineF horizon = QLineF(t.map(prevPoint), QPointF(t.map(*handleOpp).x(),t.map(prevPoint).y()));
2025 const QPointF sp = QPointF(0,horizon.p1().y()+size);
2027 const bool preserve_distortion_snap =
event->modifiers() == Qt::ControlModifier;
2028 const bool preserve_left_right_ratio_snap =
event->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier);
2029 const bool preserve_horizon_snap =
event->modifiers() == Qt::AltModifier;
2032 QPointF opp_snap_point;
2033 QLineF sp_to_opp_vp;
2035 if (preserve_distortion_snap) {
2036 const QLineF sp_to_vp = QLineF(sp, t.map(*
m_handleDrag));
2037 sp_to_opp_vp = sp_to_vp.normalVector();
2038 sp_to_vp.intersects(horizon,&snap_point);
2039 }
else if (preserve_left_right_ratio_snap) {
2040 const QLineF prev_sp_to_vp = QLineF(sp, horizon.p1());
2041 QLineF new_sp_to_vp = prev_sp_to_vp.translated(t.map(*
m_handleDrag)-sp);
2043 new_sp_to_vp.intersects(QLineF(QPoint(0,0),QPointF(0,1)),&new_sp);
2044 sp_to_opp_vp = new_sp_to_vp.normalVector().translated(new_sp-new_sp_to_vp.p1());
2045 new_sp_to_vp.intersects(horizon,&snap_point);
2046 }
else if (preserve_horizon_snap) {
2047 snap_point = QPointF(t.map(*m_handleDrag).x(),horizon.p1().y());
2048 sp_to_opp_vp = QLineF(sp,QPointF(t.map(prevPoint).x(),horizon.p1().y())).normalVector();
2054 const bool no_intersection =
2056 sp_to_opp_vp.intersects(horizon, &opp_snap_point) == QLineF::NoIntersection;
2057 const bool origin_is_between =
2058 (snap_point.x() < 0 && opp_snap_point.x() > 0) ||
2059 (snap_point.x() > 0 && opp_snap_point.x() < 0);
2060 const bool null_opp_point =
2063 const bool overlapping_snap_points =
2067 if (!origin_is_between || no_intersection || null_opp_point || overlapping_snap_points) {
2072 if (preserve_distortion_snap) {
2073 sp_to_opp_vp = QLineF(sp, t.map(
m_dragStart)).normalVector();
2074 sp_to_opp_vp.intersects(horizon, &oppStart);
2077 const qreal p2x = preserve_horizon_snap ? t.map(*handleOpp).x() : -
p1.x();
2078 const QPointF
p2 = QPointF(p2x,
p1.y());
2079 const QLineF new_horizon = QLineF(
p1,
p2);
2080 const qreal new_size = sqrt(pow(new_horizon.length()/2.0,2) -
2081 pow(abs(new_horizon.center().x()),2));
2082 const QPointF new_sp = QPointF(0,horizon.p1().y()+new_size);
2083 sp_to_opp_vp = QLineF(new_sp, t.map(
m_dragStart)).normalVector();
2085 sp_to_opp_vp.intersects(horizon, &oppStart);
2086 *handleOpp=inv.map(oppStart);
2091 *handleOpp = inv.map(opp_snap_point);
2096 dragRadius.setLength(
m_radius.length());
2107 if (handles.size() == 2) {
2109 *handle_snap = snap_point;
2111 bool was_snapped =
false;
2114 handles.size() == 3 ? start = handles[0] : start = handles[1];
2116 *handle_snap = snap_point;
2123 QPointF center = QLineF(*handles[0], *handles[1]).center();
2124 QLineF radius = QLineF(center,*handles[0]);
2125 QLineF dragRadius = QLineF(center, event->
point);
2126 dragRadius.setLength(radius.length());
2127 *handle_snap = dragRadius.p2();
2133 handles.size() == 3 ? start = handles[1] : start = handles[2];
2135 *handle_snap = snap_point;