Code

when dragging from rulers close to the edges, one gets 45 degree angled guidelines.
[inkscape.git] / src / desktop-events.cpp
1 #define __SP_DESKTOP_EVENTS_C__
3 /*
4  * Event handlers for SPDesktop
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 1999-2002 Lauris Kaplinski
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
17 #include "display/guideline.h"
18 #include "helper/unit-menu.h"
19 #include "helper/units.h"
20 #include "desktop.h"
21 #include "document.h"
22 #include "sp-guide.h"
23 #include "sp-namedview.h"
24 #include "desktop-handles.h"
25 #include "event-context.h"
26 #include "widgets/desktop-widget.h"
27 #include "sp-metrics.h"
28 #include <glibmm/i18n.h>
29 #include "dialogs/dialog-events.h"
30 #include "message-context.h"
31 #include "xml/repr.h"
32 #include "dialogs/guidelinedialog.h"
33 #include "snap.h"
35 /* Root item handler */
37 int sp_desktop_root_handler(SPCanvasItem */*item*/, GdkEvent *event, SPDesktop *desktop)
38 {
39     return sp_event_context_root_handler(desktop->event_context, event);
40 }
43 static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw, bool horiz)
44 {
45     static bool dragging = false;
46     static SPCanvasItem *guide = NULL;
47     static Geom::Point normal;
48     int wx, wy;
50     SPDesktop *desktop = dtw->desktop;
51     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
53     gdk_window_get_pointer(GTK_WIDGET(dtw->canvas)->window, &wx, &wy, NULL);
54     NR::Point const event_win(wx, wy);
56     gint width, height;
57     gdk_window_get_geometry(GTK_WIDGET(dtw->canvas)->window, NULL /*x*/, NULL /*y*/, &width, &height, NULL/*depth*/);
59     switch (event->type) {
60     case GDK_BUTTON_PRESS:
61             if (event->button.button == 1) {
62                 dragging = true;
63                 NR::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
64                 NR::Point const event_dt(desktop->w2d(event_w));
66                 // explicitly show guidelines; if I draw a guide, I want them on
67                 sp_repr_set_boolean(repr, "showguides", TRUE);
68                 sp_repr_set_boolean(repr, "inkscape:guide-bbox", TRUE);
70                 if (horiz) {
71                     if (wx < 50) {
72                         normal = Geom::Point(-1.,1.);
73                         normal.normalize();
74                     } else if (wx > width - 50) {
75                         normal = Geom::Point(1.,1.);
76                         normal.normalize();
77                     } else {
78                         normal = Geom::Point(0.,1.);
79                     }
80                 } else {
81                     if (wy < 50) {
82                         normal = Geom::Point(-1.,1.);
83                         normal.normalize();
84                     } else if (wy > height - 50) {
85                         normal = Geom::Point(1.,1.);
86                         normal.normalize();
87                     } else {
88                         normal = Geom::Point(1.,0.);
89                     }
90                 }
92                 guide = sp_guideline_new(desktop->guides, event_dt.to_2geom(), normal);
93                 sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor);
94                 gdk_pointer_grab(widget->window, FALSE,
95                                  (GdkEventMask)(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK ),
96                                  NULL, NULL,
97                                  event->button.time);
98             }
99             break;
100     case GDK_MOTION_NOTIFY:
101             if (dragging) {
102                 NR::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
103                 NR::Point event_dt(desktop->w2d(event_w));
104                 
105                 SnapManager const &m = desktop->namedview->snap_manager;
106                 event_dt = m.guideSnap(event_dt, normal).getPoint();
107                 
108                 sp_guideline_set_position(SP_GUIDELINE(guide), event_dt.to_2geom());
109                 desktop->set_coordinate_status(event_dt);
110                 desktop->setPosition (event_dt);
111             }
112             break;
113     case GDK_BUTTON_RELEASE:
114             if (dragging && event->button.button == 1) {
115                 gdk_pointer_ungrab(event->button.time);
116                 NR::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
117                 NR::Point event_dt(desktop->w2d(event_w));
118                 
119                 SnapManager const &m = desktop->namedview->snap_manager;
120                 event_dt = m.guideSnap(event_dt, normal).getPoint();
121                                 
122                 dragging = false;
123                 gtk_object_destroy(GTK_OBJECT(guide));
124                 guide = NULL;
125                 if ((horiz ? wy : wx) >= 0) {
126                     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
127                     Inkscape::XML::Node *repr = xml_doc->createElement("sodipodi:guide");
128                     sp_repr_set_point(repr, "orientation", normal);
129                     sp_repr_set_point(repr, "position", event_dt.to_2geom());
130                     SP_OBJECT_REPR(desktop->namedview)->appendChild(repr);
131                     Inkscape::GC::release(repr);
132                     sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, 
133                                      _("Create guide"));
134                 }
135                 desktop->set_coordinate_status(event_dt);
136             }
137         default:
138             break;
139     }
141     return FALSE;
144 int sp_dt_hruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw)
146     return sp_dt_ruler_event(widget, event, dtw, true);
149 int sp_dt_vruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw)
151     return sp_dt_ruler_event(widget, event, dtw, false);
154 /* Guides */
156 gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data)
158     static bool dragging = false;
159     static bool moved = false;
160     gint ret = FALSE;
162     SPGuide *guide = SP_GUIDE(data);
163     SPDesktop *desktop = static_cast<SPDesktop*>(gtk_object_get_data(GTK_OBJECT(item->canvas), "SPDesktop"));
165         switch (event->type) {
166         case GDK_2BUTTON_PRESS:
167             if (event->button.button == 1) {
168                 dragging = false;
169                 sp_canvas_item_ungrab(item, event->button.time);
170                 Inkscape::UI::Dialogs::GuidelinePropertiesDialog::showDialog(guide, desktop);
171                 ret = TRUE;
172             }
173             break;
174         case GDK_BUTTON_PRESS:
175             if (event->button.button == 1) {
176                 dragging = true;
177                 sp_canvas_item_grab(item,
178                                     ( GDK_BUTTON_RELEASE_MASK  |
179                                       GDK_BUTTON_PRESS_MASK    |
180                                       GDK_POINTER_MOTION_MASK ),
181                                     NULL,
182                                     event->button.time);
183                 ret = TRUE;
184             }
185             break;
186     case GDK_MOTION_NOTIFY:
187             if (dragging) {
188                 NR::Point const motion_w(event->motion.x,
189                                          event->motion.y);
190                 NR::Point motion_dt(desktop->w2d(motion_w));
191                 
192                 // This is for snapping while dragging existing guidelines. New guidelines, 
193                 // which are dragged off the ruler, are being snapped in sp_dt_ruler_event
194                 SnapManager const &m = desktop->namedview->snap_manager;
195                 motion_dt = m.guideSnap(motion_dt, guide->normal_to_line).getPoint();
196                 
197                 sp_guide_moveto(*guide, motion_dt.to_2geom(), false);
198                 moved = true;
199                 desktop->set_coordinate_status(motion_dt);
200                 desktop->setPosition (motion_dt);
201                 ret = TRUE;
202             }
203             break;
204     case GDK_BUTTON_RELEASE:
205             if (dragging && event->button.button == 1) {
206                 if (moved) {
207                     NR::Point const event_w(event->button.x,
208                                             event->button.y);
209                     NR::Point event_dt(desktop->w2d(event_w));
211                     SnapManager const &m = desktop->namedview->snap_manager;
212                     event_dt = m.guideSnap(event_dt, guide->normal_to_line).getPoint();
214                     if (sp_canvas_world_pt_inside_window(item->canvas, event_w)) {
215                         sp_guide_moveto(*guide, event_dt.to_2geom(), true);
216                         sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE,
217                                      _("Move guide"));
218                     } else {
219                         /* Undo movement of any attached shapes. */
220                         sp_guide_moveto(*guide, guide->point_on_line, false);
221                         sp_guide_remove(guide);
222                         sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE,
223                                      _("Delete guide"));
224                     }
225                     moved = false;
226                     desktop->set_coordinate_status(event_dt);
227                     desktop->setPosition (event_dt);
228                 }
229                 dragging = false;
230                 sp_canvas_item_ungrab(item, event->button.time);
231                 ret=TRUE;
232             }
233     case GDK_ENTER_NOTIFY:
234     {
235             sp_guideline_set_color(SP_GUIDELINE(item), guide->hicolor);
237             char *guide_description = sp_guide_description(guide);
238             desktop->guidesMessageContext()->setF(Inkscape::NORMAL_MESSAGE, "%s", guide_description);
239             g_free(guide_description);
240             break;
241     }
242     case GDK_LEAVE_NOTIFY:
243             sp_guideline_set_color(SP_GUIDELINE(item), guide->color);
244             desktop->guidesMessageContext()->clear();
245             break;
246     default:
247             break;
248     }
250     return ret;
254 /*
255   Local Variables:
256   mode:c++
257   c-file-style:"stroustrup"
258   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
259   indent-tabs-mode:nil
260   fill-column:99
261   End:
262 */
263 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :