diff options
Diffstat (limited to 'src/ui/widget/rotateable.cpp')
-rw-r--r-- | src/ui/widget/rotateable.cpp | 179 |
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 : |