102 bool newAssistantAllowed =
true;
125 QPointF mousePos =
m_canvas->viewConverter()->documentToView(canvasDecoration->
snapToGuide(event, QPointF(),
false));
135 if (assistant->isLocked()) {
144 allAssistantHandles.append(assistant->handles());
145 allAssistantHandles.append(assistant->sideHandles());
150 if (dist < minDist) {
155 m_canvas->paintingAssistantsDecoration()->raiseAssistant(assistant);
169 if (dist < minDist) {
172 m_dragStart = QPointF(assistant->topRight().data()->x(),assistant->topRight().data()->y());
176 if (dist < minDist) {
180 m_dragStart = QPointF(assistant->topLeft().data()->x(),assistant->topLeft().data()->y());
183 if (dist < minDist) {
187 m_dragStart = QPointF(assistant->bottomRight().data()->x(),assistant->bottomRight().data()->y());
190 if (dist < minDist) {
194 m_dragStart = QPointF(assistant->bottomLeft().data()->x(),assistant->bottomLeft().data()->y());
197 m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->topLeft().data()->x())*0.5,
198 (assistant->bottomLeft().data()->y()+assistant->topLeft().data()->y())*0.5);
211 m_dragStart = QPointF((assistant->topRight().data()->x()+assistant->bottomRight().data()->x())*0.5,
212 (assistant->topRight().data()->y()+assistant->bottomRight().data()->y())*0.5);
226 m_dragStart = QPointF((assistant->topLeft().data()->x()+assistant->topRight().data()->x())*0.5,
227 (assistant->topLeft().data()->y()+assistant->topRight().data()->y())*0.5);
241 m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->bottomRight().data()->x())*0.5,
242 (assistant->bottomLeft().data()->y()+assistant->bottomRight().data()->y())*0.5);
258 else if (
m_handleDrag && assistant->handles().size()>1 && (assistant->id() ==
"ruler" ||
259 assistant->id() ==
"parallel ruler" ||
260 assistant->id() ==
"infinite ruler" ||
261 assistant->id() ==
"spline" ||
262 assistant->id() ==
"curvilinear-perspective")){
267 }
else if(assistant->handles().size()==4){
275 }
else if (
m_handleDrag && assistant->handles().size()>2 && (assistant->id() ==
"ellipse" ||
276 assistant->id() ==
"concentric ellipse" ||
277 assistant->id() ==
"fisheye-point")){
290 }
else if (
m_handleDrag && assistant->handles().size()>2 && assistant->id() ==
"two point") {
298 const QPointF
p1 = *assistant->handles()[0];
299 const QPointF
p2 = *assistant->handles()[1];
300 const QPointF
p3 = *assistant->handles()[2];
303 QTransform t = qSharedPointerCast<TwoPointAssistant>(
m_newAssistant)->localTransform(
p1,
p2,
p3,&size);
304 QTransform inv = t.inverted();
305 if (t.map(
p1).x() * t.map(
p2).x() > 0) {
309 const QPointF safe_start = QPointF(-1.0*t.map(
p1).x(),t.map(
p1).y());
312 const QPointF safe_start = QPointF(-1.0*t.map(
p2).x(),t.map(
p1).y());
322 }
else if (
m_handleDrag && assistant->id() ==
"vanishing point" &&
353 QPointF uiMousePosition = initialTransform.map(canvasDecoration->
snapToGuide(event, QPointF(),
false));
358 QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.
boundingSize));
365 QPointF actionsBGRectangle(actionsPosition + QPointF(globalEditorWidgetData.
widgetOffset,globalEditorWidgetData.
widgetOffset));
366 QRectF editorWidget = QRectF(actionsBGRectangle.x(), actionsBGRectangle.y(), globalEditorWidgetData.
boundingSize.width(), globalEditorWidgetData.
boundingSize.height());
368 if (editorWidget.contains(uiMousePosition)) {
369 assistantsPressed.push_back(assistant);
375 if (!assistantsPressed.isEmpty()) {
379 m_canvas->paintingAssistantsDecoration()->raiseAssistant(assistant);
383 QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.
boundingSize));
387 QPointF iconMovePosition(actionsPosition + globalEditorWidgetData.
moveIconPosition);
388 QRectF moveRect(iconMovePosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
390 if (moveRect.contains(uiMousePosition) && !assistant->isLocked()) {
401 QPointF iconSnapPosition(actionsPosition + globalEditorWidgetData.
snapIconPosition);
402 QRectF visibleRect(iconSnapPosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
403 if (visibleRect.contains(uiMousePosition)) {
404 newAssistantAllowed =
false;
405 assistant->setSnappingActive(!assistant->isSnappingActive());
406 assistant->uncache();
412 QPointF iconLockPosition(actionsPosition + globalEditorWidgetData.
lockedIconPosition);
413 QRectF lockRect(iconLockPosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
414 if (lockRect.contains(uiMousePosition)) {
416 assistant->setLocked(!assistant->isLocked());
425 QRectF duplicateRect(iconDuplicatePosition,QSizeF(globalEditorWidgetData.
buttonSize,globalEditorWidgetData.
buttonSize));
427 if (duplicateRect.contains(uiMousePosition)) {
429 QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> handleMap;
437 m_canvas->viewManager()->undoAdapter()->addCommand(addAssistantCmd);
444 if(assistant->isLocked()) {
445 newAssistantAllowed =
false;
466 QPointF iconDeletePosition(actionsPosition + globalEditorWidgetData.
deleteIconPosition);
467 QRectF deleteRect(iconDeletePosition, QSizeF(globalEditorWidgetData.
buttonSize, globalEditorWidgetData.
buttonSize));
468 if (deleteRect.contains(uiMousePosition) && !assistant->isLocked()) {
470 if(
m_canvas->paintingAssistantsDecoration()->assistants().isEmpty()) {
479 if((QRectF(actionsPosition + QPointF(10, 10), globalEditorWidgetData.
boundingSize).adjusted(-2, -2, 2, 2).contains(uiMousePosition))) {
480 newAssistantAllowed =
false;
491 if (newAssistantAllowed==
true) {
492 QString key =
m_options.availableAssistantsComboBox->model()->index(
m_options.availableAssistantsComboBox->currentIndex(), 0 ).data(Qt::UserRole).toString();
493 KConfigGroup cfg = KSharedConfig::openConfig()->group(
toolId());
494 cfg.writeEntry(
"AssistantType", key);
509 m_newAssistant->setAssistantGlobalColorCache(
m_canvas->paintingAssistantsDecoration()->globalAssistantsColor());
531 if (!(event->
modifiers() & Qt::ShiftModifier)) {
532 double minDist = 49.0;
533 QPointF mousePos =
m_canvas->viewConverter()->documentToView(event->
point);
540 if (dist < minDist) {
549 if (event->
modifiers() & Qt::ShiftModifier ) {
568 QPointF currentOffset = selectedAssistant->editorWidgetOffset();
569 selectedAssistant->setEditorWidgetOffset(currentOffset + (event->
point -
m_dragEnd));
577 QPointF mousep =
m_canvas->viewConverter()->documentToView(event->
point);
578 QList <KisPaintingAssistantSP> pAssistant=
m_canvas->paintingAssistantsDecoration()->assistants();
581 if(assistant->id() ==
"perspective") {
593 if(
m_handleDrag && assistant->id() ==
"vanishing point" && assistant->sideHandles().size()==4) {
596 QLineF perspectiveline = QLineF(*assistant->handles()[0],
597 *assistant->sideHandles()[0]);
599 qreal
length = QLineF(*assistant->sideHandles()[0],
600 *assistant->sideHandles()[1]).length();
606 length += perspectiveline.length();
607 perspectiveline.setLength(
length);
608 *assistant->sideHandles()[1] = perspectiveline.p2();
611 QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]);
612 qreal
length = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length();
618 length += perspectiveline.length();
619 perspectiveline.setLength(
length);
620 *assistant->sideHandles()[3] = perspectiveline.p2();
623 QPointF vanishingpoint(0,0);
624 QLineF perspectiveline = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]);
625 QLineF perspectiveline2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]);
627 if (QLineF(perspectiveline2).intersects(QLineF(perspectiveline), &vanishingpoint) != QLineF::NoIntersection){
628 *assistant->handles()[0] = vanishingpoint;
632 QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[0]);
633 QLineF perspectiveline2 = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]);
634 qreal
length = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]).length();
635 qreal length2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length();
645 length += perspectiveline.length();
646 length2 += perspectiveline2.length();
647 perspectiveline.setLength(
length);
648 perspectiveline2.setLength(length2);
649 *assistant->sideHandles()[1] = perspectiveline.p2();
650 *assistant->sideHandles()[3] = perspectiveline2.p2();
654 if (
m_handleDrag && assistant->id() ==
"two point" && assistant->handles().size() >= 3 &&
655 assistant->sideHandles().size() == 8) {
660 const bool far_handle_is_dragged =
664 if (far_handle_is_dragged) {
665 QLineF perspective_line_a, perspective_line_b;
666 QPointF vp_new_pos(0,0);
670 perspective_line_a = QLineF(*side_hndl[0],*side_hndl[1]);
671 perspective_line_b = QLineF(*side_hndl[4],*side_hndl[5]);
674 perspective_line_a = QLineF(*side_hndl[3],*side_hndl[2]);
675 perspective_line_b = QLineF(*side_hndl[6],*side_hndl[7]);
677 if (perspective_line_a.intersects(perspective_line_b, &vp_new_pos) != QLineF::NoIntersection) {
678 *vp_moved = vp_new_pos;
681 QLineF perspective_line_a1;
682 QLineF perspective_line_b1;
683 QLineF perspective_line_a2;
684 QLineF perspective_line_b2;
686 perspective_line_a1 = QLineF(*hndl[0], *side_hndl[0]);
687 perspective_line_a1.setLength(QLineF(*side_hndl[0],*side_hndl[1]).
length());
688 perspective_line_a1.translate(*side_hndl[0] - perspective_line_a1.p1());
689 *side_hndl[1] = perspective_line_a1.p2();
691 perspective_line_b1 = QLineF(*hndl[0], *side_hndl[4]);
692 perspective_line_b1.setLength(QLineF(*side_hndl[4],*side_hndl[5]).
length());
693 perspective_line_b1.translate(*side_hndl[4] - perspective_line_b1.p1());
694 *side_hndl[5] = perspective_line_b1.p2();
696 perspective_line_a2 = QLineF(*hndl[1], *side_hndl[2]);
697 perspective_line_a2.setLength(QLineF(*side_hndl[2],*side_hndl[3]).
length());
698 perspective_line_a2.translate(*side_hndl[2] - perspective_line_a2.p1());
699 *side_hndl[3] = perspective_line_a2.p2();
701 perspective_line_b2 = QLineF(*hndl[1], *side_hndl[6]);
702 perspective_line_b2.setLength(QLineF(*side_hndl[6],*side_hndl[7]).
length());
703 perspective_line_b2.translate(*side_hndl[6] - perspective_line_b2.p1());
704 *side_hndl[7] = perspective_line_b2.p2();
709 if (
m_handleDrag && (assistant->id() ==
"ruler" || assistant->id() ==
"infinite ruler")
710 && qSharedPointerCast<RulerAssistant>(assistant)->hasFixedLength()
711 && assistant->isAssistantComplete()) {
721 QPointF center = *ruler->handles()[0];
722 QPointF handle = *ruler->handles()[1];
724 QPointF direction = handle - center;
726 QPointF delta = direction /
distance * ruler->fixedLength();
728 *ruler->handles()[1] = center + delta;
864 int horizontalButtonCount = 0;
872 horizontalButtonCount++;
873 if(horizontalButtonCount > horizontalButtonLimit)
875 horizontalButtonCount = 1;
887 horizontalButtonCount++;
888 if(horizontalButtonCount > horizontalButtonLimit)
890 horizontalButtonCount = 1;
900 horizontalButtonCount++;
901 if(horizontalButtonCount > horizontalButtonLimit)
903 horizontalButtonCount = 1;
913 horizontalButtonCount++;
914 if(horizontalButtonCount > horizontalButtonLimit)
916 horizontalButtonCount = 0;
926 horizontalButtonCount++;
927 if(horizontalButtonCount > horizontalButtonLimit)
929 horizontalButtonCount = 1;
939 int boundingWidgetWidth = (buttonCount < horizontalButtonLimit) ? buttonCount*buttonSection:horizontalButtonLimit*buttonSection;
940 boundingWidgetWidth += 5;
943 int buttonToWidthRatio = (buttonCount/horizontalButtonLimit);
944 if(buttonCount%horizontalButtonLimit != 0) {
945 buttonToWidthRatio++;
948 int boundingWidgetHeight = buttonToWidthRatio*buttonSection;
949 boundingWidgetHeight += 5;
950 globalEditorWidgetData.
boundingSize.setHeight(boundingWidgetHeight);
953 m_canvas->updateCanvasDecorations();
980 bool hasActiveAssistant = m_selectedAssistant ? true :
false;
993 m_options.showDuplicate->setChecked(
true);
999 if (m_selectedAssistant) {
1000 bool isVanishingPointAssistant = m_selectedAssistant->id() ==
"vanishing point";
1001 bool isTwoPointAssistant = m_selectedAssistant->id() ==
"two point";
1002 bool isRulerAssistant = m_selectedAssistant->id() ==
"ruler"
1003 || m_selectedAssistant->id() ==
"infinite ruler";
1004 bool isPerspectiveAssistant = m_selectedAssistant->id() ==
"perspective";
1006 m_options.vanishingPointAngleSpinbox->setVisible(isVanishingPointAssistant);
1007 m_options.twoPointDensitySpinbox->setVisible(isTwoPointAssistant);
1008 m_options.twoPointUseVerticalCheckbox->setVisible(isTwoPointAssistant);
1009 m_options.subdivisionsSpinbox->setVisible(isRulerAssistant || isPerspectiveAssistant);
1010 m_options.minorSubdivisionsSpinbox->setVisible(isRulerAssistant);
1011 m_options.fixedLengthCheckbox->setVisible(isRulerAssistant);
1016 m_options.showDuplicate->setVisible(
true);
1021 if (isVanishingPointAssistant) {
1022 QSharedPointer <VanishingPointAssistant> assis = qSharedPointerCast<VanishingPointAssistant>(m_selectedAssistant);
1023 m_options.vanishingPointAngleSpinbox->setValue(assis->referenceLineDensity());
1026 if (isTwoPointAssistant) {
1027 QSharedPointer <TwoPointAssistant> assis = qSharedPointerCast<TwoPointAssistant>(m_selectedAssistant);
1028 m_options.twoPointDensitySpinbox->setValue(assis->gridDensity());
1029 m_options.twoPointUseVerticalCheckbox->setChecked(assis->useVertical());
1032 if (isRulerAssistant) {
1033 QSharedPointer <RulerAssistant> assis = qSharedPointerCast<RulerAssistant>(m_selectedAssistant);
1034 m_options.subdivisionsSpinbox->setValue(assis->subdivisions());
1035 m_options.minorSubdivisionsSpinbox->setValue(assis->minorSubdivisions());
1036 m_options.fixedLengthCheckbox->setChecked(assis->hasFixedLength());
1038 m_options.fixedLengthSpinbox->setVisible(assis->hasFixedLength());
1039 m_options.fixedLengthUnit->setVisible(assis->hasFixedLength());
1042 QSignalBlocker b(
m_options.fixedLengthSpinbox);
1045 m_options.fixedLengthSpinbox->changeValue(assis->fixedLength());
1047 m_options.fixedLengthSpinbox->setPrefix(
"");
1049 m_options.fixedLengthSpinbox->setVisible(
false);
1050 m_options.fixedLengthUnit->setVisible(
false);
1053 if (isPerspectiveAssistant) {
1054 QSharedPointer <PerspectiveAssistant> assis = qSharedPointerCast<PerspectiveAssistant>(m_selectedAssistant);
1055 m_options.subdivisionsSpinbox->setValue(assis->subdivisions());
1059 m_options.useCustomAssistantColor->setChecked(m_selectedAssistant->useCustomColor());
1060 m_options.customAssistantColorButton->setColor(m_selectedAssistant->assistantCustomColor());
1063 double opacity = (double)m_selectedAssistant->assistantCustomColor().alpha()/(double)255.00 * (
double)100.00 ;
1064 opacity = ceil(opacity);
1066 m_options.customColorOpacitySlider->blockSignals(
true);
1067 m_options.customColorOpacitySlider->setValue((
double)opacity);
1068 m_options.customColorOpacitySlider->blockSignals(
false);
1071 m_options.vanishingPointAngleSpinbox->setVisible(
false);
1072 m_options.twoPointDensitySpinbox->setVisible(
false);
1073 m_options.twoPointUseVerticalCheckbox->setVisible(
false);
1074 m_options.subdivisionsSpinbox->setVisible(
false);
1075 m_options.minorSubdivisionsSpinbox->setVisible(
false);
1076 m_options.fixedLengthCheckbox->setVisible(
false);
1077 m_options.fixedLengthSpinbox->setVisible(
false);
1078 m_options.fixedLengthUnit->setVisible(
false);
1082 m_options.useCustomAssistantColor->setVisible(hasActiveAssistant);
1085 bool showCustomColorSettings =
m_options.useCustomAssistantColor->isChecked() && hasActiveAssistant;
1086 m_options.customColorOpacitySlider->setVisible(showCustomColorSettings);
1087 m_options.customAssistantColorButton->setVisible(showCustomColorSettings);
1090 m_options.assistantsGlobalOpacitySlider->setEnabled(!showCustomColorSettings);
1091 m_options.assistantsColor->setEnabled(!showCustomColorSettings);
1092 m_options.globalColorLabel->setEnabled(!showCustomColorSettings);
1094 QString key =
m_options.availableAssistantsComboBox->model()->index(
m_options.availableAssistantsComboBox->currentIndex(), 0 ).data(Qt::UserRole).toString();
1095 m_options.localAssistantCheckbox->setVisible(key ==
"two point" || key ==
"vanishing point" || key ==
"parallel ruler");
1438 dialog.setCaption(i18n(
"Select an Assistant"));
1439 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1440 dialog.setMimeTypeFilters(
QStringList() <<
"application/x-krita-assistant",
"application/x-krita-assistant");
1441 QString filename = dialog.filename();
1443 QFile file(filename);
1444 if (!file.open(QIODevice::ReadOnly)) {
return; }
1446 QByteArray data = file.readAll();
1447 QXmlStreamReader xml(data);
1448 QMap<int, KisPaintingAssistantHandleSP> handleMap;
1449 QMap<int, KisPaintingAssistantHandleSP> sideHandleMap;
1451 bool errors =
false;
1456 while (!xml.atEnd()) {
1457 switch (xml.readNext()) {
1458 case QXmlStreamReader::StartElement:
1459 if (xml.name() ==
"handle") {
1460 if (assistant && !xml.attributes().value(
"ref").isEmpty()) {
1468 QString strId = xml.attributes().value(
"id").toString(),
1469 strX = xml.attributes().value(
"x").toString(),
1470 strY = xml.attributes().value(
"y").toString();
1474 if (!strId.isEmpty() && !strX.isEmpty() && !strY.isEmpty()) {
1475 int id = strId.toInt();
1476 double x = strX.toDouble(),
1477 y = strY.toDouble();
1478 if (!handleMap.contains(
id)) {
1488 }
else if (xml.name() ==
"sidehandle"){
1491 if (!xml.attributes().value(
"id").isEmpty()) {
1492 QString strId = xml.attributes().value(
"id").toString(),
1493 strX = xml.attributes().value(
"x").toString(),
1494 strY = xml.attributes().value(
"y").toString();
1495 if (!strId.isEmpty() && !strX.isEmpty() && !strY.isEmpty()) {
1496 int id = strId.toInt();
1497 double x = strX.toDouble();
1498 double y = strY.toDouble();
1499 if (!sideHandleMap.contains(
id)) {
1504 if (!xml.attributes().value(
"ref").isEmpty() && assistant) {
1511 }
else if (xml.name() ==
"assistant") {
1526 if (xml.attributes().hasAttribute(
"useCustomColor")) {
1527 auto useCustomColor = xml.attributes().value(
"useCustomColor");
1529 bool usingColor =
false;
1530 if (useCustomColor.toString() ==
"1") {
1533 assistant->setUseCustomColor(usingColor);
1536 if ( xml.attributes().hasAttribute(
"useCustomColor")) {
1537 auto customColor = xml.attributes().value(
"customColor");
1545 assistant->loadCustomXml(&xml);
1550 case QXmlStreamReader::EndElement:
1551 if (xml.name() ==
"assistant") {
1553 if (assistant->handles().size() == assistant->numHandles()) {
1554 if (assistant->id() ==
"vanishing point" && sideHandleMap.empty()){
1556 QPointF pos = *assistant->handles()[0];
1562 m_canvas->paintingAssistantsDecoration()->addAssistant(assistant);
1580 if (xml.hasError()) {
1581 QMessageBox::warning(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), xml.errorString());
1584 QMessageBox::warning(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Errors were encountered. Not all assistants were successfully loaded."));
1588 m_canvas->viewManager()->undoAdapter()->addCommand(command);
1600 QXmlStreamWriter xml(&data);
1601 xml.writeStartDocument();
1602 xml.writeStartElement(
"paintingassistant");
1603 xml.writeAttribute(
"color",
1605 m_canvas->paintingAssistantsDecoration()->globalAssistantsColor()));
1608 xml.writeStartElement(
"handles");
1609 QMap<KisPaintingAssistantHandleSP, int> handleMap;
1611 int id = handleMap.size();
1612 handleMap.insert(handle,
id);
1613 xml.writeStartElement(
"handle");
1615 xml.writeAttribute(
"id", QString::number(
id));
1616 xml.writeAttribute(
"x", QString::number(
double(handle->x()),
'f', 3));
1617 xml.writeAttribute(
"y", QString::number(
double(handle->y()),
'f', 3));
1618 xml.writeEndElement();
1620 xml.writeEndElement();
1621 xml.writeStartElement(
"sidehandles");
1622 QMap<KisPaintingAssistantHandleSP, int> sideHandleMap;
1625 int id = sideHandleMap.size();
1626 sideHandleMap.insert(handle,
id);
1627 xml.writeStartElement(
"sidehandle");
1628 xml.writeAttribute(
"id", QString::number(
id));
1629 xml.writeAttribute(
"x", QString::number(
double(handle->x()),
'f', 3));
1630 xml.writeAttribute(
"y", QString::number(
double(handle->y()),
'f', 3));
1631 xml.writeEndElement();
1634 xml.writeStartElement(
"assistants");
1638 xml.writeStartElement(
"assistant");
1639 xml.writeAttribute(
"type", assistant->id());
1640 xml.writeAttribute(
"useCustomColor", QString::number(assistant->useCustomColor()));
1646 assistant->saveCustomXml(&xml);
1649 xml.writeStartElement(
"handles");
1651 xml.writeStartElement(
"handle");
1652 xml.writeAttribute(
"ref", QString::number(handleMap.value(handle)));
1653 xml.writeEndElement();
1655 xml.writeEndElement();
1656 if (!sideHandleMap.empty()) {
1657 xml.writeStartElement(
"sidehandles");
1659 xml.writeStartElement(
"sidehandle");
1660 xml.writeAttribute(
"ref", QString::number(sideHandleMap.value(handle)));
1661 xml.writeEndElement();
1663 xml.writeEndElement();
1665 xml.writeEndElement();
1667 xml.writeEndElement();
1668 xml.writeEndElement();
1669 xml.writeEndDocument();
1672 dialog.setCaption(i18n(
"Save Assistant"));
1673 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1674 dialog.setMimeTypeFilters(
QStringList() <<
"application/x-krita-assistant",
"application/x-krita-assistant");
1675 QString filename = dialog.filename();
1676 if (filename.isEmpty())
return;
1678 QFile file(filename);
1679 if (file.open(QIODevice::WriteOnly)) {
1682 qWarning() <<
"Couldn't open file" << file.fileName() <<
"for writing:" << file.errorString();
1692 KConfigGroup cfg = KSharedConfig::openConfig()->group(
toolId());
1696 specialSpacer->setObjectName(
"SpecialSpacer");
1697 specialSpacer->setFixedSize(0, 0);
1701 m_options.loadAssistantButton->setIconSize(QSize(16, 16));
1703 m_options.saveAssistantButton->setIconSize(QSize(16, 16));
1705 m_options.deleteAllAssistantsButton->setIconSize(QSize(16, 16));
1708 m_options.showDockerOptionsButton->setIconSize(QSize(16, 16));
1713 assistants <<
KoID(key, name);
1717 QString currentAssistantType = cfg.readEntry(
"AssistantType",
"two point");
1719 int currentAssistantIndex = 0;
1720 Q_FOREACH(
const KoID &
id, assistants) {
1721 m_options.availableAssistantsComboBox->addItem(
id.name(),
id.
id());
1722 if (
id.
id() == currentAssistantType) {
1723 currentAssistantIndex = i;
1727 m_options.availableAssistantsComboBox->setCurrentIndex(currentAssistantIndex);
1756 const QColor color =
m_canvas->paintingAssistantsDecoration()->globalAssistantsColor();
1758 QColor opaqueColor = color;
1759 opaqueColor.setAlpha(255);
1761 m_options.assistantsColor->setColor(opaqueColor);
1762 m_options.customAssistantColorButton->setColor(opaqueColor);
1763 m_options.assistantsGlobalOpacitySlider->setValue(color.alphaF() * 100.0);
1766 m_options.assistantsColor->setColor(QColor(176, 176, 176, 255));
1767 m_options.assistantsGlobalOpacitySlider->setValue(100);
1770 m_options.assistantsGlobalOpacitySlider->setPrefix(i18n(
"Opacity: "));
1771 m_options.assistantsGlobalOpacitySlider->setSuffix(
" %");
1775 m_options.customColorOpacitySlider->setValue(100);
1776 m_options.customColorOpacitySlider->setPrefix(i18n(
"Opacity: "));
1777 m_options.customColorOpacitySlider->setSuffix(
" %");
1783 m_options.twoPointDensitySpinbox->setPrefix(i18n(
"Density: "));
1784 m_options.twoPointDensitySpinbox->setRange(0.1, 4.0, 2);
1785 m_options.twoPointDensitySpinbox->setSingleStep(0.1);
1787 m_options.vanishingPointAngleSpinbox->setPrefix(i18n(
"Density: "));
1788 m_options.vanishingPointAngleSpinbox->setSuffix(QStringLiteral(
"°"));
1789 m_options.vanishingPointAngleSpinbox->setRange(1.0, 180.0);
1790 m_options.vanishingPointAngleSpinbox->setSingleStep(1.0);
1792 m_options.subdivisionsSpinbox->setPrefix(i18n(
"Subdivisions: "));
1793 m_options.subdivisionsSpinbox->setRange(0, 100);
1794 m_options.subdivisionsSpinbox->setSoftRange(0, 20);
1796 m_options.minorSubdivisionsSpinbox->setPrefix(i18n(
"Minor Subdivisions: "));
1797 m_options.minorSubdivisionsSpinbox->setRange(1, 5);
1801 m_options.fixedLengthSpinbox->setDisplayUnit(
false);
1802 m_options.fixedLengthSpinbox->setMinimum(0);
1808 m_options.vanishingPointAngleSpinbox->setVisible(
false);
1809 m_options.twoPointDensitySpinbox->setVisible(
false);
1810 m_options.subdivisionsSpinbox->setVisible(
false);
1811 m_options.minorSubdivisionsSpinbox->setVisible(
false);
1812 m_options.fixedLengthCheckbox->setVisible(
false);
1813 m_options.fixedLengthSpinbox->setVisible(
false);
1814 m_options.fixedLengthUnit->setVisible(
false);
1817 m_options.localAssistantCheckbox->setChecked(cfg.readEntry(
"LimitAssistantToArea",
false));
1837 m_options.showDuplicate->setChecked(
true);
2000 if (event->
modifiers() == Qt::NoModifier) {
2009 if (selectedAssistant->id() ==
"two point" &&
m_handleDrag != handles[2] &&
2010 event->
modifiers() != Qt::ShiftModifier) {
2020 const QTransform t = assis->localTransform(prevPoint,*handleOpp,*handles[2],&size);
2021 const QTransform inv = t.inverted();
2026 const QLineF horizon = QLineF(t.map(prevPoint), QPointF(t.map(*handleOpp).x(),t.map(prevPoint).y()));
2027 const QPointF sp = QPointF(0,horizon.p1().y()+size);
2029 const bool preserve_distortion_snap =
event->modifiers() == Qt::ControlModifier;
2030 const bool preserve_left_right_ratio_snap =
event->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier);
2031 const bool preserve_horizon_snap =
event->modifiers() == Qt::AltModifier;
2034 QPointF opp_snap_point;
2035 QLineF sp_to_opp_vp;
2037 if (preserve_distortion_snap) {
2038 const QLineF sp_to_vp = QLineF(sp, t.map(*
m_handleDrag));
2039 sp_to_opp_vp = sp_to_vp.normalVector();
2040 sp_to_vp.intersects(horizon,&snap_point);
2041 }
else if (preserve_left_right_ratio_snap) {
2042 const QLineF prev_sp_to_vp = QLineF(sp, horizon.p1());
2043 QLineF new_sp_to_vp = prev_sp_to_vp.translated(t.map(*
m_handleDrag)-sp);
2045 new_sp_to_vp.intersects(QLineF(QPoint(0,0),QPointF(0,1)),&new_sp);
2046 sp_to_opp_vp = new_sp_to_vp.normalVector().translated(new_sp-new_sp_to_vp.p1());
2047 new_sp_to_vp.intersects(horizon,&snap_point);
2048 }
else if (preserve_horizon_snap) {
2049 snap_point = QPointF(t.map(*m_handleDrag).x(),horizon.p1().y());
2050 sp_to_opp_vp = QLineF(sp,QPointF(t.map(prevPoint).x(),horizon.p1().y())).normalVector();
2056 const bool no_intersection =
2058 sp_to_opp_vp.intersects(horizon, &opp_snap_point) == QLineF::NoIntersection;
2059 const bool origin_is_between =
2060 (snap_point.x() < 0 && opp_snap_point.x() > 0) ||
2061 (snap_point.x() > 0 && opp_snap_point.x() < 0);
2062 const bool null_opp_point =
2065 const bool overlapping_snap_points =
2069 if (!origin_is_between || no_intersection || null_opp_point || overlapping_snap_points) {
2074 if (preserve_distortion_snap) {
2075 sp_to_opp_vp = QLineF(sp, t.map(
m_dragStart)).normalVector();
2076 sp_to_opp_vp.intersects(horizon, &oppStart);
2079 const qreal p2x = preserve_horizon_snap ? t.map(*handleOpp).x() : -
p1.x();
2080 const QPointF
p2 = QPointF(p2x,
p1.y());
2081 const QLineF new_horizon = QLineF(
p1,
p2);
2082 const qreal new_size = sqrt(pow(new_horizon.length()/2.0,2) -
2083 pow(abs(new_horizon.center().x()),2));
2084 const QPointF new_sp = QPointF(0,horizon.p1().y()+new_size);
2085 sp_to_opp_vp = QLineF(new_sp, t.map(
m_dragStart)).normalVector();
2087 sp_to_opp_vp.intersects(horizon, &oppStart);
2088 *handleOpp=inv.map(oppStart);
2093 *handleOpp = inv.map(opp_snap_point);
2098 dragRadius.setLength(
m_radius.length());
2109 if (handles.size() == 2) {
2111 *handle_snap = snap_point;
2113 bool was_snapped =
false;
2116 handles.size() == 3 ? start = handles[0] : start = handles[1];
2118 *handle_snap = snap_point;
2125 QPointF center = QLineF(*handles[0], *handles[1]).center();
2126 QLineF radius = QLineF(center,*handles[0]);
2127 QLineF dragRadius = QLineF(center, event->
point);
2128 dragRadius.setLength(radius.length());
2129 *handle_snap = dragRadius.p2();
2135 handles.size() == 3 ? start = handles[1] : start = handles[2];
2137 *handle_snap = snap_point;