From b5cf8b2303ef0469f59d64a0a4ffa4fa803e4c78 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Apr 2021 19:43:29 +0200 Subject: [PATCH] Clip-Drag: draft the dragging controller logic direct implementation with state flags in-class Intention is to refactor this into a state machine eventually --- src/stage/interact/cmd-context.cpp | 7 + src/stage/interact/cmd-context.hpp | 4 +- .../interact/drag-relocate-controller.hpp | 78 +++++++++- src/stage/timeline/clip-presenter.hpp | 23 ++- tests/stage/interact/cmd-context-test.cpp | 2 + wiki/thinkPad.ichthyo.mm | 137 ++++++++++++++++-- 6 files changed, 230 insertions(+), 21 deletions(-) diff --git a/src/stage/interact/cmd-context.cpp b/src/stage/interact/cmd-context.cpp index e25065a5a..adf3d2069 100644 --- a/src/stage/interact/cmd-context.cpp +++ b/src/stage/interact/cmd-context.cpp @@ -36,11 +36,13 @@ //#include "lib/util.hpp" //#include "lib/symbol.hpp" +#include "stage/gtk-base.hpp" #include "lib/depend.hpp" //#include "include/logging.h" #include "include/ui-protocol.hpp" #include "stage/interact/cmd-context.hpp" #include "stage/interact/gesture-state.hpp" +#include "lib/format-string.hpp" //#include //#include @@ -50,9 +52,11 @@ //using util::contains; //using util::isnil; +using util::_Fmt; namespace stage { namespace interact { + namespace error = lumiera::error; namespace { // internal details lib::Depend gestures; @@ -62,6 +66,8 @@ namespace interact { { if ( GESTURE_dragReolcate == ctxID) return gestures().getStateFor (GestureState::DRAG, GestureState::ON_TIMELINE); + throw error::Config (_Fmt{"Unknown Context-ID '%s' encountered in Gesture wiring."} + % ctxID); } } // internal details @@ -95,6 +101,7 @@ namespace interact { * @remarks this service is used to resolve command arguments * based on the current state of UI interaction. This can be used * to get e.g. the scope enclosing the element currently in focus + * @todo 4/21 this was an idea from the initial draft in 2017 -- undecided yet */ CmdContext::Resolver::operator LuidH () { diff --git a/src/stage/interact/cmd-context.hpp b/src/stage/interact/cmd-context.hpp index a1be57284..1e3260520 100644 --- a/src/stage/interact/cmd-context.hpp +++ b/src/stage/interact/cmd-context.hpp @@ -94,7 +94,9 @@ namespace interact { virtual ~Subject(); ///< this is an interface public: - virtual Gtk::Widget& exposeWidget() =0; + virtual Gtk::Widget& exposeWidget() =0; + virtual void fireGesture (Symbol cmdID) =0; + virtual void gestureOffset (Symbol cmdID, gdouble deltaX, gdouble deltaY) =0; }; diff --git a/src/stage/interact/drag-relocate-controller.hpp b/src/stage/interact/drag-relocate-controller.hpp index 1ec5cfb2a..b1c20c9e2 100644 --- a/src/stage/interact/drag-relocate-controller.hpp +++ b/src/stage/interact/drag-relocate-controller.hpp @@ -50,8 +50,8 @@ #include "stage/gtk-base.hpp" #include "stage/interact/interaction-state.hpp" #include "stage/interact/cmd-context.hpp" -#include "lib/format-string.hpp" -#include "lib/format-cout.hpp" +#include "lib/format-string.hpp"//////////////////////////////////TODO +#include "lib/format-cout.hpp" //////////////////////////////////TODO //#include "lib/idi/entry-id.hpp" //#include "lib/symbol.hpp" #include "lib/nocopy.hpp" @@ -67,7 +67,7 @@ namespace interact { // using util::isnil; // using std::string; using util::isnil; - using util::_Fmt; + using util::_Fmt;//////////////////////////////////TODO @@ -82,6 +82,8 @@ namespace interact { * controller. * * @todo write type comment... + * @remarks tracking of signal connections _is not relevant here,_ since this controller + * is managed by the UI backbone and thus ensured to outlive any event processing. * @todo WIP-WIP as of /3/2021 * ///////////////////////////////////TODO do we need a translation unit interaction-state.cpp (otherwise delete it!) */ @@ -89,6 +91,11 @@ namespace interact { : public InteractionState { bool buttonPressed_ = false; + Symbol cmdID_ = Symbol::BOTTOM; + Subject* subject_ = nullptr; + bool isInFormation_ = false; + gdouble anchorX_ = 0.0; + gdouble anchorY_ = 0.0; void linkTrigger (Subject& subject, Symbol cmdID) override @@ -100,9 +107,9 @@ namespace interact { widget.signal_button_release_event().connect( sigc::mem_fun (*this, &DragRelocateController::watchButton)); widget.signal_motion_notify_event().connect( - [&](GdkEventMotion* motion) -> bool + [&, cmdID](GdkEventMotion* motion) -> bool { - try{ return detectActivation(subject, motion); } + try{ return maybeActivate(cmdID, subject, motion); } ON_EXCEPTION_RETURN (false, "activate dragging gesture") } ); @@ -116,25 +123,80 @@ namespace interact { buttonPressed_ = true; else if (button_event->type & GDK_BUTTON_RELEASE) - buttonPressed_ = true; + buttonPressed_ = false; return false; } + /** Gesture detection state logic */ bool - detectActivation (Subject& subject, GdkEventMotion* motion_event) + maybeActivate (Symbol cmdID, Subject& subject, GdkEventMotion* motion_event) { if (not buttonPressed_) - return false; + { + if (isActive()) + doCompleteGesture(); + return false; // Event not handled by this controller + } REQUIRE (motion_event); std::cerr << _Fmt{"MOVE x=%3.1f y=%3.1f subject=%s"} % motion_event->x % motion_event->y % subject << std::endl; + if (not isAnchored()) + anchor (cmdID, subject, motion_event); + if (not isActive()) + return false; + doTrackGesture(motion_event); return true; // Event handled } + /* === gesture implementation === */ + bool + isActive() + { + return subject_ + and isInFormation_; + } + + bool + isAnchored() + { + return bool{subject_}; + } + + void + anchor (Symbol cmdID, Subject& subject, GdkEventMotion* motion_event) + { + REQUIRE (motion_event); + this->cmdID_ = cmdID; + this->subject_ = & subject; + this->anchorX_ = motion_event->x; + this->anchorY_ = motion_event->y; + } + + void + doTrackGesture (GdkEventMotion* motion_event) + { + REQUIRE (motion_event); + gdouble deltaX = motion_event->x - this->anchorX_; + gdouble deltaY = motion_event->y - this->anchorY_; + // notify Subject to feed current delta + subject_->gestureOffset (cmdID_, deltaX, deltaY); + } + + void + doCompleteGesture() + { + subject_->fireGesture (cmdID_); + // return to inactive state + cmdID_ = Symbol::BOTTOM; + subject_ = nullptr; + anchorX_ = anchorY_ = 0.0; + } + + public: DragRelocateController() // : diff --git a/src/stage/timeline/clip-presenter.hpp b/src/stage/timeline/clip-presenter.hpp index b0dbcca6c..335ef345e 100644 --- a/src/stage/timeline/clip-presenter.hpp +++ b/src/stage/timeline/clip-presenter.hpp @@ -60,6 +60,8 @@ #include "stage/interact/cmd-context.hpp" #include "lib/time/timevalue.hpp" #include "steam/cmd.hpp" +#include "lib/format-cout.hpp" //////////////////////////////////TODO +#include "lib/format-string.hpp"//////////////////////////////////TODO //#include "lib/util.hpp" @@ -79,6 +81,7 @@ namespace timeline { using lib::time::TimeSpan; using lib::diff::TreeMutator; using lib::diff::collection; + using util::_Fmt;//////////////////////////////////TODO /** @@ -219,11 +222,29 @@ namespace timeline { private:/* ===== Subject-Interface ===== */ Gtk::Widget& - exposeWidget() override + exposeWidget() override { return ClipDelegate::expect_and_expose_Widget (widget_); } + void + fireGesture (Symbol cmdID) override + { + std::cerr << _Fmt{"!!BANG!! Gesture-Cmd '%s'"} + % cmdID + << std::endl; + } + + void + gestureOffset (Symbol cmdID, gdouble deltaX, gdouble deltaY) override + { + std::cerr << _Fmt{"Gesture(%s) --> Δ := (%3.1f,%3.1f)"} + % cmdID + % deltaX + % deltaY + << std::endl; + } + private:/* ===== Internals ===== */ /** diff --git a/tests/stage/interact/cmd-context-test.cpp b/tests/stage/interact/cmd-context-test.cpp index 2003a7cd8..577043aa3 100644 --- a/tests/stage/interact/cmd-context-test.cpp +++ b/tests/stage/interact/cmd-context-test.cpp @@ -29,6 +29,7 @@ #include "lib/test/run.hpp" //#include "lib/test/test-helper.hpp" +typedef double gdouble; ////////////////////TODO this is a code smell. Test Code should not depend on GTK. Problem is the usage of gdouble for Screen coordinates in cmdt-context.hpp #include "stage/interact/cmd-context.hpp" //#include "lib/idi/entry-id.hpp" //#include "lib/diff/gen-node.hpp" @@ -44,6 +45,7 @@ //using util::isnil; + namespace stage { namespace interact { namespace test { diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 15be28a75..9b3af7ad7 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -5773,7 +5773,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6907,7 +6933,7 @@ - + @@ -31975,7 +32001,7 @@

- gehört er nun dem Layout-Manager, oder gehört er der Geste? + gehört diese nun dem Layout-Manager, oder gehört er der Geste?

@@ -32527,8 +32553,8 @@
- - + + @@ -32564,13 +32590,13 @@ - - + + - - + + @@ -32849,6 +32875,94 @@ + + + + + + + + + + + + + + + + +

+ Demnach wäre die Übersetzung von Pixel-Koordinaten in irgend etwas modell-Releavantes komplet in das Subject eingekapselt; der Gesten-Controller würde dann einen Screen-relativen Offset aggregieren. Aber auf der zweiten Stufe bleiben wir bei dem Ansatz, daß die Geste direkt das Modell manipuliert +

+ +
+
+ + + + + + +

+ ...Auch wenn ich ein ungutes Bauchgefühl habe, alle Argumente sprechen im Moment dafür, diesem Hinweis zu folgen und das Design in dieser Richtung auszubauen. Im Besonderen würde nämlich ein konsequentes Umsetzen meines ursprünglichen Konzepts bedeuten, daß das Subject-Interface etwas von der Metrik im Modell, und im Besonderen von eine Zeit-Parameter wissen müßte ― es ist aber absehbar, daß in anderen Situationen gänzlich andere Parameter relevant sein könnten ... man denke bloß an die "Position im Fork" +

+ +
+
+
+ + + + + + + + + + +

+ (gtypes.h): Provide type definitions for commonly used types. +

+

+ These are useful because a "gint8" can be adjusted  to be 1 byte (8 bits) on all platforms. Similarly and more importantly, "gint32" can be adjusted to be 4 bytes (32 bits) on all platforms. +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +

+ sehe nur die MOVE-Meldungen.
eigentlich sollte das Subject ebenfalls Meldungen ausspucken +

+ +
+ +
+
+
@@ -33156,8 +33270,9 @@ - - + + +