Code

noop: reverted one line of commit #17642 (it's safe to call g_free with NULL)
[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"
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 NR::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item,
80                                         NR::Point const &pt, NR::Point const &center, int state)
81 {
82     NR::Point p[2];
84     bool const shift = state & GDK_SHIFT_MASK;
85     bool const control = state & GDK_CONTROL_MASK;
87     SnapManager const &m = desktop->namedview->snap_manager;
89     if (control) {
91         /* Control is down: we are constrained to producing integer-ratio rectangles */
93         /* Vector from the centre of the box to the point we are dragging to */
94         NR::Point delta = pt - center;
96         /* Round it so that we have an integer-ratio (or golden ratio) box */
97         if (fabs(delta[NR::X]) > fabs(delta[NR::Y]) && (delta[NR::Y] != 0.0)) {
98             double ratio = delta[NR::X] / delta[NR::Y];
99             double ratioabs = fabs (ratio);
100             double sign = (ratio < 0 ? -1 : 1);
101             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
102                 delta[NR::X] = sign * goldenratio * delta[NR::Y];
103             } else {
104                 delta[NR::X] = floor(ratio + 0.5) * delta[NR::Y];
105             }
106         } else if (delta[NR::X] != 0.0) {
107             double ratio = delta[NR::Y] / delta[NR::X];
108             double ratioabs = fabs (ratio);
109             double sign = (ratio < 0 ? -1 : 1);
110             if (midpt_1_goldenratio < ratioabs && ratioabs < midpt_goldenratio_2) {
111                 delta[NR::Y] = sign * goldenratio * delta[NR::X];
112             } else {
113                 delta[NR::Y] = floor(delta[NR::Y] / delta[NR::X] + 0.5) * delta[NR::X];
114             }
115         }
117         /* p[1] is the dragged point with the integer-ratio constraint */
118         p[1] = center + delta;
120         if (shift) {
122             /* Shift is down, so our origin is the centre point rather than the corner
123             ** point; this means that corner-point movements are bound to each other.
124             */
126             /* p[0] is the opposite corner of our box */
127             p[0] = center - delta;
129             Inkscape::SnappedPoint s[2];
131             /* Try to snap p[0] (the opposite corner) along the constraint vector */
132             s[0] = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, p[0],
133                                      Inkscape::Snapper::ConstraintLine(p[0] - p[1]), item);
135             /* Try to snap p[1] (the dragged corner) along the constraint vector */
136             s[1] = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, p[1],
137                                      Inkscape::Snapper::ConstraintLine(p[1] - p[0]), item);
139             /* Choose the best snap and update points accordingly */
140             if (s[0].getDistance() < s[1].getDistance()) {
141                 p[0] = s[0].getPoint();
142                 p[1] = 2 * center - s[0].getPoint();
143             } else {
144                 p[0] = 2 * center - s[1].getPoint();
145                 p[1] = s[1].getPoint();
146             }
148         } else {
150             /* Our origin is the opposite corner.  Snap the drag point along the constraint vector */
151             p[0] = center;
152             p[1] = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, p[1],
153                                      Inkscape::Snapper::ConstraintLine(p[1] - p[0]), item).getPoint();
154         }
156     } else if (shift) {
158         /* Shift is down, so our origin is the centre point rather than the corner point;
159         ** this means that corner-point movements are bound to each other.
160         */
162         p[1] = pt;
163         p[0] = 2 * center - p[1];
165         Inkscape::SnappedPoint s[2];
167         s[0] = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, p[0], item);
168         s[1] = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, p[1], item);
170         if (s[0].getDistance() < s[1].getDistance()) {
171             p[0] = s[0].getPoint();
172             p[1] = 2 * center - s[0].getPoint();
173         } else {
174             p[0] = 2 * center - s[1].getPoint();
175             p[1] = s[1].getPoint();
176         }
178     } else {
180         /* There's no constraint on the corner point, so just snap it to anything */
181         p[0] = center;
182         p[1] = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, pt, item).getPoint();
183     }
185     p[0] = sp_desktop_dt2root_xy_point(desktop, p[0]);
186     p[1] = sp_desktop_dt2root_xy_point(desktop, p[1]);
188     return NR::Rect(NR::Point(MIN(p[0][NR::X], p[1][NR::X]), MIN(p[0][NR::Y], p[1][NR::Y])),
189                     NR::Point(MAX(p[0][NR::X], p[1][NR::X]), MAX(p[0][NR::Y], p[1][NR::Y])));
194 NR::Point Inkscape::setup_for_drag_start(SPDesktop *desktop, SPEventContext* ec, GdkEvent *ev)
196     ec->xp = static_cast<gint>(ev->button.x);
197     ec->yp = static_cast<gint>(ev->button.y);
198     ec->within_tolerance = true;
200     NR::Point const p(ev->button.x, ev->button.y);
201     ec->item_to_select = sp_event_context_find_item(desktop, p, ev->button.state & GDK_MOD1_MASK, TRUE);
202     return ec->desktop->w2d(p);
206 /*
207   Local Variables:
208   mode:c++
209   c-file-style:"stroustrup"
210   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
211   indent-tabs-mode:nil
212   fill-column:99
213   End:
214 */
215 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :