diff --git a/doc/devel/draw/StaveBracket.svg b/doc/devel/draw/StaveBracket.svg index cb5b9058b..c14f51a65 100644 --- a/doc/devel/draw/StaveBracket.svg +++ b/doc/devel/draw/StaveBracket.svg @@ -10,7 +10,7 @@ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="100mm" - height="100mm" + height="120mm" viewBox="0 0 100 100" version="1.1" id="svg8" @@ -19,7 +19,21 @@
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 @@ -3714,7 +3714,7 @@ 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'' ( → [[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. +[>img[Clip presentation control|draw/UI-TimelineLayout-1.png]]The representation is split into a ''Header pane'' exposing structure and configuration ( → [[Patchbay|TimelinePatchbay]]), 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|ZoomWindow]] 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.// @@ -3731,6 +3731,7 @@ The workspace dimension (vertical layout) is more like a ''Fork'', which can be @@ This collapsed, expanded and possibly nested workspace structure is always exactly paralleled in the header pane. In addition, it allows to configure specific placement properties for each nested scope, which especially means to display faders and some toggles, depending on what kind of placement was added. Of course, this placement configuration needs to be collapsible too. Effects and markers can appear at various different scopes, sometimes requiring an abridged display → more about [[the actual drawing code|GuiTimelineDraw]] +→ the [[Track Head display|TrackHead]] !!!lifecycle and instances @@ -3760,7 +3761,7 @@ In the most general case, there can be per-track content and nested content at t
The Timeline is probably the most prominent place in the GUI where we need to come up with a custom UI design.
Instead of combining standard components in one of the well-known ways, here we need to come up with our own handling solution -- which also involves to build several custom GTK widgets. Thus the question of layout and screen space division and organisation becomes a crucial design decision. The ~GTK-2 UI, as implemented during the initial years of the Lumiera project, did already take some steps along this route, which was was valuable as foundation for assessment and further planning.
@@ -3769,7 +3770,7 @@ As it stands, this topic touches a tricky design and architectural challenge: th
In a nutshell, ~GTKmm offers several degrees of customisation, namely to build a custom widget class, to build a custom container widget, and to use the [[Gtk::Layout "canvas widget"|GtkLayoutWidget]], possibly combined with //custom drawing.// In addition to assembling a timeline widget class by combining several nested panes, the timeline display needs to rely on the latter approach to allow for the necessary flexible arrangement of [[clip widgets|GuiClipWidget]] within the [[track fork|Fork]].
!the header pane problem
-Based on principles of //conventional UI design,// we derive the necessity to have a track header pane area, always visible to the left, and scrolling vertically in sync with the actual track display to the right of the timeline area. This insight brings about several consequences. For one this means that our top level widget organisation in the timeline will be a horizontal split. And furthermore this means that we get two distinct sub widgets, whose vertical layout needs to be kept in sync. And even more so, presumably the most adequate implementation technique is different in both parts: the header pane looks like a classical fit for the paradigm of nested boxes and grid layout within those boxes, while the right part -- the actual track contents -- impose very specific layout constraints, not served by any of the pre-existing layout containers -- which means we have to resort to custom drawing on a canvas widget. Following this line of thought, we need an overarching layout manager to coordinate these two disjoint technologies. Any viable alternatives?
+Based on principles of //conventional UI design,// we derive the necessity to have a [[track header pane area|TimelinePatchbay]], always visible to the left, and scrolling vertically in sync with the actual track display to the right of the timeline area. This insight brings about several consequences. For one this means that our top level widget organisation in the timeline will be a horizontal split. And furthermore this means that we get two distinct sub widgets, whose vertical layout needs to be kept in sync. And even more so, presumably the most adequate implementation technique is different in both parts: the header pane looks like a classical fit for the paradigm of nested boxes and grid layout within those boxes, while the right part -- the actual track contents -- impose very specific layout constraints, not served by any of the pre-existing layout containers -- which means we have to resort to custom drawing on a canvas widget. Following this line of thought, we need an overarching layout manager to coordinate these two disjoint technologies. Any viable alternatives?
!!!considering a table grid layout
The layout mechanics we try to establish here by explicit implementation would be more or less a given, if instead we'd build the whole timeline display from one base widget, which needs to be a table layout, i.e. {{{Gtk::Grid}}}. We'd use two columns, one for the header pane area, one for the timeline display, and we'd use N+1 rows, with the head row holding the time ruler and the additional rows holding individual tracks. But to get the specific UI mechanics desirable for a timeline display, we had to introduce some twists:
@@ -3781,7 +3782,7 @@ The layout mechanics we try to establish here by explicit implementation would b
* this problem is mitigated once we add a track with //automation data// linked to the mentioned controls. Yet still, this is not the default situation...
On the other hand, what would be the //obvious benefits...?//
* we just have to add stuff in both the left / right part of the display and get the vertical space management sorted out by framework code
-While the special setup for scrolling doesn't really count (since it is necessary anyway), after this initial investigation it seems clear that a global grid layout doesn't yield enough benefit to justify all the quirks and limitations its use would impose.
+While the special setup for scrolling doesn't really count (since it is necessary anyway), after this initial investigation it seems clear that a global grid layout doesn't yield enough benefit to justify all the quirks and limitations its use would impose -- however, //we can indeed benefit// from GTK's automatic layout management when it comes to building the [[nested Track Head controls|TrackHead]], which can be implemented as nested {{{Gtk::Grid}}}.
!!!follow-up to the obvious choices
We came to this point of re-considering the overall organisation of widgets, after having to re-write the initial version of our timeline widget. This initial version was developed until 2011 by Joel Holdsworth, and it followed a similar reasoning, involving a global timeline layout manager. The distinction between the two panes was not so clear though, and the access to the model code was awkward at places, so the necessity to re-write the timeline widget due to the transition to ~GTK-3 looks like a good opportunity to re-do the same basic reasoning a second time, verify decisions taken and improve matters turning out as difficult on first attempt.
@@ -3798,7 +3799,7 @@ The handling of objects structured into nested scopes is a hallmark of the very
The structure of the display is extended or altered under two circumstances:
# some component receives a [[diff mutation message|MutationMessage]], prompting to add or remove a //child component.//
# the display (style) of some component is expanded or collapsed.
-Here, the "component" relevant for such structural changes is always the UI representation of a track. Beyond that, the layout can also be changed //without changing the display structure,// when some embedded component, be it placement (in the track heads / the patchbay) or a clip, effect or transition, is expanded or collapsed. In such a case, a resizing challenge needs to be directed towards the next enclosing track container.
+Here, the "component" relevant for such structural changes is always the UI representation of a track. Beyond that, the layout can also be changed //without changing the display structure,// when some embedded component, be it placement (in the [[track heads|TrackHead]] / the [[patchbay|TimelinePatchbay]]) or a clip, effect or transition, is expanded or collapsed. In such a case, a resizing challenge needs to be directed towards the next enclosing track container.
From these observations we can draw the conclusion, that we'll build a ''local structural model'', to reflect the logical relations between the parts comprising the timeline display. More precisely, these structuring components are not mere model objects, rather they are mediating entities used to guide and organise the actual view entities, which in turn are passive. They are more like a view model, while also bearing some local controller responsibilities. For this reason, we prefer to term these as ''presenters'' -- i.e. TrackPresenter and ClipPresenter. And each of these local representation components holds onto a ''display context'', which generally links it //into two different display widget stacks// within the two parts of the actual timeline display. Adding a child component thus becomes a rather tricky operation, involving to link possibly two child widgets into two disjoint parent widgets, thereby forming a similar display context for the child presenter. Overall, the guiding idea is that of self similarity: on each level, we have to reproduce the same relations and collaborations as present in the parent level.
@@ -9293,6 +9294,15 @@ Another, closely related topic, handled within this context, is the mapping from
By principle, //widgets always work exclusively in pixel coordinates// -- thus we need the help of a coordinating entity to find out where some entity shall be located on the GTK drawing canvas. This becomes especially relevant for the timeline body, since there we're relying on a GuiCustomWidget to perform and control some of the UI drawing by specific custom rules and procedures. And to add to this complexity, several structures are //nested,// thus anchoring their coordinates relative to the parent entity. These challenges are resolved by the introduction of yet another abstraction, the [[»canvas interface«|GuiCanvasInterface]], allowing to attach widgets relative to a //reference canvas// and to maintain uniform coordinates and a [[zoom metric|ZoomWindow]] used for a properly calibrated timeline display.
//The TimelineNavigator is a small widget at the left top side of the timeline display and allows to jump and control the current location.//
+
+{{red{Unspecified and implementation postponed for later, as of 2/2023}}}
+//The »''Patchbay''« at the left of the timeline provides controls to influence the scopes within the fork of tracks, most notably levels, mix-mode and routing.// +Structurally, it reflects the nesting of scopes in the ''Fork'' of tracks; each track is represented as a TrackHead widget, with sub-Tracks displayed recursively.+
There is a three-level hierarchy: [[Project|Session]], [[Timeline]], [[Sequence]]. Each project can contain ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, these timelines may not be combined further. You can always just render (or view) one specific timeline. Each of those timelines refers to a Sequence, which is a bunch of [[media objects|MObject]] placed to a [[fork ("tree of tracks")|Fork]]. Of course it is possible to use ~sub-sequences within the top-level sequence within a timeline to organize a movie into several scenes or chapters.
@@ -9366,6 +9376,19 @@ Matters are quite different for the placement of a Track within the tree of trac
* obviously, one wants the __edit function__ used to create such an overlapping placement also to create an [[transition|TransitionsHandling]] between the overlapping objects. Meaning this edit function will automatically create an transition processor object and provide it with a placement such as to attach it to the region of overlap.
//The TrackHead display is always visible to the left of the timeline and provides controls for a Track's scope, including all nested sub track//
+In Lumiera, »Tracks« are arranged as a system of nested scopes, starting top-down from the root-track of the Timeline. For each Track, there is a {{{timeline::TrackBody}}} element in the //content area// of the Timeline display, and a corresponding {{{timeline::TrackHeadWidget}}}, arranged at apropriate level within the [[»Patchbay«|TimelinePatchbay]] area to the left. The //model entity »Track«// corresponds to a TrackPresenter in the timeline display, which in turn manages and synchronises both related display zones in the body and header space.
+
+!Structure of the Track Head display
+While the //content area// is rendered by [[custom drawing onto a canvas widget|GuiTimelineDraw]], the //header display// is built up „conventionally“ -- <br/>based on nested {{{Gtk::Grid}}} widgets (i.e. the {{{TrackHeadWidget}}} inherits from {{{Gtk::Grid}}}).
+* For any track, this grid is comprised of two columns and will initially be populated with three rows:
+**a row holding the Track Header label and menu (actually an [[ElementBoxWidget|GuiElementBoxWidget]])
+**a row corresponding to the //content// of the track itself, to hold the controls to govern this track's scope,<br/>i.e. the track //together with all nested sub-tracks.//
+** a padding row to help synchronising track head and track body display.
+*Additional sub-Tracks are added as additional lines to the grid, while nested sub-Tracks will be handled by nested TrackHead widgets
+*The column to the left side will be increased accordingly to display the nested fork structure in the form of [[nested brackets|TrackStaveBracket]]
+''towards a definition of »Track«''. We don't want to tie ourself to some naive and overly simplistic definition, just because it is convenient. For classical (analogue) media, tracks are physical entities dictated by the nature of the process by which the media works. Especially, Tape machines have read/writing heads, which creates fixed tracks to which to route the signals. This is a practical geometric necessity. For digital media, there is no such necessity. We are bound primarily by the editor's habits of working. @@ -9394,12 +9417,12 @@ Placements are __resolved__ resulting in an ExplicitPlacement. In most cases thi → [[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.
-A special twist arises from the fact that track display has to happen aligned and in sync within the two display panes of the timeline at the same time. This means that each TrackPresenter has to hold and manage //two slave display elements,// each of which is inserted within a disjoint hierarchy of display elements. For one, there is the {{{timeline::TrackHeadWidget}}} which in turn renders a {{{PatchbayWidget}}}, and on the other side there is a {{{TrackBody}}} element, which is not strictly a widget of itself, but inserted into our custom drawing {{{timeline::BodyCanvasWidget}}} to manage the custom drawing of the respective track working area.
+A special twist arises from the fact that track display has to happen aligned and in sync within the two display panes of the timeline at the same time. This means that each TrackPresenter has to hold and manage //two slave display elements,// each of which is inserted within a disjoint hierarchy of display elements. For one, there is the {{{timeline::HeaderPaneWidget}}} which in turn renders a [[Navigation Control|TimelineNavigator]] and below the [[»Patchbay«|TimelinePatchbay]], holding a [[timeline::TrackHeadWidget|TrackHead]] for each track -- while on the other side there is a {{{TrackBody}}} element, which is not strictly a widget of itself, but inserted into our custom drawing {{{timeline::BodyCanvasWidget}}} to manage the custom drawing of the respective track working area.
To deal with this typical problem of recursive programming, we introduce a binding element, the {{{DisplayFrame}}}
* the TrackPresenter holds a {{{DisplayFrame}}} member, which in turn houses the two head and body widgets. So basically the widgets are allocated within the presenter.
@@ -9429,6 +9452,25 @@ The actual presentation of ruler elements is a fusion of parametrisation, track
** 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
//Graphical representation of the nested Track scopes as part of the TrackHead display.//
+The design (and the name) of this graphical display is inspired by musical notation, where it is customary to indicate with a bracket the grouping of stems (or staves) forming an ensemble, while a brace typically groups the staves to be played on a single instrument, e.g. a grand piano or organ.
+
+In the Lumiera Timeline UI, »Tracks« are arranged into a ''Fork'' of nested scopes; the Timeline has a single root Track, which in turn might hold several nested sub-Tracks, and the nesting can be continued recursively. In the [[»Patchbay«|TimelinePatchbay]], settings and properties can be controlled to influence a specific part of the scope hierarchy, and this part is always represented by the TrackHead of the specific track forming this scope. [>img[Nested Track Heads grouped by stave brackets|draw/TrackHeadNesting.png]] In this {{{TrackHeadWidget}}}, there is a cell holding the actual controls, while further grid cells below possibly hold further nested sub-Track heads -- while the left side of this Track head arrangement is used to indicate the grouping of scopes with the aforementioned brackets.
+
+!Design
+The design of the grouping Bracket in the graphical display is based on proportions governed by the ''Golden Ratio'' Φ = ½·(1+√5)
+Relying on those proportions has much tradition, and often leads to a design perceived as natural and unobtrusive.
+
+The Golden Ratio creates a division into a larger part and smaller part, denoted as Φ-major and Φ-minor -- and the defining property of Φ is that these divisions can be extended or subdivided endlessly, always reproducing the same ratio Φ: A distance divided by Golden ratio gan be //extended// by adding the Φ-minor, with the surprising result that the now extended distance and the original distance are again governed by the Golden Ratio, leading to geometric structures intricately interwoven.
+[<img[Stave Bracket construction|draw/StaveBracket.png]]
+
+This way, the size and shape of the Stave Bracket is determined by choosing a single ''base width'', which in this case is the horizontal extension of the double vertical line. This base width is divided by Φ, and the smaller part, the Φ-minor is used as the filled bold vertical bar, while the larger distance, the Φ-major is used to define the spacing to the smaller vertical line. The right side of the bold vertical bar is used as anchor line, with the origin of the coordinate system at the top end, just below the top cap.
+
+The cap is enclosed into a bounding box, which is again defined through the Golden Ratio, by using the //base width// as it's Φ-minor. Consequently, the size of this bounding square is thus Φ². The curved contour of the cap is inscribed into that bounding square, along the main diagonal, and with a tangent at the tip pointing down to the end of the smaller line (and thus at Φ-minor of the bounding square's lower base). To find the centre of this curved arc, a perpendicular is erected in the middle of the main diagonal (since the arc can be assumed to be symmetrical to this line); furthermore the radius of this arc must touch the tangent at the tip of the figure, and thus a perpendicular attached at the tip to the tangent will subtend the symmetry line and yield the centre point. By a similar construction, the inner arc -- which forms the outer side of the cap -- can be constructed along the „upper diagonal“, running down from the tip to the Φ-minor at the left side.
+
+__''Implementation''__: while rather simple in geometrical terms, obtaining the coordinates by trigonometric calculations can be challenging. To simplify this tedious task, the ''Constraint'' system of ''~FreeCAD'' was used to directly define the geometric relations outlined above; the resulting coordinates were then be picked from the ~FreeCAD XML document, and embedded as hard wired constants into the {{{timeline::StaveBracketWidget}}} code. For the purpose of this construction, the base width was defined as 1 Unit -- yet for the actual drawing code, an //uniform scaling factor// is applied, based on the font size available in the CSS style context of the widget. As GTK uses the vector graphics libary ''Cairo'' for drawing, the outline of the shape can be directly translated into path instructions, and the resulting contour will then be filled with a solid colour, as defined by the foreground {{{color}}} attribute of CSS. For the curved arcs, a slight adaptation is necessary, since ~FreeCAD defines circle segments in mathematical orientation ↶, while SVG and libCairo use a clockwise ↻ orientation starting at +X axis.
+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 1206651f9..468f4efd6 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -28077,8 +28077,10 @@- - -+ -+ + + @@ -28507,14 +28509,17 @@ + + + @@ -28532,21 +28537,42 @@ - - + + ++ + + + - - + ++ ++ + + + + + + + Mitte der »Oberdiogonalen«, d.h die Diagonale durch das obere Rechteck mit Höhe Φ-major und voller Breite +
+ ++ + + @@ -28600,8 +28626,8 @@ - + + -@@ -28622,13 +28648,26 @@ - + + @@ -28735,29 +28774,29 @@+ + -+ ++ ++ + + + + + ++ - - + + -+ - - + + -- - - - +- - -+ +- + + - + ++ -+ + -+ @@ -28816,7 +28855,7 @@ + @@ -28895,12 +28934,47 @@ - + + + + -- +- + + ++ + ++ + ++ + + + + ++ ...denn es muß die obere und die untere Kappe gezeichnet werden, und deren Höhe ergibt sich qua Konstruktion aus der Basisbreite +
+ ++ + ++ + + + + ++ ➩ Skala für gesamte Klammer verkleinern +
+ ++ + -+ @@ -29194,8 +29268,10 @@ - + -+ -+ + @@ -29213,20 +29289,37 @@ + @@ -29297,19 +29390,6 @@+ -+ + -+ + -+ ++ + + + + + + ++ Style-Klasse: .fork__bracket +
+ ++ - - - - - - -- Style-Klasse: .fork__bracket -
- -- @@ -70870,8 +70950,8 @@ - +