From 2429c5413c8d0d76b2ae660e54a0bbe7b88dee24 Mon Sep 17 00:00:00 2001 From: buliabyak Date: Wed, 24 Oct 2007 00:56:44 +0000 Subject: [PATCH] new class for widgets adjustable by rotation-like gestures --- src/ui/widget/Makefile_insert | 2 + src/ui/widget/rotateable.cpp | 137 ++++++++++++++++++++++++++++++++++ src/ui/widget/rotateable.h | 66 ++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/ui/widget/rotateable.cpp create mode 100644 src/ui/widget/rotateable.h diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 11a5ef920..c5bde795a 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -52,6 +52,8 @@ ui_widget_libuiwidget_a_SOURCES = \ ui/widget/registered-enums.h \ ui/widget/registry.cpp \ ui/widget/registry.h \ + ui/widget/rotateable.h \ + ui/widget/rotateable.cpp \ ui/widget/ruler.cpp \ ui/widget/ruler.h \ ui/widget/scalar-unit.cpp \ diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp new file mode 100644 index 000000000..e434c10c5 --- /dev/null +++ b/src/ui/widget/rotateable.cpp @@ -0,0 +1,137 @@ +/** + * \brief widget adjustable by dragging it to rotate away from a zero-change axis + * + * Authors: + * buliabyak@gmail.com + * + * Copyright (C) 2007 authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#include "event-context.h" +#include "rotateable.h" +#include "libnr/nr-point.h" +#include "libnr/nr-point-fns.h" +#include +#include +#include + +namespace Inkscape { +namespace UI { +namespace Widget { + + Rotateable::Rotateable(): + axis(-M_PI/4), + maxdecl(M_PI/4) + { + dragging = false; + working = 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)); + } + + 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) { + if (state & GDK_CONTROL_MASK) + return 1; // ctrl + if (state & GDK_SHIFT_MASK) + return 2; // shift + return 0; + } else { + if (!(state & GDK_CONTROL_MASK) && !(state & GDK_SHIFT_MASK)) + return 0; // none + if (old == 1) + if (state & GDK_SHIFT_MASK && !(state & GDK_CONTROL_MASK)) + return 2; // shift + else + return 1; + if (old == 2) + if (state & GDK_CONTROL_MASK && !(state & GDK_SHIFT_MASK)) + return 1; // ctrl + else + return 2; + return old; + } + } + + + bool Rotateable::on_motion(GdkEventMotion *event) { + if (dragging) { + double dist = NR::L2(NR::Point(event->x, event->y) - NR::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); + } + } + gobble_motion_events(GDK_BUTTON1_MASK); + 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); + dragging = false; + working = false; + current_axis = axis; + return true; + } + return false; + } + + + Rotateable::~Rotateable() { + } + + + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/ui/widget/rotateable.h b/src/ui/widget/rotateable.h new file mode 100644 index 000000000..65f3c598c --- /dev/null +++ b/src/ui/widget/rotateable.h @@ -0,0 +1,66 @@ +/** + * \brief widget adjustable by dragging it to rotate away from a zero-change axis + * + * Authors: + * buliabyak@gmail.com + * + * Copyright (C) 2007 authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_ROTATEABLE_H +#define INKSCAPE_UI_ROTATEABLE_H + +#include +#include +#include + +namespace Inkscape { +namespace UI { +namespace Widget { + +class Rotateable: public Gtk::EventBox +{ +public: + Rotateable(); + + ~Rotateable(); + + bool on_click(GdkEventButton *event); + bool on_motion(GdkEventMotion *event); + bool on_release(GdkEventButton *event); + + double axis; + double current_axis; + double maxdecl; + +private: + double drag_started_x; + double drag_started_y; + guint modifier; + bool dragging; + bool working; + + guint get_single_modifier(guint old, guint state); + + virtual void do_motion (double by, guint state) {} + virtual void do_release (double by, guint state) {} +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_ROTATEABLE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- 2.30.2