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) Lumiera.org
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
52 #ifndef STAGE_TIMELINE_CLIP_PRESENTER_H
53 #define STAGE_TIMELINE_CLIP_PRESENTER_H
54 
55 #include "stage/gtk-base.hpp"
56 #include "include/ui-protocol.hpp"
61 #include "lib/time/timevalue.hpp"
62 #include "steam/cmd.hpp"
63 #include "lib/format-cout.hpp"
64 #include "lib/format-string.hpp"
65 
66 //#include "lib/util.hpp"
67 
68 //#include <memory>
69 #include <optional>
70 #include <vector>
71 
72 
73 
74 namespace stage {
75 namespace timeline {
76 
77  using std::vector;
78  using std::optional;
79  using std::unique_ptr;
80  using std::make_unique;
81  using lib::time::TimeSpan;
84  using util::_Fmt;
85 
86 
97  : public model::Controller
98  , public interact::Subject
99  {
100  vector<unique_ptr<ClipPresenter>> channels_;
101  vector<unique_ptr<ClipPresenter>> effects_;
102  vector<unique_ptr<MarkerWidget>> markers_;
103 
104  unique_ptr<ClipDelegate> widget_;
105 
111  static const ClipDelegate::Appearance defaultAppearance = ClipDelegate::COMPACT;
112 
113 
114  public:
123  ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetHook& view, optional<TimeSpan> const& timing)
124  : Controller{identity, nexus}
125  , channels_{}
126  , effects_{}
127  , markers_{}
128  , widget_{}
129  {
130  establishAppearance (&view, timing);
131  ENSURE (widget_);
132  }
133 
134  ~ClipPresenter() { };
135 
136 
138  virtual void
140  {
141  using PChannel = unique_ptr<ClipPresenter>;
142  using PEffect = unique_ptr<ClipPresenter>;
143  using PMarker = unique_ptr<MarkerWidget>;
144 
145  buffer.emplace(
147  .attach (collection(markers_)
148  .isApplicableIf ([&](GenNode const& spec) -> bool
149  { // »Selector« : require object-like sub scope with type-field "Marker"
150  return TYPE_Marker == spec.data.recordType();
151  })
152  .constructFrom ([&](GenNode const& spec) -> PMarker
153  {
154  return make_unique<MarkerWidget> (spec.idi, this->uiBus_);
155  }))
156  .attach (collection(effects_)
157  .isApplicableIf ([&](GenNode const& spec) -> bool
158  { // »Selector« : require object-like sub scope with type-field "Effect"
159  return TYPE_Effect == spec.data.recordType();
160  })
161  .constructFrom ([&](GenNode const& spec) -> PEffect
162  {
163  std::optional<TimeSpan> timing = spec.retrieveAttribute<TimeSpan> (string{ATTR_timing});
164  return make_unique<ClipPresenter> (spec.idi, this->uiBus_
165  ,getClipContentCanvas()
166  ,timing);
167  }))
168  .attach (collection(channels_)
169  .isApplicableIf ([&](GenNode const& spec) -> bool
170  { // »Selector« : require object-like sub scope with type-field "Channel"
171  return TYPE_Channel == spec.data.recordType();
172  })
173  .constructFrom ([&](GenNode const& spec) -> PChannel
174  {
175  return make_unique<ClipPresenter> (spec.idi, this->uiBus_
176  ,getClipContentCanvas()
177  ,std::nullopt);
178  }))
179  .change(ATTR_name, [&](string val)
180  { // »Attribute Setter« : receive a new value for the clip name field
181  REQUIRE (widget_);
182  widget_->setClipName (val);
183  })
184  .change(ATTR_timing, [&](TimeSpan val)
185  {
186  REQUIRE (widget_);
187  widget_->accessStartTime() = val.start();
188  widget_->accessDuration() = val.duration();
189  })
190  //-Diff-Change-Listener----------------
191  .onLocalChange ([this]()
192  {
193  this->establishAppearance();
194  }));
195  }
196 
197 
202  uint
204  {
205  REQUIRE (widget_);
206  return widget_->calcRequiredHeight()
207  + widget_->getVerticalOffset();
208  }
209 
217  void
219  {
220  REQUIRE (widget_);
221  widget_->updatePosition();
222  }
223 
224 
225  private:/* ===== Subject-Interface ===== */
226 
230  {
231  ClipPresenter& subject_;
232  model::DisplayMetric const& metric_;
233  TimeVar& newTime_;
234  Time oldTime_;
235 
236  void
237  updateOffset (double deltaX, double deltaY) override
238  {
239  newTime_ = metric_.applyScreenDelta(oldTime_, deltaX);
240  subject_.widget_->updatePosition();
241  std::cerr << _Fmt{"Gesture(%s) → Δ ≔ (%3.1f,%3.1f) ⟹ %s ↷ %s"}
242  % getCmdID()
243  % deltaX
244  % deltaY
245  % oldTime_
246  % subject_.widget_->accessStartTime()
247  << std::endl;
248  }
249 
250  void
251  markGestureCompleted() override
252  {
253  std::cerr << _Fmt{"!!BANG!! Gesture-Cmd '%s' Time ↷ %s"}
254  % getCmdID()
255  % newTime_
256  << std::endl;
257  }
258 
259  public:
260  DragRelocateObserver(Symbol cmdID, ClipPresenter& clipPresenter)
262  , subject_{clipPresenter}
263  , metric_ {subject_.widget_->getCanvas().getMetric()}
264  , newTime_{subject_.widget_->accessStartTime()}
265  , oldTime_{newTime_}
266  { }
267  };
268 
269  void
270  buildGestureObserver (Symbol cmdID, Buffer buffer) override
271  {
272  buffer.create<DragRelocateObserver> (cmdID, *this);
273  }
274 
275  Gtk::Widget&
276  exposeWidget() override
277  {
279  }
280 
281 
282 
283  private:/* ===== Internals ===== */
295  void
296  establishAppearance(WidgetHook* newView =nullptr,
297  optional<TimeSpan> const& timing =nullopt)
298  {
299  void* prevDelegate = widget_.get();
300  auto newAppearance = ClipDelegate::selectAppearance (this->widget_, defaultAppearance, newView, timing);
301 
302  if (prevDelegate != widget_.get()
303  and newAppearance > ClipDelegate::DEGRADED)
304  {// a new dedicated clip widget has been created...
305  interact::CmdContext::of (steam::cmd::scope_moveRelocateClip, GESTURE_dragReolcate)
306  .linkSubject (*this)
308  }
309  }
310 
311 
312  WidgetHook&
313  getClipContentCanvas()
314  {
315  UNIMPLEMENTED ("how to create and wire an embedded canvas for the clip contents/effects");
316  }
317  };
318 
319 
320 }}// namespace stage::timeline
321 #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:241
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:105
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:82
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:308
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:94
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:126
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:113
static CmdContext of(Symbol cmdID, Symbol ctxID)
global static service accessor function.
Definition: cmd-context.cpp:86
static const ClipDelegate::Appearance defaultAppearance
default maximum level of detail presentation desired for each clip.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:46
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:809
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:769
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:582
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:97
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:231
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...