Lumiera  0.pre.03
»edit your freedom«
track-presenter.hpp File Reference

Go to the source code of this file.

Description

Presentation control element to model and manage a track within the timeline UI.

In the Lumiera timeline UI, we are mixing two different scope of concerns: For one, we have the globally tangible scope of actual session elements and operations performed on those. And then there are more local considerations regarding the "mechanics" of the UI elements, their state and immediate feedback to user interactions. The Presenter – as known from the MVP pattern – serves as link between both levels. For the global angle of view, it is a model::Tangible and thus plays the role of the View, while the Model and Controller roles are mediated through the stage::UiBus, exchanging command, state and mutation messages. On the other hand, for the local angle of view, the Presenter is a structural model element, kind of a view model, and corresponds to the respective element within the session. In addition, it manages actively the collaborative part of layout building, delegating to a mostly passive GTK widget for the actual display. This way it becomes possible to manage the actual UI resources on a global level, avoiding to represent potentially several thousand individual elements as GTK entities, while at any time only a small number of elements can be visible and active as far as user interaction is concerned.

Structure of the TrackPresenter

Each TrackPresenter corresponds to a "sub-Fork" of timeline tracks. Since Lumiera always arranges tracks as nested scopes into a tree, there is one root fork, recursively holding several sub forks.

  • thus each TrackPresenter holds a collection #subFork_ – possibly empty.
  • moreover, it holds a collection #clips_, which represent the actual content of this track itself, as opposed to content on some sub-track. These clips are to be arranged within the content area of the track display, in the track body area (at the right side of the timeline). Actually, this collection holds timeline::ClipPresenter objects, thus repeating the same design pattern.
  • in addition, there can be a collection of #markers_, to be translated into various kinds of region or point/location markup, typically shown in the (optional) overview ruler, running along the top-side of this track's display area.

Since TrackPresenter is a model::Tangible, a central concern is the ability to respond to diff messages. In fact, any actual content, including all the nested sub-structures, is populated through such mutation messages sent from the session up via the stage::UiBus. Thus, the TrackPresenter::buildMutator() implementation hooks up the necessary callbacks, to allow adding and removing of sub elements and properties of a track.

Another concern handled here is the coordination of layout and display activities. A special twist arises here: The track header ("patchbay") display can be designed as a classical tree / grid control, while the actual timeline body contents require us to perform custom drawing activities. Which leads to the necessity to coordinate and connect two distinct presentation schemes to form a coherent layout. We solve this challenge by introducing a helper entity, the DisplayFrame. These act as a bridge to hook into both display hierarchies (the nested TrackHeaderWidget and the TrackBody record managed by the BodyCanvasWidget). Display frames are hooked down from their respective parent frame, thereby creating a properly interwoven fabric.

After assembling the necessary GTK widgets, typically our custom drawing code will be invoked at some point, thereby triggering BodyCanvasWidget::maybeRebuildLayout(). At this point the timeline::TrackProfile needs to be established, so to reflect the succession and extension of actual track spaces running alongside the time axis. This is accomplished through a global timeline::DisplayEvaluation pass, recursively visiting all the involved parts to perform size adjustments, until the layout is globally balanced.

Relative Coordinate System

With respect to the TrackBody, the DisplayFrame within each Track acts as a relative attachment point and relative coordinate system; this is implemented as stage::model::RelativeCanvasHook. The top-level anchor point is established in the ctor of timeline::TimelineController, where the actual TimelineLayout is passed as parent CanvasHook; hinged below this anchor, each parent track acts as reference CanvasHook for the child tracks.

Impact of indirections:
to keep matters simple for the initial implementation, these relationships were modelled as layered interfaces / overridden virtual methods. This leads to a chain of calls through several VTables; the practical impact of this scheme on the performance of the timeline GUI will be investigated when there is a sufficiently complete implementation available – see #1254
Todo:

as of 10/2018 timeline display in the UI is rebuilt to match the architecture

as of 3/2023, the basic structure is settled and the design validated

Definition in file track-presenter.hpp.

Classes

class  DisplayFrame
 Reference frame to organise the presentation related to a specific Track in the Timeline-GUI. More...
 
class  RelativeCanvasHook< WID >
 Special CanvasHook decorator to apply a (dynamic) offset when attaching or moving Widgets on the shared canvas. More...
 
class  TrackPresenter
 A View-Model entity to represent a timeline track in the UI. More...
 

Typedefs

using PClip = unique_ptr< ClipPresenter >
 
using PFork = unique_ptr< TrackPresenter >
 
using PMark = unique_ptr< MarkerWidget >
 
using PRuler = unique_ptr< RulerTrack >
 

Namespaces

 stage
 Lumiera GTK UI implementation root.
 
 stage::timeline
 The timeline display and editing operations.