Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
drag-relocate-controller.hpp
Go to the documentation of this file.
1/*
2 DRAG-RELOCATE-CONTROLLER.hpp - concrete gesture controller to relocate a widget by dragging
3
4 Copyright (C)
5 2021, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
37#ifndef STAGE_INTERACT_DRAG_RELOCATE_CONTROLLER_H
38#define STAGE_INTERACT_DRAG_RELOCATE_CONTROLLER_H
39
40
41#include "stage/gtk-base.hpp"
44#include "lib/opaque-holder.hpp"
45#include "lib/format-string.hpp"
46#include "lib/format-cout.hpp"
47//#include "lib/idi/entry-id.hpp"
48//#include "lib/symbol.hpp"
49#include "lib/nocopy.hpp"
50#include "lib/util.hpp"
51
52//#include <string>
53
54
55namespace stage {
56namespace interact {
57
58// using lib::HashVal;
59// using util::isnil;
60// using std::string;
61 using util::isnil;
62 using util::_Fmt;
63
64 namespace {
65 const gdouble DISTANCE_THRESHOLD = 5.0;
66
69 const size_t OBSERVER_BUFF_SIZ = sizeof(void*)
70 + sizeof(Symbol)
71 + 4 * sizeof(void*);
72 }
73
74
97 : public InteractionState
98 {
99 bool buttonPressed_ = false;
100 Subject* subject_ = nullptr;
101 bool isInFormation_ = false;
102 gdouble anchorX_ = 0.0;
103 gdouble anchorY_ = 0.0;
104
106
108
109 void
110 linkTrigger (Subject& subject, Symbol cmdID) override
111 {
112 REQUIRE (not isnil (cmdID));
113 auto& widget = subject.exposeWidget();
114 widget.signal_button_press_event().connect(
115 sigc::mem_fun (*this, &DragRelocateController::watchButton));
116 widget.signal_button_release_event().connect(
117 sigc::mem_fun (*this, &DragRelocateController::watchButton));
118 widget.signal_motion_notify_event().connect(
119 [&, cmdID](GdkEventMotion* motion) -> bool
120 {
121 try{ return maybeActivate(cmdID, subject, motion); }
122 ON_EXCEPTION_RETURN (false, "activate dragging gesture")
123 }
124 );
125 }
126
127 bool
128 watchButton (GdkEventButton* button_event) noexcept
129 {
130 REQUIRE (button_event);
131 if (GDK_BUTTON_PRESS == button_event->type)
132 buttonPressed_ = true;
133 else
134 if (GDK_BUTTON_RELEASE == button_event->type)
135 {
136 buttonPressed_ = false;
137 if (isActive())
139 resetState();
140 }
141 std::cerr << _Fmt{"BUTT %s flag=%d"} % buttonPressed_ % button_event->type << std::endl;
142 return false;
143 }
144
146 bool
147 maybeActivate (Symbol cmdID, Subject& subject, GdkEventMotion* motion_event)
148 {
149 if (not buttonPressed_)
150 return false; // Event not handled by this controller
151 REQUIRE (motion_event);
152 std::cerr << _Fmt{"MOVE x=%3.1f y=%3.1f subject=%s"}
153 % motion_event->x_root
154 % motion_event->y_root
155 % subject
156 << std::endl;
157 if (not isAnchored())
158 anchor (cmdID, subject, motion_event);
159 if (not isActive())
160 {
161 probeActivation (motion_event);
162 if (isActive())
163 initGestureTracking(cmdID, subject);
164 return false;
165 }
166 else
167 {
168 doTrackGesture (motion_event);
169 return true; // Event handled
170 }
171 }
172
173
174 /* === gesture implementation === */
175 bool
177 {
178 return subject_
179 and isInFormation_;
180 }
181
182 bool
184 {
185 return bool(subject_);
186 }
187
188 void
189 anchor (Symbol cmdID, Subject& subject, GdkEventMotion* motion_event)
190 {
191 REQUIRE (motion_event);
192 this->subject_ = & subject;
193 this->anchorX_ = motion_event->x_root;
194 this->anchorY_ = motion_event->y_root;
195 std::cerr << _Fmt{"ANCHOR at x=%3.1f y=%3.1f ('%s')"}
196 % anchorX_
197 % anchorY_
198 % cmdID
199 << std::endl;
200 }
201
202 void
203 probeActivation (GdkEventMotion* motion_event)
204 {
205 isInFormation_ = DISTANCE_THRESHOLD < abs (motion_event->x_root - anchorX_)
206 or DISTANCE_THRESHOLD < abs (motion_event->y_root - anchorY_);
207 }
208
209 void
211 {
213 }
214
215 void
216 doTrackGesture (GdkEventMotion* motion_event)
217 {
218 REQUIRE (motion_event);
219 gdouble deltaX = motion_event->x_root - this->anchorX_;
220 gdouble deltaY = motion_event->y_root - this->anchorY_;
221 // notify Subject to feed current delta
222 observer_->updateOffset (deltaX, deltaY);
223 }
224
225 void
227 {
228 observer_->markGestureCompleted();
229 }
230
231 void
233 {
234 isInFormation_ = false;
235 anchorX_ = anchorY_ = 0.0;
236 subject_ = nullptr;
238 }
239
240
241 public:
245
246 private:
247 };
248
249
250
251}} // namespace stage::interact
252#endif /*STAGE_INTERACT_DRAG_RELOCATE_CONTROLLER_H*/
PlantingHandle< GestureObserver, InactiveObserver > Handle
a "planting handle" can be used to expose an opaque InPlaceBuffer through an API
Token or Atom with distinct identity.
Definition symbol.hpp:120
Gesture controller for dragging objects within the Timeline display.
void linkTrigger(Subject &subject, Symbol cmdID) override
Hook up a trigger signal to initiate a specific interaction gesture.
bool watchButton(GdkEventButton *button_event) noexcept
void initGestureTracking(Symbol cmdID, Subject &subject)
void anchor(Symbol cmdID, Subject &subject, GdkEventMotion *motion_event)
bool maybeActivate(Symbol cmdID, Subject &subject, GdkEventMotion *motion_event)
Gesture detection state logic.
void probeActivation(GdkEventMotion *motion_event)
void doTrackGesture(GdkEventMotion *motion_event)
Abstract foundation for context dependent UI interactions.
Role-Interface: the Subject of Interaction.
virtual void buildGestureObserver(Symbol cmdID, Buffer)=0
prompt the Subject to build an Observer for the gesture in formation
virtual Gtk::Widget & exposeWidget()=0
the exposed widget can be used for wiring signal handlers
A front-end for using printf-style formatting.
Abstraction: support for binding command invocation into an UI context.
#define ON_EXCEPTION_RETURN(_VAL_, _OP_DESCR_)
convenience shortcut to catch and absorb any exception, then returning a default value instead.
Definition error.hpp:305
Automatically use custom string conversion in C++ stream output.
Front-end for printf-style string template interpolation.
A set of basic GTK includes for the UI.
Abstraction: a component to watch, maintain and guide UI state.
const size_t OBSERVER_BUFF_SIZ
heuristics for sizing the inline buffer where the Subject will construct its Observer/Adapter
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
bool isnil(lib::time::Duration const &dur)
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Helper allowing type erasure while holding the actual object inline.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...