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 ¢er, 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])));
214 }
218 Geom::Point Inkscape::setup_for_drag_start(SPDesktop *desktop, SPEventContext* ec, GdkEvent *ev)
219 {
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);
227 }
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 :