Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
clip-presenter.hpp
Go to the documentation of this file.
1/*
2 CLIP-PRESENTER.hpp - presentation control element for a clip within the timeline
3
4 Copyright (C)
5 2016, 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
43#ifndef STAGE_TIMELINE_CLIP_PRESENTER_H
44#define STAGE_TIMELINE_CLIP_PRESENTER_H
45
46#include "stage/gtk-base.hpp"
53#include "steam/cmd.hpp"
54#include "lib/format-cout.hpp"
55#include "lib/format-string.hpp"
56
57//#include "lib/util.hpp"
58
59//#include <memory>
60#include <optional>
61#include <vector>
62
63
64
65namespace stage {
66namespace timeline {
67
68 using std::vector;
69 using std::optional;
70 using std::unique_ptr;
71 using std::make_unique;
74 using lib::diff::collection;
75 using util::_Fmt;
76
77
88 : public model::Controller
89 , public interact::Subject
90 {
91 vector<unique_ptr<ClipPresenter>> channels_;
92 vector<unique_ptr<ClipPresenter>> effects_;
93 vector<unique_ptr<MarkerWidget>> markers_;
94
95 unique_ptr<ClipDelegate> widget_;
96
103
104
105 public:
114 ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetHook& view, optional<TimeSpan> const& timing)
115 : Controller{identity, nexus}
116 , channels_{}
117 , effects_{}
118 , markers_{}
119 , widget_{}
120 {
121 establishAppearance (&view, timing);
122 ENSURE (widget_);
123 }
124
126
127
129 virtual void
131 {
132 using PChannel = unique_ptr<ClipPresenter>;
133 using PEffect = unique_ptr<ClipPresenter>;
134 using PMarker = unique_ptr<MarkerWidget>;
135
136 buffer.emplace(
138 .attach (collection(markers_)
139 .isApplicableIf ([&](GenNode const& spec) -> bool
140 { // »Selector« : require object-like sub scope with type-field "Marker"
141 return TYPE_Marker == spec.data.recordType();
142 })
143 .constructFrom ([&](GenNode const& spec) -> PMarker
144 {
145 return make_unique<MarkerWidget> (spec.idi, this->uiBus_);
146 }))
147 .attach (collection(effects_)
148 .isApplicableIf ([&](GenNode const& spec) -> bool
149 { // »Selector« : require object-like sub scope with type-field "Effect"
150 return TYPE_Effect == spec.data.recordType();
151 })
152 .constructFrom ([&](GenNode const& spec) -> PEffect
153 {
154 std::optional<TimeSpan> timing = spec.retrieveAttribute<TimeSpan> (string{ATTR_timing});
155 return make_unique<ClipPresenter> (spec.idi, this->uiBus_
157 ,timing);
158 }))
159 .attach (collection(channels_)
160 .isApplicableIf ([&](GenNode const& spec) -> bool
161 { // »Selector« : require object-like sub scope with type-field "Channel"
162 return TYPE_Channel == spec.data.recordType();
163 })
164 .constructFrom ([&](GenNode const& spec) -> PChannel
165 {
166 return make_unique<ClipPresenter> (spec.idi, this->uiBus_
168 ,std::nullopt);
169 }))
170 .change(ATTR_name, [&](string val)
171 { // »Attribute Setter« : receive a new value for the clip name field
172 REQUIRE (widget_);
173 widget_->setClipName (val);
174 })
175 .change(ATTR_timing, [&](TimeSpan val)
176 {
177 REQUIRE (widget_);
178 widget_->accessStartTime() = val.start();
179 widget_->accessDuration() = val.duration();
180 })
181 //-Diff-Change-Listener----------------
182 .onLocalChange ([this]()
183 {
184 this->establishAppearance();
185 }));
186 }
187
188
193 uint
195 {
196 REQUIRE (widget_);
197 return widget_->calcRequiredHeight()
198 + widget_->getVerticalOffset();
199 }
200
208 void
210 {
211 REQUIRE (widget_);
212 widget_->updatePosition();
213 }
214
215
216 private:/* ===== Subject-Interface ===== */
217
221 {
226
227 void
228 updateOffset (double deltaX, double deltaY) override
229 {
231 subject_.widget_->updatePosition();
232 std::cerr << _Fmt{"Gesture(%s) → Δ ≔ (%3.1f,%3.1f) ⟹ %s ↷ %s"}
233 % getCmdID()
234 % deltaX
235 % deltaY
236 % oldTime_
237 % subject_.widget_->accessStartTime()
238 << std::endl;
239 }
240
241 void
243 {
244 std::cerr << _Fmt{"!!BANG!! Gesture-Cmd '%s' Time ↷ %s"}
245 % getCmdID()
246 % newTime_
247 << std::endl;
248 }
249
250 public:
252 : interact::GestureObserver{cmdID}
253 , subject_{clipPresenter}
254 , metric_ {subject_.widget_->getCanvas().getMetric()}
255 , newTime_{subject_.widget_->accessStartTime()}
257 { }
258 };
259
260 void
261 buildGestureObserver (Symbol cmdID, Buffer buffer) override
262 {
263 buffer.create<DragRelocateObserver> (cmdID, *this);
264 }
265
266 Gtk::Widget&
267 exposeWidget() override
268 {
270 }
271
272
273
274 private:/* ===== Internals ===== */
286 void
288 optional<TimeSpan> const& timing =nullopt)
289 {
290 void* prevDelegate = widget_.get();
291 auto newAppearance = ClipDelegate::selectAppearance (this->widget_, defaultAppearance, newView, timing);
292
293 if (prevDelegate != widget_.get()
294 and newAppearance > ClipDelegate::DEGRADED)
295 {// a new dedicated clip widget has been created...
297 .linkSubject (*this)
299 }
300 }
301
302
305 {
306 UNIMPLEMENTED ("how to create and wire an embedded canvas for the clip contents/effects");
307 }
308 };
309
310
311}}// namespace stage::timeline
312#endif /*STAGE_TIMELINE_CLIP_PRESENTER_H*/
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
SUB & create(ARGS &&...args)
Abbreviation for placement new of a subclass SUB into the opaque buffer.
Token or Atom with distinct identity.
Definition symbol.hpp:120
string recordType() const
peek into the type field of a nested Record<GenNode>
Definition gen-node.hpp:761
Customisable intermediary to abstract mutating operations on arbitrary, hierarchical object-like data...
static Builder< TreeMutator > build()
DSL: start building a custom adapted tree mutator, where the operations are tied by closures or wrapp...
A time interval anchored at a specific point in time.
a mutable time value, behaving like a plain number, allowing copy and re-accessing
Lumiera's internal time value datatype.
connection point at the UI-Bus.
Definition bus-term.hpp:98
static CmdContext of(Symbol cmdID, Symbol ctxID)
global static service accessor function.
CmdContext && linkSubject(Subject &subj)
Builder operation: define the subject to use for the following interaction bindings.
void setupRelocateDrag()
Terminal builder operation: establish the infrastructure for the already defined participants to be i...
Collaboration interface for tracking the formation of a gesture.
Role-Interface: the Subject of Interaction.
Mix-in interface to allow for concrete CanvasHooked widgets to adapt themselves to the metric current...
virtual TimeValue applyScreenDelta(Time anchor, double deltaPx) const =0
translate an offset in pixel coordinates into a temporal position
ctrl::BusTerm::ID ID
Definition tangible.hpp:162
Appearance
desired appearance style for the clip
static Gtk::Widget & expect_and_expose_Widget(PDelegate &manager)
Wrapper to safely expose the actual clip implementation widget.
static Appearance selectAppearance(PDelegate &existing, Appearance desired=PENDING, WidgetHook *newView=nullptr, optional< TimeSpan > const &timing=nullopt)
request to change the clip delegate's appearance style, if possible.
void updateOffset(double deltaX, double deltaY) override
DragRelocateObserver(Symbol cmdID, ClipPresenter &clipPresenter)
A View-Model entity to represent a clip within the timeline-UI.
vector< unique_ptr< ClipPresenter > > effects_
void buildGestureObserver(Symbol cmdID, Buffer buffer) override
prompt the Subject to build an Observer for the gesture in formation
vector< unique_ptr< MarkerWidget > > markers_
void establishAppearance(WidgetHook *newView=nullptr, optional< TimeSpan > const &timing=nullopt)
reevaluate desired presentation mode and available data, possibly leading to a changed appearance sty...
void relink()
update and re-attach the presentation widget into its presentation context.
vector< unique_ptr< ClipPresenter > > channels_
unique_ptr< ClipDelegate > widget_
Gtk::Widget & exposeWidget() override
the exposed widget can be used for wiring signal handlers
virtual void buildMutator(TreeMutator::Handle buffer) override
set up a binding to respond to mutation messages via UiBus
static const ClipDelegate::Appearance defaultAppearance
default maximum level of detail presentation desired for each clip.
uint determineRequiredVerticalExtension() const
find out the number of pixels necessary to render this clip properly, assuming its current presentati...
ClipPresenter(ID identity, ctrl::BusTerm &nexus, WidgetHook &view, optional< TimeSpan > const &timing)
A front-end for using printf-style formatting.
This widget provides the concrete rendering of a clip-like entity.
Abstraction: support for binding command invocation into an UI context.
Common ID definitions for Steam-Layer commands.
Common Abstraction of all sub-controller, coordinated by the UI-Bus.
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.
unsigned int uint
Definition integral.hpp:29
Widget to show a marker at various places.
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
const Symbol TYPE_Channel
const Symbol ATTR_name
const Symbol TYPE_Marker
const Symbol TYPE_Effect
const Symbol ATTR_timing
const Symbol GESTURE_dragReolcate
CommandSetup scope_moveRelocateClip
generic data element node within a tree
Definition gen-node.hpp:224
std::optional< X > retrieveAttribute(string key) const
mismatch tolerant convenience shortcut to peek into the attributes of a nested Record
Definition gen-node.hpp:801
a family of time value like entities and their relationships.
Hard wired key constants and basic definitions for communication with the GUI.