From f995dd51e2bd03110b2ba95b536ae2cc12545a88 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 3 Dec 2016 05:42:34 +0100 Subject: [PATCH] define creation and control structure of TimelineWidget --- src/gui/ctrl/nexus.hpp | 2 + src/gui/model/controller.hpp | 1 + src/gui/timeline/timeline-controller.cpp | 4 +- src/gui/timeline/timeline-controller.hpp | 22 ++- src/gui/timeline/timeline-widget.cpp | 5 +- src/gui/timeline/timeline-widget.hpp | 52 +++++- src/gui/ui-bus.hpp | 8 +- src/lib/ref-array.hpp | 1 + src/proc/asset/timeline.hpp | 14 +- src/proc/mobject/session.hpp | 2 +- tests/gui/abstract-tangible-test.cpp | 8 +- wiki/renderengine.html | 12 +- wiki/thinkPad.ichthyo.mm | 219 ++++++++++++++++++++++- 13 files changed, 314 insertions(+), 36 deletions(-) diff --git a/src/gui/ctrl/nexus.hpp b/src/gui/ctrl/nexus.hpp index 0476e8770..c43b80b16 100644 --- a/src/gui/ctrl/nexus.hpp +++ b/src/gui/ctrl/nexus.hpp @@ -27,6 +27,8 @@ ** through some [bus terminal](bus-term.hpp). Actually, there is one special BustTerm ** implementation, which acts as router and messaging hub. ** + ** @note messages to unknown target elements are silently dropped. + ** ** @todo initial draft and WIP-WIP-WIP as of 11/2015 ** ** @see TODO_abstract-tangible-test.cpp diff --git a/src/gui/model/controller.hpp b/src/gui/model/controller.hpp index cd9393185..8ebdfea29 100644 --- a/src/gui/model/controller.hpp +++ b/src/gui/model/controller.hpp @@ -38,6 +38,7 @@ #include "lib/error.hpp" +#include "gui/model/tangible.hpp" //#include "lib/symbol.hpp" //#include "lib/util.hpp" diff --git a/src/gui/timeline/timeline-controller.cpp b/src/gui/timeline/timeline-controller.cpp index 430db8044..ab6005942 100644 --- a/src/gui/timeline/timeline-controller.cpp +++ b/src/gui/timeline/timeline-controller.cpp @@ -45,6 +45,7 @@ //using util::_Fmt; +using lib::diff::TreeMutator; //using std::shared_ptr; //using std::weak_ptr; //using util::contains; @@ -65,7 +66,8 @@ namespace timeline { - TimelineController::TimelineController () + TimelineController::TimelineController (ID identity, ctrl::BusTerm& nexus) + : Controller{identity, nexus} { } diff --git a/src/gui/timeline/timeline-controller.hpp b/src/gui/timeline/timeline-controller.hpp index 0733c7a6d..449bb90fd 100644 --- a/src/gui/timeline/timeline-controller.hpp +++ b/src/gui/timeline/timeline-controller.hpp @@ -54,6 +54,7 @@ #define GUI_TIMELINE_TIMELINE_CONTROLLER_H #include "gui/gtk-base.hpp" +#include "gui/model/controller.hpp" #include "lib/time/timevalue.hpp" @@ -67,19 +68,23 @@ namespace timeline { /** - * Core timeline display (custom widget). + * Controller to supervise the timeline display. + * As a [tangible element](model::Tangible), it is attached to the UI-Bus. * @todo WIP-WIP-rewrite as of 12/2016 - * @remarks At top level, this widget is split into a header pane (left) - * and a scrollable timeline body (right). The layout of both parts is aligned. + * @remarks a Timeline always has an attached Sequence, which in turn has + * a single mandatory root track. This in turn might hold further child tracks, + * thus forming a fork of nested scopes. */ class TimelineController + : public model::Controller { public: /** - * @param source_state state to be used used as the - * data source (model) for this timeline widget. + * @param identity used to refer to a corresponding timeline element in the Session + * @param nexus some established connection to the UI-Bus, used for registration. */ - TimelineController(); + TimelineController (ID identity, ctrl::BusTerm& nexus); + ~TimelineController(); @@ -91,7 +96,10 @@ namespace timeline { private:/* ===== Events ===== */ private:/* ===== Internals ===== */ - + + /** set up a binding to respond to mutation messages via UiBus */ + virtual void buildMutator (lib::diff::TreeMutator::Handle) override; + }; diff --git a/src/gui/timeline/timeline-widget.cpp b/src/gui/timeline/timeline-widget.cpp index 03f4ae263..2b0b3ac3d 100644 --- a/src/gui/timeline/timeline-widget.cpp +++ b/src/gui/timeline/timeline-widget.cpp @@ -65,9 +65,12 @@ namespace timeline { - TimelineWidget::TimelineWidget () + TimelineWidget::TimelineWidget (TimelineID identity, ctrl::BusTerm& nexus) : Gtk::Paned{Gtk::ORIENTATION_VERTICAL} + , control_{new TimelineController{identity, nexus}} + , layout_{new LayoutManager} { + UNIMPLEMENTED ("build the timeline UI"); } diff --git a/src/gui/timeline/timeline-widget.hpp b/src/gui/timeline/timeline-widget.hpp index d09a88f78..54811b3f0 100644 --- a/src/gui/timeline/timeline-widget.hpp +++ b/src/gui/timeline/timeline-widget.hpp @@ -33,6 +33,20 @@ ** to a single session::Timeline, known by its ID. The widget creates a TimelineController ** right away, which takes initiative to populate the display with that Timeline's contents. ** + ** #Lifecycle + ** The assumption is that any element creation and deletion is triggered through messages over + ** the [UI-Bus](\ref ui-bus.hpp). So there will be a _parent element,_ corresponding to the + ** ["model root"](\ref session::Root), and this parent, in response to some mutation message, + ** will create a TimelineWidget, add it into the appropriate GTK display setup and manage it + ** as child element; the [construction parameters](TimelineWidget::TimelineWidget] ensure + ** it gets connected to the bus as well. Incidentally, this assumption also implies that + ** this parent element has set up a _binding for diff mutation,_ typically by implementing + ** model::Tangible::buildMutator. And further on this means that the parent will also + ** destroy the TimelineWidget, prompted by a message to that end. All deregistration + ** and unwinding happens automatically. Widgets, and also our model::Controller + ** is `sigc::trackable`, which means after destruction any further signals + ** will be silently ignored. + ** ** @todo as of 12/2016 a complete rework of the timeline display is underway ** */ @@ -42,18 +56,28 @@ #define GUI_TIMELINE_TIMELINE_WIDGET_H #include "gui/gtk-base.hpp" -#include "gui/timeline/timeline-controller.hpp" +#include "gui/timeline/timeline-controller.hpp" /////TODO possible to push that into the implementation? +#include "gui/timeline/layout-manager.hpp" +#include "gui/ctrl/bus-term.hpp" #include "lib/time/timevalue.hpp" +#include "lib/diff/diff-mutable.hpp" +#include "lib/idi/entry-id.hpp" //#include //#include +namespace proc { +namespace asset{ + class Timeline; +}} + namespace gui { namespace timeline { + using TimelineID = lib::idi::EntryID; /** * Core timeline display (custom widget). @@ -65,12 +89,30 @@ namespace timeline { class TimelineWidget : public Gtk::Paned { + std::unique_ptr control_; + std::unique_ptr layout_; + public: - /** - * @param source_state state to be used used as the - * data source (model) for this timeline widget. + /** build a new timeline display and attach it to the UI-Bus. + * @param identity used to refer to a corresponding element in the Session + * @param nexus some established connection to the UI-Bus, will be used + * to register the embedded TimelineController as communication + * partner to respond under the given ID. + * @remarks after creation, the widget can just be hooked up and wired like + * any ordinary GTK element; it becomes passive and just responds to + * signals. The active role is played by the controller, which also + * responds to mutation messages; this is the only way to populate + * the timeline display. Likewise, a timeline shall be deleted by + * sending an respective mutation message to its _parent element,_ + * the one that created it, typically also in response to a message. + * Non the less it is possible just to delete a TimelineWidget, since + * it is a Gtk::Widget, and the controller is also `sigc::trackable` + * and additionally, as a gui::model::Tangible, it will deregister + * automatically from the UI-Bus. After that, any further messages + * towards this element will be dropped silently. */ - TimelineWidget (); + TimelineWidget (TimelineID identity, ctrl::BusTerm& nexus); + ~TimelineWidget(); diff --git a/src/gui/ui-bus.hpp b/src/gui/ui-bus.hpp index 89e38edf7..c5b8f605a 100644 --- a/src/gui/ui-bus.hpp +++ b/src/gui/ui-bus.hpp @@ -29,14 +29,14 @@ ** inherit from the gui::model::Tangible base. The top-level gui::UiBus element is ** a front-end and framework component managed by the [GTK-main](\ref GtkLumiera::main). ** - ** @warning as of 12/2015, this is still totally a mess. This \em will remain + ** @warning as of 12/2016, this is still totally a mess. This \em will remain ** the one-and-only master controller of the UI, but I am determined ** to change the architecture and implementation technique altogether. ** For the time being, we keep the controller::Controller in place, as ** written by Joel Holdsworth, while building the new UI-Bus frontend ** to take on this central role eventually. ** - ** \par rationale + ** # Rationale ** The UI-Bus acts as a **mediating backbone**, impersonating the role ** of the _Model_ and the _Controler_ in the [MVC-Pattern]in common UI architecture. ** @@ -54,9 +54,9 @@ ** feedback and reactions to operating some interface controls. Any actual operations and ** actions relevant to the application as a whole, are to be sent as messages into the ** UI-Bus. The interface code can assume some "core services" to be available _somewhere;_ - ** these core services will receive the messages, act on them and _respond asynchronously_. + ** these core services will receive the messages, act on them and _respond asynchronously._ ** - ** \par Bus interactions + ** # Bus interactions ** The UI-Bus has a star shaped topology, with a central "bus master" hub, the ["Nexus"](\ref Nexus), ** which maintains a routing table. Attachment and detachment of elements can be managed automatically, ** since all of the UI-Bus operations _perform within the UI event thread._ diff --git a/src/lib/ref-array.hpp b/src/lib/ref-array.hpp index ddbc06da1..341645678 100644 --- a/src/lib/ref-array.hpp +++ b/src/lib/ref-array.hpp @@ -35,6 +35,7 @@ namespace lib { * Typically the return type is an interface, * and the Implementation wraps some datastructure * holding subclasses. + * @todo ouch -- a collection that isn't iterable... ///////////////////////TICKET #1040 */ template struct RefArray : boost::noncopyable diff --git a/src/proc/asset/timeline.hpp b/src/proc/asset/timeline.hpp index 6f862f147..a9975ac2e 100644 --- a/src/proc/asset/timeline.hpp +++ b/src/proc/asset/timeline.hpp @@ -38,10 +38,15 @@ ** Like every structural asset, the creation of timelines happens automatically ** on referral; Timelines can be queried from the StructFactory, providing additional ** requested capabilities. Commonly clients will retrieve a given timeline by query - ** on the name-ID of the timeline: \c Struct::retrieve(Query("id(theName).")) + ** on the name-ID of the timeline: `Struct::retrieve (Query("id(theName)."))` ** Additionally, the binding to a specific sequence may be established alongside: - ** \c "timeline(theTimelineName),bindSequence(theTimelineName,sequenceID)." + ** `"timeline(theTimelineName), bindSequence(theTimelineName,sequenceID)."` ** + ** @todo around 2010, the concept of Timeline and Session binding was defined, + ** together with a rough preliminary implementation. Up to 2017, there + ** was no opportunity to set this system really into motion; this is + ** not necessarily a bad thing, since meanwhile we understand way + ** better in which way the Session will actually be accessed... ** @see Session ** @see Sequence ** @see StructFactory @@ -84,7 +89,10 @@ namespace asset { /** - * TODO type comment + * @todo this new Timeline API was invented about 2010 + * and remained in half finished state ever since. + * @todo 2016 can confirm that we still want to go that route + * @todo we need some actual interface, beyond just creating timelines! */ class Timeline : public Struct diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp index 979231782..b3c4dd9c7 100644 --- a/src/proc/mobject/session.hpp +++ b/src/proc/mobject/session.hpp @@ -24,7 +24,7 @@ /** @file session.hpp ** @ingroup session ** Primary Interface to the current Session. - ** The session interface can be used to discover session's contents. + ** The session interface can be used to discover session contents. ** Mostly, these objects within the session are MObject subclasses, but they ** are attached into the session by a Placement. Usually, you'd want to use ** the discovered objects to invoke operations on them; in most cases, diff --git a/tests/gui/abstract-tangible-test.cpp b/tests/gui/abstract-tangible-test.cpp index 048e2ec7d..4c0eb4f6b 100644 --- a/tests/gui/abstract-tangible-test.cpp +++ b/tests/gui/abstract-tangible-test.cpp @@ -177,7 +177,7 @@ namespace test { * - error state indication * - structural changes by diff message * - * This test documents a generic interaction protocoll supported by all + * This test documents a generic interaction protocol supported by all * "tangible" elements of the Lumiera GTK UI. This works by connecting any * such element to a messaging backbone, the *UI-Bus*. By sending messages * according to this protocol, typical state changes can be detected and @@ -187,7 +187,7 @@ namespace test { * @note the actions in this test are verified with the help of an EventLog * built into the mock UI element and the mock UI-Bus counterpart. * Additionally, each test case dumps those log contents to STDOUT, - * which hopefully helps to undrstand the interactions in detail. + * which hopefully helps to understand the interactions in detail. * * @see BusTerm_test * @see DiffTreeApplication_test @@ -211,7 +211,7 @@ namespace test { /** @test verify the UI widget unit test support framework. * The generic backbone of the Lumiera UI offers a mock UI element, * with the ability to stand-in for actual elements present in the real GUI. - * This allows us to rig a emulated test user interface to cover interactions + * This allows us to rig an emulated test user interface to cover interactions * involving some communication from or to interface elements. After setting up * a [mock UI-element](\ref MockElm) with a suitable name / ID, we're able to * operate this element programmatically and to send messages and responses @@ -338,7 +338,7 @@ namespace test { MARK_TEST_FUN EventLog nexusLog = gui::test::Nexus::startNewLog(); - // Setup test stage: define an command/action "in Proc" + // Setup test stage: define a command/action "in Proc" CommandDef (DUMMY_CMD_ID) .operation (operate) .captureUndo (capture) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 747a9a5d4..1a9c099c2 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3517,8 +3517,8 @@ For each meta asset instance, initially a //builder// is created for setting up
Lumiera's Proc-Layer is built around //two interconnected models,// mediated by the [[Builder]]. Basically, the →[[Session]] is an external interface to the HighLevelModel, while the →RenderEngine operates the structures of the LowLevelModel.
-
-
Our design of the models (both [[high-level|HighLevelModel]] and [[low-level|LowLevelModel]]) relies partially on dependent objects being kept consitently in sync. Currently (2/2010), __ichthyo__'s assessment is to consider this topic not important and pervasive enough to justify building a dedicated solution, like e.g. a central tracking and registration service. An important point to consider with this assesment is the fact that the session implementation is beeing kept mostly single-threaded. Thus, lacking one central place to handle this issue, care has to be taken to capture and treat all the relevant individual dependencies properly at the implementation level.
+
+
Our design of the models (both [[high-level|HighLevelModel]] and [[low-level|LowLevelModel]]) relies partially on dependent objects being kept consitently in sync. Currently (2/2010), __ichthyo__'s assessment is to consider this topic not important and pervasive enough to justify building a dedicated solution, like e.g. a central tracking and registration service. An important point to consider with this assessment is the fact that the session implementation is deliberately kept single-threaded. While this simplifies reasoning, we also lack one central place to handle this issue, ans so care has to be taken to capture and treat all the relevant individual dependencies properly at the implementation level.
 
 !known interdependencies
 [>img[Fundamental object relations used in the session|uml/fig136453.png]]
@@ -3527,7 +3527,7 @@ For each meta asset instance, initially a //builder// is created for setting up
 * currently as of 2/2010 the exact dependency of the automation calculation during the render process onto the automation definitions within the HighLevelModel remains to be specified.
 
 !!Timelines and Sequences
-While implemented as StructAsset, additionally we need to assure every instance gets linked to the relevant parts of the model and registered with the session. Contrast this with other kinds of assets, which may just remain enlisted, but never actually used.
+While implemented as StructAsset, additionally we need to ensure every instance gets linked to the relevant parts of the model and registered with the session. Contrast this with other kinds of assets, which may just remain enlisted, but never actually used.
 
 ;the Session
 :...is linked 1:1 with timelines and sequences. Registration and deregistration is directly tied to creation and destruction.
@@ -3539,7 +3539,7 @@ While implemented as StructAsset, additionally we need to assure every instance
 : __created__ ⇒ create a dedicated new binding, either useing an existing sequence, or a newly created empty sequence
 : __destroy__ ⇒ remove binding, while the previously bound sequence remains in model.
 ;root-placed Binding
-:while generally a Binding can exist in the model, when attached to root, a Timeline will be created
+:while generally a Binding can just exist somewhere in the model, when attached to root, a Timeline will be created
 : __created__ ⇒ an existing sequence might be given on creation, otherwhise a default configured sequence is created
 : __destroy__ ⇒ implemented by detaching from root (see below) prior to purging from the model.
 : __attached__ to root ⇒ invoke Timeline creation
@@ -8144,14 +8144,14 @@ Currently (1/11), the strategy is implemented according to (1) and (4) above, le
 Implementation of this strategy is still broken: it doesn't work properly when actually the change passing over the zero point happens by propagation from lower digits. Because then -- given the way the mutators are implemented -- the //new value of the wrapping digit hasn't been stored.// It seems the only sensible solution is to change the definition of the functors, so that any value will be changed by side-effect {{red{Question 4/11 -- isn't this done and fixed by now??}}}
 
-
+
Timeline is the top level element within the [[Session (Project)|Session]]. It is visible within a [[timeline view in the GUI|GuiTimelineView]] and represents the effective (resulting) arrangement of media objects, to be rendered for output or viewed in a Monitor (viewer window). A timeline is comprised of:
 * a time axis in abolute time ({{red{WIP 1/10}}}: not clear if this is an entity or just a conceptual definition) 
 * a list of [[global Pipes|GlobalPipe]] representing the possible outputs (master busses)
 * //exactly one// top-level [[Sequence]], which in turn may contain further nested Sequences.
 * when used for Playback, a ViewConnection is necessary, allowing to get or connect to a PlayController
 
-Please note especially that following this design //a timeline doesn't define tracks.// [[Tracks form a Tree|Fork]] and are part of the individual sequences, together with the media objects placed to these tracks. Thus sequences are independent entities which may exist stand-alone within the model, while a timeline is //always bound to hold a sequence.// → see ModelDependencies
+Please note especially that following this design //a timeline doesn't define tracks.// [[Tracks form a Tree|Fork]] and are part of the individual sequences, together with the media objects placed to this //track fork.// Thus sequences are independent entities which may exist stand-alone within the model, while a timeline is //always bound to hold a sequence.// → see ModelDependencies
 [>img[Fundamental object relations used in the session|uml/fig136453.png]]
 
 Within the Project, there may be ''multiple timelines'', to be viewed and rendered independently. But, being the top-level entities, multiple timelines may not be combined further. You can always just render (or view) one specific timeline. A given sequence may be referred directly or indirectly from multiple timelines though. A given timeline is represented within the GUI according to [[distinct principles and conventions|GuiTimelineView]]
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 1063f0be8..e49d469cf 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -176,6 +176,141 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+    
+  
+  
+    

+ braucht feste Speicher-Addresse +

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

+ ..d.h. der Controller muß wieder auf das Widget zugreifen +

+

+ und sei es auch bloß über ein Interface! +

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

+ aber: Binding im Diff-System durchaus möglich +

+ + +
+ + + + + +

+ ...denn: +

+

+ das Diff-System verlangt nicht, daß Kinder in der Collection auch Tangible sind. +

+

+ Es verlangt nur +

+
    +
  • + daß wir wissen, wie wir Kinder machen +
  • +
  • + daß wir für ein gegebenes Kind ein DiffMutable beschaffen können +
  • +
+ + +
+ +
+ + + + +
+
+
@@ -184,7 +319,7 @@ - + @@ -219,6 +354,10 @@ + + + + @@ -325,7 +464,8 @@ - + + @@ -431,10 +571,81 @@ - + + + + + + + + + + + + +

+ eigentlich... +

+

+ würde eine BareEntryID genügen. +

+

+ Aber die strengere Typisierung erscheint mir ein +

+

+ hilfreicher Wink für den User +

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

+ ...abstraktes Interface +

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

+ latürnich +

+

+ ...den muß jeder individuell implementieren, +

+

+ um die Bindung herzustellen +

+ + +
+ +
+
+
@@ -6347,7 +6558,7 @@ - +