Lumiera  0.pre.03
»edit your freedom«
track-presenter.hpp
Go to the documentation of this file.
1 /*
2  TRACK-PRESENTER.hpp - presentation control element for a track 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 
87 #ifndef STAGE_TIMELINE_TRACK_PRESENTER_H
88 #define STAGE_TIMELINE_TRACK_PRESENTER_H
89 
90 #include "stage/gtk-base.hpp"
91 #include "include/ui-protocol.hpp"
99 #include "lib/time/timevalue.hpp"
100 #include "lib/iter-explorer.hpp"
101 #include "lib/util-coll.hpp"
102 
103 #include "lib/nocopy.hpp"
104 
105 #include <optional>
106 #include <utility>
107 #include <vector>
108 
109 
110 
111 namespace stage {
112 namespace timeline {
113 
114  using std::vector;
115  using std::unique_ptr;
116  using std::make_unique;
117 
118  using lib::time::TimeSpan;
120  using lib::diff::collection;
121  using lib::explore;
122  using util::max;
123 
124 
125 
137  template<class WID>
139  : public model::CanvasHook<WID>
140  {
141  model::CanvasHook<WID>& refHook_;
142 
143 
144  /* ==== Interface: ViewHook ===== */
145 
146  void
147  hook (WID& widget, int xPos=0, int yPos=0) override
148  {
149  refHook_.hook (widget, hookAdjX (xPos), hookAdjY (yPos));
150  }
151 
152  void
153  move (WID& widget, int xPos, int yPos) override
154  {
155  refHook_.move (widget, hookAdjX (xPos), hookAdjY (yPos));
156  }
157 
158  void
159  remove (WID& widget) override
160  {
161  refHook_.remove (widget);
162  }
163 
166  getAnchorHook() noexcept override
167  {
168  return this->refHook_;
169  }
170 
171  protected: /* === extended Interface for relative canvas hook === */
172  virtual int hookAdjX (int xPos) =0;
173  virtual int hookAdjY (int yPos) =0;
174 
177  getMetric() const override
178  {
179  return refHook_.getMetric();
180  }
181 
182  public:
184  : refHook_{baseHook.getAnchorHook()}
185  { }
186  };
187 
188 
189 
190  using PFork = unique_ptr<TrackPresenter>;
191  using PClip = unique_ptr<ClipPresenter>;
192  using PMark = unique_ptr<MarkerWidget>;
193  using PRuler = unique_ptr<RulerTrack>;
194 
206  , public DisplayViewHooks
207  , public RelativeCanvasHook<Gtk::Widget>
208  {
211 
212  /* === extended Interface for relative view/canvas hook === */
213 
214  int hookAdjX (int xPos) override { return xPos; };
215  int hookAdjY (int yPos) override { return yPos + body_.getContentOffsetY(); };
216 
217  public: /* ==== Interface: DisplayViewHooks===== */
218 
219  model::ViewHook<TrackHeadWidget>& getHeadHook() override { return head_; };
220  model::ViewHook<TrackBody>& getBodyHook() override { return body_; };
221  model::CanvasHook<Gtk::Widget>& getClipHook() override { return *this; };
222 
223  public:
224  DisplayFrame (DisplayViewHooks& displayAnchor)
225  : RelativeCanvasHook{displayAnchor.getClipHook()}
226  , head_{displayAnchor.getHeadHook()}
227  , body_{displayAnchor.getBodyHook()}
228  { }
229 
230  void
231  setTrackName (cuString& name)
232  {
233  head_.setTrackName (name);
234  body_.setTrackName (name);
235  }
236 
237  vector<unique_ptr<RulerTrack>>&
238  bindRulers()
239  {
240  return body_.bindRulers();
241  }
242 
243  void establishExtension (vector<PClip>&, vector<PMark>&);
244  void sync_and_balance (DisplayEvaluation&);
245  };
246 
247 
253  : public model::Controller
254  , public LayoutElement
255  {
256  DisplayFrame display_;
257 
258  vector<PFork> subFork_;
259  vector<PMark> markers_;
260  vector<PClip> clips_;
261 
262 
263  public:
269  TrackPresenter (ID id, ctrl::BusTerm& nexus, DisplayViewHooks& displayAnchor)
270  : Controller{id, nexus}
271  , display_{displayAnchor}
272  , subFork_{}
273  , markers_{}
274  , clips_{}
275  {
276  setTrackName (id.getSym()); // fallback initialise track-name from human-readable ID symbol
277  }
278 
279 
281  virtual void buildMutator (lib::diff::TreeMutator::Handle) override;
282 
283 
284  protected: /* ==== Interface: LayoutElement ===== */
285 
286  void establishLayout (DisplayEvaluation&) override;
287  void completeLayout (DisplayEvaluation&) override;
288 
289  private:/* ===== Internals ===== */
290 
292  void
294  {
295  display_.setTrackName (name);
296  }
297 
298  void relinkContents ();
299  };
300 
301 
302 
303 
313  inline void
315  {
316  buffer.emplace(
318  .attach (collection(display_.bindRulers())
319  .isApplicableIf ([&](GenNode const& spec) -> bool
320  { // »Selector« : require object-like sub scope with type-field "Ruler"
321  return TYPE_Ruler == spec.data.recordType();
322  })
323  .constructFrom ([&](GenNode const& spec) -> PRuler
324  { // »Constructor« : how to attach a new ruler track
325  return make_unique<RulerTrack> (spec.idi, this->uiBus_, *this);
326  }))
327  .attach (collection(markers_)
328  .isApplicableIf ([&](GenNode const& spec) -> bool
329  { // »Selector« : require object-like sub scope with type-field "Marker"
330  return TYPE_Marker == spec.data.recordType();
331  })
332  .constructFrom ([&](GenNode const& spec) -> PMark
333  {
334  return make_unique<MarkerWidget> (spec.idi, this->uiBus_);
335  }))
336  .attach (collection(clips_)
337  .isApplicableIf ([&](GenNode const& spec) -> bool
338  { // »Selector« : require object-like sub scope with type-field "Clip"
339  return TYPE_Clip == spec.data.recordType();
340  })
341  .constructFrom ([&](GenNode const& spec) -> PClip
342  {
343  std::optional<TimeSpan> timing = spec.retrieveAttribute<TimeSpan> (string{ATTR_timing});
344  return make_unique<ClipPresenter> (spec.idi, this->uiBus_, display_.getClipHook(), timing);
345  }))
346  .attach (collection(subFork_)
347  .isApplicableIf ([&](GenNode const& spec) -> bool
348  { // »Selector« : require object-like sub scope with type-field "Fork"
349  return TYPE_Fork == spec.data.recordType();
350  })
351  .constructFrom ([&](GenNode const& spec) -> PFork
352  {
353  return make_unique<TrackPresenter> (spec.idi, uiBus_, this->display_);
354  }))
355  .change(ATTR_name, [&](string val)
356  { // »Attribute Setter« : receive a new value for the track name field
357  this->setTrackName (val);
358  }));
359  }
360 
361 
362 
364  inline void
366  {
367  ASSERT (displayEvaluation.isCollectPhase());
368  display_.establishExtension (clips_, markers_);
369  for (auto& subTrack: subFork_)
370  subTrack->establishLayout (displayEvaluation);
371  }
372 
374  inline void
376  {
377  ASSERT (not displayEvaluation.isCollectPhase());
378  // recursion first, so all sub-Tracks are already balanced
379  for (auto& subTrack: subFork_)
380  subTrack->completeLayout (displayEvaluation);
381  this->relinkContents();
382  // re-sync and match the header / body display
383  display_.sync_and_balance (displayEvaluation);
384  }
385 
395  inline void
396  DisplayFrame::establishExtension (vector<PClip>& clips, vector<PMark>&)
397  {
398  uint maxVSize = max (explore (clips)
399  .transform([](PClip const& clip)
400  {
401  return clip->determineRequiredVerticalExtension();
402  }));
403  maxVSize = max (maxVSize, head_.getContentHeight());
404  this->body_.accommodateContentHeight (maxVSize);
405  this->head_.accommodateContentHeight (maxVSize);
406  }
407 
412  inline void
414  {
415  for (auto& clip: clips_)
416  clip->relink();
417  for (auto& mark: markers_)
418  mark->relink();
419  }
420 
421 
439  inline void
441  {
442  uint contentHeight = body_.calcContentHeight();
443  uint overallHeight = contentHeight + body_.calcSubtrackHeight();
444  head_.syncSubtrackStartHeight (contentHeight);
445  head_.accommodateOverallHeight (overallHeight);
446  }
447 
448 
449 
450 
451 
452 }}// namespace stage::timeline
453 #endif /*STAGE_TIMELINE_TRACK_PRESENTER_H*/
void relinkContents()
second pass of the DisplayEvaluation: reassemble content to match adjusted layout ...
A widget attached onto a display canvas or similar central presentation context.
Definition: view-hook.hpp:114
Hard wired key constants and basic definitions for communication with the GUI.
Widget to show a marker at various places.
model::DisplayMetric & getMetric() const override
delegating layout metric to the root canvas
connection point at the UI-Bus.
Definition: bus-term.hpp:96
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
Mix-in interface to allow for concrete CanvasHooked widgets to adapt themselves to the metric current...
Definition: canvas-hook.hpp:73
void sync_and_balance(DisplayEvaluation &)
re-flow and adjust after the global layout has been established At this point we can assume that both...
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
void setTrackName(string name)
invoked via diff to show a (changed) track name
void establishLayout(DisplayEvaluation &) override
handle Phase-1 of the DisplayEvaluation pass for this track and its sub-tracks.
Allow widgets to connect to a common shared presentation context.
void establishExtension(vector< PClip > &, vector< PMark > &)
Find out about the vertical extension of a single track display.
virtual DisplayMetric & getMetric() const =0
access the component to handle layout metric
Interface to represent _"some presentation layout entity",_ with the ability to place widgets (manage...
A View-Model entity to represent a timeline track in the UI.
A collaboration to establish a globally coherent timeline display layout.
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
Widget to represent a track head with placement parameters, within the timeline header pane...
Visitor and state holder for a collaborative layout adjustment pass.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:104
virtual CanvasHook< WID > & getAnchorHook() noexcept
Anchor point to build chains of related View Hooks.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
Interface: a compound of anchoring facilities.
model::CanvasHook< WID > & getAnchorHook() noexcept override
allow to build a derived relative hook with different offset
TrackPresenter(ID id, ctrl::BusTerm &nexus, DisplayViewHooks &displayAnchor)
Presentation control element to model and manage a clip within the timeline UI.
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 helper class serves to manage the layout and display of the horizontally extended space of a "tr...
string recordType() const
peek into the type field of a nested Record<GenNode>
Definition: gen-node.hpp:760
Reference frame to organise the presentation related to a specific Track in the Timeline-GUI.
Special CanvasHook decorator to apply a (dynamic) offset when attaching or moving Widgets on the shar...
virtual void buildMutator(lib::diff::TreeMutator::Handle) override
set up a binding to respond to mutation messages via UiBus
Some small helpers and convenience shortcuts to ease working with collections and sequences (given by...
void completeLayout(DisplayEvaluation &) override
handle Phase-2 (collect/balancing phase) for this track and its sub-tracks.
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.
Building tree expanding and backtracking evaluations within hierarchical scopes.
a family of time value like entities and their relationships.
Common Abstraction of all sub-controller, coordinated by the UI-Bus.
A set of basic GTK includes for the UI.
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption
generic data element node within a tree
Definition: gen-node.hpp:222
Customisable intermediary to abstract mutating operations on arbitrary, hierarchical object-like data...