diff --git a/src/stage/timeline/ruler-track.cpp b/src/stage/timeline/ruler-track.cpp index b45e92afa..e14df70c4 100644 --- a/src/stage/timeline/ruler-track.cpp +++ b/src/stage/timeline/ruler-track.cpp @@ -32,7 +32,9 @@ #include "stage/gtk-base.hpp" +#include "include/ui-protocol.hpp" #include "stage/timeline/ruler-track.hpp" +#include "stage/timeline/track-presenter.hpp" //#include "stage/ui-bus.hpp" //#include "lib/format-string.hpp" @@ -44,6 +46,7 @@ //#include +using lib::diff::TreeMutator; //using util::_Fmt; using util::isnil; @@ -70,14 +73,26 @@ namespace timeline { - RulerTrack::RulerTrack() - : scales_{} + RulerTrack::RulerTrack (ID id, ctrl::BusTerm& nexus, TrackPresenter& parent) + : Controller{id, nexus} + , track_{parent} + , scales_ {} { } - RulerTrack::~RulerTrack() + RulerTrack::~RulerTrack() { } + + void + RulerTrack::buildMutator (TreeMutator::Handle buffer) { - TODO ("detach from parent; store a functor or backreference"); + UNIMPLEMENTED ("what can actually be manipulated on a RulerTrack by diff message?"); + +// buffer.create ( +// TreeMutator::build() +// .change(ATTR_name, [&](string val) +// { // »Attribute Setter« : receive a new value for the track name field +// this->setTrackName (val); +// })); } diff --git a/src/stage/timeline/ruler-track.hpp b/src/stage/timeline/ruler-track.hpp index 5281545c8..7c10f1e0a 100644 --- a/src/stage/timeline/ruler-track.hpp +++ b/src/stage/timeline/ruler-track.hpp @@ -45,6 +45,7 @@ #define STAGE_TIMELINE_RULER_TRACK_H #include "stage/gtk-base.hpp" +#include "stage/model/controller.hpp" //#include "lib/util.hpp" @@ -56,6 +57,8 @@ namespace stage { namespace timeline { + class TrackPresenter; + ////////////////////////////////////////////////////////////////////TICKET #1195 : Timecode Ruler presentation struct RulerScale { @@ -70,18 +73,29 @@ namespace timeline { * @todo this is more or less preliminary/placeholder code as of 4/2019 ////////////////////////TICKET #1194 : proper handling of ruler tracks */ class RulerTrack + : public model::Controller { using Scales = std::vector; + TrackPresenter& track_; Scales scales_; public: - RulerTrack(); ~RulerTrack(); + /** + * @param id identity used to refer to a corresponding session::Fork + * @param nexus a way to connect this Controller to the UI-Bus. + * @param anchorDisplay a one-way closure to attach into the display fabric + */ + RulerTrack (ID id, ctrl::BusTerm& nexus, TrackPresenter& parent); + uint calcHeight(); uint getGapHeight(); + /** set up a binding to respond to mutation messages via UiBus */ + virtual void buildMutator (lib::diff::TreeMutator::Handle) override; + private:/* ===== Internals ===== */ }; diff --git a/src/steam/mobject/session/dummy-session-connection.cpp b/src/steam/mobject/session/dummy-session-connection.cpp index 9b91dad6b..c6f63bde6 100644 --- a/src/steam/mobject/session/dummy-session-connection.cpp +++ b/src/steam/mobject/session/dummy-session-connection.cpp @@ -88,6 +88,20 @@ namespace session { ) .genNode(baseID); } + + GenNode + emptyTrack (string trackID) + { + return MakeRec() + .type (string{stage::TYPE_Fork}) + .genNode(trackID); + } + + GenNode + ruler() + { + UNIMPLEMENTED("send diff to constitute a new ruler track"); + } } //(End)Implementation details.... @@ -123,6 +137,31 @@ namespace session { } + /** + * Build another population diff message for a way more contrived timeline structure + */ + MutationMessage + DummySessionConnection::fabricateSeq2 (string baseID) + { + const RandID forkRootID{stage::ATTR_fork}; + const GenNode timeline = emptyTimeline (baseID, forkRootID); + const GenNode rootTrackName = GenNode{string{stage::ATTR_name}, "Fork-Root"}; + const GenNode forkRoot = MakeRec().genNode(forkRootID); + + return MutationMessage{ ins (timeline) + , mut (timeline) + , mut (forkRoot) + , set (rootTrackName) + , ins (emptyTrack ("Track-1")) + , ins (emptyTrack ("Track-2")) + , ins (ruler()) + , emu (forkRoot) + , emu (timeline) + }; + } + + + /** @todo build an internal "shadow data structure" and apply all diffs there as well...*/ void DummySessionConnection::applyCopy (MutationMessage const& diff) { @@ -192,6 +231,10 @@ COMMAND_DEFINITION (test_fake_injectSequence_2) { string message{_Fmt{"fabricate Sequence_2 (dummyID='%s')"} % dummyID}; GuiNotification::facade().displayInfo (NOTE_INFO, message); + auto popuDiff = DummySess::instance().fabricateSeq2 (dummyID); + DummySess::instance().applyCopy (popuDiff); + auto rootID = session::Root::getID(); + GuiNotification::facade().mutate (rootID, move(popuDiff)); }) .captureUndo ([](string dummyID) -> string { diff --git a/src/steam/mobject/session/dummy-session-connection.hpp b/src/steam/mobject/session/dummy-session-connection.hpp index 8bd0c757d..9a2dbaeb7 100644 --- a/src/steam/mobject/session/dummy-session-connection.hpp +++ b/src/steam/mobject/session/dummy-session-connection.hpp @@ -110,6 +110,7 @@ namespace session { /* == forget Y == */ MutationMessage fabricateSeq1 (string baseID); + MutationMessage fabricateSeq2 (string baseID); void applyCopy (MutationMessage const&); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index af5d0977a..f44824ea0 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3562,7 +3562,7 @@ Now, since we build our UI on the notion of mapping session contents via a messa In any case, this is an advanced topic, and nowhere near trivial. It seems reasonable to reject opening duplicate timeline presentations as a first step, and then address this topic way later, when we've gained sufficient knowledge regarding all the subtleties of timeline presentation and editing. -
+
Within the Lumieara GUI, the [[Timeline]] structure(s) from the HighLevelModel are arranged and presented according to the following principles and conventions.
 Several timeline views may be present at the same time -- and there is not necessarily a relation between them, since »a Timeline« is the top-level concept within the [[Session]]. Obviously, there can also be several //views// based on the same »Timeline« model element, and in this latter case, these //coupled views// behave according to a linked common state. An entity »Timeline« as represented through the GUI, emerges from the combination of several model elements
 * a root level [[Binding|BindingMO]] acts as framework
@@ -3575,13 +3575,13 @@ Several timeline views may be present at the same time -- and there is not neces
 Session, Binding and Sequence are the mandatory ingredients.
 
 !Basic layout
-[>img[Clip presentation control|draw/UI-TimelineLayout-1.png]]The representation is split into a ''Header pane'' exposing structure and configuration, and a ''Content pane'' extending in time. The ''Time ruler'' running alongside the top of the content pane represents the //position in time.// Beyond this temporal dimension, the content area is conceived as a flexible working space. This working space //can// be structured hierarchically -- when interacting with the GUI, hierarchical nesting will be created and collapsed on demand. Contrast this with conventional editing applications which are built upon the rigid notion of "Tracks": Lumiera is based on //Pipes// and //Scopes// rather than Tracks.
+[>img[Clip presentation control|draw/UI-TimelineLayout-1.png]]The representation is split into a ''Header pane'' exposing structure and configuration, and a ''Content pane'' extending in time. The ''Time ruler'' ( → [[Rulers|TrackRuler]]) running alongside the top of the content pane represents the //position in time.// Beyond this temporal dimension, the content area is conceived as a flexible working space. This working space //can// be structured hierarchically -- when interacting with the GUI, hierarchical nesting will be created and collapsed on demand. Contrast this with conventional editing applications which are built upon the rigid notion of "Tracks": Lumiera is based on //Pipes// and //Scopes// rather than Tracks.
 
 In the temporal dimension, there is the usual scrolling and zooming of content, and possibly a selected time range, and after establishing a ViewerPlayConnection, there is an effective playback location featured as a "Playhead"
 The workspace dimension (vertical layout) is more like a ''Fork'', which can be expanded recursively. More specifically, each strip or layer or "track" can be featured in //collapsed// or //expanded state.//
 * the collapsed state features a condensed representation ("the tip of the iceberg"). It exposes just the topmost entity, and might show a rendered (pre)view. Elements might be stacked on top, but any element visible here //is still accessible.//
 * when expanding, the content unfolds into...
-** a ''scope ruler'' to represent the whole sub-scope. This is rendered as a small pane, extending horizontally, holding any locally attached labels and track-wide or temporally scoped effects
+** a ''scope ruler'' to represent the whole sub-scope.<br/>A [[Ruler|TrackRuler]] is rendered as a small pane, extending horizontally, to hold any locally attached labels and track-wide or temporally scoped effects
 ** the content stack, comprised of [[clip widgets|GuiClipWidget]], attached effects and transitions
 ** a stack of nested sub-scopes (recursive).
 
@@ -9233,7 +9233,7 @@ Placements are __resolved__ resulting in an ExplicitPlacement. In most cases thi
 &rarr; [[Definition|Pipe]] and [[handling of Pipes|PipeHandling]]
 
-
+
//mediating entity used to guide and control the track-like nested working space in the timeline display of the UI.//
 
 Similar to the ClipPresenter, judged from a global angle, this element fulfils a model-like role, while at the same time guiding and controlling a mostly passive view component, implemented as GTK widget. Here, the authority of the presenter over the widget must be total, since display management //needs to work automatically,// due to model updates and mutations arriving as [[diff messages|MutationMessage]]. In addition, this structure is prerequisite for (possibly) implementing UI rendering optimisations, since it allows us to leave out widgets entirely, when it is clear they won't become visible: A ''display evaluation pass'', which is effectively a //tree walk,// consecutively visits each part of the timeline structure, to negotiate its concrete display properties in collaboration with a global TimelineDisplayManager. As a result, the presenter knows where to show its corresponding view, and it knows if to show it at all, allowing to either adjust, create or destroy actual GTK widgets within its local reference frame.
@@ -9245,8 +9245,29 @@ To deal with this typical problem of recursive programming, we introduce a bindi
 * however, after constructing the {{{DisplayFrame}}}, it invokes an anchor functor, which is passed in from the recursive outer scope, and which does the actual work of installing those widgets into the apropriate parent widgets
 * but the {{{DisplayFrame}}} itself also exposes such an anchor functor, which can be passed down when (recursively) creating a TrackPresenter for a sub-Track
 * obviously, at top-level, we need to digress from that general pattern -- here it is the {{{timeline::TimelineLayout}}} responsible for the display structure of the whole timeline which exposes the necessary anchor function to attach the root track for a timeline.
+
+!Organisation of track profile and rulers
+Related to the problem of building the nested track structure is the problem of proper graphical representation of this nested structure -- especially within the right pane, //the body part,// where the actual track content will be shown. Due to various limitations of typical UI frameworks, we prefer to handle this body part by [[custom drawing|GuiCustomWidget]] onto a canvas widget. Which places us into the situation to generate suitable graphical elements based on the effective nested structure of the tracks. We solve this challenge by performing an //evaluation pass// over the actual {{{TrackBody}}} structure, which is built starting from the {{{DisplayFrame}}} for each track. The {{{TrackBody}}} elements are helper objects, and serve the sole purpose of getting this drawing and display control requirements settled; basically they mirror the track structure, and the corresponding structure of GTK widgets in the header pane, and they likewise form a tree structure, which can be traversed to collect information. Which is what we, for building up a "track profile", which can then later be &rarr; [[rendered consistently onto the body canvas|GuiTimelineDraw]].
+
+Another related concern are the [[track rulers|TrackRuler]]. These are overview panes running alongside the track time axis. As UI model entities, they are attached to the corresponding {{{TrackBody}}} element, while collaborating with the {{{TrackPresenter}}} to retrieve the actual content to be shown in the overview. The purpose of track rulers is to show effects or selection states; and especially in the top-level track the ''time ruler'' indicates the current time and frame position.
 
+
+
//A small overview pane running alongside a track in the timeline display.//
+The presence and specific configuration of a ruler is governed by the [[Session model|HighLevelModel]], while the actual content is derived from the context appropriately by the presentation code in the UI. Rulers can be used for various purposes
+* the ''time ruler'' at the top of the timeline display indicates the time axis position in various formats.
+* an ''overview ruler'' shows the effective content of a track in condensed form
+* location- and range markers can be shown on top of a ruler
+* selection- and processing state may likewise be visualised.
+
+!Organisation of track ruler presentation
+The actual presentation of ruler elements is a fusion of parametrisation, track content and (persistent) UI state.
+* The fact that a ruler is present, and also its presentation style is controlled by the Session. {{red{7/19 not clear yet in which form they are represented in the model}}}
+* Rulers are sensitive to the expanded/collapsed state of their corresponding track; there is a distinct parametrisation for three distinct cases
+** the ruler of a //collapsed// track can either be hidden, or shown in condensed form
+** the ruler of an //expanded fork// (a track with nested child tracks) will typically give a summary of effective content, but can also be hidden, or feature other content
+** the ruler of an //expanded leaf track// (no child tracks) will typically be hidden, but can likewise be configured to show specific data
+
Transitions combine the data from at least two processing chains and do this combining in a time varying fashion. So, any transition has
 * N input connections
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 67377a8e5..81a804014 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -4946,7 +4946,7 @@
 
 
 
-
+
 
   
     
@@ -19417,7 +19417,8 @@
 
 
 
-
+
+
 
 
 
@@ -19425,6 +19426,13 @@
 
 
 
+
+
+
+
+
+
+
 
 
 
@@ -19481,6 +19489,10 @@
 
 
 
+
+
+
+
 
 
 
@@ -19496,7 +19508,7 @@
 
 
 
-
+
 
 
 
@@ -19663,6 +19675,112 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+    
+  
+  
+    

+ beim initialen Aufbau sitzen wir in einem ctor-Aufruf, +

+

+ und zwar der ctor-TrackPresenter +

+ + +
+
+ + + + + + + +

+ insofern der ctor für den root-Track (fork-root) vom TimelineController aufgerufen wird, +

+

+ alle anderen verschachtelten ctors aber von den TrackPresentern +

+ + +
+
+ + + +
+ + + + + + +

+ weil nur sie sowohl durch ihren Display-Frame die beiden Kind-Widgets kennen +

+ + +
+ + + + + + +

+ inwiefern gibt es Beschränkungen, wenn man ein Kind-Widget von einem Container entfernt? +

+ + +
+ + + + + + + + + + + + + + + + + + +
+
@@ -19702,8 +19820,26 @@ - - + + + + + + + + + + +

+ aber verschachtelte sub-Tracks werden in dieser gehandhabt +

+ + +
+
+ + +
@@ -19755,7 +19891,28 @@
- + + + + + + + + + + + + + + + + + + + + + + @@ -19805,15 +19962,113 @@ - - - + + - + + + - + + + + + + + + +

+ weil der Ruler ja in die Präsentation mit einbezogen ist +

+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ ....ob es was sinnvolles in einem Overview-Ruler anzuzeigen gibt +

+ + +
+
+
+
+ + + @@ -19926,6 +20181,13 @@ + + + + + + + @@ -20835,8 +21097,8 @@ - - + + @@ -21154,7 +21416,7 @@ - + @@ -21205,7 +21467,7 @@ - + @@ -21232,7 +21494,7 @@ - + @@ -21240,6 +21502,11 @@ + + + + + @@ -21779,8 +22046,8 @@ - - + + @@ -21919,8 +22186,8 @@ - - + + @@ -22048,6 +22315,75 @@ + + + + + + + + + + + + + + + + + + + + + + + +

+ meine Einschätzung, basiert auf dem gtk-canvas-experiment.cpp +

+
    +
  • + zeichnen kann man "irgendwie" auf dem Canvas. +
  • +
  • + außerdem hat das Gtk::Layout ein hadjustment() / vadjustment() +
  • +
  • + diese können (optional) an eine Scrolled-Pane angekoppelt sein +
  • +
  • + die tatsächliche size-Allocation ist ein davon unabhängiges Thema +
  • +
+ + +
+
+ + + + + + +

+ rein gefühlsmäßig wäre aber vorher wohl geschickter +

+ + +
+ + + + + +

+ denn was passiert, wenn sich durch das Setzen einer neuen Größe der sichtbare Bereich ändert? Löst das dann nicht erneut einen draw()-Aufruf aus?? +

+ + +
+
+
@@ -22388,7 +22724,7 @@ - + @@ -31875,7 +32211,7 @@ - +