Code

Fixed signed/unsigned problem with precision calc. Fixes bug #399604.
[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 "event-context.h"
13 #include "sp-namedview.h"
14 #include "display/snap-indicator.h"
16 static const double midpt_1_goldenratio = (1 + goldenratio) / 2;
17 static const double midpt_goldenratio_2 = (goldenratio + 2) / 2;
19 /* FIXME: could probably use a template here */
21 /**
22  *  Check to see if the current layer is both unhidden and unlocked.  If not,
23  *  set a message about it on the given context.
24  *
25  *  \param desktop Desktop.
26  *  \param message Message context to put messages on.
27  *  \return true if the current layer is both unhidden and unlocked, otherwise false.
28  */
30 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageContext *message)
31 {
32     SPItem const *layer = SP_ITEM(desktop->currentLayer());
34     if ( !layer || desktop->itemIsHidden(layer) ) {
35             message->flash(Inkscape::ERROR_MESSAGE,
36                          _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
37             return false;
38     }
40     if ( !layer || layer->isLocked() ) {
41             message->flash(Inkscape::ERROR_MESSAGE,
42                          _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
43             return false;
44     }
46     return true;
47 }
50 /**
51  *  Check to see if the current layer is both unhidden and unlocked.  If not,
52  *  set a message about it on the given context.
53  *
54  *  \param desktop Desktop.
55  *  \param message Message context to put messages on.
56  *  \return true if the current layer is both unhidden and unlocked, otherwise false.
57  */
59 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageStack *message)
60 {
61     SPItem const *layer = SP_ITEM(desktop->currentLayer());
63     if ( !layer || desktop->itemIsHidden(layer) ) {
64             message->flash(Inkscape::WARNING_MESSAGE,
65                          _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
66             return false;
67     }
69     if ( !layer || layer->isLocked() ) {
70             message->flash(Inkscape::WARNING_MESSAGE,
71                          _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
72             return false;
73     }
75     return true;
76 }
79 Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item,
80                                         Geom::Point const &pt, Geom::Point const &center, int state)
81 {
82     Geom::Point p[2];
84     bool const shift = state & GDK_SHIFT_MASK;
85     bool const control = state & GDK_CONTROL_MASK;
87     SnapManager &m = desktop->namedview->snap_manager;
88     m.setup(desktop, false, item);
89     Inkscape::SnappedPoint snappoint;
91     if (control) {
93         /* Control is down: we are constrained to producing integer-ratio rectangles */
95         /* Vector from the centre of the box to the point we are dragging to */
96         Geom::Point delta = pt - center;
98         /* Round it so that we have an integer-ratio (or golden ratio) box */
99         if (fabs(delta[Geom::X]) > fabs(delta[Geom::Y]) && (delta[Geom::Y] != 0.0)) {
100             double ratio = delta[Geom::X] / delta[Geom::Y];
101             double ratioabs = fabs (ratio);
102             double sign = (ratio < 0 ? -1 : 1);
103             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
104                 delta[Geom::X] = sign * goldenratio * delta[Geom::Y];
105             } else {
106                 delta[Geom::X] = floor(ratio + 0.5) * delta[Geom::Y];
107             }
108         } else if (delta[Geom::X] != 0.0) {
109             double ratio = delta[Geom::Y] / delta[Geom::X];
110             double ratioabs = fabs (ratio);
111             double sign = (ratio < 0 ? -1 : 1);
112             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
113                 delta[Geom::Y] = sign * goldenratio * delta[Geom::X];
114             } else {
115                 delta[Geom::Y] = floor(delta[Geom::Y] / delta[Geom::X] + 0.5) * delta[Geom::X];
116             }
117         }
119         /* p[1] is the dragged point with the integer-ratio constraint */
120         p[1] = center + delta;
122         if (shift) {
124             /* Shift is down, so our origin is the centre point rather than the corner
125             ** point; this means that corner-point movements are bound to each other.
126             */
128             /* p[0] is the opposite corner of our box */
129             p[0] = center - delta;
131             Inkscape::SnappedPoint s[2];
133             /* Try to snap p[0] (the opposite corner) along the constraint vector */
134             s[0] = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[0]), Inkscape::SNAPSOURCE_HANDLE,
135                                      Inkscape::Snapper::ConstraintLine(p[0] - p[1]), false);
137             /* Try to snap p[1] (the dragged corner) along the constraint vector */
138             s[1] = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]), Inkscape::SNAPSOURCE_HANDLE,
139                                      Inkscape::Snapper::ConstraintLine(p[1] - p[0]), false);
141             /* Choose the best snap and update points accordingly */
142             if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
143                 if (s[0].getSnapped()) {
144                     p[0] = s[0].getPoint();
145                     p[1] = 2 * center - s[0].getPoint();
146                     snappoint = s[0];
147                 }
148             } else {
149                 if (s[1].getSnapped()) {
150                     p[0] = 2 * center - s[1].getPoint();
151                     p[1] = s[1].getPoint();
152                     snappoint = s[1];
153                 }
154             }
155         } else {
157             /* Our origin is the opposite corner.  Snap the drag point along the constraint vector */
158             p[0] = center;
159             snappoint = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]), Inkscape::SNAPSOURCE_HANDLE,
160                                           Inkscape::Snapper::ConstraintLine(p[1] - p[0]), false);
161             if (snappoint.getSnapped()) {
162                 p[1] = snappoint.getPoint();
163             }
164         }
166     } else if (shift) {
168         /* Shift is down, so our origin is the centre point rather than the corner point;
169         ** this means that corner-point movements are bound to each other.
170         */
172         p[1] = pt;
173         p[0] = 2 * center - p[1];
175         Inkscape::SnappedPoint s[2];
177         s[0] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[0]), Inkscape::SNAPSOURCE_HANDLE);
178         s[1] = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(p[1]), Inkscape::SNAPSOURCE_HANDLE);
180         if (s[0].getSnapDistance() < s[1].getSnapDistance()) {
181             if (s[0].getSnapped()) {
182                 p[0] = s[0].getPoint();
183                 p[1] = 2 * center - s[0].getPoint();
184                 snappoint = s[0];
185             }
186         } else {
187             if (s[1].getSnapped()) {
188                 p[0] = 2 * center - s[1].getPoint();
189                 p[1] = s[1].getPoint();
190                 snappoint = s[1];
191             }
192         }
194     } else {
196         /* There's no constraint on the corner point, so just snap it to anything */
197         p[0] = center;
198         p[1] = pt;
199         snappoint = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(pt), Inkscape::SNAPSOURCE_HANDLE);
200         if (snappoint.getSnapped()) {
201             p[1] = snappoint.getPoint();
202         }
203     }
205     if (snappoint.getSnapped()) {
206         desktop->snapindicator->set_new_snaptarget(snappoint);
207     }
209     p[0] *= desktop->dt2doc();
210     p[1] *= desktop->dt2doc();
212     return Geom::Rect(Geom::Point(MIN(p[0][Geom::X], p[1][Geom::X]), MIN(p[0][Geom::Y], p[1][Geom::Y])),
213                     Geom::Point(MAX(p[0][Geom::X], p[1][Geom::X]), MAX(p[0][Geom::Y], p[1][Geom::Y])));
218 Geom::Point Inkscape::setup_for_drag_start(SPDesktop *desktop, SPEventContext* ec, GdkEvent *ev)
220     ec->xp = static_cast<gint>(ev->button.x);
221     ec->yp = static_cast<gint>(ev->button.y);
222     ec->within_tolerance = true;
224     Geom::Point const p(ev->button.x, ev->button.y);
225     ec->item_to_select = sp_event_context_find_item(desktop, p, ev->button.state & GDK_MOD1_MASK, TRUE);
226     return ec->desktop->w2d(p);
230 /*
231   Local Variables:
232   mode:c++
233   c-file-style:"stroustrup"
234   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
235   indent-tabs-mode:nil
236   fill-column:99
237   End:
238 */
239 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :