1 /**
2 * \file snap.h
3 * \brief Per-desktop object that handles snapping queries
4 *//*
5 * Authors:
6 * Lauris Kaplinski <lauris@kaplinski.com>
7 * Frank Felfe <innerspace@iname.com>
8 * Carl Hetherington <inkscape@carlh.net>
9 * Diederik van Lierop <mail@diedenrezi.nl>
10 *
11 * Copyright (C) 2006-2007 Johan Engelen <johan@shouraizou.nl>
12 * Copyright (C) 2000-2002 Lauris Kaplinski
13 * Copyright (C) 2000-2010 Authors
14 *
15 * Released under GNU GPL, read the file 'COPYING' for more information
16 */
18 #ifndef SEEN_SNAP_H
19 #define SEEN_SNAP_H
21 #include <vector>
22 #include "guide-snapper.h"
23 #include "object-snapper.h"
24 #include "snap-preferences.h"
26 /* Guides */
27 enum SPGuideDragType { // used both here and in desktop-events.cpp
28 SP_DRAG_TRANSLATE,
29 SP_DRAG_ROTATE,
30 SP_DRAG_MOVE_ORIGIN,
31 SP_DRAG_NONE
32 };
34 class SPNamedView;
36 /// Class to coordinate snapping operations
37 /**
38 * The SnapManager class handles most (if not all) of the interfacing of the snapping mechanisms
39 * with the other parts of the code base. It stores the references to the various types of snappers
40 * for grid, guides and objects, and it stores most of the snapping preferences. Besides that
41 * it provides methods to setup the snapping environment (e.g. keeps a list of the items to ignore
42 * when looking for snap target candidates, and toggling of the snap indicator), and it provides
43 * many different methods for snapping queries (free snapping vs. constrained snapping,
44 * returning the result by reference or through a return statement, etc.)
45 *
46 * Each SPNamedView has one of these. It offers methods to snap points to whatever
47 * snappers are defined (e.g. grid, guides etc.). It also allows callers to snap
48 * points which have undergone some transformation (e.g. translation, scaling etc.)
49 *
50 * \par How snapping is implemented in Inkscape
51 * \par
52 * The snapping system consists of two key elements. The first one is the snap manager
53 * (this class), which keeps some data about objects in the document and answers queries
54 * of the type "given this point and type of transformation, what is the best place
55 * to snap to?".
56 *
57 * The second is in event-context.cpp and implements the snapping timeout. Whenever a motion
58 * events happens over the canvas, it stores it for later use and initiates a timeout.
59 * This timeout is discarded whenever a new motion event occurs. When the timeout expires,
60 * a global flag in SnapManager, accessed via getSnapPostponedGlobally(), is set to true
61 * and the stored event is replayed, but this time with snapping enabled. This way you can
62 * write snapping code directly in your control point's dragged handler as if there was
63 * no timeout.
64 */
66 class SnapManager
67 {
68 public:
69 enum Transformation {
70 TRANSLATE,
71 SCALE,
72 STRETCH,
73 SKEW,
74 ROTATE
75 };
77 SnapManager(SPNamedView const *v);
79 typedef std::list<const Inkscape::Snapper*> SnapperList;
81 bool someSnapperMightSnap() const;
82 bool gridSnapperMightSnap() const;
84 void setup(SPDesktop const *desktop,
85 bool snapindicator = true,
86 SPItem const *item_to_ignore = NULL,
87 std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes = NULL,
88 SPGuide *guide_to_ignore = NULL);
90 void setup(SPDesktop const *desktop,
91 bool snapindicator,
92 std::vector<SPItem const *> &items_to_ignore,
93 std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes = NULL,
94 SPGuide *guide_to_ignore = NULL);
96 void setupIgnoreSelection(SPDesktop const *desktop,
97 bool snapindicator = true,
98 std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes = NULL,
99 SPGuide *guide_to_ignore = NULL);
101 void unSetup() {_rotation_center_source_items = NULL;
102 _guide_to_ignore = NULL;
103 _desktop = NULL;
104 _unselected_nodes = NULL;}
106 // If we're dragging a rotation center, then setRotationCenterSource() stores the parent item
107 // of this rotation center; this reference is used to make sure that we do not snap a rotation
108 // center to itself
109 // NOTE: Must be called after calling setup(), not before!
110 void setRotationCenterSource(GSList *items) {_rotation_center_source_items = items;}
111 GSList const *getRotationCenterSource() {return _rotation_center_source_items;}
113 // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
114 // point if snapping has occurred (by overwriting p); otherwise p is untouched
115 void freeSnapReturnByRef(Geom::Point &p,
116 Inkscape::SnapSourceType const source_type,
117 Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
119 Inkscape::SnappedPoint freeSnap(Inkscape::SnapCandidatePoint const &p,
120 Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
122 void preSnap(Inkscape::SnapCandidatePoint const &p);
124 Geom::Point multipleOfGridPitch(Geom::Point const &t, Geom::Point const &origin);
126 // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
127 // point, by overwriting p, if snapping has occurred; otherwise p is untouched
128 void constrainedSnapReturnByRef(Geom::Point &p,
129 Inkscape::SnapSourceType const source_type,
130 Inkscape::Snapper::SnapConstraint const &constraint,
131 Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
133 Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapCandidatePoint const &p,
134 Inkscape::Snapper::SnapConstraint const &constraint,
135 Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
137 Inkscape::SnappedPoint multipleConstrainedSnaps(Inkscape::SnapCandidatePoint const &p,
138 std::vector<Inkscape::Snapper::SnapConstraint> const &constraints,
139 Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
141 Inkscape::SnappedPoint constrainedAngularSnap(Inkscape::SnapCandidatePoint const &p,
142 boost::optional<Geom::Point> const &p_ref,
143 Geom::Point const &o,
144 unsigned const snaps) const;
146 void guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal, SPGuideDragType drag_type) const;
147 void guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const;
149 Inkscape::SnappedPoint freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
150 Geom::Point const &pointer,
151 Geom::Point const &tr) const;
153 Inkscape::SnappedPoint constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
154 Geom::Point const &pointer,
155 Inkscape::Snapper::SnapConstraint const &constraint,
156 Geom::Point const &tr) const;
158 Inkscape::SnappedPoint freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
159 Geom::Point const &pointer,
160 Geom::Scale const &s,
161 Geom::Point const &o) const;
163 Inkscape::SnappedPoint constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
164 Geom::Point const &pointer,
165 Geom::Scale const &s,
166 Geom::Point const &o) const;
168 Inkscape::SnappedPoint constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p,
169 Geom::Point const &pointer,
170 Geom::Coord const &s,
171 Geom::Point const &o,
172 Geom::Dim2 d,
173 bool uniform) const;
175 Inkscape::SnappedPoint constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p,
176 Geom::Point const &pointer,
177 Inkscape::Snapper::SnapConstraint const &constraint,
178 Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
179 Geom::Point const &o,
180 Geom::Dim2 d) const;
182 Inkscape::SnappedPoint constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p,
183 Geom::Point const &pointer,
184 Geom::Coord const &angle,
185 Geom::Point const &o) const;
187 Inkscape::GuideSnapper guide; ///< guide snapper
188 Inkscape::ObjectSnapper object; ///< snapper to other objects
189 Inkscape::SnapPreferences snapprefs;
191 SnapperList getSnappers() const;
192 SnapperList getGridSnappers() const;
194 SPDesktop const *getDesktop() const {return _desktop;}
195 SPNamedView const *getNamedView() const {return _named_view;}
196 SPDocument *getDocument() const;
197 SPGuide const *getGuideToIgnore() const {return _guide_to_ignore;}
199 bool getSnapIndicator() const {return _snapindicator;}
201 Inkscape::SnappedPoint findBestSnap(Inkscape::SnapCandidatePoint const &p, SnappedConstraints const &sc, bool constrained, bool noCurves = false, bool allowOffScreen = false) const;
203 protected:
204 SPNamedView const *_named_view;
206 private:
207 std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
208 GSList *_rotation_center_source_items; // to avoid snapping a rotation center to itself
209 SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
210 SPDesktop const *_desktop;
211 bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
212 std::vector<Inkscape::SnapCandidatePoint> *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
214 Inkscape::SnappedPoint _snapTransformed(std::vector<Inkscape::SnapCandidatePoint> const &points,
215 Geom::Point const &pointer,
216 bool constrained,
217 Inkscape::Snapper::SnapConstraint const &constraint,
218 Transformation transformation_type,
219 Geom::Point const &transformation,
220 Geom::Point const &origin,
221 Geom::Dim2 dim,
222 bool uniform) const;
224 Geom::Point _transformPoint(Inkscape::SnapCandidatePoint const &p,
225 Transformation const transformation_type,
226 Geom::Point const &transformation,
227 Geom::Point const &origin,
228 Geom::Dim2 const dim,
229 bool const uniform) const;
231 void _displaySnapsource(Inkscape::SnapCandidatePoint const &p) const;
232 };
234 #endif /* !SEEN_SNAP_H */
236 /*
237 Local Variables:
238 mode:c++
239 c-file-style:"stroustrup"
240 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
241 indent-tabs-mode:nil
242 fill-column:99
243 End:
244 */
245 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :