Timeline: fabricate a (test/dummy) population diff for a more complex track
The population message is just made up, in order to create more interesting structures in the UI and so to further the development of the timeline display. For the actual structure I choose to mirror my example drawing in draw/UI-TimelineLayout-1.png which is also used in the TiddlyWiki, on the #GuiTimelineView tiddler https://lumiera.org/wiki/renderengine.html#GuiTimelineView
This commit is contained in:
parent
3102de9d8a
commit
e3cde9b78d
4 changed files with 93 additions and 16 deletions
|
|
@ -283,26 +283,48 @@ verb `emu(ID)`::
|
|||
made at the generation side.] At this point, this child scope is left
|
||||
and the parent scope with all existing diff state is _popped from an
|
||||
internal stack._
|
||||
verb `set(GenNode)`::
|
||||
assign a new value to the designated element. This is primarily intended
|
||||
for primitive data values and requires the payload type to be assignable,
|
||||
without changing the element's identity. The element is identified by the
|
||||
payload's ID and -- similar as with the `mut()` verb -- needs to be present
|
||||
already, i.e. it has to be mentioned by preceding order defining verbs.
|
||||
|
||||
In practical application, a diff thus is typically comprised of two parts or ``phases'':
|
||||
In a first pass, we have to mention, confirm or supply all the elements, and as second step
|
||||
we may assign new values or enter recursive mutation for some child elements. However, it is
|
||||
possible to deviate from that general scheme, as long as all elements are _confirmed_ prior to
|
||||
mutation. Some typical ``degenerated'' patterns of spelling out a diff are as follows:
|
||||
|
||||
- just a ``population diff'' without any `set` or `mut` verbs
|
||||
- on the other hand, if we just want to mutate something, with the first verb `after(Ref::END)`
|
||||
we accept all of the content as-is, while the next verbs may mutate some selected elements
|
||||
- however, single assignment- or mutation operations can be interspersed into the first phase
|
||||
of sequence confirmation (or re-ordering): because, whenever an element has just been mentioned,
|
||||
it can (in fact without further search) be mutated right away. Thus, e.g. a `pick(ID)` verb can
|
||||
immediately followed by a `set(GenNode)` to assign changed payload data without altering the
|
||||
position or the identity of the element.
|
||||
|
||||
|
||||
representation of objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
While we are talking about _structured data,_ in fact what are about to handle are *objects*, understood in the standard
|
||||
flavour of object orientation, where an object is the instance of a type and offers a contract. Incidentally, this is
|
||||
not the original, ``pure'' meaning of object orientation, but the one that became prolific in brining our daily practice
|
||||
closer to the inherent structuring of modern human organisation. And in dealing with this kind of object, we sometimes
|
||||
get into conflict with the essentially open and permissive nature of structured data. So we need to establish a
|
||||
mapping rule, which translates into additional conventions about how to spell out matters in the diff language.
|
||||
While we are talking about _structured data,_ in fact the entities we are about to handle are *objects*, understood in
|
||||
the standard flavour of object orientation, where an object is the instance of a type and offers a contract. Incidentally,
|
||||
this is not the original, ``pure'' meaning of object orientation, but the one that became prolific to bring our daily
|
||||
practice closer to the inherent structuring of modern human organisation. And in dealing with this kind of object, we
|
||||
sometimes get into conflict with the essentially open and permissive nature of structured data. So we need to establish
|
||||
a mapping rule, which translates into additional conventions about how to spell out matters in the diff language.
|
||||
|
||||
We choose to leave this largely on the level of stylistic rules, thus stressing the language nature of the diff.
|
||||
Even when this bears the danger to produce an exception very late, when it comes to applying the diff to a target
|
||||
data structure. The intention behind this whole diff approach is to transform tight coupling with strict rules
|
||||
into a loose collaboration based on a common understanding. So generally we'll assume the diff is just right,
|
||||
and if not, we'll get what we deserve.footnote:[This gives rise to a tricky discussion about loss of strictness
|
||||
and the costs incurred by that happening. We should not treat this topic in isolation, but rather consider that
|
||||
loose coupling was chosen to avoid far more serious problems caused by tight coupling, and especially the poisoning
|
||||
and dire consequences of a global fixed common data model, when used in a large, not homogeneous system.
|
||||
But when a system indeed is not homogeneous, we better try to make each part open-closed, open for change
|
||||
and the costs incurred by that happening. We should not treat this topic in isolation; we should recall that
|
||||
loose coupling was chosen to avoid far more serious problems caused by tight coupling, and especially the
|
||||
deteriorating and poisoning effect on architecture and the further dire consequences of a global fixed common
|
||||
data model -- which become prdominant when used in a large, not homogeneous system.
|
||||
And _when a system indeed is not homogeneous,_ we better try to make each part open-closed, open for change
|
||||
but closed against extension. This is especially true in the case of the UI.]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ namespace diff{
|
|||
* to the first child element, while \c after(Ref::END) means to accept
|
||||
* all of the existing data contents as-is (presumably to append further
|
||||
* elements beyond that point).
|
||||
* - \c set assign a new value to the element designated element.
|
||||
* - \c set assign a new value to the designated element.
|
||||
* This is primarily intended for primitive data values and requires
|
||||
* the payload type to be assignable, without changing the element's
|
||||
* identity. The element is identified by the payload's ID and needs
|
||||
|
|
|
|||
|
|
@ -253,6 +253,14 @@ namespace diff{
|
|||
* compound is able to consume tree diff messages and apply the respective
|
||||
* changes and mutations to an otherwise opaque implementation data structure.
|
||||
* @remarks in practice, this is the most relevant and typical `TreeMutator` setup.
|
||||
* @tparam PAR base implementation TreeMutator; anything not implemented within
|
||||
* this current "onion layer", is delegated down to the parent. This way,
|
||||
* a complete TreeMutator implementation is assembled from several layers.
|
||||
* @tparam BIN binding adapter to the actual target collection. This implementation
|
||||
* of TreeMutator operations does not directly manipulate the attached
|
||||
* collection, but rather uses the primitive operation building blocks
|
||||
* provided through the binding; typically these building blocks are
|
||||
* in fact lambdas, provided when setting up this binding to the target.
|
||||
*/
|
||||
template<class PAR, class BIN>
|
||||
class ChildCollectionMutator
|
||||
|
|
|
|||
|
|
@ -100,7 +100,17 @@ namespace session {
|
|||
GenNode
|
||||
ruler()
|
||||
{
|
||||
UNIMPLEMENTED("send diff to constitute a new ruler track");
|
||||
return MakeRec()
|
||||
.type (string{stage::TYPE_Ruler})
|
||||
.genNode("Ruler");
|
||||
}
|
||||
|
||||
/** fabricate an attribute node based on the
|
||||
* human-readable part of the given elemen's ID */
|
||||
GenNode
|
||||
makeName (GenNode const& elm)
|
||||
{
|
||||
return GenNode{string{stage::ATTR_name}, elm.idi.getSym() };
|
||||
}
|
||||
} //(End)Implementation details....
|
||||
|
||||
|
|
@ -147,14 +157,51 @@ namespace session {
|
|||
const GenNode timeline = emptyTimeline (baseID, forkRootID);
|
||||
const GenNode rootTrackName = GenNode{string{stage::ATTR_name}, "Fork-Root"};
|
||||
const GenNode forkRoot = MakeRec().genNode(forkRootID);
|
||||
const GenNode track1 = emptyTrack ("Track-1");
|
||||
const GenNode track2 = emptyTrack ("Track-2");
|
||||
const GenNode track21 = emptyTrack ("Track-21");
|
||||
const GenNode track22 = emptyTrack ("Track-22");
|
||||
const GenNode track221 = emptyTrack ("Track-221");
|
||||
const GenNode track222 = emptyTrack ("Track-222");
|
||||
const GenNode timeRuler = ruler();
|
||||
const GenNode scopeRuler0 = ruler();
|
||||
const GenNode scopeRuler2 = ruler();
|
||||
const GenNode scopeRuler22 = ruler();
|
||||
const GenNode scopeRuler221 = ruler();
|
||||
|
||||
return MutationMessage{ ins (timeline)
|
||||
, mut (timeline)
|
||||
, mut (forkRoot)
|
||||
, set (rootTrackName)
|
||||
, ins (emptyTrack ("Track-1"))
|
||||
, ins (emptyTrack ("Track-2"))
|
||||
, ins (ruler())
|
||||
, ins (rootTrackName)
|
||||
, ins (track1)
|
||||
, ins (track2)
|
||||
, ins (timeRuler)
|
||||
, ins (scopeRuler0)
|
||||
, mut (track1)
|
||||
, ins (makeName(track1))
|
||||
, emu (track1)
|
||||
, mut (track2)
|
||||
, ins (makeName(track2))
|
||||
, ins (track21)
|
||||
, ins (track22)
|
||||
, ins (scopeRuler2)
|
||||
, mut (track21)
|
||||
, ins (makeName(track21))
|
||||
, emu (track21)
|
||||
, mut (track22)
|
||||
, ins (makeName(track22))
|
||||
, ins (track221)
|
||||
, ins (track222)
|
||||
, ins (scopeRuler22)
|
||||
, mut (track221)
|
||||
, ins (makeName(track221))
|
||||
, ins (scopeRuler221)
|
||||
, emu (track221)
|
||||
, mut (track222)
|
||||
, ins (makeName(track222))
|
||||
, emu (track222)
|
||||
, emu (track22)
|
||||
, emu (track2)
|
||||
, emu (forkRoot)
|
||||
, emu (timeline)
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue