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>
16
17#include <QPainter>
18#include <QPainterPath>
19
20#include <math.h>
21#include "kis_pointer_utils.h"
22
23class Q_DECL_HIDDEN KoSnapGuide::Private
24{
25public:
26 Private(KoCanvasBase *parentCanvas)
27 : canvas(parentCanvas), additionalEditedShape(0), currentStrategy(0),
28 active(true),
29 snapDistance(10)
30 {
31 }
32
34 {
35 strategies.clear();
36 }
37
40
45
46 KoSnapGuide::Strategies usedStrategies;
47 bool active;
51};
52
54 : d(new Private(canvas))
55{
56 d->strategies.append(toQShared(new GridSnapStrategy()));
57 d->strategies.append(toQShared(new NodeSnapStrategy()));
58 d->strategies.append(toQShared(new OrthogonalSnapStrategy()));
59 d->strategies.append(toQShared(new ExtensionSnapStrategy()));
60 d->strategies.append(toQShared(new IntersectionSnapStrategy()));
61 d->strategies.append(toQShared(new BoundingBoxSnapStrategy()));
62}
63
67
69{
70 d->additionalEditedShape = shape;
71}
72
74{
75 return d->additionalEditedShape;
76}
77
79{
80 if (value) {
81 d->usedStrategies |= type;
82 } else {
83 d->usedStrategies &= ~type;
84 }
85}
86
88{
89 return d->usedStrategies & type;
90}
91
92void KoSnapGuide::enableSnapStrategies(Strategies strategies)
93{
94 d->usedStrategies = strategies;
95}
96
97KoSnapGuide::Strategies KoSnapGuide::enabledSnapStrategies() const
98{
99 return d->usedStrategies;
100}
101
103{
104 if (!customStrategy || customStrategy->type() != CustomSnapping)
105 return false;
106
107 d->strategies.append(toQShared(customStrategy));
108 return true;
109}
110
112{
113 for (auto it = d->strategies.begin(); it != d->strategies.end(); /*noop*/) {
114 if ((*it)->type() == type) {
115 if (strategy) {
116 *it = toQShared(strategy);
117 } else {
118 it = d->strategies.erase(it);
119 }
120 return;
121 } else {
122 ++it;
123 }
124 }
125
126 if (strategy) {
127 d->strategies.append(toQShared(strategy));
128 }
129}
130
132{
133 d->active = on;
134}
135
137{
138 return d->active;
139}
140
142{
143 d->snapDistance = qAbs(distance);
144}
145
147{
148 return d->snapDistance;
149}
150
151QPointF KoSnapGuide::snap(const QPointF &mousePosition, const QPointF &dragOffset, Qt::KeyboardModifiers modifiers)
152{
153 QPointF pos = mousePosition + dragOffset;
154 pos = snap(pos, modifiers);
155 return pos - dragOffset;
156}
157
158QPointF KoSnapGuide::snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
159{
160 d->currentStrategy.clear();
161
162 if (! d->active || (modifiers & Qt::ShiftModifier))
163 return mousePosition;
164
165 KoSnapProxy proxy(this);
166
167 using PriorityTuple = std::tuple<KoSnapStrategy::SnapType, qreal>;
168 PriorityTuple minPriority(KoSnapStrategy::ToLine, HUGE_VAL);
169
170 const qreal maxSnapDistance = d->canvas->viewConverter()->
171 viewToDocument(QSizeF(d->snapDistance,
172 d->snapDistance)).width();
173
174 foreach (Private::KoSnapStrategySP strategy, d->strategies) {
175 if (d->usedStrategies & strategy->type() ||
176 strategy->type() == GridSnapping ||
177 strategy->type() == CustomSnapping) {
178
179 if (! strategy->snap(mousePosition, &proxy, maxSnapDistance))
180 continue;
181
182 QPointF snapCandidate = strategy->snappedPosition();
183 qreal distance = KoSnapStrategy::squareDistance(snapCandidate, mousePosition);
184
185 const PriorityTuple priority(strategy->snappedType(), distance);
186 if (priority < minPriority) {
187 d->currentStrategy = strategy;
188 minPriority = priority;
189 }
190 }
191 }
192
193 if (! d->currentStrategy)
194 return mousePosition;
195
196 return d->currentStrategy->snappedPosition();
197}
198
200{
201 QRectF rect;
202
203 if (d->currentStrategy) {
204 rect = d->currentStrategy->decoration(*d->canvas->viewConverter()).boundingRect();
205 return rect.adjusted(-2, -2, 2, 2);
206 } else {
207 return rect;
208 }
209}
210
211void KoSnapGuide::paint(QPainter &painter, const KoViewConverter &converter)
212{
213 if (! d->currentStrategy || ! d->active)
214 return;
215
216 QPainterPath decoration = d->currentStrategy->decoration(converter);
217
218 int thickness = d->canvas->resourceManager()? d->canvas->resourceManager()->decorationThickness(): 1;
219
220 painter.setBrush(Qt::NoBrush);
221
222 QPen whitePen(Qt::white, thickness);
223 whitePen.setCosmetic(true);
224 whitePen.setStyle(Qt::SolidLine);
225 painter.setPen(whitePen);
226 painter.drawPath(decoration);
227
228 QPen redPen(Qt::red, thickness);
229 redPen.setCosmetic(true);
230 redPen.setStyle(Qt::DotLine);
231 painter.setPen(redPen);
232 painter.drawPath(decoration);
233}
234
236{
237 return d->canvas;
238}
239
241{
242 d->ignoredPoints = ignoredPoints;
243}
244
246{
247 return d->ignoredPoints;
248}
249
251{
252 d->ignoredShapes = ignoredShapes;
253}
254
256{
257 return d->ignoredShapes;
258}
259
261{
262 d->currentStrategy.clear();
263 d->additionalEditedShape = 0;
264 d->ignoredPoints.clear();
265 d->ignoredShapes.clear();
266 // remove all custom strategies
267 int strategyCount = d->strategies.count();
268 for (int i = strategyCount-1; i >= 0; --i) {
269 if (d->strategies[i]->type() == CustomSnapping) {
270 d->strategies.removeAt(i);
271 }
272 }
273}
274
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
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.
bool isStrategyEnabled(Strategy type) const
const QScopedPointer< Private > d
void setIgnoredPathPoints(const QList< KoPathPoint * > &ignoredPoints)
Sets a list of path points to ignore.
void paint(QPainter &painter, const KoViewConverter &converter)
paints the guide
QList< KoSnapStrategySP > StrategiesList
void setSnapDistance(int distance)
sets the snap distances in pixels
Strategy
the different possible snap Strategies
Definition KoSnapGuide.h:49
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