diff --git a/src/stage/timeline/body-canvas-widget.cpp b/src/stage/timeline/body-canvas-widget.cpp index b797b3757..62bb6dbb4 100644 --- a/src/stage/timeline/body-canvas-widget.cpp +++ b/src/stage/timeline/body-canvas-widget.cpp @@ -377,8 +377,7 @@ namespace timeline { { // for the initial empty canvas -- use all space the enclosing scrolled window got. auto currSize = get_allocation(); int height = currSize.get_height(); - rulerCanvas_.set_size (currSize.get_width(), INITIAL_TIMERULER_HEIGHT_px); - mainCanvas_.set_size (currSize.get_width(), max(0, height-INITIAL_TIMERULER_HEIGHT_px)); + adjustCanvasHeight(currSize.get_width(), height, INITIAL_TIMERULER_HEIGHT_px); } // realise all initially configured elements.... @@ -421,11 +420,29 @@ namespace timeline { if (rootBody_ and isnil (profile_)) { layout_.triggerDisplayEvaluation(); + TODO("retrieve the vertical extension established by the triggerDisplayEvaluation() "); +// adjustCanvasHeight(currSize.get_width(), height, INITIAL_TIMERULER_HEIGHT_px); //////////////////////////TODO rootBody_->establishTrackSpace (profile_); } } + /** + * After the (recent) [display evaluation pass](\ref DisplayManager::triggerDisplayEvaluation() ) + * has negotiated the required space for the currently presented content, this function adjusts + * the actual Gtk::Layout canvas extension to match. Note that we use two Gtk::Layout controls, + * one to show the always visible overview rules, while the second one is placed into a scrollable + * pane to accommodate an arbitrary numbers of tracks + */ + void + BodyCanvasWidget::adjustCanvasHeight(int canvasWidth, int totalHeight, int rulerHeight) + { + rulerCanvas_.set_size (canvasWidth, rulerHeight); + mainCanvas_.set_size (canvasWidth, max(0, totalHeight-rulerHeight)); + } + + + diff --git a/src/stage/timeline/body-canvas-widget.hpp b/src/stage/timeline/body-canvas-widget.hpp index d592094f1..3ad3e11f0 100644 --- a/src/stage/timeline/body-canvas-widget.hpp +++ b/src/stage/timeline/body-canvas-widget.hpp @@ -136,6 +136,7 @@ namespace timeline { void slotStructureChange() noexcept; void maybeRebuildLayout(); + void adjustCanvasHeight(int canvasWidth, int totalHeight, int rulerHeight); }; diff --git a/src/stage/timeline/track-body.cpp b/src/stage/timeline/track-body.cpp index d375f9fb8..2f749ffee 100644 --- a/src/stage/timeline/track-body.cpp +++ b/src/stage/timeline/track-body.cpp @@ -121,7 +121,7 @@ namespace timeline { * recursively establish the screen space allocation for this structure of nested tracks. * The TrackProfile is an abstracted description of the sequence of track elements, * which constitute a vertical cross section through the track bodies - * - pre: the given profile is built and complete up to the (upper side) start of this timeline + * - pre: the given profile is built and complete up to the (upper side) start of the current track. * - post: the profile is elaborated for this track and its children, down to the lower end. * @todo 6/19 this very much looks like the "display evaluation pass" envisioned for the timeline::DisplayManager. * Need to find out if we'll need a dedicated evaluation pass and how to interconnect both. @@ -135,7 +135,7 @@ namespace timeline { // global setup for the profile profile.append_prelude(); - // Profile elements are always visible on top: + // The first Profile elements are always visible on top: // Top-level rules and one additionally for the prelude profile.pinnedPrefixCnt = 1 + rulers_.size(); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index f44824ea0..075a8bd63 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3524,7 +3524,7 @@ In accordance with the Lumiera application architecture in general, the UI is no
A specially configured LumieraPlugin, which actually contains or loads the complete code of the (GTK)GUI, and additionally is linked dynamically against the application core lib. During the [[UI startup process|GuiStart]], loading of this Plugin is triggered from {{{main()}}}. Actually this causes spawning of the GTK event thread and execution of the GTK main loop.
-The presentation of the track body area relies on the [[Gtk::Layout "canvas widget"|GtkLayoutWidget]], thus allowing for a mixture of custom drawing with embedded custom Gtk widgets. The actual drawing routine is activated in response to the {{{on_draw}}} signal -- and invoking the inherited handler function will initiate the standard drawing for the embedded child widgets. This partitions the additional, specific drawing activities into a pre-widget drawing phase to prepare the background and framework structure of the track area, and a post-widget drawing phase to show all kinds of overlays, markers cursors and similar UI indicators. A nested structure of {{{TrackBody}}} objects serves as organisational device to structure these custom drawing activities in accordance with the nested structure of the track fork.
!Building a nested 3D structure
@@ -3545,6 +3545,32 @@ The actual expression of these elements depends on the content, which is injecte
| | | !__Track-11__ |>|>|>|>|!__Track-12__ | |
|~|~|>| | |!__Track-121__ |!__Track-122__ | |~|
|r(1),r(1),g,''c''(2)|⤵|r(1),g,''c''(3)|r(1),g,r(1)|⤵|r(1),''c''(2) |r(1),''c''(1)|⤴|⤴|
+
+
+!!!Drawing strategy
+Once the fundamental decision towards a 3D structure is taken, there still is some room for choices regarding the actual strategy to perform the drawing primitives. However, there are also known limitations in what can be achieved by shading within an essentially flat drawing (unless we'll get some kind of holographic display technology at our disposal, somewhere in the future). The point to note is, we can not convey a fully three dimensional structure merely through shading -- rather we can only imply //local depth relations.// And since the actual structure of our nested tracks can be quite elaborate and wide spanning, we should focus on expressing such local relations, in order to support the user and help to grasp the presented structure.
+* shading can indicate a //barrier.//
+* shading can indicate a //slope// up or down.
+An immediate consequence to draw from this observation is that ~CSS3 effects are only of limited use for this purpose. They are more helpful to highlight compact and local structures, like a menu button, or some element or handle on the clips. We can (and likely will) use CSS shading for the [[track overview rulers|TrackRuler]] though. We possibly could use a slight inset box shadow within the actual track content area. However, it is rather pointless to use a box shadow to paint the nested track scope insets -- we rather need to rely on gradients and direct colour shading for that purpose.
+
+Another consequence is that we do not need to apply an overall "stacked boxes" approach -- there is not much to gain from doing so (and we would do a lot of unnecessary filling operations, most of which will actually clipped away). For that reason, we define our ''track profile'' to represent a vertical //top-down drawing sweep.// Non the less, the actual colours and shades can be defined completely through CSS rules. To achieve this, we apply some tricks
+* we define //virtual widgets,// which are only used to match against selectors and pick up the attached CSS styles
+** the virtual element {{{fork}}} represents "a timeline track"
+** and a virtual {{{frame}}} element nested therein represents "a ruler on top of a timeline track"
+* this leads to the following selectors to attach the actual styling rules
+*;track fork
+*:attach rules to the selector {{{.timeline__page > .timeline__body fork.timeline__fork}}}
+*:* the {{{border top}}} and {{{border bottom}}} rules will be used to //draw the nested inset.//
+*:* a {{{margin}}} at top will add additional space between consecutive tracks
+*:* while the {{{padding}}} will be used within the track content area -- <br/> of course only in vertical direction, since the horizontal extension is ruled by the time position of elements within the track
+*:* please note that {{{background}}} stylings apply to the //content area// and not the track space at a whole.
+*;track ruler
+*:attach rules to the selector{{{fork.timeline__fork frame.timeline__ruler}}}
+*:* again the {{{border top}}} and {{{border bottom}}} settings will delimit the ruler form the other track content
+*:* while {{{margin}}} and {{{padding}}} apply as usual outside and within the border
+*:* here the {{{box shadow}}} will be drawn with the background -- however, only an {{{inset}}} makes sense here,<br/>since a regular (outer) box shadow will be covered by consecutive drawing actions, unless it sticks within the limits of the {{{margin}}}
+
+Please note also that our drawing code operates in several ''passes''. First, a ''background'' pass is used to fill the area, then GTK is invoked recursively for any widgets on the dawing canvas, most notably the ''clips''. Then, a final ''overlay'' pass allows to paint range markers, selections and indicators on top.