Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
clip-widget.cpp
Go to the documentation of this file.
1/*
2 ClipWidget - display of a clip in timeline or media bin view
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
84#include "stage/gtk-base.hpp"
87
88#include "lib/format-string.hpp"
89
90#include "lib/util.hpp"
91
92#include <utility>
93
94
95
96using util::_Fmt;
98using util::unConst;
99using std::optional;
100
101
102namespace stage {
103namespace timeline {
104 namespace error = lumiera::error;
105
106 const int ClipDelegate::defaultOffsetY{0};
107 const string ClipDelegate::defaultName{_("clip")};
108
109
112
113
114 namespace {// details of concrete clip appearance styles...
115
118
119
121 : public ClipDelegate
123 {
126
127 public: /* === Partial implementation of ClipDelegate === */
128 TimeVar&
130 {
131 return start_;
132 }
133
134 TimeVar&
135 accessDuration() override
136 {
137 return this->dur_;
138 }
139
140
141 public:
142 ClipData(TimeSpan const& timings =TimeSpan{Time::NEVER, Duration::NIL})
143 : ClipDelegate{}
144 , start_{timings.start()}
145 , dur_{timings.duration()}
146 { }
147
148 ClipData (ClipData&&) = default;
149 };
150
151
157 : public ClipData
158 {
161
162 /* === Interface ClipDelegate === */
163
165 currentAppearance() const override
166 {
167 return Appearance::PENDING;
168 }
169
170 Appearance
172 {
173 return currentAppearance();
174 }
175
177 getClipName() const override
178 {
179 return clipName_;
180 }
181
182 void
183 setClipName(cuString& newName) override
184 {
185 clipName_ = newName;
186 }
187
188
193 uint
194 calcRequiredHeight() const override
195 {
196 return 0;
197 }
198
199 uint
200 getVerticalOffset() const override
201 {
202 return 0;
203 }
204
206 getCanvas() const override
207 {
208 return unConst(this)->display_;
209 }
210
211 void
212 updatePosition() override
213 {
214 /* NOOP */
215 }
216
217
218 public:
219 DormantClip(WidgetHook& displayAnchor)
220 : ClipData{}
221 , display_{displayAnchor}
222 , clipName_{}
223 { }
224
227 : ClipData{std::move (existing)}
228 , display_{existing.getCanvas()}
229 , clipName_{existing.getClipName()}
230 { }
231 };
232
233
235 : public HookedWidget
236 , public ClipData
237 {
238
239 /* === Interface ClipDelegate === */
240
242 currentAppearance() const override
243 {
245 return Appearance::COMPACT;
246 }
247
248 Appearance
249 changeAppearance (Appearance desired) override
250 {
252 return currentAppearance();
253 }
254
256 getClipName() const override
257 {
258 return widget::ElementBoxWidget::getName();
259 }
260
261 void
262 setClipName(cuString& newName) override
263 {
264 widget::ElementBoxWidget::setName (newName);
265 }
266
267 uint
268 getVerticalOffset() const override
269 {
270 return defaultOffsetY;
271 }
272
273 uint
274 calcRequiredHeight() const override
275 {
276 return this->get_height();
277 }
278
280 getCanvas() const override
281 {
282 return HookedWidget::getCanvas();
283 }
284
285 void
286 updatePosition() override
287 {
288 WidgetHook::Pos nominalPos = establishHookPoint(nullptr);
289 this->moveTo (nominalPos.x, nominalPos.y);
290 establishHorizontalExtension();
291 }
292
293 /* ==== Size and Layout handling ==== */
294
298 int
300 {
301 int hsiz = getCanvas().getMetric().translateTimeToPixels (accessDuration());
302 return hsiz;
303 }
304
305
306 public:
307 ClipWidget(WidgetHook& displayAnchor, TimeSpan const& timings)
308 : HookedWidget{displayAnchor.hookedAt(timings, defaultOffsetY), widget::Kind::CONTENT
309 , widget::Type::VIDEO
310 , widget::name(defaultName)
311 , widget::constrained(
312 [this]() { return establishHorizontalExtension(); }
313 )}
314 , ClipData{timings}
315 {
316 show_all();
317 }
318
320 ClipWidget(ClipData&& existing, WidgetHook* newView =nullptr)
321 : HookedWidget{existing.establishHookPoint(newView) , widget::Kind::CONTENT
322 , widget::Type::VIDEO
323 , widget::name(existing.getClipName())
324 , widget::constrained(
325 [this]() { return establishHorizontalExtension(); }
326 )}
327 , ClipData{std::move (existing)}
328 {
329 show_all();
330 }
331 };
332
333
334
336
337 inline Mode
339 {
340 return appearance < ClipDelegate::SYMBOLIC? HIDDEN
341 : appearance < ClipDelegate::ABRIDGED? SUMMARY
342 : INDIVIDUAL;
343 }
344
345
347 inline bool
348 canShow (Time start)
349 {
350 return start != Time::NEVER;
351 }
352
353 inline bool
354 canRepresentAsClip (PDelegate& existing, optional<TimeSpan> const& timing)
355 {
356 return (existing and canShow(existing->accessStartTime()))
357 or (not existing and timing and canShow(timing->start())) ;
358 }
359
360
366 inline ClipDelegate*
367 buildDelegateFor (Mode newMode, PDelegate& existingDelegate, WidgetHook* newView, optional<TimeSpan> const& timing)
368 {
369 if (existingDelegate)
370 { // flip existing delegate to another instance for newMode...
371 REQUIRE (INSTANCEOF (ClipData, existingDelegate.get()));
372 ClipData& clipData = static_cast<ClipData&> (*existingDelegate);
373
374 switch (newMode)
375 {
376 case HIDDEN:
377 return new DormantClip (std::move (clipData));
378 case INDIVIDUAL:
379 return new ClipWidget (std::move (clipData), newView);
380 case SUMMARY:
381 UNIMPLEMENTED ("Summary/Overview presentation style");
382 }
383 }
384 else
385 { // First time: build new delegate from scratch
386 REQUIRE (newMode==HIDDEN or (timing and canShow (timing->start())));
387 REQUIRE (newView);
388
389 switch (newMode)
390 {
391 case HIDDEN:
392 return new DormantClip{*newView};
393 case INDIVIDUAL:
394 return new ClipWidget{*newView, *timing};
395 case SUMMARY:
396 UNIMPLEMENTED ("Summary/Overview presentation style");
397 }
398 }
399 NOTREACHED("unsupported clip display mode.");
400 }
401 }//(End)clip appearance details.
402
403
404
405 /* === Appearance Style state transitions === */
406
407 ClipDelegate::Appearance
408 ClipDelegate::selectAppearance (PDelegate& existing, Appearance desired, WidgetHook* newView, optional<TimeSpan> const& timing)
409 {
410 REQUIRE (existing or newView, "need either an existing delegate or also a new View/Canvas");
411
412 Appearance current = existing? existing->currentAppearance()
413 : Appearance::PENDING;
414 if (not canRepresentAsClip (existing, timing))
415 desired = Appearance::PENDING;
416 // classify all possible appearances into three base presentation modes
417 Mode curMode = classifyAppearance (current);
418 Mode newMode = classifyAppearance (desired);
419
420 if (newView or newMode != curMode)
421 { // need to switch the clip delegate
422 PDelegate newState (buildDelegateFor (newMode, existing, newView, timing));
423 swap (existing, newState);
424 }
425 ENSURE (existing);
426 return existing->changeAppearance (desired);
427 // fine-tune appearance style within limits of the mode established
428 }
429
430
431 WidgetHook::Pos
432 ClipDelegate::establishHookPoint (WidgetHook* newView)
433 {
434 if (not newView)
435 newView = & getCanvas();
436 return newView->hookedAt (Time{accessStartTime()}, defaultOffsetY);
437 }
438
439
440 Gtk::Widget&
441 ClipDelegate::expect_and_expose_Widget (PDelegate& manager)
442 {
443 if (manager and manager->currentAppearance() >= ClipDelegate::ABRIDGED)
444 return static_cast<ClipWidget&> (*manager);
445
446 else
447 throw error::State (_Fmt{"Attempt to access the Widget for clip('%s') in presentation state %d. "
448 "This implies an error in the signal wiring logic and state handling."}
449 % string{manager? manager->getClipName() : "<not initialised>"}
450 % int {manager? manager->currentAppearance() : -1}
451 ,LERR_(UIWIRING)
452 );
453 }
454
455
456
457}}// namespace stage::timeline
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.
Pos hookedAt(int x, int y)
A widget attached onto a display canvas or similar central presentation context.
Appearance
desired appearance style for the clip
static const string defaultName
placeholder name – typically overridden from the model
virtual ~ClipDelegate()
this is an interface
static const int defaultOffsetY
vertical offset below the track start
ClipData(TimeSpan const &timings=TimeSpan{Time::NEVER, Duration::NIL})
Appearance currentAppearance() const override
presentation mode and style currently employed
Appearance changeAppearance(Appearance desired) override
alter appearance style, to the degree possible for this delegate.
int establishHorizontalExtension()
use underlying canvas metric to derive a size constraint, taking into account the duration of the cli...
ClipWidget(WidgetHook &displayAnchor, TimeSpan const &timings)
ClipWidget(ClipData &&existing, WidgetHook *newView=nullptr)
state switch ctor
cuString getClipName() const override
human readable rendering of the clip's name or identity
A Clip not directly mapped into presentation, yet present as entity within the timeline framework.
Appearance currentAppearance() const override
presentation mode and style currently employed
Appearance changeAppearance(Appearance) override
alter appearance style, to the degree possible for this delegate.
cuString getClipName() const override
human readable rendering of the clip's name or identity
uint calcRequiredHeight() const override
This is a mere data record without actual presentation, and thus can not occupy any screen extension.
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
A front-end for using printf-style formatting.
This widget provides the concrete rendering of a clip-like entity.
Widget to render an ID label with associated icon.
#define LERR_(_NAME_)
Definition error.hpp:45
Front-end for printf-style string template interpolation.
A set of basic GTK includes for the UI.
#define _(String)
Definition gtk-base.hpp:68
unsigned int uint
Definition integral.hpp:29
LumieraError< LERR_(STATE)> State
Definition error.hpp:209
bool canShow(Time start)
special convention to suppress a clip with start time == Time::NEVER
Mode classifyAppearance(ClipDelegate::Appearance appearance)
bool canRepresentAsClip(PDelegate &existing, optional< TimeSpan > const &timing)
ClipDelegate * buildDelegateFor(Mode newMode, PDelegate &existingDelegate, WidgetHook *newView, optional< TimeSpan > const &timing)
std::unique_ptr< ClipDelegate > PDelegate
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
const uString cuString
Definition gtk-base.hpp:93
Glib::ustring uString
Definition gtk-base.hpp:92
STL namespace.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
#define Type(_EXPR_)
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition util.hpp:514