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 }