Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSelection.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2
3 SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
4 SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
5 SPDX-FileCopyrightText: 2006 Jan Hambrecht <jaham@gmx.net>
6 SPDX-FileCopyrightText: 2006-2007, 2009 Thomas Zander <zander@kde.org>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "KoSelection.h"
12#include "KoSelection_p.h"
13#include "KoShapeContainer.h"
14#include "KoShapeGroup.h"
15#include "KoPointerEvent.h"
16#include "kis_algebra_2d.h"
18
19#include <QPainter>
20
21#include "kis_debug.h"
23 : QObject(parent)
24 , KoShape()
25 , d(new Private)
26{
27 connect(d->selectionChangedCompressor, SIGNAL(timeout()), SIGNAL(selectionChanged()));
28}
29
31 : QObject()
32 , KoShape(rhs)
33 , d(rhs.d)
34{
35}
36
40
41void KoSelection::paint(QPainter &painter) const
42{
43 Q_UNUSED(painter);
44}
45
46void KoSelection::setSize(const QSizeF &size)
47{
48 Q_UNUSED(size);
49 qWarning() << "WARNING: KoSelection::setSize() should never be used!";
50}
51
52QSizeF KoSelection::size() const
53{
54 return outlineRect().size();
55}
56
58{
59 const QTransform invertedTransform = transformation().inverted();
60 QRectF boundingRect;
61
62 Q_FOREACH (KoShape *shape, selectedVisibleShapes()) {
63 // it is cheaper to invert-transform each outline, than
64 // to group 300+ rotated rectangles into a polygon
66 invertedTransform.map(
67 shape->absoluteTransformation().map(
68 QPolygonF(shape->outlineRect()))).boundingRect();
69 }
70
71 return boundingRect;
72}
73
78
80{
81 KIS_SAFE_ASSERT_RECOVER_RETURN(shape != this);
83
84 if (!shape->isSelectable() || !shape->isVisible()) {
85 return;
86 }
87
88 // check recursively
89 if (isSelected(shape)) {
90 return;
91 }
92
93 // find the topmost parent to select
94 while (KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(shape->parent())) {
95 if (parentGroup && parentGroup->isSelectable()) {
96 shape = parentGroup;
97 } else {
98 break;
99 }
100 }
101
102 d->selectedShapes << shape;
103 shape->addShapeChangeListener(this);
104
105 if (d->selectedShapes.size() == 1) {
107 } else {
108 setTransformation(QTransform());
109 }
110
111 d->selectionChangedCompressor->start();
112}
113
115{
116 if (!d->selectedShapes.contains(shape))
117 return;
118
119 d->selectedShapes.removeAll(shape);
120 shape->removeShapeChangeListener(this);
121
122 if (d->selectedShapes.size() == 1) {
123 setTransformation(d->selectedShapes.first()->absoluteTransformation());
124 }
125
126 d->selectionChangedCompressor->start();
127}
128
130{
131
132 if (d->selectedShapes.isEmpty())
133 return;
134
135 Q_FOREACH (KoShape *shape, d->selectedShapes) {
136 shape->removeShapeChangeListener(this);
137 }
138
139 // reset the transformation matrix of the selection
140 setTransformation(QTransform());
141
142 d->selectedShapes.clear();
143 d->selectionChangedCompressor->start();
144}
145
147{
148 return d->selectedShapes.size();
149}
150
151bool KoSelection::hitTest(const QPointF &position) const
152{
153
154 Q_FOREACH (KoShape *shape, d->selectedShapes) {
155 if (shape->isVisible()) continue;
156 if (shape->hitTest(position)) return true;
157 }
158
159 return false;
160}
161
163{
164 return d->selectedShapes;
165}
166
168{
170
171 KritaUtils::filterContainer (shapes, [](KoShape *shape) {
172 return shape->isVisible();
173 });
174
175 return shapes;
176}
177
179{
181
182 KritaUtils::filterContainer (shapes, [](KoShape *shape) {
183 return shape->isShapeEditable();
184 });
185
186 return shapes;
187}
188
190{
191 QList<KoShape*> shapes;
192 Q_FOREACH (KoShape *shape, selectedShapes()) {
193 QSet<KoShape *> delegates = shape->toolDelegates();
194 if (delegates.isEmpty()) {
195 shapes.append(shape);
196 } else {
197 Q_FOREACH (KoShape *delegatedShape, delegates) {
198 shapes.append(delegatedShape);
199 }
200 }
201 }
202 return shapes;
203}
204
205bool KoSelection::isSelected(const KoShape *shape) const
206{
207 if (shape == this)
208 return true;
209
210 const KoShape *tmpShape = shape;
211 while (tmpShape && std::find(d->selectedShapes.begin(), d->selectedShapes.end(), tmpShape) == d->selectedShapes.end()) {
212 tmpShape = tmpShape->parent();
213 }
214
215 return tmpShape;
216}
217
219{
220 return !d->selectedShapes.isEmpty() ? d->selectedShapes.first() : 0;
221}
222
224{
225 d->activeLayer = layer;
226 Q_EMIT currentLayerChanged(layer);
227}
228
230{
231 return d->activeLayer;
232}
233
235{
236 Q_UNUSED(shape);
237 if (type == KoShape::Deleted) {
238 deselect(shape);
239
240 // HACK ALERT: the caller will also remove the listener, which was
241 // removed in deselect(), so re-add it here
242 shape->addShapeChangeListener(this);
243 }
244}
const QList< KoShape * > selectedVisibleShapes() const
QRectF outlineRect() const override
KoSelection(QObject *parent=0)
bool isSelected(const KoShape *shape) const
return true if the shape is selected
bool hitTest(const QPointF &position) const override
Check if the shape is hit on position.
void deselectAll()
clear the selections list
QSizeF size() const override
Get the size of the shape in pt.
QRectF boundingRect() const override
Get the bounding box of the shape.
~KoSelection() override
void setActiveLayer(KoShapeLayer *layer)
void currentLayerChanged(const KoShapeLayer *layer)
emitted when the current layer is changed
void selectionChanged()
emitted when the selection is changed
QSharedDataPointer< Private > d
void deselect(KoShape *shape)
void setSize(const QSizeF &size) override
Resize the shape.
const QList< KoShape * > selectedEditableShapesAndDelegates() const
void select(KoShape *shape)
int count() const
return the selection count, i.e. the number of all selected shapes
void paint(QPainter &painter) const override
Paint the shape fill The class extending this one is responsible for painting itself....
void notifyShapeChanged(ChangeType type, KoShape *shape) override
const QList< KoShape * > selectedEditableShapes() const
KoShape * firstSelectedShape() const
const QList< KoShape * > selectedShapes() const
KoShapeLayer * activeLayer() const
virtual QRectF outlineRect() const
Definition KoShape.cpp:566
void addShapeChangeListener(ShapeChangeListener *listener)
Definition KoShape.cpp:1157
bool isSelectable() const
Definition KoShape.cpp:837
void removeShapeChangeListener(ShapeChangeListener *listener)
Definition KoShape.cpp:1165
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
Definition KoShape.cpp:970
QSet< KoShape * > toolDelegates() const
Definition KoShape.cpp:1107
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:299
KoShapeContainer * parent() const
Definition KoShape.cpp:862
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:374
ChangeType
Used by shapeChanged() to select which change was made.
Definition KoShape.h:92
@ Deleted
the shape was deleted
Definition KoShape.h:101
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:383
virtual bool hitTest(const QPointF &position) const
Check if the shape is hit on position.
Definition KoShape.cpp:280
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:802
QPointF position() const
Get the position of the shape in pt.
Definition KoShape.cpp:745
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
auto filterContainer(C &container, KeepIfFunction keepIf) -> decltype(bool(keepIf(container[0])), void())