From f5ea31a533c1ea6f5dd25cdc14e6cd7a2c776642 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 26 Nov 2016 04:18:43 +0100 Subject: [PATCH] consider how diff application might interplay with display changes ...it seemed first that we'd might run into a very fundamental problem; but after some consideration it turns out the interspersed display manager and the decoupling between model/presenter and widget happens to mitigate this problem as well. --- wiki/renderengine.html | 18 +++- wiki/thinkPad.ichthyo.mm | 197 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 200 insertions(+), 15 deletions(-) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index b1fc088f4..b59f490b2 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2827,7 +2827,7 @@ In the most general case, there can be per-track content and nested content at t → important question: how to [[organise the widgets|GuiTimelineWidgetStructure]] -
+
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 means to write one or several custom GTK widgets. Thus the question of layout and screen space division and organisation becomes a crucial design decision. The ~GTK-2 Gui, as implemented currently, did already take some steps along this route, yet this kind of decision should be cast and documented explicitly (be it after the fact).
 
@@ -2853,18 +2853,26 @@ While the special setup for scrolling doesn't really count (since it is necessar
 !!!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 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.
 
-So we get a timeline custom widget, which at top level establishes this two-part layout, provides the global scrollbars and integrates custom widget components for both parts. And this top-level timeline widget owns a layout manager, plus it exposes a common view management interface, to be used both from internal components (e.g. zoom widgets within the UI) and from external actors controlling the timeline display from a global level. Also at this global level, we get to define a layout control interface, which has to be implemented by the recursively structured parts of the timeline display, and which is used by the global layout manager to execute its control over the layout as a whole. {{red{Note (11/2016)}}}: if this layout control interface works push or pull style is a decision to be worked out still in the course of the implementation.
+So we get a timeline custom widget, which at top level establishes this two-part layout, provides the global scrollbars and integrates custom widget components for both parts. And this top-level timeline widget owns a layout manager, plus it exposes a common view management interface, to be used both from internal components (e.g. zoom widgets within the UI) and from external actors controlling the timeline display from a global level. Also at this global level, we get to define a layout control interface, which has to be implemented by the recursively structured parts of the timeline display, and which is used by the global layout manager to execute its control over the layout as a whole. {{red{Note (11/2016)}}}: if this layout control interface works push or pull style is a decision yet to be worked out during the course of the implementation.
 
 
 !dealing with nested structures
 The handling of objects structured into nested scopes is a hallmark of the very specific approach taken by Lumiera when it comes to attaching, arranging and relating media objects. But here in the UI display of the timeline, this approach creates a special architectural challenge: the only sane way to deal with nested structures without exploding complexity is to find some way to exploit the ''recursive self similarity'' inherent in any tree structure. But the problematic consequence of this assessment is the tension, even contradiction it creates to the necessities of GUI programming, which forces us to come up with one single, definitive widget representation of what is going on eventually. The conclusion is that we need to come up with an interface such as to allow building and remoulding of the UI display through incremental steps -- where each of this incremental steps relies solely on relative, context based information. Because this is the only way we can deal with building a tree structure by recursive programming. We must not demand the individual step to know its arrangement within the tree, other than indicating a "current" or a "parent" reference point.
 
 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. But beyond that, the layout can 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.
+# 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.
 
 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. And each of these local representation components holds onto a display context, which in fact links it into two different display widget stacks in the two parts of the actual timeline display. Thus, if a component, especially a track, adds a child, it has to pass this child to its own display context, which in turn has to consult its parts, attach new child widgets to those parts and form a new child display context, which then has to be returned to the newly formed child and stored there for future referral.
+
+!!!interplay with diff mutation
+Applying a diff changes the structure, that is, the structure of the local model, not the structure of the display widgets. Because the latter are a entirely private concern of the UI and their structure is controlled by the model components in conjunction with the display manager. And since diff application effects the contents of the model such as to make the intended structural changes happen (indirectly), we are well advised to tie the display control and the widgets very closely to those local model elements, such as to //adjust the display automatically.//
+* when a new model element is added, it has automatically to inject something into the display
+* when a model element happens to be destructed, the corresponding display element has to be removed.
+* such might be triggered indirectly, by clean-up of leftovers, since the DiffApplicator re-orders and deletes by leaving some data behind
+* the diff also re-orders model elements, which does not have an immediate effect on the display, but needs to be interpreted separately.
+Together this means we get a fix up stage after model changes, where the display is re-adjusted to fit the new situation. This works in concert with the display manager representing only those elements as actual widgets, which get a real chance to become visible. This way we can build on the assumption that the actual number of widgets to be managed any time remains so small as to get away with simple linear list processing. It remains to be seen how far this assumption can be pushed -- the problem is that the GTK container components don't support anything beyond such simple linear list processing; there isn't even a call to remove all child widgets of a container in a single pass.
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index a918aa660..31b9129ca 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -114,8 +114,7 @@ Details im  TiddlyWiki....

- - + @@ -135,6 +134,188 @@ + + + + + + + + + + + + +

+ grundsätzliches +

+

+ Problem +

+ +
+ + + + + + + + +

+ speziell die Umordnungen ergeben sich +

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

+ ...und der Dekorator würde die beobachteten Operationen +

+

+ an diese Notifikations-Schnittstelle senden. +

+

+ Implementiert würde sie vom jeweiligen Widget +

+ + +
+
+ + + + + + +

+ korrekt wäre, die Diff-Verben mitzulesen. +

+

+ Das geht aber nicht, weil wir intern (aktiv) iterieren. +

+

+ Wollten wir das doch, müßten wir das gesamte Diff-Applikator-Design wegwerfen. +

+

+ +

+

+ Da aber eigentlich eine 1:1-Zuordnung zwischen Diff-Verben und Operations-Primitiven besteht, +

+

+ könnte man trotzdem (mit etwas Hängen und Würgen) noch hinkommen. +

+

+ Der Dekorator würde also auf dem TreeMutator sitzen... +

+ + +
+
+ + + + + + +

+ Weil wir die "skip"-Operation für zwei Zwecke verwenden, +

+

+ und man im Skip nicht weiß, ob man das Element überhaupt noch anfassen darf, +

+

+ denn es könnte ja auch ein von "find" zurückgelassener Müll sein. +

+

+ Daher gibt es die matchSrc-Operation. Effektiv wird die aber nur bei einem Delete aufgerufen... +

+ + +
+
+ + + + + + +
    +
  • + man sitzt mit dem Detektor unter dem API +
  • +
  • + dadurch entstehen "ungeschriebene Regeln", wie das API auzurufen ist +
  • +
  • + alternativ könnten wir die Operationen komplett 1:1 definieren, also eine explizite delete-Operation einführen +
  • +
  • + dafür würde dann die matchSrc wegfallen, was praktisch alle sinnvollen Unit-Tests stark beschränkt. +
  • +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ nach der Mutation erfolgt Display-Neubewertung +

+ + +
+ + + + + + + @@ -195,8 +376,7 @@ UI-Bus gilt nur für globale Belange

- - + @@ -216,8 +396,7 @@ es geht nur um Rollen

- - +
@@ -232,8 +411,7 @@ das lokale Element muß nur als View fungieren

- - +
@@ -257,8 +435,7 @@ transformieren

- - +