Krita Source Code Documentation
Loading...
Searching...
No Matches
KoShapeManager.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2
3 SPDX-FileCopyrightText: 2006-2008 Thorsten Zachmann <zachmann@kde.org>
4 SPDX-FileCopyrightText: 2006-2010 Thomas Zander <zander@kde.org>
5 SPDX-FileCopyrightText: 2009-2010 Jan Hambrecht <jaham@gmx.net>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "KoShapeManager.h"
11#include "KoShapeManager_p.h"
12#include "KoSelection.h"
13#include "KoToolManager.h"
14#include "KoPointerEvent.h"
15#include "KoShape.h"
16#include "KoShape_p.h"
17#include "KoCanvasBase.h"
18#include "KoShapeContainer.h"
19#include "KoShapeStrokeModel.h"
20#include "KoShapeGroup.h"
21#include "KoToolProxy.h"
22#include "KoShapeShadow.h"
23#include "KoShapeLayer.h"
24#include "KoFilterEffect.h"
25#include "KoFilterEffectStack.h"
27#include "KoShapeBackground.h"
28#include <KoRTree.h>
29#include "KoClipPath.h"
30#include "KoClipMaskPainter.h"
31#include "KoViewConverter.h"
33#include "KoSvgTextShape.h"
34#include <QApplication>
35
36#include <QPainter>
37#include <QPainterPath>
38#include <QThread>
39#include <QMutexLocker>
40#include <FlakeDebug.h>
41
42#include "kis_painting_tweaks.h"
43#include "kis_debug.h"
44#include "KisForest.h"
45#include <unordered_set>
46
47
48namespace {
49
54inline bool shapeUsedInRenderingTree(KoShape *shape)
55{
56 // FIXME: make more general!
57
58 return !dynamic_cast<KoShapeGroup*>(shape) &&
59 !dynamic_cast<KoShapeLayer*>(shape);
60}
61
66inline bool shapeHasGroupEffects(KoShape *shape) {
67 return shape->clipPath() ||
68 (shape->filterEffectStack() && !shape->filterEffectStack()->isEmpty()) ||
69 shape->clipMask();
70}
71
75inline bool shapeIsVisible(KoShape *shape) {
76 return shape->isVisible(false) && shape->transparency() < 1.0;
77}
78
79
86void populateRenderSubtree(KoShape *parentShape,
89 std::function<bool(KoShape*)> shouldIncludeNode,
90 std::function<bool(KoShape*)> shouldEnterSubtree)
91{
92 KoShapeContainer *parentContainer = dynamic_cast<KoShapeContainer*>(parentShape);
93 if (!parentContainer) return;
94
95 QList<KoShape*> children = parentContainer->shapes();
96 std::sort(children.begin(), children.end(), KoShape::compareShapeZIndex);
97
98 for (auto it = children.constBegin(); it != children.constEnd(); ++it) {
99 auto newParentIt = parentIt;
100
101 if (shouldIncludeNode(*it)) {
102 newParentIt = tree.insert(childEnd(parentIt), *it);
103 }
104
105 if (shouldEnterSubtree(*it)) {
106 populateRenderSubtree(*it, newParentIt, tree, shouldIncludeNode, shouldEnterSubtree);
107 }
108 }
109
110}
111
125void buildRenderTree(QList<KoShape*> leafShapes,
127{
128 QList<KoShape*> sortedShapes = leafShapes;
129 std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
130
131 std::unordered_set<KoShape*> includedShapes;
132
133 Q_FOREACH (KoShape *shape, sortedShapes) {
134 bool shouldSkipShape = !shapeIsVisible(shape);
135 if (shouldSkipShape) continue;
136
137 bool shapeIsPartOfIncludedSubtree = false;
138 QVector<KoShape*> hierarchy = {shape};
139
140 while ((shape = shape->parent())) {
141 if (!shapeIsVisible(shape)) {
142 shouldSkipShape = true;
143 break;
144 }
145
146 if (includedShapes.find(shape) != end(includedShapes)) {
147 shapeIsPartOfIncludedSubtree = true;
148 break;
149 }
150
151 if (shapeHasGroupEffects(shape)) {
152 hierarchy << shape;
153 }
154 }
155
156 if (shouldSkipShape) continue;
157
158 if (!shapeIsPartOfIncludedSubtree &&
159 includedShapes.find(hierarchy.last()) == end(includedShapes)) {
160
161 tree.insert(childEnd(tree), hierarchy.last());
162 }
163 std::copy(hierarchy.begin(), hierarchy.end(),
164 std::inserter(includedShapes, end(includedShapes)));
165 }
166
167 auto shouldIncludeShape =
168 [includedShapes] (KoShape *shape) {
169 // included shapes are guaranteed to be visible
170 return includedShapes.find(shape) != end(includedShapes);
171 };
172
173 for (auto it = childBegin(tree); it != childEnd(tree); ++it) {
174 populateRenderSubtree(*it, it, tree, shouldIncludeShape, &shapeIsVisible);
175 }
176}
177
181void renderShapes(typename KisForest<KoShape*>::child_iterator beginIt,
183 QPainter &painter)
184{
185 for (auto it = beginIt; it != endIt; ++it) {
186 KoShape *shape = *it;
187
188 KisQPainterStateSaver saver(&painter);
189
190 if (!isEnd(parent(it))) {
191 painter.setTransform(shape->transformation() * painter.transform());
192 } else {
193 painter.setTransform(shape->absoluteTransformation() * painter.transform());
194 }
195
196 KoClipPath::applyClipping(shape, painter);
197
198 qreal transparency = shape->transparency(true);
199 if (transparency > 0.0) {
200 painter.setOpacity(1.0-transparency);
201 }
202
203 if (shape->shadow()) {
204 KisQPainterStateSaver saver(&painter);
205 shape->shadow()->paint(shape, painter);
206 }
207
208 QScopedPointer<KoClipMaskPainter> clipMaskPainter;
209 QPainter *shapePainter = &painter;
210
211 KoClipMask *clipMask = shape->clipMask();
212 if (clipMask) {
217 const QRectF bounds = painter.transform().mapRect(shape->outlineRect() & painter.clipBoundingRect());
218
219 clipMaskPainter.reset(new KoClipMaskPainter(&painter, bounds));
220 shapePainter = clipMaskPainter->shapePainter();
221 }
222
228 const QTransform sanityCheckTransformSaved = shapePainter->transform();
229
230 renderShapes(childBegin(it), childEnd(it), *shapePainter);
231
232 Q_FOREACH(const KoShape::PaintOrder p, shape->paintOrder()) {
233 if (p == KoShape::Fill) {
234 shape->paint(*shapePainter);
235 } else if (p == KoShape::Stroke) {
236 shape->paintStroke(*shapePainter);
237 } else if (p == KoShape::Markers) {
238 shape->paintMarkers(*shapePainter);
239 }
240 }
241
242 KIS_SAFE_ASSERT_RECOVER(shapePainter->transform() == sanityCheckTransformSaved) {
243 shapePainter->setTransform(sanityCheckTransformSaved);
244 }
245
246 if (clipMask) {
247 clipMaskPainter->maskPainter()->save();
248
249 shape->clipMask()->drawMask(clipMaskPainter->maskPainter(), shape);
250 clipMaskPainter->renderOnGlobalPainter();
251
252 clipMaskPainter->maskPainter()->restore();
253 }
254 }
255}
256
257}
258
259void KoShapeManager::Private::updateTree()
260{
261 bool selectionModified = false;
262 bool anyModified = false;
263
264 {
265 QMutexLocker l(&this->treeMutex);
266
267 Q_FOREACH (KoShape *shape, aggregate4update) {
268 selectionModified = selectionModified || selection->isSelected(shape);
269 anyModified = true;
270 }
271
272 foreach (KoShape *shape, aggregate4update) {
273 if (!shapeUsedInRenderingTree(shape)) continue;
274
275 tree.remove(shape);
276 QRectF br(shape->boundingRect());
277 tree.insert(br, shape);
278 }
279
280 aggregate4update.clear();
281 shapeIndexesBeforeUpdate.clear();
282 }
283
284 if (selectionModified) {
285 Q_EMIT q->selectionContentChanged();
286 }
287 if (anyModified) {
288 Q_EMIT q->contentChanged();
289 }
290}
291
292void KoShapeManager::Private::forwardCompressedUpdate()
293{
294 bool shouldUpdateDecorations = false;
295 QRectF scheduledUpdate;
296
297 {
298 QMutexLocker l(&shapesMutex);
299
300 if (!compressedUpdate.isEmpty()) {
301 scheduledUpdate = compressedUpdate;
302 compressedUpdate = QRect();
303 }
304
305 Q_FOREACH (const KoShape *shape, compressedUpdatedShapes) {
306 if (selection->isSelected(shape)) {
307 shouldUpdateDecorations = true;
308 break;
309 }
310 }
311 compressedUpdatedShapes.clear();
312 }
313
314 if (shouldUpdateDecorations && canvas->toolProxy()) {
315 canvas->toolProxy()->repaintDecorations();
316 }
317 canvas->updateCanvas(scheduledUpdate);
318
319}
320
322 : d(new Private(this, canvas))
323{
324 Q_ASSERT(d->canvas); // not optional.
325 connect(d->selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
327
332 this->moveToThread(qApp->thread());
333 connect(this, SIGNAL(forwardUpdate()), this, SLOT(forwardCompressedUpdate()));
334}
335
337 : d(new Private(this, canvas))
338{
339 Q_ASSERT(d->canvas); // not optional.
340 connect(d->selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
341
342 // see a comment in another constructor
343 this->moveToThread(qApp->thread());
344 connect(this, SIGNAL(forwardUpdate()), this, SLOT(forwardCompressedUpdate()));
345}
346
347void KoShapeManager::Private::unlinkFromShapesRecursively(const QList<KoShape*> &shapes)
348{
349 Q_FOREACH (KoShape *shape, shapes) {
350 shape->removeShapeManager(q);
351
352 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
353 if (container) {
354 unlinkFromShapesRecursively(container->shapes());
355 }
356 }
357}
358
360{
361 d->unlinkFromShapesRecursively(d->shapes);
362 d->shapes.clear();
363
364 delete d;
365}
366
368{
369 {
370 QMutexLocker l1(&d->shapesMutex);
371 QMutexLocker l2(&d->treeMutex);
372
373 //clear selection
374 d->selection->deselectAll();
375 d->unlinkFromShapesRecursively(d->shapes);
376 d->compressedUpdate = QRect();
377 d->compressedUpdatedShapes.clear();
378 d->aggregate4update.clear();
379 d->shapeIndexesBeforeUpdate.clear();
380 d->tree.clear();
381 d->shapes.clear();
382 }
383
384 Q_FOREACH (KoShape *shape, shapes) {
385 addShape(shape, repaint);
386 }
387}
388
390{
391 {
392 QMutexLocker l1(&d->shapesMutex);
393
394 if (d->shapes.contains(shape))
395 return;
396 shape->addShapeManager(this);
397 d->shapes.append(shape);
398
399 if (shapeUsedInRenderingTree(shape)) {
400 QMutexLocker l2(&d->treeMutex);
401
402 QRectF br(shape->boundingRect());
403 d->tree.insert(br, shape);
404 }
405 }
406
407 if (repaint == PaintShapeOnAdd) {
408 shape->update();
409 }
410
411 // add the children of a KoShapeContainer
412 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
413
414 if (container) {
415 foreach (KoShape *containerShape, container->shapes()) {
416 addShape(containerShape, repaint);
417 }
418 }
419}
420
422{
423 QRectF dirtyRect;
424 {
425 QMutexLocker l1(&d->shapesMutex);
426 QMutexLocker l2(&d->treeMutex);
427
428 dirtyRect = shape->boundingRect();
429
430 shape->removeShapeManager(this);
431 d->selection->deselect(shape);
432 d->aggregate4update.remove(shape);
433 d->compressedUpdatedShapes.remove(shape);
434
435 if (shapeUsedInRenderingTree(shape)) {
436 d->tree.remove(shape);
437 }
438 d->shapes.removeAll(shape);
439 }
440
441 if (!dirtyRect.isEmpty()) {
442 d->canvas->updateCanvas(dirtyRect);
443 }
444
445 // remove the children of a KoShapeContainer
446 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
447 if (container) {
448 foreach (KoShape *containerShape, container->shapes()) {
449 remove(containerShape);
450 }
451 }
452}
453
458
460{
461 QMutexLocker l1(&q->d->shapesMutex);
462 QMutexLocker l2(&q->d->treeMutex);
463
464 q->d->selection->deselect(shape);
465 q->d->aggregate4update.remove(shape);
466 q->d->compressedUpdatedShapes.remove(shape);
467
468 // we cannot access RTTI of the semi-destructed shape, so just
469 // unlink it lazily
470 if (q->d->tree.contains(shape)) {
471 q->d->tree.remove(shape);
472 }
473
474 q->d->shapes.removeAll(shape);
475}
476
477
479{
480 return &d->shapeInterface;
481}
482
484 KoShape *excludeRoot)
485{
486 d->updateTree();
487
488 QMutexLocker l1(&d->shapesMutex);
489
490 QSet<KoShape*> rootShapesSet;
491 Q_FOREACH (KoShape *shape, d->shapes) {
492 while (shape->parent() && shape->parent() != excludeRoot) {
493 shape = shape->parent();
494 }
495
496 if (!rootShapesSet.contains(shape) && shape != excludeRoot) {
497 rootShapesSet.insert(shape);
498 }
499 }
500 const QList<KoShape*> rootShapes(rootShapesSet.begin(), rootShapesSet.end());
501 QList<KoShape*> newRootShapes;
502
503 Q_FOREACH (KoShape *srcShape, rootShapes) {
504 KIS_SAFE_ASSERT_RECOVER(srcShape->parent() == excludeRoot
505 || !srcShape->parent()) {
506 continue;
507 }
508
509 KoShape *clonedShape = srcShape->cloneShape();
510
511 KoShapeContainer *parentShape = srcShape->parent();
512
513 if (parentShape && !parentShape->transformation().isIdentity()) {
514 clonedShape->applyAbsoluteTransformation(parentShape->transformation());
515 }
516
517 newRootShapes << clonedShape;
518 }
519
520 PaintJobsOrder result;
521
522 PaintJob::SharedSafeStorage shapesStorage = std::make_shared<PaintJob::ShapesStorage>();
523 Q_FOREACH (KoShape *shape, newRootShapes) {
524 shapesStorage->emplace_back(std::unique_ptr<KoShape>(shape));
525 }
526
527 const QList<KoShape*> originalShapes = KoShape::linearizeSubtreeSorted(rootShapes);
528 const QList<KoShape*> clonedShapes = KoShape::linearizeSubtreeSorted(newRootShapes);
529 KIS_SAFE_ASSERT_RECOVER_RETURN(clonedShapes.size() == originalShapes.size());
530
531 QHash<KoShape*, KoShape*> clonedFromOriginal;
532 for (int i = 0; i < originalShapes.size(); i++) {
533 clonedFromOriginal[originalShapes[i]] = clonedShapes[i];
534 }
535
536
537 for (auto it = std::begin(jobsOrder.jobs); it != std::end(jobsOrder.jobs); ++it) {
538 QMutexLocker l(&d->treeMutex);
539 QList<KoShape*> unsortedOriginalShapes = d->tree.intersects(it->docUpdateRect);
540
541 it->allClonedShapes = shapesStorage;
542
543 Q_FOREACH (KoShape *shape, unsortedOriginalShapes) {
544 KIS_SAFE_ASSERT_RECOVER(shapeUsedInRenderingTree(shape)) { continue; }
545 it->shapes << clonedFromOriginal[shape];
546 }
547 }
548}
549
550void KoShapeManager::paintJob(QPainter &painter, const KoShapeManager::PaintJob &job)
551{
552 painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off.
553 painter.setBrush(Qt::NoBrush);
554
555 KisForest<KoShape*> renderTree;
556 buildRenderTree(job.shapes, renderTree);
557
558 renderShapes(childBegin(renderTree), childEnd(renderTree), painter);
559}
560
561void KoShapeManager::paint(QPainter &painter)
562{
563 d->updateTree();
564
565 QMutexLocker l1(&d->shapesMutex);
566
567 painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off.
568 painter.setBrush(Qt::NoBrush);
569
570 QList<KoShape*> unsortedShapes;
571 if (painter.hasClipping()) {
572 QMutexLocker l(&d->treeMutex);
573
575 unsortedShapes = d->tree.intersects(rect);
576 } else {
577 unsortedShapes = d->shapes;
578 warnFlake << "KoShapeManager::paint Painting with a painter that has no clipping will lead to too much being painted!";
579 }
580
581 KisForest<KoShape*> renderTree;
582 buildRenderTree(unsortedShapes, renderTree);
583 renderShapes(childBegin(renderTree), childEnd(renderTree), painter);
584}
585
586void KoShapeManager::renderSingleShape(KoShape *shape, QPainter &painter)
587{
588 KisForest<KoShape*> renderTree;
589
590 KoViewConverter converter;
591
592 auto root = renderTree.insert(childBegin(renderTree), shape);
593 populateRenderSubtree(shape, root, renderTree, &shapeIsVisible, &shapeIsVisible);
594 renderShapes(childBegin(renderTree), childEnd(renderTree), painter);
595}
596
597KoShape *KoShapeManager::shapeAt(const QPointF &position, KoFlake::ShapeSelection selection, bool omitHiddenShapes)
598{
599 d->updateTree();
600
601 QMutexLocker l(&d->shapesMutex);
602
603 QList<KoShape*> sortedShapes;
604
605 {
606 QMutexLocker l(&d->treeMutex);
607 sortedShapes = d->tree.contains(position);
608 }
609
610 std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
611 KoShape *firstUnselectedShape = 0;
612 for (int count = sortedShapes.count() - 1; count >= 0; count--) {
613 KoShape *shape = sortedShapes.at(count);
614 if (omitHiddenShapes && ! shape->isVisible())
615 continue;
616 if (! shape->hitTest(position))
617 continue;
618
619 switch (selection) {
621 if (shape->isSelectable())
622 return shape;
623 break;
625 if (d->selection->isSelected(shape))
626 return shape;
627 break;
629 if (! d->selection->isSelected(shape))
630 return shape;
631 break;
633 // we want an unselected shape
634 if (d->selection->isSelected(shape))
635 continue;
636 // memorize the first unselected shape
637 if (! firstUnselectedShape)
638 firstUnselectedShape = shape;
639 // check if the shape above is selected
640 if (count + 1 < sortedShapes.count() && d->selection->isSelected(sortedShapes.at(count + 1)))
641 return shape;
642 break;
643 }
644 }
645 // if we want the next unselected below a selected but there was none selected,
646 // return the first found unselected shape
647 if (selection == KoFlake::NextUnselected && firstUnselectedShape)
648 return firstUnselectedShape;
649
650 if (d->selection->hitTest(position))
651 return d->selection;
652
653 return 0; // missed everything
654}
655
656QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes, bool containedMode)
657{
658 QMutexLocker l(&d->shapesMutex);
659
660 d->updateTree();
662
663 {
664 QMutexLocker l(&d->treeMutex);
665 shapes = containedMode ? d->tree.contained(rect) : d->tree.intersects(rect);
666 }
667
668 for (int count = shapes.count() - 1; count >= 0; count--) {
669
670 KoShape *shape = shapes.at(count);
671
672 if (omitHiddenShapes && !shape->isVisible()) {
673 shapes.removeAt(count);
674 } else {
675 const QPainterPath outline = shape->absoluteTransformation().map(shape->outline());
676
677 if (!containedMode && !outline.intersects(rect) && !outline.contains(rect)) {
678 shapes.removeAt(count);
679
680 } else if (containedMode) {
681
682 QPainterPath containingPath;
683 containingPath.addRect(rect);
684
685 if (!containingPath.contains(outline)) {
686 shapes.removeAt(count);
687 }
688 }
689 }
690 }
691
692 return shapes;
693}
694
695void KoShapeManager::update(const QRectF &rect, const KoShape *shape, bool selectionHandles)
696{
697 if (d->updatesBlocked) return;
698
699 {
700 QMutexLocker l(&d->shapesMutex);
701
702 d->compressedUpdate |= rect;
703
704 if (selectionHandles) {
705 d->compressedUpdatedShapes.insert(shape);
706 }
707 }
708
709 emit(forwardUpdate());
710}
711
713{
714 d->updatesBlocked = value;
715}
716
718{
719 return d->updatesBlocked;
720}
722{
723 {
724 QMutexLocker l(&d->treeMutex);
725
726 Q_ASSERT(shape);
727 if (d->aggregate4update.contains(shape)) {
728 return;
729 }
730
731 d->aggregate4update.insert(shape);
732 d->shapeIndexesBeforeUpdate.insert(shape, shape->zIndex());
733 }
734
735 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
736 if (container) {
737 Q_FOREACH (KoShape *child, container->shapes())
738 notifyShapeChanged(child);
739 }
740}
741
743{
744 QMutexLocker l(&d->shapesMutex);
745
746 return d->shapes;
747}
748
750{
751 QMutexLocker l(&d->shapesMutex);
752
754 // get all toplevel shapes
755 Q_FOREACH (KoShape *shape, d->shapes) {
756 if (!shape->parent() || dynamic_cast<KoShapeLayer*>(shape->parent())) {
757 shapes.append(shape);
758 }
759 }
760 return shapes;
761}
762
764{
765 return d->selection;
766}
767
769{
770 d->updateTree();
771}
772
774{
775 return d->canvas;
776}
777
778//have to include this because of Q_PRIVATE_SLOT
779#include "moc_KoShapeManager.cpp"
#define warnFlake
Definition FlakeDebug.h:16
float value(const T *src, size_t ch)
const Params2D p
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void updateCanvas(const QRectF &rc) override
child_iterator insert(child_iterator pos, X &&value)
Inserts element value into position pos. value becomes the child of the same parent as pos and is pla...
Definition KisForest.h:943
static void applyClipping(KoShape *clippedShape, QPainter &painter)
Applies the clipping to the given painter.
QList< KoShape * > shapes() const
Repaint
enum for add()
@ PaintShapeOnAdd
Causes each shapes 'update()' to be called after being added to the shapeManager.
QList< KoShape * > topLevelShapes() const
KoShapeManager(KoCanvasBase *canvas)
~KoShapeManager() override
QList< KoShape * > shapes
QList< KoShape * > shapesAt(const QRectF &rect, bool omitHiddenShapes=true, bool containedMode=false)
KoShape * shapeAt(const QPointF &position, KoFlake::ShapeSelection selection=KoFlake::ShapeOnTop, bool omitHiddenShapes=true)
KoShapeManager::ShapeInterface shapeInterface
void forwardCompressedUpdate()
void paintJob(QPainter &painter, const KoShapeManager::PaintJob &job)
void setShapes(const QList< KoShape * > &shapes, Repaint repaint=PaintShapeOnAdd)
void selectionChanged()
emitted when the selection is changed
void update(const QRectF &rect, const KoShape *shape=0, bool selectionHandles=false)
void setUpdatesBlocked(bool value)
Private *const d
KoCanvasBase * canvas
void paint(QPainter &painter)
void explicitlyIssueShapeChangedSignals()
void notifyShapeChanged(KoShape *shape)
static void renderSingleShape(KoShape *shape, QPainter &painter)
renderSingleShape renders a shape on painter. This method includes all the needed steps for painting ...
void forwardUpdate()
Emitted upon update and used to update the canvas.
void remove(KoShape *shape)
KoSelection * selection
KoShapeManager * q
void addShape(KoShape *shape, KoShapeManager::Repaint repaint=PaintShapeOnAdd)
void preparePaintJobs(PaintJobsOrder &jobsOrder, KoShape *excludeRoot)
void paint(KoShape *shape, QPainter &painter)
virtual void paintStroke(QPainter &painter) const
paintStroke paints the shape's stroked outline
Definition KoShape.cpp:223
virtual QRectF outlineRect() const
Definition KoShape.cpp:637
virtual QPainterPath outline() const
Definition KoShape.cpp:630
virtual QVector< PaintOrder > paintOrder() const
paintOrder
Definition KoShape.cpp:773
bool isSelectable() const
Definition KoShape.cpp:1014
void addShapeManager(KoShapeManager *manager)
Definition KoShape.cpp:148
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:400
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:434
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:335
KoClipPath * clipPath() const
Returns the currently set clip path or 0 if there is no clip path set.
Definition KoShape.cpp:1128
virtual void update() const
Definition KoShape.cpp:605
KoShapeContainer * parent() const
Definition KoShape.cpp:1039
void removeShapeManager(KoShapeManager *manager)
Definition KoShape.cpp:153
static QList< KoShape * > linearizeSubtreeSorted(const QList< KoShape * > &shapes)
Definition KoShape.cpp:1397
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
virtual void paintMarkers(QPainter &painter) const
paintStroke paints the shape's markers
Definition KoShape.cpp:230
KoShapeShadow * shadow() const
Returns the currently set shadow or 0 if there is no shadow set.
Definition KoShape.cpp:1116
KoClipMask * clipMask() const
Returns the currently set clip mask or 0 if there is no clip mask set.
Definition KoShape.cpp:1140
virtual void paint(QPainter &painter) const =0
Paint the shape fill The class extending this one is responsible for painting itself....
virtual KoShape * cloneShape() const
creates a deep copy of the shape or shape's subtree
Definition KoShape.cpp:200
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:424
KoFilterEffectStack * filterEffectStack() const
Definition KoShape.cpp:1294
@ Stroke
Definition KoShape.h:147
@ Markers
Definition KoShape.h:148
virtual bool hitTest(const QPointF &position) const
Check if the shape is hit on position.
Definition KoShape.cpp:308
qint16 zIndex() const
Definition KoShape.cpp:600
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:979
qreal transparency(bool recursive=false) const
Definition KoShape.cpp:730
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define bounds(x, a, b)
bool isEnd(const ChildIterator< T, is_const > &it)
Definition KisForest.h:341
ChildIterator< value_type, is_const > childBegin(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:290
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
ChildIterator< value_type, is_const > childEnd(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:300
QRect safeClipBoundingRect(const QPainter &painter)
ShapeSelection
Definition KoFlake.h:70
@ Unselected
return the first unselected on top.
Definition KoFlake.h:72
@ Selected
return the first selected with the highest z-ordering (i.e. on top).
Definition KoFlake.h:71
@ ShapeOnTop
return the shape highest z-ordering, regardless of selection.
Definition KoFlake.h:74
@ NextUnselected
return the first unselected directly under a selected shape, or the top most one if nothing is select...
Definition KoFlake.h:73
void drawMask(QPainter *painter, KoShape *shape)
std::shared_ptr< ShapesStorage > SharedSafeStorage
QList< KoShape * > shapes
void notifyShapeDestructed(KoShape *shape)
KisCanvas2 * canvas