Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_painting_assistants_decoration.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2017 Scott Petrovic <scottpetrovic@gmail.com>
4 * SPDX-FileCopyrightText: 2026 Ayanami Kaine <personal@ayanamikaine.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
10
11#include <optional>
12#include <cstdint>
13#include <limits>
14
15#include <QList>
16#include <QPointF>
17#include <klocalizedstring.h>
18#include <kactioncollection.h>
19#include <ktoggleaction.h>
20#include <kis_algebra_2d.h>
21#include "kis_debug.h"
22#include "KisDocument.h"
23#include "kis_canvas2.h"
25#include "kis_icon_utils.h"
26#include "KisViewManager.h"
27#include <KoColor.h>
30#include "kis_tool_proxy.h"
32
33#include <QPainter>
34#include <QPainterPath>
35#include <QApplication>
36
38
39namespace {
40bool hasLockedValidTemporaryConstraint(const std::optional<KisTemporaryPaintConstraint> &constraint)
41{
42 return constraint && constraint->isLocked() && constraint->hasValidLine();
43}
44}
45
72
73
74
76 KisCanvasDecoration("paintingAssistantsDecoration", parent),
77 d(new Private)
78{
81 setPriority(95);
82 d->snapOnlyOneAssistant = true; //turn on by default.
83 d->snapEraser = false;
84
85 slotConfigChanged(); // load the initial config
86}
87
92
94{
95 const bool shouldBeVisible = !assistants().isEmpty() || d->temporaryConstraint.has_value();
96
97 if (visible() != shouldBeVisible) {
98 setVisible(shouldBeVisible);
99 }
100}
101
111
113{
114 QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
115 if (assistants.contains(assistant)) return;
116
117 assistants.append(assistant);
118 assistant->setAssistantGlobalColorCache(view()->document()->assistantsGlobalColor());
119
120 view()->document()->setAssistants(assistants);
122 Q_EMIT assistantChanged();
123}
124
125// bring assistant to front of assistants list, effectively causing assistant to be rendered above the others
127{
128 QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
129 assistants.removeOne(assistant);
130
131 if (!assistant) return;
132 assistants.append(assistant);
133
134 view()->document()->setAssistants(assistants);
136 Q_EMIT assistantChanged();
137
138}
139
141{
142 QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
143 KIS_ASSERT_RECOVER_NOOP(assistants.contains(assistant));
144
145 if (assistants.removeAll(assistant)) {
146 view()->document()->setAssistants(assistants);
148 Q_EMIT assistantChanged();
149 }
150}
151
153{
154 QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
155 assistants.clear();
156 view()->document()->setAssistants(assistants);
158
159 Q_EMIT assistantChanged();
160}
161
163{
164 Q_FOREACH (KisPaintingAssistantSP assistant, assistants) {
165 assistant->setAssistantGlobalColorCache(view()->document()->assistantsGlobalColor());
166 }
167 view()->document()->setAssistants(assistants);
169
170 Q_EMIT assistantChanged();
171}
172
174{
175 if (hasLockedValidTemporaryConstraint(d->temporaryConstraint)) {
178
179 if (d->m_canvas) {
181 }
182 }
183
184 if (!assistants().empty()) {
185 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
186 assistant->setAdjustedBrushPosition(position);
187 }
188 }
189}
190
191
192QPointF KisPaintingAssistantsDecoration::adjustPosition(const QPointF& point, const QPointF& strokeBegin)
193{
194 if (assistants().empty() && !hasLockedValidTemporaryConstraint(d->temporaryConstraint)) {
195 // No assistants, so no adjustment
196 return point;
197 }
198
199 if (!d->m_canvas && view()) {
200 d->m_canvas = view()->canvasBase();
201 }
202
203 if (!d->m_canvas) {
204 return point;
205 }
206
207 if (!d->snapEraser
209 // No snapping if eraser snapping is disabled and brush is an eraser
210 return point;
211 }
212
213 KisImageSP image = d->m_canvas->image();
215
217 const qreal moveThresholdPt = 4.0 / (converter->effectiveZoom() * qMax(image->xRes(), image->yRes()));
218
219 if (hasLockedValidTemporaryConstraint(d->temporaryConstraint)) {
220 return d->temporaryConstraint->adjustPosition(point, strokeBegin, false, 0.0);
221 }
222
223 QPointF best = point;
224 qreal minSquareDistance = std::numeric_limits<qreal>::max();
225 qreal secondSquareDistance = std::numeric_limits<qreal>::max();
226
228 // In these cases the best assistant needs to be determined.
229 int numSuitableAssistants = 0;
230 KisPaintingAssistantSP bestAssistant;
231
232 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
233 if (assistant->isSnappingActive() == true){ // the toggle button with eye icon to disable assistants
234 QPointF newpoint = assistant->adjustPosition(point, strokeBegin, true, moveThresholdPt);
235 // Assistants that can't or don't want to snap return NaN values (aside from possible numeric issues)
236 // NOTE: It would be safer to also reject points too far outside canvas (or widget?) area,
237 // because for example squashed concentric ellipses can currently shoot points far off.
238 if (qIsNaN(newpoint.x()) || qIsNaN(newpoint.y())) {
239 continue;
240 }
241 ++numSuitableAssistants;
242 qreal dist = kisSquareDistance(newpoint, point);
243 if (dist < minSquareDistance) {
244 best = newpoint;
245 secondSquareDistance = minSquareDistance;
246 minSquareDistance = dist;
247 bestAssistant = assistant;
248 } else if (dist < secondSquareDistance) {
249 secondSquareDistance = dist;
250 }
251 assistant->setFollowBrushPosition(true);
252 }
253 }
254
255 // When there are multiple choices within moveThresholdPt, delay the decision until movement leaves
256 // threshold to determine which curve follows cursor movement the closest. Assistants with multiple
257 // snapping curves also need this movement to decide the best choice.
258 // NOTE: It is currently not possible to tell painting tools that a decision is pending, or that
259 // the active snapping curve changed, so certain artifact lines from snapping changes are unavoidable.
260
261 if (numSuitableAssistants > 1 && KisAlgebra2D::norm(point - strokeBegin) <= moveThresholdPt
262 && (sqrt(secondSquareDistance) < moveThresholdPt)) {
263 return strokeBegin;
264 } else if (numSuitableAssistants > 0 && d->snapOnlyOneAssistant) {
265 // if only snapping to one assistant, register it
266 d->firstAssistant = bestAssistant;
267 }
268 } else {
269 // Make sure BUG:448187 doesn't crop up again
270 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(d->firstAssistant->isSnappingActive(), point);
271 // there already is an assistant locked in, check if it can be used
272 QPointF newpoint = d->firstAssistant->adjustPosition(point, strokeBegin, false, moveThresholdPt);
273 // BUGFIX: 402535
274 // assistants might return (NaN,NaN), must always check for that
275 if (!(qIsNaN(newpoint.x()) || qIsNaN(newpoint.y()))) {
276 best = newpoint;
277 }
278 }
279
280 return best;
281}
282
283void KisPaintingAssistantsDecoration::adjustLine(QPointF &point, QPointF &strokeBegin)
284{
285 if (assistants().empty()) {
286 // No assistants, so no adjustment
287 return;
288 }
289
290 // TODO: figure it out
291 if (!d->snapEraser
293 // No snapping if eraser snapping is disabled and brush is an eraser
294 return;
295 }
296
297 QPointF originalPoint = point;
298 QPointF originalStrokeBegin = strokeBegin;
299
300 qreal minDistance = 10000.0;
301 bool minDistValid = false;
302 QPointF finalPoint = originalPoint;
303 QPointF finalStrokeBegin = originalStrokeBegin;
304 KisPaintingAssistantSP bestAssistant;
305 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
306 if(assistant->isSnappingActive() == true){//this checks if the assistant in question has it's snapping boolean turned on//
307 //QPointF pt = assistant->adjustPosition(point, strokeBegin, true);
308 QPointF p1 = originalPoint;
309 QPointF p2 = originalStrokeBegin;
310 assistant->adjustLine(p1, p2);
311 if (p1.isNull() || p2.isNull()) {
312 // possibly lines cannot snap to this assistant, or this line cannot, at least
313 continue;
314 }
315 qreal distance = kisSquareDistance(p1, originalPoint) + kisSquareDistance(p2, originalStrokeBegin);
316 if (distance < minDistance || !minDistValid) {
317 finalPoint = p1;
318 finalStrokeBegin = p2;
319 minDistValid = true;
320 bestAssistant = assistant;
321 }
322 }
323 }
324 if (bestAssistant) {
325 bestAssistant->setFollowBrushPosition(true);
326 }
327 point = finalPoint;
328 strokeBegin = finalStrokeBegin;
329}
330
332{
333 d->firstAssistant.clear();
334
335 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
336 assistant->endStroke();
337 }
338}
339
340void KisPaintingAssistantsDecoration::setTemporaryConstraint(std::optional<KisTemporaryPaintConstraint> constraint)
341{
342 const bool hadTemporaryConstraint = d->temporaryConstraint.has_value();
343 d->temporaryConstraint = constraint;
344 const bool hasTemporaryConstraint = d->temporaryConstraint.has_value();
345
346 if (!hasLockedValidTemporaryConstraint(d->temporaryConstraint)) {
348 }
349
350 if (hadTemporaryConstraint != hasTemporaryConstraint) {
352 }
353
355
356 if (d->m_canvas) {
358 }
359}
360
361std::optional<KisTemporaryPaintConstraint> KisPaintingAssistantsDecoration::temporaryConstraint() const
362{
363 return d->temporaryConstraint;
364}
365
366void KisPaintingAssistantsDecoration::drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, KisCanvas2* canvas)
367{
368 if (!canvas) {
369 dbgFile<<"canvas does not exist in painting assistant decoration, you may have passed arguments incorrectly:"<<canvas;
370 } else {
371 d->m_canvas = canvas;
372 }
373
374 if(assistants().isEmpty() && !d->temporaryConstraint) {
375 return; // no assistants to worry about, ok to exit
376 }
377
378 // the preview functionality for assistants. do not show while editing
379
380 KoToolProxy *proxy = view()->canvasBase()->toolProxy();
382 KisToolProxy *kritaProxy = dynamic_cast<KisToolProxy*>(proxy);
384
385 const bool outlineVisible =
388 kritaProxy->supportsPaintingAssistants();
389
390 if (outlineVisible && d->temporaryConstraint && d->temporaryConstraint->hasLine()) {
391 gc.save();
392 gc.resetTransform();
393 gc.setRenderHint(QPainter::Antialiasing, true);
394
395 QTransform initialTransform = converter->documentToWidgetTransform();
396 QPointF p1 = initialTransform.map(d->temporaryConstraint->lineAnchor());
397 QPointF p2 = initialTransform.map(d->temporaryConstraint->lineSecondPoint());
398
399 QColor color = globalAssistantsColor();
400 color.setAlpha(180);
402 pen.setCosmetic(true);
403 gc.setPen(pen);
404
405 if (!d->temporaryConstraint->isLocked()) {
406 QPen anchorOutlinePen(QColor(0, 0, 0, 180), 1.0);
407 anchorOutlinePen.setCosmetic(true);
408 gc.setPen(anchorOutlinePen);
409 gc.setBrush(Qt::NoBrush);
410 gc.drawEllipse(p1, 4.0, 4.0);
411
413 anchorPen.setCosmetic(true);
414 gc.setPen(anchorPen);
415 gc.drawLine(p1 + QPointF(-6.0, 0.0), p1 + QPointF(6.0, 0.0));
416 gc.drawLine(p1 + QPointF(0.0, -6.0), p1 + QPointF(0.0, 6.0));
417 }
418
419 gc.setPen(pen);
420 if (KisAlgebra2D::normSquared(p1 - p2) > 1e-6) {
421 QLineF snapLine(p1, p2);
422 KisAlgebra2D::intersectLineRect(snapLine, gc.viewport(), true);
423
424 QPainterPath path;
425 path.moveTo(snapLine.p1());
426 path.lineTo(snapLine.p2());
427 gc.drawPath(path);
428 }
429
430 if (d->temporaryConstraint) {
431 const QPointF markerDocPos =
434 d->temporaryConstraint->lineSecondPoint();
435
436 const QPointF brushPos = initialTransform.map(markerDocPos);
437 const qreal markerRadius = 9.0;
438
439 QPen markerOutlinePen(QColor(0, 0, 0, 190), 1.0);
440 markerOutlinePen.setCosmetic(true);
441 gc.setPen(markerOutlinePen);
442 gc.setBrush(Qt::NoBrush);
443 gc.drawEllipse(brushPos, markerRadius, markerRadius);
444
446 markerPen.setCosmetic(true);
447 gc.setPen(markerPen);
448 gc.drawEllipse(brushPos, markerRadius - 2.0, markerRadius - 2.0);
449 }
450 gc.restore();
451 }
452
453
454 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
455 assistant->drawAssistant(gc, updateRect, converter, canvas->displayRendererInterface(), d->useCache, canvas, assistantVisibility(), outlineVisible);
456
457 if (isEditingAssistants()) {
458 drawHandles(assistant, gc, converter, canvas->displayRendererInterface());
459 }
460 }
461
462 // draw editor controls on top of all assistant lines (why this code is last)
463 if (isEditingAssistants()) {
464 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
465 drawEditorWidget(assistant, gc, converter, canvas->displayRendererInterface());
466 }
467 }
468}
469
471{
472 QTransform initialTransform = converter->documentToWidgetTransform();
473
474 KoColor c;
475 c.fromQColor(assistant->effectiveAssistantColor());
476 QColor colorToPaint = renderInterface->convertColorToDisplayColorSpace(c);
477
478 Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) {
479
480
481 QPointF transformedHandle = initialTransform.map(*handle);
482 QRectF ellipse(transformedHandle - QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize()));
483
484 QPainterPath path;
485 path.addEllipse(ellipse);
486
487 gc.save();
488 gc.setPen(Qt::NoPen);
489 gc.setBrush(colorToPaint);
490 gc.drawPath(path);
491 gc.restore();
492 }
493
494 // some assistants have side handles like the vanishing point assistant
495 Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) {
496 QPointF transformedHandle = initialTransform.map(*handle);
497 QRectF ellipse(transformedHandle - QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize()));
498
499 QPainterPath path;
500 path.addEllipse(ellipse);
501
502 gc.save();
503 gc.setPen(Qt::NoPen);
504 gc.setBrush(colorToPaint);
505 gc.drawPath(path);
506 gc.restore();
507 }
508}
509
514
519
521{
523 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
524 Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) {
525 if (!hs.contains(handle)) {
526 hs.push_back(handle);
527 }
528 }
529 Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) {
530 if (!hs.contains(handle)) {
531 hs.push_back(handle);
532 }
533 }
534 }
535 return hs;
536}
537
539{
541 if (view()) {
542 if (view()->document()) {
543 assistants = view()->document()->assistants();
544 }
545 }
546 return assistants;
547}
548
550{
551 return !assistants().isEmpty() || hasLockedValidTemporaryConstraint(d->temporaryConstraint);
552}
553
558
564
569
570
575
580
585
587{
588 d->snapEraser = assistant;
589}
590
600{
601 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
602 assistant->uncache();
603 }
604
605 // Redraw canvas decorations in case the change was made off canvas
606 if (d->m_canvas) {
608 }
609}
615
617{
618 // "outline" means assistant preview (line that depends on the mouse cursor)
620 uncache();
621}
622
624{
625 return view()->document()->assistantsGlobalColor();
626}
627
629{
630 // view()->document() is referenced multiple times in this class
631 // it is used to later store things in the KRA file when saving.
632 view()->document()->setAssistantsGlobalColor(color);
633
634 Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
635 assistant->setAssistantGlobalColorCache(color);
636 }
637
638 uncache();
639}
640
642{
643 setVisible(true); // this turns on the decorations in general. we leave it on at this point
644 d->m_isEditingAssistants = true;
645 uncache(); // updates visuals when editing
646}
647
649{
650 if (!d->m_canvas) {
651 return;
652 }
653
654 d->m_isEditingAssistants = false; // some elements are hidden when we aren't editing
655 uncache(); // updates visuals when not editing
656}
657
662
663QPointF KisPaintingAssistantsDecoration::snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers)
664{
665 if (!d->m_canvas || !d->m_canvas->currentImage()) {
666 return e->point;
667 }
668
669
670 KoSnapGuide *snapGuide = d->m_canvas->snapGuide();
671 QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier);
672
673 return pos;
674}
675
676QPointF KisPaintingAssistantsDecoration::snapToGuide(const QPointF& pt, const QPointF &offset)
677{
678 if (!d->m_canvas) {
679 return pt;
680 }
681
682
683 KoSnapGuide *snapGuide = d->m_canvas->snapGuide();
684 QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier);
685
686 return pos;
687}
688
689/*
690 * functions only used internally in this class
691 * we potentially could make some of these inline to speed up performance
692*/
693
694void drawSingleState(QPainter& gc, const QIcon &icon, const QSize &iconSize, QRect maxRect, const QPoint &position, const KoColorDisplayRendererInterface *renderInterface, QPoint additional = QPoint()) {
695 maxRect.moveTopLeft(position+additional);
696 const QMargins m(2, 2, 2, 2);
697
698#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
699 QRect target(QPoint(), iconSize);
700 target.moveCenter(maxRect.center());
701 target = target.marginsRemoved(m);
702 icon.paint(&gc, target);
703#else
704
705 QImage ic = icon.pixmap(iconSize.width(), iconSize.height()).toImage();
706 QRect target(QPoint(), (ic.size()/ic.devicePixelRatioF()));
707 target.moveCenter(maxRect.center());
708 target = target.marginsRemoved(m);
709 gc.drawImage(target.intersected(maxRect), renderInterface->convertImageToDisplayColorSpace(ic));
710#endif
711}
712
713void drawDoubleState(QPainter& gc, const QIcon &icon, const QSize &iconSize, const QIcon &icon2, QRect maxRect, const QPoint &position, const bool state, const KoColorDisplayRendererInterface *renderInterface) {
714 maxRect.moveTopLeft(position);
715 const QMargins m(2, 2, 2, 2);
716#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
717 QRect target(QPoint(), iconSize);
718 target.moveCenter(maxRect.center());
719 target = target.marginsRemoved(m);
720 if (state) {
721 icon.paint(&gc, target);
722 } else {
723 gc.save();
724 gc.setOpacity(0.35);
725 icon2.paint(&gc, target);
726 gc.restore();
727 }
728#else
729 QImage ic = state? icon.pixmap(iconSize.width(), iconSize.height()).toImage(): icon2.pixmap(iconSize.width(), iconSize.height()).toImage();
730 QRect target(QPoint(), (ic.size()/ic.devicePixelRatioF()));
731 target.moveCenter(maxRect.center());
732 target = target.marginsRemoved(m);
733 if (state) {
734 gc.drawImage(target.intersected(maxRect), renderInterface->convertImageToDisplayColorSpace(ic));
735 } else {
736 gc.save();
737 gc.setOpacity(0.35);
738 gc.drawImage(target.intersected(maxRect.marginsRemoved(m)), renderInterface->convertImageToDisplayColorSpace(ic));
739 gc.restore();
740 }
741#endif
742}
743
745{
746 if (!assistant->isAssistantComplete() || !globalEditorWidgetData.widgetActivated) {
747 return;
748 }
749
750 QTransform initialTransform = converter->documentToWidgetTransform();
751 QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.boundingSize));
752
753 //draw editor widget background
754 QPalette sysPalette = renderInterface->systemPaletteForDisplayColorSpace();
755
756 QBrush backgroundColor = sysPalette.window();
757 QPointF actionsBGRectangle(actionsPosition + QPointF(globalEditorWidgetData.widgetOffset,globalEditorWidgetData.widgetOffset));
758 QPen stroke(sysPalette.window(), 2);
759
760
761 gc.setRenderHint(QPainter::Antialiasing);
762
763
764 QPainterPath bgPath;
765 QRectF bgRect(actionsBGRectangle.x(),
766 actionsBGRectangle.y(),
769 bgPath.addRoundedRect(bgRect, 6, 6);
770
771
772 // if the assistant is selected, make outline stroke fatter and use theme's highlight color
773 // for better visual feedback
774 if (selectedAssistant()) { // there might not be a selected assistant, so do not seg fault
775 if (assistant->getEditorPosition() == selectedAssistant()->getEditorPosition()) {
776 stroke.setWidth(6);
777 stroke.setColor(sysPalette.color(QPalette::Highlight));
778
779 }
780 }
781
782 gc.setPen(stroke);
783 gc.drawPath(bgPath);
784 gc.fillPath(bgPath, backgroundColor);
785
786 // If the assistant uses a custom color, draw a colored strip at the bottom
787 // of the editor rectangle so that the association is clear.
788 if (assistant->useCustomColor()) {
789 KoColor c;
790 c.fromQColor(assistant->effectiveAssistantColor());
791 QColor assistantColor = renderInterface->convertColorToDisplayColorSpace(c);
792 assistantColor.setAlpha(255); // No point in having transparency here.
793
794 gc.save();
795 gc.setClipPath(bgPath, Qt::IntersectClip);
796 gc.fillRect(QRectF(QPointF(bgRect.left(), bgRect.bottom() - 4.0), bgRect.bottomRight()), assistantColor);
797 gc.restore();
798 }
799
800 //draw drag handle
801 KoColor c;
802 c.fromQColor(QColor(150,150,150,255));
803 QColor dragDecorationColor = renderInterface->convertColorToDisplayColorSpace(c);
804
805 QPainterPath dragRect;
808
809 gc.fillPath(bgPath.intersected(dragRect),dragDecorationColor);
810
811 //draw dot decoration on handle
812 QPainterPath dragRectDots;
813 c.fromQColor(QColor(50,50,50,255));
814 QColor dragDecorationDotsColor = renderInterface->convertColorToDisplayColorSpace(c);
815 int dotSize = 2;
816 dragRectDots.addEllipse(3,2.5,dotSize,dotSize);
817 dragRectDots.addEllipse(3,7.5,dotSize,dotSize);
818 dragRectDots.addEllipse(3,-2.5,dotSize,dotSize);
819 dragRectDots.addEllipse(3,-7.5,dotSize,dotSize);
820 dragRectDots.addEllipse(-3,2.5,dotSize,dotSize);
821 dragRectDots.addEllipse(-3,7.5,dotSize,dotSize);
822 dragRectDots.addEllipse(-3,-2.5,dotSize,dotSize);
823 dragRectDots.addEllipse(-3,-7.5,dotSize,dotSize);
824 dragRectDots.translate((globalEditorWidgetData.dragDecorationWidth/2)+width,(globalEditorWidgetData.boundingSize.height()/2)+actionsPosition.y()+globalEditorWidgetData.widgetOffset);
825 gc.fillPath(dragRectDots,dragDecorationDotsColor);
826
827 QRect buttonRect(QPoint(0,0), QSize(globalEditorWidgetData.buttonSize, globalEditorWidgetData.buttonSize));
828 //loop over all visible buttons and render them
830 QPoint pos = QPointF(actionsPosition + globalEditorWidgetData.moveIconPosition).toPoint();
831 drawSingleState(gc, globalEditorWidgetData.m_iconMove, QSize(globalEditorWidgetData.buttonSize+10, globalEditorWidgetData.buttonSize+10), buttonRect, pos, renderInterface, QPoint(5, 5));
832 }
834 QPoint pos = QPointF(actionsPosition + globalEditorWidgetData.snapIconPosition).toPoint();
836 }
838 QPoint pos = QPointF(actionsPosition + globalEditorWidgetData.lockedIconPosition).toPoint();
840 }
842 QPoint pos = QPointF(actionsPosition + globalEditorWidgetData.duplicateIconPosition).toPoint();
844 }
846 QPoint pos = QPointF(actionsPosition + globalEditorWidgetData.deleteIconPosition).toPoint();
848 }
849}
QPointF p2
QPointF p1
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
const QString COMPOSITE_ERASE
qreal distance(const QPointF &p1, const QPointF &p2)
int iconSize(qreal width, qreal height)
KoColorDisplayRendererInterface * displayRendererInterface() const override
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
KisImageWSP currentImage() const
KisCoordinatesConverter * coordinatesConverter
KisImageWSP image() const
void updateCanvasDecorations()
QPointer< KisView > view() const
virtual void setVisible(bool v)
@ ASSISTANTS_DRAW_MODE_PIXMAP_CACHE
Definition kis_config.h:873
@ ASSISTANTS_DRAW_MODE_LARGE_PIXMAP_CACHE
Definition kis_config.h:874
AssistantsDrawMode assistantsDrawMode(bool defaultValue=false) const
double xRes() const
double yRes() const
void drawHandles(KisPaintingAssistantSP assistant, QPainter &gc, const KisCoordinatesConverter *converter, const KoColorDisplayRendererInterface *renderInterface)
QList< KisPaintingAssistantSP > assistants() const
void addAssistant(KisPaintingAssistantSP assistant)
QPointF snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers)
void drawEditorWidget(KisPaintingAssistantSP assistant, QPainter &gc, const KisCoordinatesConverter *converter, const KoColorDisplayRendererInterface *renderInterface)
void setAssistantVisible(bool set)
sets whether the main assistant is visible
void toggleOutlineVisible()
toggles whether there will be a preview of the assistant result when painting
std::optional< KisTemporaryPaintConstraint > temporaryConstraint() const
void setSelectedAssistant(KisPaintingAssistantSP assistant)
void toggleAssistantVisible()
toggles whether the assistant is active or not
void setOnlyOneAssistantSnap(bool assistant)
sets whether we snap to only one assistant
KisPaintingAssistantsDecoration(QPointer< KisView > parent)
void removeAssistant(KisPaintingAssistantSP assistant)
void raiseAssistant(KisPaintingAssistantSP assistant)
void setTemporaryConstraint(std::optional< KisTemporaryPaintConstraint > constraint)
bool assistantVisibility()
returns assistant visibility
void setAssistants(const QList< KisPaintingAssistantSP > &assistants)
void drawDecoration(QPainter &gc, const QRectF &updateRect, const KisCoordinatesConverter *converter, KisCanvas2 *canvas) override
void setEraserSnap(bool assistant)
sets whether eraser brushes snap
void adjustLine(QPointF &point, QPointF &strokeBegin)
void setOutlineVisible(bool set)
sets whether the preview is visible
QList< KisPaintingAssistantHandleSP > handles()
QPointF adjustPosition(const QPointF &point, const QPointF &strokeBegin)
bool supportsPaintingAssistants() const
KoSnapGuide * snapGuide
QPointer< KoCanvasResourceProvider > resourceManager
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
virtual QImage convertImageToDisplayColorSpace(const QImage source) const =0
convertImageToDisplayColorSpace
virtual QPalette systemPaletteForDisplayColorSpace() const =0
systemPaletteForDisplayColorSpace
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define dbgFile
Definition kis_debug.h:57
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:194
void drawDoubleState(QPainter &gc, const QIcon &icon, const QSize &iconSize, const QIcon &icon2, QRect maxRect, const QPoint &position, const bool state, const KoColorDisplayRendererInterface *renderInterface)
void drawSingleState(QPainter &gc, const QIcon &icon, const QSize &iconSize, QRect maxRect, const QPoint &position, const KoColorDisplayRendererInterface *renderInterface, QPoint additional=QPoint())
qreal normSquared(const T &a)
qreal norm(const T &a)
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)
std::optional< KisTemporaryPaintConstraint > temporaryConstraint
static KoColorSpaceRegistry * instance()