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 /* FIXME: could probably use a template here */
18 /**
19 * Check to see if the current layer is both unhidden and unlocked. If not,
20 * set a message about it on the given context.
21 *
22 * \param desktop Desktop.
23 * \param message Message context to put messages on.
24 * \return true if the current layer is both unhidden and unlocked, otherwise false.
25 */
27 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageContext *message)
28 {
29 SPItem const *layer = SP_ITEM(desktop->currentLayer());
31 if ( !layer || desktop->itemIsHidden(layer) ) {
32 message->flash(Inkscape::ERROR_MESSAGE,
33 _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
34 return false;
35 }
37 if ( !layer || layer->isLocked() ) {
38 message->flash(Inkscape::ERROR_MESSAGE,
39 _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
40 return false;
41 }
43 return true;
44 }
47 /**
48 * Check to see if the current layer is both unhidden and unlocked. If not,
49 * set a message about it on the given context.
50 *
51 * \param desktop Desktop.
52 * \param message Message context to put messages on.
53 * \return true if the current layer is both unhidden and unlocked, otherwise false.
54 */
56 bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageStack *message)
57 {
58 SPItem const *layer = SP_ITEM(desktop->currentLayer());
60 if ( !layer || desktop->itemIsHidden(layer) ) {
61 message->flash(Inkscape::WARNING_MESSAGE,
62 _("<b>Current layer is hidden</b>. Unhide it to be able to draw on it."));
63 return false;
64 }
66 if ( !layer || layer->isLocked() ) {
67 message->flash(Inkscape::WARNING_MESSAGE,
68 _("<b>Current layer is locked</b>. Unlock it to be able to draw on it."));
69 return false;
70 }
72 return true;
73 }
76 NR::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item,
77 NR::Point const &pt, NR::Point const ¢er, int state)
78 {
79 NR::Point p[2];
81 bool const shift = state & GDK_SHIFT_MASK;
82 bool const control = state & GDK_CONTROL_MASK;
84 SnapManager const &m = desktop->namedview->snap_manager;
86 if (control) {
88 /* Control is down: we are constrained to producing integer-ratio rectangles */
90 /* Vector from the centre of the box to the point we are dragging to */
91 NR::Point delta = pt - center;
93 /* Round it so that we have an integer-ratio box */
94 if (fabs(delta[NR::X]) > fabs(delta[NR::Y]) && (delta[NR::Y] != 0.0)) {
95 delta[NR::X] = floor(delta[NR::X] / delta[NR::Y] + 0.5) * delta[NR::Y];
96 } else if (delta[NR::X] != 0.0) {
97 delta[NR::Y] = floor(delta[NR::Y] / delta[NR::X] + 0.5) * delta[NR::X];
98 }
100 /* p[1] is the dragged point with the integer-ratio constraint */
101 p[1] = center + delta;
103 if (shift) {
105 /* Shift is down, so our origin is the centre point rather than the corner
106 ** point; this means that corner-point movements are bound to each other.
107 */
109 /* p[0] is the opposite corner of our box */
110 p[0] = center - delta;
112 Inkscape::SnappedPoint s[2];
114 /* Try to snap p[0] (the opposite corner) along the constraint vector */
115 s[0] = m.constrainedSnap(Inkscape::Snapper::SNAP_POINT, p[0],
116 Inkscape::Snapper::ConstraintLine(p[0] - p[1]), item);
118 /* Try to snap p[1] (the dragged corner) along the constraint vector */
119 s[1] = m.constrainedSnap(Inkscape::Snapper::SNAP_POINT, p[1],
120 Inkscape::Snapper::ConstraintLine(p[1] - p[0]), item);
122 /* Choose the best snap and update points accordingly */
123 if (s[0].getDistance() < s[1].getDistance()) {
124 p[0] = s[0].getPoint();
125 p[1] = 2 * center - s[0].getPoint();
126 } else {
127 p[0] = 2 * center - s[1].getPoint();
128 p[1] = s[1].getPoint();
129 }
131 } else {
133 /* Our origin is the opposite corner. Snap the drag point along the constraint vector */
134 p[0] = center;
135 p[1] = m.constrainedSnap(Inkscape::Snapper::SNAP_POINT, p[1],
136 Inkscape::Snapper::ConstraintLine(p[1] - p[0]), item).getPoint();
137 }
139 } else if (shift) {
141 /* Shift is down, so our origin is the centre point rather than the corner point;
142 ** this means that corner-point movements are bound to each other.
143 */
145 p[1] = pt;
146 p[0] = 2 * center - p[1];
148 Inkscape::SnappedPoint s[2];
150 s[0] = m.freeSnap(Inkscape::Snapper::SNAP_POINT, p[0], item);
151 s[1] = m.freeSnap(Inkscape::Snapper::SNAP_POINT, p[1], item);
153 if (s[0].getDistance() < s[1].getDistance()) {
154 p[0] = s[0].getPoint();
155 p[1] = 2 * center - s[0].getPoint();
156 } else {
157 p[0] = 2 * center - s[1].getPoint();
158 p[1] = s[1].getPoint();
159 }
161 } else {
163 /* There's no constraint on the corner point, so just snap it to anything */
164 p[0] = center;
165 p[1] = m.freeSnap(Inkscape::Snapper::SNAP_POINT, pt, item).getPoint();
166 }
168 p[0] = sp_desktop_dt2root_xy_point(desktop, p[0]);
169 p[1] = sp_desktop_dt2root_xy_point(desktop, p[1]);
171 return NR::Rect(NR::Point(MIN(p[0][NR::X], p[1][NR::X]), MIN(p[0][NR::Y], p[1][NR::Y])),
172 NR::Point(MAX(p[0][NR::X], p[1][NR::X]), MAX(p[0][NR::Y], p[1][NR::Y])));
173 }
177 NR::Point Inkscape::setup_for_drag_start(SPDesktop *desktop, SPEventContext* ec, GdkEvent *ev)
178 {
179 ec->xp = static_cast<gint>(ev->button.x);
180 ec->yp = static_cast<gint>(ev->button.y);
181 ec->within_tolerance = true;
183 NR::Point const p(ev->button.x, ev->button.y);
184 ec->item_to_select = sp_event_context_find_item(desktop, p, ev->button.state & GDK_MOD1_MASK, TRUE);
185 return ec->desktop->w2d(p);
186 }
189 /*
190 Local Variables:
191 mode:c++
192 c-file-style:"stroustrup"
193 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
194 indent-tabs-mode:nil
195 fill-column:99
196 End:
197 */
198 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :