Lumiera  0.pre.03
»edit your freedom«
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"
47 #include "include/ui-protocol.hpp"
52 #include "lib/time/timevalue.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 
65 namespace stage {
66 namespace timeline {
67 
68  using std::vector;
69  using std::optional;
70  using std::unique_ptr;
71  using std::make_unique;
72  using lib::time::TimeSpan;
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 
102  static const ClipDelegate::Appearance defaultAppearance = ClipDelegate::COMPACT;
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 
125  ~ClipPresenter() { };
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_
156  ,getClipContentCanvas()
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_
167  ,getClipContentCanvas()
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  {
222  ClipPresenter& subject_;
223  model::DisplayMetric const& metric_;
224  TimeVar& newTime_;
225  Time oldTime_;
226 
227  void
228  updateOffset (double deltaX, double deltaY) override
229  {
230  newTime_ = metric_.applyScreenDelta(oldTime_, deltaX);
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
242  markGestureCompleted() override
243  {
244  std::cerr << _Fmt{"!!BANG!! Gesture-Cmd '%s' Time ↷ %s"}
245  % getCmdID()
246  % newTime_
247  << std::endl;
248  }
249 
250  public:
251  DragRelocateObserver(Symbol cmdID, ClipPresenter& clipPresenter)
253  , subject_{clipPresenter}
254  , metric_ {subject_.widget_->getCanvas().getMetric()}
255  , newTime_{subject_.widget_->accessStartTime()}
256  , oldTime_{newTime_}
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
287  establishAppearance(WidgetHook* newView =nullptr,
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...
296  interact::CmdContext::of (steam::cmd::scope_moveRelocateClip, GESTURE_dragReolcate)
297  .linkSubject (*this)
299  }
300  }
301 
302 
303  WidgetHook&
304  getClipContentCanvas()
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*/
static Appearance selectAppearance(PDelegate &existing, Appearance desired=PENDING, WidgetHook *newView=nullptr, optional< TimeSpan > const &timing=nullopt)
request to change the clip delegate&#39;s appearance style, if possible.
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:232
void establishAppearance(WidgetHook *newView=nullptr, optional< TimeSpan > const &timing=nullopt)
reevaluate desired presentation mode and available data, possibly leading to a changed appearance sty...
Automatically use custom string conversion in C++ stream output.
A View-Model entity to represent a clip within the timeline-UI.
Hard wired key constants and basic definitions for communication with the GUI.
CmdContext && linkSubject(Subject &subj)
Builder operation: define the subject to use for the following interaction bindings.
Widget to show a marker at various places.
connection point at the UI-Bus.
Definition: bus-term.hpp:96
void buildGestureObserver(Symbol cmdID, Buffer buffer) override
prompt the Subject to build an Observer for the gesture in formation
Mix-in interface to allow for concrete CanvasHooked widgets to adapt themselves to the metric current...
Definition: canvas-hook.hpp:73
ClipPresenter(ID identity, ctrl::BusTerm &nexus, WidgetHook &view, optional< TimeSpan > const &timing)
Front-end for printf-style string template interpolation.
Appearance
desired appearance style for the clip
SUB & create(ARGS &&...args)
Abbreviation for placement new of a subclass SUB into the opaque buffer.
Common ID definitions for Steam-Layer commands.
A front-end for using printf-style formatting.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
Gtk::Widget & exposeWidget() override
the exposed widget can be used for wiring signal handlers
void setupRelocateDrag()
Terminal builder operation: establish the infrastructure for the already defined participants to be i...
Definition: cmd-context.cpp:85
void relink()
update and re-attach the presentation widget into its presentation context.
static Builder< TreeMutator > build()
DSL: start building a custom adapted tree mutator, where the operations are tied by closures or wrapp...
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
Token or Atom with distinct identity.
Definition: symbol.hpp:117
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:104
static CmdContext of(Symbol cmdID, Symbol ctxID)
global static service accessor function.
Definition: cmd-context.cpp:77
static const ClipDelegate::Appearance defaultAppearance
default maximum level of detail presentation desired for each clip.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
virtual TimeValue applyScreenDelta(Time anchor, double deltaPx) const =0
translate an offset in pixel coordinates into a temporal position
std::optional< X > retrieveAttribute(string key) const
mismatch tolerant convenience shortcut to peek into the attributes of a nested Record ...
Definition: gen-node.hpp:800
This widget provides the concrete rendering of a clip-like entity.
string recordType() const
peek into the type field of a nested Record<GenNode>
Definition: gen-node.hpp:760
virtual void buildMutator(TreeMutator::Handle buffer) override
set up a binding to respond to mutation messages via UiBus
uint determineRequiredVerticalExtension() const
find out the number of pixels necessary to render this clip properly, assuming its current presentati...
static Gtk::Widget & expect_and_expose_Widget(PDelegate &manager)
Wrapper to safely expose the actual clip implementation widget.
A time interval anchored at a specific point in time.
Definition: timevalue.hpp:573
auto collection(COLL &coll)
Entry point to a nested DSL for setup and configuration of a collection binding.
a family of time value like entities and their relationships.
Collaboration interface for tracking the formation of a gesture.
Definition: cmd-context.hpp:88
Common Abstraction of all sub-controller, coordinated by the UI-Bus.
A set of basic GTK includes for the UI.
generic data element node within a tree
Definition: gen-node.hpp:222
Abstraction: support for binding command invocation into an UI context.
Role-Interface: the Subject of Interaction.
Customisable intermediary to abstract mutating operations on arbitrary, hierarchical object-like data...