summaryrefslogtreecommitdiffstats
path: root/src/ui/widget/rotateable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widget/rotateable.cpp')
-rw-r--r--src/ui/widget/rotateable.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp
new file mode 100644
index 0000000..7f32823
--- /dev/null
+++ b/src/ui/widget/rotateable.cpp
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Authors:
+ * buliabyak@gmail.com
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <gtkmm/box.h>
+#include <gtkmm/eventbox.h>
+#include <2geom/point.h>
+#include "ui/tools/tool-base.h"
+#include "rotateable.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+Rotateable::Rotateable():
+ axis(-M_PI/4),
+ maxdecl(M_PI/4)
+{
+ dragging = false;
+ working = false;
+ scrolling = false;
+ modifier = 0;
+ current_axis = axis;
+
+ signal_button_press_event().connect(sigc::mem_fun(*this, &Rotateable::on_click));
+ signal_motion_notify_event().connect(sigc::mem_fun(*this, &Rotateable::on_motion));
+ signal_button_release_event().connect(sigc::mem_fun(*this, &Rotateable::on_release));
+ gtk_widget_add_events(GTK_WIDGET(gobj()), GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
+ signal_scroll_event().connect(sigc::mem_fun(*this, &Rotateable::on_scroll));
+
+}
+
+bool Rotateable::on_click(GdkEventButton *event) {
+ if (event->button == 1) {
+ drag_started_x = event->x;
+ drag_started_y = event->y;
+ modifier = get_single_modifier(modifier, event->state);
+ dragging = true;
+ working = false;
+ current_axis = axis;
+ return true;
+ }
+ return false;
+}
+
+guint Rotateable::get_single_modifier(guint old, guint state) {
+
+ if (old == 0 || old == 3) {
+ if (state & GDK_CONTROL_MASK)
+ return 1; // ctrl
+ if (state & GDK_SHIFT_MASK)
+ return 2; // shift
+ if (state & GDK_MOD1_MASK)
+ return 3; // alt
+ return 0;
+ } else {
+ if (!(state & GDK_CONTROL_MASK) && !(state & GDK_SHIFT_MASK)) {
+ if (state & GDK_MOD1_MASK)
+ return 3; // alt
+ else
+ return 0; // none
+ }
+ if (old == 1) {
+ if (state & GDK_SHIFT_MASK && !(state & GDK_CONTROL_MASK))
+ return 2; // shift
+ if (state & GDK_MOD1_MASK && !(state & GDK_CONTROL_MASK))
+ return 3; // alt
+ return 1;
+ }
+ if (old == 2) {
+ if (state & GDK_CONTROL_MASK && !(state & GDK_SHIFT_MASK))
+ return 1; // ctrl
+ if (state & GDK_MOD1_MASK && !(state & GDK_SHIFT_MASK))
+ return 3; // alt
+ return 2;
+ }
+ return old;
+ }
+}
+
+
+bool Rotateable::on_motion(GdkEventMotion *event) {
+ if (dragging) {
+ double dist = Geom::L2(Geom::Point(event->x, event->y) - Geom::Point(drag_started_x, drag_started_y));
+ double angle = atan2(event->y - drag_started_y, event->x - drag_started_x);
+ if (dist > 20) {
+ working = true;
+ double force = CLAMP (-(angle - current_axis)/maxdecl, -1, 1);
+ if (fabs(force) < 0.002)
+ force = 0; // snap to zero
+ if (modifier != get_single_modifier(modifier, event->state)) {
+ // user has switched modifiers in mid drag, close past drag and start a new
+ // one, redefining axis temporarily
+ do_release(force, modifier);
+ current_axis = angle;
+ modifier = get_single_modifier(modifier, event->state);
+ } else {
+ do_motion(force, modifier);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool Rotateable::on_release(GdkEventButton *event) {
+ if (dragging && working) {
+ double angle = atan2(event->y - drag_started_y, event->x - drag_started_x);
+ double force = CLAMP(-(angle - current_axis) / maxdecl, -1, 1);
+ if (fabs(force) < 0.002)
+ force = 0; // snap to zero
+ do_release(force, modifier);
+ current_axis = axis;
+ dragging = false;
+ working = false;
+ return true;
+ }
+ dragging = false;
+ working = false;
+ return false;
+}
+
+bool Rotateable::on_scroll(GdkEventScroll* event)
+{
+ double change = 0.0;
+
+ if (event->direction == GDK_SCROLL_UP) {
+ change = 1.0;
+ } else if (event->direction == GDK_SCROLL_DOWN) {
+ change = -1.0;
+ } else if (event->direction == GDK_SCROLL_SMOOTH) {
+ double delta_y_clamped = CLAMP(event->delta_y, -1.0, 1.0); // values > 1 result in excessive changes
+ change = 1.0 * -delta_y_clamped;
+ } else {
+ return FALSE;
+ }
+
+ drag_started_x = event->x;
+ drag_started_y = event->y;
+ modifier = get_single_modifier(modifier, event->state);
+ dragging = false;
+ working = false;
+ scrolling = true;
+ current_axis = axis;
+
+ do_scroll(change, modifier);
+
+ dragging = false;
+ working = false;
+ scrolling = false;
+
+ return TRUE;
+}
+
+Rotateable::~Rotateable() = default;
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :