Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSnapGuide.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2008-2009 Jan Hambrecht <jaham@gmx.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "KoSnapGuide.h"
8#include "KoSnapProxy.h"
9#include "KoSnapStrategy.h"
10
11#include <KoPathShape.h>
12#include <KoPathPoint.h>
13#include <KoViewConverter.h>
14#include <KoCanvasBase.h>
17
18#include <QPainter>
19#include <QPainterPath>
20
21#include <math.h>
22#include "kis_pointer_utils.h"
23
24class Q_DECL_HIDDEN KoSnapGuide::Private
25{
26public:
27 Private(KoCanvasBase *parentCanvas)
28 : canvas(parentCanvas), additionalEditedShape(0), currentStrategy(0),
29 active(true),
30 snapDistance(10)
31 {
32 }
33
35 {
36 strategies.clear();
37 }
38
41
46
47 KoSnapGuide::Strategies usedStrategies;
48 bool active;
52};
53
55 : d(new Private(canvas))
56{
57 d->strategies.append(toQShared(new GridSnapStrategy()));
58 d->strategies.append(toQShared(new NodeSnapStrategy()));
59 d->strategies.append(toQShared(new OrthogonalSnapStrategy()));
60 d->strategies.append(toQShared(new ExtensionSnapStrategy()));
61 d->strategies.append(toQShared(new IntersectionSnapStrategy()));
62 d->strategies.append(toQShared(new BoundingBoxSnapStrategy()));
63}
64
68
70{
71 d->additionalEditedShape = shape;
72}
73
75{
76 return d->additionalEditedShape;
77}
78
80{
81 if (value) {
82 d->usedStrategies |= type;
83 } else {
84 d->usedStrategies &= ~type;
85 }
86}
87
89{
90 return d->usedStrategies & type;
91}
92
93void KoSnapGuide::enableSnapStrategies(Strategies strategies)
94{
95 d->usedStrategies = strategies;
96}
97
98KoSnapGuide::Strategies KoSnapGuide::enabledSnapStrategies() const
99{
100 return d->usedStrategies;
101}
102
104{
105 if (!customStrategy || customStrategy->type() != CustomSnapping)
106 return false;
107
108 d->strategies.append(toQShared(customStrategy));
109 return true;
110}
111
113{
114 for (auto it = d->strategies.begin(); it != d->strategies.end(); /*noop*/) {
115 if ((*it)->type() == type) {
116 if (strategy) {
117 *it = toQShared(strategy);
118 } else {
119 it = d->strategies.erase(it);
120 }
121 return;
122 } else {
123 ++it;
124 }
125 }
126
127 if (strategy) {
128 d->strategies.append(toQShared(strategy));
129 }
130}
131
133{
134 d->active = on;
135}
136
138{
139 return d->active;
140}
141
143{
144 d->snapDistance = qAbs(distance);
145}
146
148{
149 return d->snapDistance;
150}
151
152QPointF KoSnapGuide::snap(const QPointF &mousePosition, const QPointF &dragOffset, Qt::KeyboardModifiers modifiers)
153{
154 QPointF pos = mousePosition + dragOffset;
155 pos = snap(pos, modifiers);
156 return pos - dragOffset;
157}
158
159QPointF KoSnapGuide::snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
160{
161 d->currentStrategy.clear();
162
163 if (! d->active || (modifiers & Qt::ShiftModifier))
164 return mousePosition;
165
166 KoSnapProxy proxy(this);
167
168 using PriorityTuple = std::tuple<KoSnapStrategy::SnapType, qreal>;
169 PriorityTuple minPriority(KoSnapStrategy::ToLine, HUGE_VAL);
170
171 const qreal maxSnapDistance = d->canvas->viewConverter()->
172 viewToDocument(QSizeF(d->snapDistance,
173 d->snapDistance)).width();
174
175 foreach (Private::KoSnapStrategySP strategy, d->strategies) {
176 if (d->usedStrategies & strategy->type() ||
177 strategy->type() == GridSnapping ||
178 strategy->type() == CustomSnapping) {
179
180 if (! strategy->snap(mousePosition, &proxy, maxSnapDistance))
181 continue;
182
183 QPointF snapCandidate = strategy->snappedPosition();
184 qreal distance = KoSnapStrategy::squareDistance(snapCandidate, mousePosition);
185
186 const PriorityTuple priority(strategy->snappedType(), distance);
187 if (priority < minPriority) {
188 d->currentStrategy = strategy;
189 minPriority = priority;
190 }
191 }
192 }
193
194 if (! d->currentStrategy)
195 return mousePosition;
196
197 return d->currentStrategy->snappedPosition();
198}
199
201{
202 QRectF rect;
203
204 if (d->currentStrategy) {
205 rect = d->currentStrategy->decoration(*d->canvas->viewConverter()).boundingRect();
206 return rect.adjusted(-2, -2, 2, 2);
207 } else {
208 return rect;
209 }
210}
211
212void KoSnapGuide::paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
213{
214 if (! d->currentStrategy || ! d->active)
215 return;
216
217 QPainterPath decoration = d->currentStrategy->decoration(converter);
218
219 int thickness = d->canvas->resourceManager()? d->canvas->resourceManager()->decorationThickness(): 1;
220
221 painter.setBrush(Qt::NoBrush);
222
223 KoColor c;
224 c.fromQColor(Qt::white);
225
226 QPen whitePen(displayRenderer->convertColorToDisplayColorSpace(c), thickness);
227 whitePen.setCosmetic(true);
228 whitePen.setStyle(Qt::SolidLine);
229 painter.setPen(whitePen);
230 painter.drawPath(decoration);
231
232 c.fromQColor(Qt::red);
233 QPen redPen(displayRenderer->convertColorToDisplayColorSpace(c), thickness);
234 redPen.setCosmetic(true);
235 redPen.setStyle(Qt::DotLine);
236 painter.setPen(redPen);
237 painter.drawPath(decoration);
238}
239
241{
242 return d->canvas;
243}
244
246{
247 d->ignoredPoints = ignoredPoints;
248}
249
251{
252 return d->ignoredPoints;
253}
254
256{
257 d->ignoredShapes = ignoredShapes;
258}
259
261{
262 return d->ignoredShapes;
263}
264
266{
267 d->currentStrategy.clear();
268 d->additionalEditedShape = 0;
269 d->ignoredPoints.clear();
270 d->ignoredShapes.clear();
271 // remove all custom strategies
272 int strategyCount = d->strategies.count();
273 for (int i = strategyCount-1; i >= 0; --i) {
274 if (d->strategies[i]->type() == CustomSnapping) {
275 d->strategies.removeAt(i);
276 }
277 }
278}
279
float value(const T *src, size_t ch)
qreal distance(const QPointF &p1, const QPointF &p2)
snaps to shape bounding boxes
snaps extension lines of path shapes
snaps to the canvas grid
snaps to intersections of shapes
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
StrategiesList strategies
QList< KoPathPoint * > ignoredPoints
QSharedPointer< KoSnapStrategy > KoSnapStrategySP
bool addCustomSnapStrategy(KoSnapStrategy *customStrategy)
KoSnapGuide(KoCanvasBase *canvas)
Creates the snap guide to work on the given canvas.
Private(KoCanvasBase *parentCanvas)
void reset()
Resets the snap guide.
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
paints the guide
bool isStrategyEnabled(Strategy type) const
const QScopedPointer< Private > d
void setIgnoredPathPoints(const QList< KoPathPoint * > &ignoredPoints)
Sets a list of path points to ignore.
QList< KoSnapStrategySP > StrategiesList
void setSnapDistance(int distance)
sets the snap distances in pixels
Strategy
the different possible snap Strategies
Definition KoSnapGuide.h:50
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
QList< KoShape * > ignoredShapes
void enableSnapping(bool on)
enables the snapping guides
virtual ~KoSnapGuide()
QList< KoPathPoint * > ignoredPathPoints() const
Returns list of ignored points.
void setIgnoredShapes(const QList< KoShape * > &ignoredShapes)
Sets list of ignored shapes.
void enableSnapStrategies(Strategies strategies)
enables the strategies used for snapping
KoShape * additionalEditedShape
void enableSnapStrategy(Strategy type, bool value)
void setAdditionalEditedShape(KoShape *shape)
Adds an additional shape to snap to (useful when creating a path)
KoSnapStrategySP currentStrategy
KoSnapGuide::Strategies enabledSnapStrategies() const
returns the enabled snap strategies
KoSnapGuide::Strategies usedStrategies
QRectF boundingRect()
returns the bounding rect of the guide
void overrideSnapStrategy(Strategy type, KoSnapStrategy *strategy)
KoCanvasBase * canvas
bool isSnapping() const
returns if snapping is enabled
static qreal squareDistance(const QPointF &p1, const QPointF &p2)
KoSnapGuide::Strategy type() const
returns the strategies type
snaps to path points
snaps to x- or y-coordinates of path points
QSharedPointer< T > toQShared(T *ptr)
KisCanvas2 * canvas