Code

e434c10c568cf1cc8575b8433e5625619eeb6204
[inkscape.git] / src / ui / widget / rotateable.cpp
1 /**
2  * \brief widget adjustable by dragging it to rotate away from a zero-change axis
3  *
4  * Authors:
5  *   buliabyak@gmail.com
6  *
7  * Copyright (C) 2007 authors
8  *
9  * Released under GNU GPL.  Read the file 'COPYING' for more information.
10  */
12 #include "event-context.h"
13 #include "rotateable.h"
14 #include "libnr/nr-point.h"
15 #include "libnr/nr-point-fns.h"
16 #include <gtkmm/box.h>
17 #include <gtkmm/eventbox.h>
18 #include <glibmm/i18n.h>
20 namespace Inkscape {
21 namespace UI {
22 namespace Widget {
24         Rotateable::Rotateable():
25     axis(-M_PI/4),
26     maxdecl(M_PI/4)
27   {
28                 dragging = false;
29                 working = false;
30                 modifier = 0;
31                 current_axis = axis;
33     signal_button_press_event().connect(sigc::mem_fun(*this, &Rotateable::on_click));
34     signal_motion_notify_event().connect(sigc::mem_fun(*this, &Rotateable::on_motion));
35     signal_button_release_event().connect(sigc::mem_fun(*this, &Rotateable::on_release));
36         }
38   bool Rotateable::on_click(GdkEventButton *event) {
39                 if (event->button == 1) {
40                         drag_started_x = event->x;
41                         drag_started_y = event->y;
42                         modifier = get_single_modifier(modifier, event->state); 
43                 dragging = true;
44                 working = false;
45                         current_axis = axis;
46           return true;
47                 } 
48                 return false; 
49         }
51   guint Rotateable::get_single_modifier(guint old, guint state) {
53                 if (old == 0) {
54                         if (state & GDK_CONTROL_MASK)
55                                 return 1; // ctrl
56                         if (state & GDK_SHIFT_MASK)
57                                 return 2; // shift
58                         return 0;
59                 } else {
60                         if (!(state & GDK_CONTROL_MASK) && !(state & GDK_SHIFT_MASK))
61                                 return 0; // none
62                         if (old == 1) 
63                         if (state & GDK_SHIFT_MASK && !(state & GDK_CONTROL_MASK))
64                                 return 2; // shift
65         else 
66           return 1;
67                         if (old == 2) 
68                         if (state & GDK_CONTROL_MASK && !(state & GDK_SHIFT_MASK))
69                                 return 1; // ctrl
70         else 
71           return 2;
72                 return old;
73                 }
74         }
77   bool Rotateable::on_motion(GdkEventMotion *event) {
78                 if (dragging) {
79                         double dist = NR::L2(NR::Point(event->x, event->y) - NR::Point(drag_started_x, drag_started_y));
80                         double angle = atan2(event->y - drag_started_y, event->x - drag_started_x);
81                         if (dist > 20) {
82                                 working = true;
83                         double force = CLAMP (-(angle - current_axis)/maxdecl, -1, 1);
84                         if (fabs(force) < 0.002)
85                                 force = 0; // snap to zero
86                                 if (modifier != get_single_modifier(modifier, event->state)) { 
87           // user has switched modifiers in mid drag, close past drag and start a new
88           // one, redefining axis temporarily
89                                 do_release(force, modifier);
90                                         current_axis = angle;
91                         modifier = get_single_modifier(modifier, event->state); 
92                                 } else {
93                                 do_motion(force, modifier);
94                                 }
95                         }
96       gobble_motion_events(GDK_BUTTON1_MASK);
97                 return true;
98                 } 
99                 return false; 
100         }
103   bool Rotateable::on_release(GdkEventButton *event) {
104                 if (dragging && working) {
105                         double angle = atan2(event->y - drag_started_y, event->x - drag_started_x);
106                         double force = CLAMP (-(angle - current_axis)/maxdecl, -1, 1);
107                         if (fabs(force) < 0.002)
108                                 force = 0; // snap to zero
109                         do_release(force, modifier);
110                         dragging = false;
111                         working = false;
112                         current_axis = axis;
113                         return true;
114                 }
115                 return false;
116         }
119         Rotateable::~Rotateable() {
120         }
124 } // namespace Widget
125 } // namespace UI
126 } // namespace Inkscape
128 /* 
129   Local Variables:
130   mode:c++
131   c-file-style:"stroustrup"
132   c-file-offsets:((innamespace . 0)(inline-open . 0))
133   indent-tabs-mode:nil
134   fill-column:99
135   End:
136 */
137 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :