File indexing completed on 2024-05-19 04:29:03

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2017 Scott Petrovic <scottpetrovic@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "kis_painting_assistants_decoration.h"
0009 
0010 #include <limits>
0011 
0012 #include <QList>
0013 #include <QPointF>
0014 #include <klocalizedstring.h>
0015 #include <kactioncollection.h>
0016 #include <ktoggleaction.h>
0017 #include <kis_algebra_2d.h>
0018 #include "kis_debug.h"
0019 #include "KisDocument.h"
0020 #include "kis_canvas2.h"
0021 #include "kis_canvas_resource_provider.h"
0022 #include "kis_icon_utils.h"
0023 #include "KisViewManager.h"
0024 #include <KoCompositeOpRegistry.h>
0025 #include "kis_tool_proxy.h"
0026 
0027 #include <QPainter>
0028 #include <QPainterPath>
0029 #include <QApplication>
0030 
0031 struct KisPaintingAssistantsDecoration::Private {
0032     Private()
0033         : assistantVisible(false)
0034         , outlineVisible(false)
0035         , snapOnlyOneAssistant(true)
0036         , snapEraser(false)
0037         , useCache(false)
0038         , firstAssistant(0)
0039         , m_handleSize(14)
0040     {}
0041 
0042     bool assistantVisible;
0043     bool outlineVisible;
0044     bool snapOnlyOneAssistant;
0045     bool snapEraser;
0046     bool useCache;
0047     KisPaintingAssistantSP firstAssistant;
0048     KisPaintingAssistantSP selectedAssistant;
0049     bool m_isEditingAssistants = false;
0050     int m_handleSize; // size of editor handles on assistants
0051 
0052     KisCanvas2 * m_canvas = 0;
0053 };
0054 
0055 
0056 
0057 KisPaintingAssistantsDecoration::KisPaintingAssistantsDecoration(QPointer<KisView> parent) :
0058     KisCanvasDecoration("paintingAssistantsDecoration", parent),
0059     d(new Private)
0060 {
0061     setAssistantVisible(true);
0062     setOutlineVisible(true);
0063     setPriority(95);
0064     d->snapOnlyOneAssistant = true; //turn on by default.
0065     d->snapEraser = false;
0066 
0067     slotConfigChanged(); // load the initial config
0068 }
0069 
0070 KisPaintingAssistantsDecoration::~KisPaintingAssistantsDecoration()
0071 {
0072     delete d;
0073 }
0074 
0075 void KisPaintingAssistantsDecoration::slotUpdateDecorationVisibility()
0076 {
0077     const bool shouldBeVisible = !assistants().isEmpty();
0078 
0079     if (visible() != shouldBeVisible) {
0080         setVisible(shouldBeVisible);
0081     }
0082 }
0083 
0084 void KisPaintingAssistantsDecoration::slotConfigChanged()
0085 {
0086     KisConfig cfg(true);
0087     const KisConfig::AssistantsDrawMode drawMode = cfg.assistantsDrawMode();
0088 
0089     d->useCache =
0090         (drawMode == KisConfig::ASSISTANTS_DRAW_MODE_PIXMAP_CACHE) ||
0091         (drawMode == KisConfig::ASSISTANTS_DRAW_MODE_LARGE_PIXMAP_CACHE);
0092 }
0093 
0094 void KisPaintingAssistantsDecoration::addAssistant(KisPaintingAssistantSP assistant)
0095 {
0096     QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
0097     if (assistants.contains(assistant)) return;
0098 
0099     assistants.append(assistant);
0100     assistant->setAssistantGlobalColorCache(view()->document()->assistantsGlobalColor());
0101 
0102     view()->document()->setAssistants(assistants);
0103     setVisible(!assistants.isEmpty());
0104     emit assistantChanged();
0105 }
0106 
0107 void KisPaintingAssistantsDecoration::removeAssistant(KisPaintingAssistantSP assistant)
0108 {
0109     QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
0110     KIS_ASSERT_RECOVER_NOOP(assistants.contains(assistant));
0111 
0112     if (assistants.removeAll(assistant)) {
0113         view()->document()->setAssistants(assistants);
0114         setVisible(!assistants.isEmpty());
0115         emit assistantChanged();
0116     }
0117 }
0118 
0119 void KisPaintingAssistantsDecoration::removeAll()
0120 {
0121     QList<KisPaintingAssistantSP> assistants = view()->document()->assistants();
0122     assistants.clear();
0123     view()->document()->setAssistants(assistants);
0124     setVisible(!assistants.isEmpty());
0125 
0126     emit assistantChanged();
0127 }
0128 
0129 void KisPaintingAssistantsDecoration::setAssistants(const QList<KisPaintingAssistantSP> &assistants)
0130 {
0131     Q_FOREACH (KisPaintingAssistantSP assistant, assistants) {
0132         assistant->setAssistantGlobalColorCache(view()->document()->assistantsGlobalColor());
0133     }
0134     view()->document()->setAssistants(assistants);
0135     setVisible(!assistants.isEmpty());
0136 
0137     emit assistantChanged();
0138 }
0139 
0140 void KisPaintingAssistantsDecoration::setAdjustedBrushPosition(const QPointF position)
0141 {
0142     if (!assistants().empty()) {
0143         Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0144             assistant->setAdjustedBrushPosition(position);
0145         }
0146     }
0147 }
0148 
0149 
0150 QPointF KisPaintingAssistantsDecoration::adjustPosition(const QPointF& point, const QPointF& strokeBegin)
0151 {
0152 
0153     if (assistants().empty()) {
0154         // No assistants, so no adjustment
0155         return point;
0156     }
0157 
0158     if  (!d->snapEraser
0159         && (d->m_canvas->resourceManager()->resource(KoCanvasResource::CurrentEffectiveCompositeOp).toString() == COMPOSITE_ERASE)) {
0160         // No snapping if eraser snapping is disabled and brush is an eraser
0161         return point;
0162     }
0163 
0164     KisImageSP image = d->m_canvas->image();
0165     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(image, point);
0166 
0167     const KisCoordinatesConverter *converter = d->m_canvas->coordinatesConverter();
0168     const qreal moveThresholdPt = 4.0 / (converter->effectiveZoom() * qMax(image->xRes(), image->yRes()));
0169 
0170     QPointF best = point;
0171     qreal minSquareDistance = std::numeric_limits<qreal>::max();
0172     qreal secondSquareDistance = std::numeric_limits<qreal>::max();
0173 
0174     if (!d->snapOnlyOneAssistant || !d->firstAssistant) {
0175         // In these cases the best assistant meeds to be determined.
0176         int numSuitableAssistants = 0;
0177         KisPaintingAssistantSP bestAssistant;
0178 
0179         Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0180             if (assistant->isSnappingActive() == true){ // the toggle button with eye icon to disable assistants
0181                 QPointF newpoint = assistant->adjustPosition(point, strokeBegin, true, moveThresholdPt);
0182                 // Assistants that can't or don't want to snap return NaN values (aside from possible numeric issues)
0183                 // NOTE: It would be safer to also reject points too far outside canvas (or widget?) area,
0184                 // because for example squashed concentric ellipses can currently shoot points far off.
0185                 if (qIsNaN(newpoint.x()) ||  qIsNaN(newpoint.y())) {
0186                     continue;
0187                 }
0188                 ++numSuitableAssistants;
0189                 qreal dist = kisSquareDistance(newpoint, point);
0190                 if (dist < minSquareDistance) {
0191                     best = newpoint;
0192                     secondSquareDistance = minSquareDistance;
0193                     minSquareDistance = dist;
0194                     bestAssistant = assistant;
0195                 } else if (dist < secondSquareDistance) {
0196                     secondSquareDistance = dist;
0197                 }
0198                 assistant->setFollowBrushPosition(true);
0199             }
0200         }
0201 
0202         // When there are multiple choices within moveThresholdPt, delay the decision until movement leaves
0203         // threshold to determine which curve follows cursor movement the closest. Assistants with multiple
0204         // snapping curves also need this movement to decide the best choice.
0205         // NOTE: It is currently not possible to tell painting tools that a decision is pending, or that
0206         // the active snapping curve changed, so certain artifact lines from snapping changes are unavoidable.
0207 
0208         if (numSuitableAssistants > 1 && KisAlgebra2D::norm(point - strokeBegin) <= moveThresholdPt
0209                 && (sqrt(secondSquareDistance) < moveThresholdPt)) {
0210             return strokeBegin;
0211         } else if (numSuitableAssistants > 0 && d->snapOnlyOneAssistant) {
0212             // if only snapping to one assistant, register it
0213             d->firstAssistant = bestAssistant;
0214         }
0215     } else {
0216         // Make sure BUG:448187 doesn't crop up again
0217         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(d->firstAssistant->isSnappingActive(), point);
0218         // there already is an assistant locked in, check if it can be used
0219         QPointF newpoint = d->firstAssistant->adjustPosition(point, strokeBegin, false, moveThresholdPt);
0220         // BUGFIX: 402535
0221         // assistants might return (NaN,NaN), must always check for that
0222         if (!(qIsNaN(newpoint.x()) || qIsNaN(newpoint.y()))) {
0223             best = newpoint;
0224         }
0225     }
0226 
0227     return best;
0228 }
0229 
0230 void KisPaintingAssistantsDecoration::adjustLine(QPointF &point, QPointF &strokeBegin)
0231 {
0232     if (assistants().empty()) {
0233         // No assistants, so no adjustment
0234         return;
0235     }
0236 
0237     // TODO: figure it out
0238     if  (!d->snapEraser
0239         && (d->m_canvas->resourceManager()->resource(KoCanvasResource::CurrentEffectiveCompositeOp).toString() == COMPOSITE_ERASE)) {
0240         // No snapping if eraser snapping is disabled and brush is an eraser
0241         return;
0242     }
0243 
0244     QPointF originalPoint = point;
0245     QPointF originalStrokeBegin = strokeBegin;
0246 
0247     qreal minDistance = 10000.0;
0248     bool minDistValid = false;
0249     QPointF finalPoint = originalPoint;
0250     QPointF finalStrokeBegin = originalStrokeBegin;
0251     int id = 0;
0252     KisPaintingAssistantSP bestAssistant;
0253     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0254         if(assistant->isSnappingActive() == true){//this checks if the assistant in question has it's snapping boolean turned on//
0255             //QPointF pt = assistant->adjustPosition(point, strokeBegin, true);
0256             QPointF p1 = originalPoint;
0257             QPointF p2 = originalStrokeBegin;
0258             assistant->adjustLine(p1, p2);
0259             if (p1.isNull() || p2.isNull()) {
0260                 // possibly lines cannot snap to this assistant, or this line cannot, at least
0261                 continue;
0262             }
0263             qreal distance = kisSquareDistance(p1, originalPoint) + kisSquareDistance(p2, originalStrokeBegin);
0264             if (distance < minDistance || !minDistValid) {
0265                 finalPoint = p1;
0266                 finalStrokeBegin = p2;
0267                 minDistValid = true;
0268                 bestAssistant = assistant;
0269             }
0270         }
0271         id ++;
0272     }
0273     if (bestAssistant) {
0274         bestAssistant->setFollowBrushPosition(true);
0275     }
0276     point = finalPoint;
0277     strokeBegin = finalStrokeBegin;
0278 }
0279 
0280 void KisPaintingAssistantsDecoration::endStroke()
0281 {
0282     d->firstAssistant.clear();
0283 
0284     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0285         assistant->endStroke();
0286     }
0287 }
0288 
0289 void KisPaintingAssistantsDecoration::drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, KisCanvas2* canvas)
0290 {
0291     if(assistants().isEmpty()) {
0292         return; // no assistants to worry about, ok to exit
0293     }
0294 
0295     if (!canvas) {
0296         dbgFile<<"canvas does not exist in painting assistant decoration, you may have passed arguments incorrectly:"<<canvas;
0297     } else {
0298         d->m_canvas = canvas;
0299     }
0300 
0301     // the preview functionality for assistants. do not show while editing
0302 
0303     KoToolProxy *proxy = view()->canvasBase()->toolProxy();
0304     KIS_SAFE_ASSERT_RECOVER_RETURN(proxy);
0305     KisToolProxy *kritaProxy = dynamic_cast<KisToolProxy*>(proxy);
0306     KIS_SAFE_ASSERT_RECOVER_RETURN(kritaProxy);
0307 
0308     const bool outlineVisible =
0309         outlineVisibility() &&
0310         !d->m_isEditingAssistants &&
0311         kritaProxy->supportsPaintingAssistants();
0312 
0313     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0314         assistant->drawAssistant(gc, updateRect, converter, d->useCache, canvas, assistantVisibility(), outlineVisible);
0315 
0316         if (isEditingAssistants()) {
0317             drawHandles(assistant, gc, converter);
0318         }
0319     }
0320 
0321     // draw editor controls on top of all assistant lines (why this code is last)
0322     if (isEditingAssistants()) {
0323         Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0324             drawEditorWidget(assistant, gc, converter);
0325         }
0326      }
0327 }
0328 
0329 void KisPaintingAssistantsDecoration::drawHandles(KisPaintingAssistantSP assistant, QPainter& gc, const KisCoordinatesConverter *converter)
0330 {
0331         QTransform initialTransform = converter->documentToWidgetTransform();
0332 
0333         QColor colorToPaint = assistant->effectiveAssistantColor();
0334 
0335         Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) {
0336 
0337 
0338             QPointF transformedHandle = initialTransform.map(*handle);
0339             QRectF ellipse(transformedHandle -  QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize()));
0340 
0341             QPainterPath path;
0342             path.addEllipse(ellipse);
0343 
0344             gc.save();
0345             gc.setPen(Qt::NoPen);
0346             gc.setBrush(colorToPaint);
0347             gc.drawPath(path);
0348             gc.restore();
0349         }
0350 
0351          // some assistants have side handles like the vanishing point assistant
0352          Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) {
0353              QPointF transformedHandle = initialTransform.map(*handle);
0354              QRectF ellipse(transformedHandle -  QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize()));
0355 
0356              QPainterPath path;
0357              path.addEllipse(ellipse);
0358 
0359              gc.save();
0360              gc.setPen(Qt::NoPen);
0361              gc.setBrush(colorToPaint);
0362              gc.drawPath(path);
0363              gc.restore();
0364          }
0365 }
0366 
0367 int KisPaintingAssistantsDecoration::handleSize()
0368 {
0369     return  d->m_handleSize;
0370 }
0371 
0372 void KisPaintingAssistantsDecoration::setHandleSize(int handleSize)
0373 {
0374     d->m_handleSize = handleSize;
0375 }
0376 
0377 QList<KisPaintingAssistantHandleSP> KisPaintingAssistantsDecoration::handles()
0378 {
0379     QList<KisPaintingAssistantHandleSP> hs;
0380     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0381         Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) {
0382             if (!hs.contains(handle)) {
0383                 hs.push_back(handle);
0384             }
0385         }
0386         Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) {
0387             if (!hs.contains(handle)) {
0388                 hs.push_back(handle);
0389             }
0390         }
0391     }
0392     return hs;
0393 }
0394 
0395 QList<KisPaintingAssistantSP> KisPaintingAssistantsDecoration::assistants() const
0396 {
0397     QList<KisPaintingAssistantSP> assistants;
0398     if (view()) {
0399         if (view()->document()) {
0400             assistants = view()->document()->assistants();
0401         }
0402     }
0403     return assistants;
0404 }
0405 
0406 bool KisPaintingAssistantsDecoration::hasPaintableAssistants() const
0407 {
0408     return !assistants().isEmpty();
0409 }
0410 
0411 KisPaintingAssistantSP KisPaintingAssistantsDecoration::selectedAssistant()
0412 {
0413     return d->selectedAssistant;
0414 }
0415 
0416 void KisPaintingAssistantsDecoration::setSelectedAssistant(KisPaintingAssistantSP assistant)
0417 {
0418     d->selectedAssistant = assistant;
0419     emit selectedAssistantChanged();
0420 }
0421 
0422 void KisPaintingAssistantsDecoration::deselectAssistant()
0423 {
0424     d->selectedAssistant.clear();
0425 }
0426 
0427 
0428 void KisPaintingAssistantsDecoration::setAssistantVisible(bool set)
0429 {
0430     d->assistantVisible=set;
0431 }
0432 
0433 void KisPaintingAssistantsDecoration::setOutlineVisible(bool set)
0434 {
0435     d->outlineVisible=set;
0436 }
0437 
0438 void KisPaintingAssistantsDecoration::setOnlyOneAssistantSnap(bool assistant)
0439 {
0440     d->snapOnlyOneAssistant = assistant;
0441 }
0442 
0443 void KisPaintingAssistantsDecoration::setEraserSnap(bool assistant)
0444 {
0445     d->snapEraser = assistant;
0446 }
0447 
0448 bool KisPaintingAssistantsDecoration::assistantVisibility()
0449 {
0450     return d->assistantVisible;
0451 }
0452 bool KisPaintingAssistantsDecoration::outlineVisibility()
0453 {
0454     return d->outlineVisible;
0455 }
0456 void KisPaintingAssistantsDecoration::uncache()
0457 {
0458     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0459         assistant->uncache();
0460     }
0461 }
0462 void KisPaintingAssistantsDecoration::toggleAssistantVisible()
0463 {
0464     setAssistantVisible(!assistantVisibility());
0465     uncache();
0466 }
0467 
0468 void KisPaintingAssistantsDecoration::toggleOutlineVisible()
0469 {
0470     // "outline" means assistant preview (line that depends on the mouse cursor)
0471     setOutlineVisible(!outlineVisibility());
0472 }
0473 
0474 QColor KisPaintingAssistantsDecoration::globalAssistantsColor()
0475 {
0476     return view()->document()->assistantsGlobalColor();
0477 }
0478 
0479 void KisPaintingAssistantsDecoration::setGlobalAssistantsColor(QColor color)
0480 {
0481     // view()->document() is referenced multiple times in this class
0482     // it is used to later store things in the KRA file when saving.
0483     view()->document()->setAssistantsGlobalColor(color);
0484 
0485     Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) {
0486         assistant->setAssistantGlobalColorCache(color);
0487     }
0488 
0489     uncache();
0490 }
0491 
0492 void KisPaintingAssistantsDecoration::activateAssistantsEditor()
0493 {
0494     setVisible(true); // this turns on the decorations in general. we leave it on at this point
0495     d->m_isEditingAssistants = true;
0496     uncache(); // updates visuals when editing
0497 }
0498 
0499 void KisPaintingAssistantsDecoration::deactivateAssistantsEditor()
0500 {
0501     if (!d->m_canvas) {
0502         return;
0503     }
0504 
0505     d->m_isEditingAssistants = false; // some elements are hidden when we aren't editing
0506     uncache(); // updates visuals when not editing
0507 }
0508 
0509 bool KisPaintingAssistantsDecoration::isEditingAssistants()
0510 {
0511     return d->m_isEditingAssistants;
0512 }
0513 
0514 QPointF KisPaintingAssistantsDecoration::snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers)
0515 {
0516     if (!d->m_canvas || !d->m_canvas->currentImage()) {
0517         return e->point;
0518     }
0519 
0520 
0521     KoSnapGuide *snapGuide = d->m_canvas->snapGuide();
0522     QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier);
0523 
0524     return pos;
0525 }
0526 
0527 QPointF KisPaintingAssistantsDecoration::snapToGuide(const QPointF& pt, const QPointF &offset)
0528 {
0529     if (!d->m_canvas) {
0530          return pt;
0531     }
0532 
0533 
0534     KoSnapGuide *snapGuide = d->m_canvas->snapGuide();
0535     QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier);
0536 
0537     return pos;
0538 }
0539 
0540 /*
0541  * functions only used internally in this class
0542  * we potentially could make some of these inline to speed up performance
0543 */
0544 
0545 void KisPaintingAssistantsDecoration::drawEditorWidget(KisPaintingAssistantSP assistant, QPainter& gc, const KisCoordinatesConverter *converter)
0546 {
0547     const int widgetOffset = 10;
0548     if (!assistant->isAssistantComplete() || !globalEditorWidgetData.widgetActivated) {
0549         return;
0550     }
0551 
0552     QTransform initialTransform = converter->documentToWidgetTransform();
0553     QPointF actionsPosition = initialTransform.map(assistant->viewportConstrainedEditorPosition(converter, globalEditorWidgetData.boundingSize));
0554 
0555     //draw editor widget background
0556     QBrush backgroundColor = d->m_canvas->viewManager()->mainWindowAsQWidget()->palette().window();
0557     QPointF actionsBGRectangle(actionsPosition + QPointF(widgetOffset, widgetOffset));
0558     QPen stroke(QColor(60, 60, 60, 80), 2);
0559 
0560     gc.setRenderHint(QPainter::Antialiasing);
0561 
0562 
0563     QPainterPath bgPath;
0564     bgPath.addRoundedRect(QRectF(actionsBGRectangle.x(), actionsBGRectangle.y(), globalEditorWidgetData.boundingSize.width(), globalEditorWidgetData.boundingSize.height()), 6, 6);
0565 
0566 
0567     // if the assistant is selected, make outline stroke fatter and use theme's highlight color
0568     // for better visual feedback
0569     if (selectedAssistant()) { // there might not be a selected assistant, so do not seg fault
0570         if (assistant->getEditorPosition() == selectedAssistant()->getEditorPosition()) {
0571             stroke.setWidth(6);
0572             stroke.setColor(qApp->palette().color(QPalette::Highlight));
0573 
0574         }
0575     }
0576      
0577     gc.setPen(stroke);
0578     gc.drawPath(bgPath);
0579     gc.fillPath(bgPath, backgroundColor);   
0580    
0581 
0582     //draw drag handle
0583     QColor dragDecorationColor(150,150,150,255);
0584 
0585     QPainterPath dragRect;
0586     int width = actionsPosition.x()+globalEditorWidgetData.boundingSize.width()-globalEditorWidgetData.dragDecorationWidth+widgetOffset;
0587     int height = actionsPosition.y()+globalEditorWidgetData.boundingSize.height()+widgetOffset;
0588     dragRect.addRect(QRectF(width,actionsPosition.y()+widgetOffset,globalEditorWidgetData.dragDecorationWidth,globalEditorWidgetData.boundingSize.height()));
0589     
0590     gc.fillPath(bgPath.intersected(dragRect),dragDecorationColor);
0591     
0592     //draw dot decoration on handle
0593     QPainterPath dragRectDots;
0594     QColor dragDecorationDotsColor(50,50,50,255);
0595     int dotSize = 2;
0596     dragRectDots.addEllipse(3,2.5,dotSize,dotSize);
0597     dragRectDots.addEllipse(3,7.5,dotSize,dotSize);
0598     dragRectDots.addEllipse(3,-2.5,dotSize,dotSize);
0599     dragRectDots.addEllipse(3,-7.5,dotSize,dotSize);
0600     dragRectDots.addEllipse(-3,2.5,dotSize,dotSize);
0601     dragRectDots.addEllipse(-3,7.5,dotSize,dotSize);
0602     dragRectDots.addEllipse(-3,-2.5,dotSize,dotSize);
0603     dragRectDots.addEllipse(-3,-7.5,dotSize,dotSize);
0604     dragRectDots.translate((globalEditorWidgetData.dragDecorationWidth/2)+width,(globalEditorWidgetData.boundingSize.height()/2)+actionsPosition.y()+widgetOffset);
0605     gc.fillPath(dragRectDots,dragDecorationDotsColor);
0606 
0607 
0608     //loop over all visible buttons and render them
0609     if (globalEditorWidgetData.moveButtonActivated) {
0610         QPointF iconMovePosition(actionsPosition + globalEditorWidgetData.moveIconPosition);
0611         gc.drawPixmap(iconMovePosition, globalEditorWidgetData.m_iconMove);
0612     }
0613     if (globalEditorWidgetData.snapButtonActivated) {
0614         QPointF iconSnapPosition(actionsPosition + globalEditorWidgetData.snapIconPosition);
0615         if (assistant->isSnappingActive() == true) {
0616             gc.drawPixmap(iconSnapPosition, globalEditorWidgetData.m_iconSnapOn);
0617         }else {
0618             gc.drawPixmap(iconSnapPosition, globalEditorWidgetData.m_iconSnapOff);
0619         }
0620     }
0621     if (globalEditorWidgetData.lockButtonActivated) {
0622         QPointF iconLockedPosition(actionsPosition + globalEditorWidgetData.lockedIconPosition);
0623         if (assistant->isLocked()) {
0624             gc.drawPixmap(iconLockedPosition, globalEditorWidgetData.m_iconLockOn);
0625         } else {
0626             qreal oldOpacity = gc.opacity();
0627             gc.setOpacity(0.35);
0628             gc.drawPixmap(iconLockedPosition, globalEditorWidgetData.m_iconLockOff);
0629             gc.setOpacity(oldOpacity);
0630         }
0631     }
0632     if (globalEditorWidgetData.duplicateButtonActivated) {
0633         QPointF iconDuplicatePosition(actionsPosition + globalEditorWidgetData.duplicateIconPosition);
0634         if(assistant->isDuplicating()) {
0635             //draw button depressed
0636             qreal oldOpacity = gc.opacity();
0637             gc.setOpacity(0.35);
0638             gc.drawPixmap(iconDuplicatePosition,globalEditorWidgetData.m_iconDuplicate);
0639             gc.setOpacity(oldOpacity);
0640         }else {
0641             gc.drawPixmap(iconDuplicatePosition,globalEditorWidgetData.m_iconDuplicate);
0642         }
0643     }
0644     if (globalEditorWidgetData.deleteButtonActivated) {
0645         QPointF iconDeletePosition(actionsPosition + globalEditorWidgetData.deleteIconPosition);
0646         gc.drawPixmap(iconDeletePosition, globalEditorWidgetData.m_iconDelete);
0647     }
0648 
0649     
0650 
0651 
0652 }