Code

snap indicator: try a diamond shaped indicator for snapping to nodes. see how we...
[inkscape.git] / src / context-fns.cpp
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <glibmm/i18n.h>
6 #include "sp-item.h"
7 #include "desktop.h"
8 #include "message-context.h"
9 #include "message-stack.h"
10 #include "context-fns.h"
11 #include "snap.h"
12 #include "desktop-affine.h"
13 #include "event-context.h"
14 #include "sp-namedview.h"
15 #include "display/snap-indicator.h"
17 static const double midpt_1_goldenratio = (1 + goldenratio) / 2;
18 static const double midpt_goldenratio_2 = (goldenratio + 2) / 2;
20 /* FIXME: could probably use a template here */
22 /**
23  *  Check to see if the current layer is both unhidden and unlocked.  If not,
24  *  set a message about it on the given context.
25  *
26  *  \param desktop Desktop.
27  *  \param message Message context to put messages on.
28  *  \return true if the current layer is both unhidden and unlocked, otherwise false.
29  */
31 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageContext *message)
32 {
33     SPItem const *layer = SP_ITEM(desktop->currentLayer());
35     if ( !layer || desktop->itemIsHidden(layer) ) {
36             message->flash(Inkscape::ERROR_MESSAGE,
37                          _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
38             return false;
39     }
41     if ( !layer || layer->isLocked() ) {
42             message->flash(Inkscape::ERROR_MESSAGE,
43                          _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
44             return false;
45     }
47     return true;
48 }
51 /**
52  *  Check to see if the current layer is both unhidden and unlocked.  If not,
53  *  set a message about it on the given context.
54  *
55  *  \param desktop Desktop.
56  *  \param message Message context to put messages on.
57  *  \return true if the current layer is both unhidden and unlocked, otherwise false.
58  */
60 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageStack *message)
61 {
62     SPItem const *layer = SP_ITEM(desktop->currentLayer());
64     if ( !layer || desktop->itemIsHidden(layer) ) {
65             message->flash(Inkscape::WARNING_MESSAGE,
66                          _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
67             return false;
68     }
70     if ( !layer || layer->isLocked() ) {
71             message->flash(Inkscape::WARNING_MESSAGE,
72                          _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
73             return false;
74     }
76     return true;
77 }
80 Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item,
81                                         Geom::Point const &pt, Geom::Point const &center, int state)
82 {
83     Geom::Point p[2];
85     bool const shift = state & GDK_SHIFT_MASK;
86     bool const control = state & GDK_CONTROL_MASK;
88     SnapManager &m = desktop->namedview->snap_manager;
89     m.setup(desktop, false, item);
90     Inkscape::SnappedPoint snappoint;
92     if (control) {
94         /* Control is down: we are constrained to producing integer-ratio rectangles */
96         /* Vector from the centre of the box to the point we are dragging to */
97         Geom::Point delta = pt - center;
99         /* Round it so that we have an integer-ratio (or golden ratio) box */
100         if (fabs(delta[Geom::X]) > fabs(delta[Geom::Y]) && (delta[Geom::Y] != 0.0)) {
101             double ratio = delta[Geom::X] / delta[Geom::Y];
102             double ratioabs = fabs (ratio);
103             double sign = (ratio < 0 ? -1 : 1);
104             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
105                 delta[Geom::X] = sign * goldenratio * delta[Geom::Y];
106             } else {
107                 delta[Geom::X] = floor(ratio + 0.5) * delta[Geom::Y];
108             }
109         } else if (delta[Geom::X] != 0.0) {
110             double ratio = delta[Geom::Y] / delta[Geom::X];
111             double ratioabs = fabs (ratio);
112             double sign = (ratio < 0 ? -1 : 1);
113             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
114                 delta[Geom::Y] = sign * goldenratio * delta[Geom::X];
115             } else {
116                 delta[Geom::Y] = floor(delta[Geom::Y] / delta[Geom::X] + 0.5) * delta[Geom::X];
117             }
118         }
120         /* p[1] is the dragged point with the integer-ratio constraint */
121         p[1] = center + delta;
123         if (shift) {
125             /* Shift is down, so our origin is the centre point rather than the corner
126             ** point; this means that corner-point movements are bound to each other.
127             */
129             /* p[0] is the opposite corner of our box */
130             p[0] = center - delta;
132             Inkscape::SnappedPoint s[2];
134             /* Try to snap p[0] (the opposite corner) along the constraint vector */
135             s[0] = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[0]),
136                                      Inkscape::Snapper::ConstraintLine(p[0] - p[1]));
138             /* Try to snap p[1] (the dragged corner) along the constraint vector */
139             s[1] = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]),
140                                      Inkscape::Snapper::ConstraintLine(p[1] - p[0]));
142             /* Choose the best snap and update points accordingly */
143             if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
144                 if (s[0].getSnapped()) {
145                     p[0] = s[0].getPoint();
146                     p[1] = 2 * center - s[0].getPoint();
147                     snappoint = s[0];
148                 }
149             } else {
150                 if (s[1].getSnapped()) {
151                     p[0] = 2 * center - s[1].getPoint();
152                     p[1] = s[1].getPoint();
153                     snappoint = s[1];
154                 }
155             }
156         } else {
158             /* Our origin is the opposite corner.  Snap the drag point along the constraint vector */
159             p[0] = center;
160             snappoint = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]),
161                                           Inkscape::Snapper::ConstraintLine(p[1] - p[0]));
162             if (snappoint.getSnapped()) {
163                 p[1] = snappoint.getPoint();
164             }
165         }
167     } else if (shift) {
169         /* Shift is down, so our origin is the centre point rather than the corner point;
170         ** this means that corner-point movements are bound to each other.
171         */
173         p[1] = pt;
174         p[0] = 2 * center - p[1];
176         Inkscape::SnappedPoint s[2];
178         s[0] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[0]));
179         s[1] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]));
181         if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
182             if (s[0].getSnapped()) {
183                 p[0] = s[0].getPoint();
184                 p[1] = 2 * center - s[0].getPoint();
185                 snappoint = s[0];
186             }
187         } else {
188             if (s[1].getSnapped()) {
189                 p[0] = 2 * center - s[1].getPoint();
190                 p[1] = s[1].getPoint();
191                 snappoint = s[1];
192             }
193         }
195     } else {
197         /* There's no constraint on the corner point, so just snap it to anything */
198         p[0] = center;
199         p[1] = pt;
200         snappoint = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(pt));
201         if (snappoint.getSnapped()) {
202             p[1] = snappoint.getPoint();
203         }
204     }
206     if (snappoint.getSnapped()) {
207         desktop->snapindicator->set_new_snaptarget(snappoint);
208     }
210     p[0] = sp_desktop_dt2doc_xy_point(desktop, p[0]);
211     p[1] = sp_desktop_dt2doc_xy_point(desktop, p[1]);
212     
213     return Geom::Rect(Geom::Point(MIN(p[0][Geom::X], p[1][Geom::X]), MIN(p[0][Geom::Y], p[1][Geom::Y])),
214                     Geom::Point(MAX(p[0][Geom::X], p[1][Geom::X]), MAX(p[0][Geom::Y], p[1][Geom::Y])));
219 Geom::Point Inkscape::setup_for_drag_start(SPDesktop *desktop, SPEventContext* ec, GdkEvent *ev)
221     ec->xp = static_cast<gint>(ev->button.x);
222     ec->yp = static_cast<gint>(ev->button.y);
223     ec->within_tolerance = true;
225     Geom::Point const p(ev->button.x, ev->button.y);
226     ec->item_to_select = sp_event_context_find_item(desktop, p, ev->button.state & GDK_MOD1_MASK, TRUE);
227     return ec->desktop->w2d(p);
231 /*
232   Local Variables:
233   mode:c++
234   c-file-style:"stroustrup"
235   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
236   indent-tabs-mode:nil
237   fill-column:99
238   End:
239 */
240 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :