diff --git a/src/gui/ctrl/bus-controller.cpp b/src/gui/ctrl/bus-controller.cpp index de7e3374f..66b362dde 100644 --- a/src/gui/ctrl/bus-controller.cpp +++ b/src/gui/ctrl/bus-controller.cpp @@ -69,18 +69,19 @@ namespace ctrl { - /** Builder function: establish and wire - * a new BusTerm as connected to this one */ - BusTerm&& - BusTerm::attach (ID newAddress) + /** Builder function: establish and wire a new BusTerm. + * @param newNode the UI-Element corresponding to and using the new BusTerm + * @remarks automatically establishes a down-link connection to the given + * [Tangible]; the UI-Bus will use this node as target to dispatch + * `mark` messages addressed to the new node's ID. It is expected + * that the Tangible in turn will use the returned BusTerm for + * any up-link communication. Thus, on destruction, the new + * BusTerm will detach this UI-Bus connection alltogether. + */ + BusTerm + BusTerm::attach (ID identity, Tangible newNode) { - return std::move( BusTerm(newAddress, *this)); - } - - BusTerm::ID - BusTerm::getID() const - { - return endpointID_; + return BusTerm(identity, theBus_.routeAdd(newNode)); } @@ -88,43 +89,59 @@ namespace ctrl { /* ==== standard implementation of the BusTerm interface ==== */ void - BusTerm::act (GenNode command) + BusTerm::act (GenNode const& command) { UNIMPLEMENTED("issue command"); } - /** */ + /** record state mark from this subject */ void - BusTerm::note (GenNode mark) + BusTerm::note (GenNode const& mark) { - UNIMPLEMENTED("send notification downstream"); + theBus_.note(this->endpointID_, mark); } /** */ void - BusTerm::note (ID subject, GenNode mark) - { - UNIMPLEMENTED("send notification to subject"); - } - - - /** */ - void - BusTerm::mark (GenNode mark) - { - UNIMPLEMENTED("record state mark"); - } - - - /** */ - void - BusTerm::mark (ID subject, GenNode mark) + BusTerm::note (ID subject, GenNode const& mark) { UNIMPLEMENTED("forward state mark from subject"); } + /** */ + void + BusTerm::mark (ID subject, GenNode const& mark) + { + UNIMPLEMENTED("send notification or state mark to subject"); + } + + + /** + * @internal establish new down-link connection form UI-Bus + * @param node reference to the [Tangible] to be connected. + * @return corresponding up-link for the initiating node to use + */ + BusTerm& + BusTerm::routeAdd (Tangible node) + { + return theBus_.routeAdd(node); + } + + + /** + * @internal disable down-link connection + * @remarks corresponding node is about to go away. + */ + void + BusTerm::routeDetach(ID node) noexcept + { + theBus_.routeDetach (node); + } + + + }} // namespace gui::ctrl diff --git a/src/gui/ctrl/bus-term.hpp b/src/gui/ctrl/bus-term.hpp index 4ab45d811..f02b969b7 100644 --- a/src/gui/ctrl/bus-term.hpp +++ b/src/gui/ctrl/bus-term.hpp @@ -62,6 +62,9 @@ namespace gui { +namespace model { + class Tangible; +} namespace ctrl{ // using lib::HashVal; @@ -92,24 +95,26 @@ namespace ctrl{ */ class BusTerm { - using ID = lib::idi::BareEntryID; + using EntryID = lib::idi::BareEntryID; + using ID = EntryID const&; + using Tangible = gui::model::Tangible const&; - ID endpointID_; + EntryID endpointID_; BusTerm& theBus_; public: virtual ~BusTerm(); ///< this is an interface - virtual void act (GenNode command); - virtual void note (GenNode mark); - virtual void mark (GenNode mark); + virtual void act (GenNode const& command); + virtual void note (GenNode const& mark); - virtual void note (ID subject, GenNode mark); - virtual void mark (ID subject, GenNode mark); + virtual void note (ID subject, GenNode const& mark); + virtual void mark (ID subject, GenNode const& mark); - BusTerm&& attach (ID newAddress); + ID getID() const { return endpointID_; } - ID getID() const; + + BusTerm attach (ID, Tangible newNode); /** may be moved, but not copied, * due to the embedded identity */ @@ -120,6 +125,9 @@ namespace ctrl{ : endpointID_(identity) , theBus_(attached_to) { } + + virtual BusTerm& routeAdd(Tangible); + virtual void routeDetach(ID) noexcept; }; diff --git a/src/gui/model/tangible.cpp b/src/gui/model/tangible.cpp index 7cc3feaa0..47dc6832c 100644 --- a/src/gui/model/tangible.cpp +++ b/src/gui/model/tangible.cpp @@ -77,7 +77,7 @@ namespace model { void Tangible::prepareCommand (Cmd const& prototype, Rec&& arguments) { - uiBus_.act (prototype.bind(std::forward(arguments))); + uiBus_.act (prototype.bind (std::forward(arguments))); } diff --git a/src/gui/model/tangible.hpp b/src/gui/model/tangible.hpp index 5134c4de9..e343d2c0a 100644 --- a/src/gui/model/tangible.hpp +++ b/src/gui/model/tangible.hpp @@ -71,18 +71,20 @@ namespace model { using GenNode = lib::diff::GenNode; using Cmd = interact::InvocationTrail; using Rec = lib::diff::Rec; - using ID = lib::idi::BareEntryID; + using ID = lib::idi::BareEntryID const&; ctrl::BusTerm uiBus_; Tangible(ID identity, ctrl::BusTerm& nexus) - : uiBus_(nexus.attach(identity)) + : uiBus_(nexus.attach(identity, *this)) { } public: virtual ~Tangible(); ///< this is an interface + operator ID() const { return uiBus_.getID();} + void reset(); void prepareCommand (Cmd const& prototype, Rec&& arguments); diff --git a/tests/gui/abstract-tangible-test.cpp b/tests/gui/abstract-tangible-test.cpp index 2c8254e43..8ac433ed7 100644 --- a/tests/gui/abstract-tangible-test.cpp +++ b/tests/gui/abstract-tangible-test.cpp @@ -22,7 +22,7 @@ /** @file abstract-tangible-test.cpp - * Verify the common base shared by all interface elements of relevance. + ** Verify the common base shared by all interface elements of relevance. ** This test is not so much a test, than a test of the test support for testing ** [primary elements][gui::model::Tangible] of the Lumiera GTK UI. Any such element ** is connected to the [UI-Bus][gui::UiBus] and responds to some generic actions and diff --git a/tests/gui/test/nexus.cpp b/tests/gui/test/nexus.cpp index e3b6816f3..a5e369cc6 100644 --- a/tests/gui/test/nexus.cpp +++ b/tests/gui/test/nexus.cpp @@ -23,7 +23,8 @@ /** @file test/nexus.cpp ** Implementation of a fake UI backbone for testing. - ** This compilation unit provides the actual setup for running a faked interface from tests. + ** This compilation unit provides the actual setup for running a faked + ** user interface from unit tests. ** ** @todo initial draft and WIP-WIP-WIP as of 11/2015 ** diff --git a/wiki/renderengine.html b/wiki/renderengine.html index ad0e5c0e7..8e09a7fc9 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -8365,11 +8365,28 @@ For now, as of 6/10, we use specialised QueryResolver instances explicitly and d &rarr; QueryRegistration -
+
Abstraction used in the Backbone of Lumiera's GTK User Interface
 The UI-Bus is a ''Mediator'' -- impersonating the role of the //Model// and the //Controler// in the [[MVC-Pattern|http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller]] in common UI architecture.
 
-The ~MVC-Pattern as such is fine, and probably the best we know for construction of user interfaces. But it doesn't scale well towards the integration into a larger and more structured system. There is a tension between the Controller in the UI and other parts of an application, which as well need to be //in control.// And, even more important, there is a tension between the demands of UI elements for support by a model, and the demands to be placed on a core domain model of a large scale application. This tension is resolved by enacting these roles while transforming the requests and demands into //Messages.//
+The ~MVC-Pattern as such is fine, and probably the best we know for construction of user interfaces. But it doesn't scale well towards the integration into a larger and more structured system. There is a tension between the Controller in the UI and other parts of an application, which as well need to be //in control.// And, even more important, there is a tension between the demands of UI elements for support by a model, and the demands to be placed on a core domain model of a large scale application. This tension is resolved by enacting these roles while transforming the requests and demands into //Messages.// + +!!!rationale +This way, we separate between immediate local control of UI state and the more global, generic [[interaction control|InteractionControl]] and [[command binding|GuiCommandBinding]]. +And we arrive at a backbone like structure, which can be wired, programmed and reasoned about while abstracting from the local concerns of UI toolkit set internal state management. Any element of more than local relevance -- be it a controller or be it a widget representing some entity from the model -- will be attached to the UI-Bus by virtue of a ''bus terminal'', establishing a bi-directional connection. This enables any UI element so invoke commands and persist presentation state (by sending //"state mark" mesages//), and in turn this allows the session and engine core to "cast" state updates towards the UI, without precisely knowing where and how to reach the relevant presentation entities. + +!Bus interactions +The UI-Bus has a star shaped topology, with a central "bus master" hub, which maintains a routing table. Attachment and detachment of elements can be managed automatically, since all of the UI-Bus operations perform within the GUI event thread. We distinguish between up-link messages, directed towards some central service (presentation state management or command invocation) and down-link messages, directed towards individual elements. The interactions at the bus are closely interrelated with the elementary UI-Element operations. +;act +:send a GenNode representing the action +:* in a first step, a command prototype is outfitted with actual parameter values +:* the actual command invocation is triggered by a "bang" message +;note +:send a GenNode representing the //state mark// +:some (abstracted) presentation state manager is expected to listen to these messages, possibly recording state to be restored later +;mark +:down-link communication to //feed back// state updates or to replay previously recorded //state marks// +
While our UI widgets are implemented the standard way as proposed by GTKmm, some key elements -- which are especially relevant for the anatomy and mechanics of the interface -- are made to conform to a common interface and behaviour protocol. {{red{WIP 11/15 work out what this protocol is all about}}}. #975
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 4a338ae48..02dfe96a2 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -5,7 +5,7 @@
 
 
 
-
+
 
   
     
@@ -19,7 +19,7 @@
     

- + @@ -453,7 +453,7 @@ - + @@ -470,6 +470,7 @@ + @@ -486,8 +487,8 @@ - - + + @@ -504,9 +505,21 @@ - - - + + + + + + + + + + + + + + +