Code

Reduce libsigc++ usage to partially fix performance regressions
[inkscape.git] / src / ui / tool / selector.cpp
1 /** @file
2  * Selector component (click and rubberband)
3  */
4 /* Authors:
5  *   Krzysztof KosiƄski <tweenk.pl@gmail.com>
6  *
7  * Copyright (C) 2009 Authors
8  * Released under GNU GPL, read the file 'COPYING' for more information
9  */
11 #include "desktop.h"
12 #include "desktop-handles.h"
13 #include "display/sodipodi-ctrlrect.h"
14 #include "event-context.h"
15 #include "preferences.h"
16 #include "ui/tool/control-point.h"
17 #include "ui/tool/event-utils.h"
18 #include "ui/tool/selector.h"
20 namespace Inkscape {
21 namespace UI {
23 /** A hidden control point used for rubberbanding and selection.
24  * It uses a clever hack: the canvas item is hidden and only receives events when they
25  * are passed to it using Selector's event() function. When left mouse button
26  * is pressed, it grabs events and handles drags and clicks in the usual way. */
27 class SelectorPoint : public ControlPoint {
28 public:
29     SelectorPoint(SPDesktop *d, SPCanvasGroup *group, Selector *s)
30         : ControlPoint(d, Geom::Point(0,0), Gtk::ANCHOR_CENTER, SP_CTRL_SHAPE_SQUARE,
31             1, &invisible_cset, group)
32         , _selector(s)
33         , _cancel(false)
34     {
35         setVisible(false);
36         _rubber = static_cast<CtrlRect*>(sp_canvas_item_new(sp_desktop_controls(_desktop),
37         SP_TYPE_CTRLRECT, NULL));
38         sp_canvas_item_hide(_rubber);
39     }
40     ~SelectorPoint() {
41         gtk_object_destroy(_rubber);
42     }
43     SPDesktop *desktop() { return _desktop; }
44     bool event(GdkEvent *e) {
45         return _eventHandler(e);
46     }
48 protected:
49     virtual bool _eventHandler(GdkEvent *event) {
50         if (event->type == GDK_KEY_PRESS && shortcut_key(event->key) == GDK_Escape &&
51             sp_canvas_item_is_visible(_rubber))
52         {
53             _cancel = true;
54             sp_canvas_item_hide(_rubber);
55             return true;
56         }
57         return ControlPoint::_eventHandler(event);
58     }
60 private:
61     virtual bool grabbed(GdkEventMotion *) {
62         _cancel = false;
63         _start = position();
64         sp_canvas_item_show(_rubber);
65         return false;
66     }
67     virtual void dragged(Geom::Point &new_pos, GdkEventMotion *) {
68         if (_cancel) return;
69         Geom::Rect sel(_start, new_pos);
70         _rubber->setRectangle(sel);
71     }
72     virtual void ungrabbed(GdkEventButton *event) {
73         if (_cancel) return;
74         sp_canvas_item_hide(_rubber);
75         Geom::Rect sel(_start, position());
76         _selector->signal_area.emit(sel, event);
77     }
78     virtual bool clicked(GdkEventButton *event) {
79         if (event->button != 1) return false;
80         _selector->signal_point.emit(position(), event);
81         return true;
82     }
83     CtrlRect *_rubber;
84     Selector *_selector;
85     Geom::Point _start;
86     bool _cancel;
87 };
90 Selector::Selector(SPDesktop *d)
91     : Manipulator(d)
92     , _dragger(new SelectorPoint(d, sp_desktop_controls(d), this))
93 {
94     _dragger->setVisible(false);
95 }
97 Selector::~Selector()
98 {
99     delete _dragger;
102 bool Selector::event(GdkEvent *event)
104     // The hidden control point will capture all events after it obtains the grab,
105     // but it relies on this function to initiate it. Here we can filter what events
106     // it will receive.
107     switch (event->type) {
108     case GDK_BUTTON_PRESS:
109         // Do not pass button presses other than left button to the control point.
110         // This way middle click and right click can be handled in SPEventContext.
111         if (event->button.button != 1) return false;
112         _dragger->setPosition(_desktop->w2d(event_point(event->motion)));
113         break;
114     default: break;
115     }
116     return _dragger->event(event);
119 } // namespace UI
120 } // namespace Inkscape
122 /*
123   Local Variables:
124   mode:c++
125   c-file-style:"stroustrup"
126   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
127   indent-tabs-mode:nil
128   fill-column:99
129   End:
130 */
131 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :