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 shape = parentGroup;
96 }
97
98 d->selectedShapes << shape;
99 shape->addShapeChangeListener(this);
100
101 if (d->selectedShapes.size() == 1) {
103 } else {
104 setTransformation(QTransform());
105 }
106
107 d->selectionChangedCompressor->start();
108}
109
111{
112 if (!d->selectedShapes.contains(shape))
113 return;
114
115 d->selectedShapes.removeAll(shape);
116 shape->removeShapeChangeListener(this);
117
118 if (d->selectedShapes.size() == 1) {
119 setTransformation(d->selectedShapes.first()->absoluteTransformation());
120 }
121
122 d->selectionChangedCompressor->start();
123}
124
126{
127
128 if (d->selectedShapes.isEmpty())
129 return;
130
131 Q_FOREACH (KoShape *shape, d->selectedShapes) {
132 shape->removeShapeChangeListener(this);
133 }
134
135 // reset the transformation matrix of the selection
136 setTransformation(QTransform());
137
138 d->selectedShapes.clear();
139 d->selectionChangedCompressor->start();
140}
141
143{
144 return d->selectedShapes.size();
145}
146
147bool KoSelection::hitTest(const QPointF &position) const
148{
149
150 Q_FOREACH (KoShape *shape, d->selectedShapes) {
151 if (shape->isVisible()) continue;
152 if (shape->hitTest(position)) return true;
153 }
154
155 return false;
156}
157
159{
160 return d->selectedShapes;
161}
162
164{
166
167 KritaUtils::filterContainer (shapes, [](KoShape *shape) {
168 return shape->isVisible();
169 });
170
171 return shapes;
172}
173
175{
177
178 KritaUtils::filterContainer (shapes, [](KoShape *shape) {
179 return shape->isShapeEditable();
180 });
181
182 return shapes;
183}
184
186{
187 QList<KoShape*> shapes;
188 Q_FOREACH (KoShape *shape, selectedShapes()) {
189 QSet<KoShape *> delegates = shape->toolDelegates();
190 if (delegates.isEmpty()) {
191 shapes.append(shape);
192 } else {
193 Q_FOREACH (KoShape *delegatedShape, delegates) {
194 shapes.append(delegatedShape);
195 }
196 }
197 }
198 return shapes;
199}
200
201bool KoSelection::isSelected(const KoShape *shape) const
202{
203 if (shape == this)
204 return true;
205
206 const KoShape *tmpShape = shape;
207 while (tmpShape && std::find(d->selectedShapes.begin(), d->selectedShapes.end(), tmpShape) == d->selectedShapes.end()) {
208 tmpShape = tmpShape->parent();
209 }
210
211 return tmpShape;
212}
213
215{
216 return !d->selectedShapes.isEmpty() ? d->selectedShapes.first() : 0;
217}
218
220{
221 d->activeLayer = layer;
222 Q_EMIT currentLayerChanged(layer);
223}
224
226{
227 return d->activeLayer;
228}
229
231{
232 Q_UNUSED(shape);
233 if (type == KoShape::Deleted) {
234 deselect(shape);
235
236 // HACK ALERT: the caller will also remove the listener, which was
237 // removed in deselect(), so re-add it here
238 shape->addShapeChangeListener(this);
239 }
240}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
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:637
void addShapeChangeListener(ShapeChangeListener *listener)
Definition KoShape.cpp:1360
bool isSelectable() const
Definition KoShape.cpp:1014
void removeShapeChangeListener(ShapeChangeListener *listener)
Definition KoShape.cpp:1368
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:1165
QSet< KoShape * > toolDelegates() const
Definition KoShape.cpp:1310
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:335
KoShapeContainer * parent() const
Definition KoShape.cpp:1039
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:417
ChangeType
Used by shapeChanged() to select which change was made.
Definition KoShape.h:95
@ Deleted
the shape was deleted
Definition KoShape.h:104
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:424
virtual bool hitTest(const QPointF &position) const
Check if the shape is hit on position.
Definition KoShape.cpp:308
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:979
QPointF position() const
Get the position of the shape in pt.
Definition KoShape.cpp:825
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
auto filterContainer(C &container, KeepIfFunction keepIf) -> decltype(bool(keepIf(container[0])), void())