Code

* Implement node snapping.
[inkscape.git] / src / snap.h
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-2009 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         TRANSLATION,
71         SCALE,
72         STRETCH,
73         SKEW
74     };
76         SnapManager(SPNamedView const *v);
78     typedef std::list<const Inkscape::Snapper*> SnapperList;
80     bool someSnapperMightSnap() const;
81     bool gridSnapperMightSnap() const;
83     void setup(SPDesktop const *desktop,
84                         bool snapindicator = true,
85                         SPItem const *item_to_ignore = NULL,
86                         std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
87                         SPGuide *guide_to_ignore = NULL);
89     void setup(SPDesktop const *desktop,
90                 bool snapindicator,
91                 std::vector<SPItem const *> const &items_to_ignore,
92                 std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
93                 SPGuide *guide_to_ignore = NULL);
94     void setupIgnoreSelection(SPDesktop const *desktop,
95                               bool snapindicator = true,
96                               std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
97                               SPGuide *guide_to_ignore = NULL);
99     // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
100     // point if snapping has occurred (by overwriting p); otherwise p is untouched
101     void freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
102                                                         Geom::Point &p,
103                                                         Inkscape::SnapSourceType const source_type,
104                                                         bool first_point = true,
105                                                         Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
108     Inkscape::SnappedPoint freeSnap(Inkscape::SnapPreferences::PointType point_type,
109                                                                         Geom::Point const &p,
110                                                             Inkscape::SnapSourceType const &source_type,
111                                         bool first_point = true,
112                                     Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
114     Geom::Point multipleOfGridPitch(Geom::Point const &t) const;
116     // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
117     // point, by overwriting p, if snapping has occurred; otherwise p is untouched
118     void constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
119                                                                         Geom::Point &p,
120                                                                         Inkscape::SnapSourceType const source_type,
121                                                                         Inkscape::Snapper::ConstraintLine const &constraint,
122                                                                         bool first_point = true,
123                                                                         Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
125     Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapPreferences::PointType point_type,
126                                                                                    Geom::Point const &p,
127                                                                                    Inkscape::SnapSourceType const &source_type,
128                                                                                    Inkscape::Snapper::ConstraintLine const &constraint,
129                                                                                    bool first_point = true,
130                                            Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
132     void guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal, SPGuideDragType drag_type) const;
133     void guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const;
135     Inkscape::SnappedPoint freeSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
136                                                std::vector<std::pair<Geom::Point, int> > const &p,
137                                                Geom::Point const &pointer,
138                                                Geom::Point const &tr) const;
140     Inkscape::SnappedPoint constrainedSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
141                                                       std::vector<std::pair<Geom::Point, int> > const &p,
142                                                       Geom::Point const &pointer,
143                                                       Inkscape::Snapper::ConstraintLine const &constraint,
144                                                       Geom::Point const &tr) const;
146     Inkscape::SnappedPoint freeSnapScale(Inkscape::SnapPreferences::PointType point_type,
147                                          std::vector<std::pair<Geom::Point, int> > const &p,
148                                          Geom::Point const &pointer,
149                                          Geom::Scale const &s,
150                                          Geom::Point const &o) const;
152     Inkscape::SnappedPoint constrainedSnapScale(Inkscape::SnapPreferences::PointType point_type,
153                                                 std::vector<std::pair<Geom::Point, int> > const &p,
154                                                 Geom::Point const &pointer,
155                                                 Geom::Scale const &s,
156                                                 Geom::Point const &o) const;
158     Inkscape::SnappedPoint constrainedSnapStretch(Inkscape::SnapPreferences::PointType point_type,
159                                                   std::vector<std::pair<Geom::Point, int> > const &p,
160                                                   Geom::Point const &pointer,
161                                                   Geom::Coord const &s,
162                                                   Geom::Point const &o,
163                                                   Geom::Dim2 d,
164                                                   bool uniform) const;
166     Inkscape::SnappedPoint constrainedSnapSkew(Inkscape::SnapPreferences::PointType point_type,
167                                                std::vector<std::pair<Geom::Point, int> > const &p,
168                                                Geom::Point const &pointer,
169                                                Inkscape::Snapper::ConstraintLine const &constraint,
170                                                Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
171                                                Geom::Point const &o,
172                                                Geom::Dim2 d) const;
174     Inkscape::GuideSnapper guide;      ///< guide snapper
175     Inkscape::ObjectSnapper object;    ///< snapper to other objects
176     Inkscape::SnapPreferences snapprefs;
178     SnapperList getSnappers() const;
179     SnapperList getGridSnappers() const;
181     SPDesktop const *getDesktop() const {return _desktop;}
182     SPNamedView const *getNamedView() const {return _named_view;}
183     SPDocument *getDocument() const;
184     SPGuide const *getGuideToIgnore() const {return _guide_to_ignore;}
186     bool getSnapIndicator() const {return _snapindicator;}
188 protected:
189     SPNamedView const *_named_view;
191 private:
192     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
193     SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
194     SPDesktop const *_desktop;
195     bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
196     std::vector<std::pair<Geom::Point, int> > *_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
197     //TODO: Make _unselected_nodes type safe; in the line above int is used for Inkscape::SnapTargetType, but if I remember
198     //correctly then in other cases the int is being used for Inkscape::SnapSourceType, or for both. How to make
199     //this type safe?
201     Inkscape::SnappedPoint _snapTransformed(Inkscape::SnapPreferences::PointType type,
202                                             std::vector<std::pair<Geom::Point, int> > const &points,
203                                             Geom::Point const &pointer,
204                                             bool constrained,
205                                             Inkscape::Snapper::ConstraintLine const &constraint,
206                                             Transformation transformation_type,
207                                             Geom::Point const &transformation,
208                                             Geom::Point const &origin,
209                                             Geom::Dim2 dim,
210                                             bool uniform) const;
212     Geom::Point _transformPoint(std::pair<Geom::Point, int> const &p,
213                                             Transformation const transformation_type,
214                                             Geom::Point const &transformation,
215                                             Geom::Point const &origin,
216                                             Geom::Dim2 const dim,
217                                             bool const uniform) const;
219     void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, std::pair<Geom::Point, int> const &p) const;
221     Inkscape::SnappedPoint findBestSnap(Geom::Point const &p, Inkscape::SnapSourceType const source_type, SnappedConstraints &sc, bool constrained, bool noCurves = false) const;
222 };
224 #endif /* !SEEN_SNAP_H */
226 /*
227   Local Variables:
228   mode:c++
229   c-file-style:"stroustrup"
230   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
231   indent-tabs-mode:nil
232   fill-column:99
233   End:
234 */
235 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :