From 2704ad4512cd6e18c8f11b45ec9200630ea0ca41 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 28 Nov 2015 08:15:32 +0100 Subject: [PATCH] decide upon the actual mechanics of command binding and invocation --- src/gui/interact/invocation-trail.hpp | 82 +++++++++++++----------- src/gui/model/tangible.cpp | 31 +++++++--- src/gui/model/tangible.hpp | 9 +++ src/proc/control/command-closure.hpp | 2 + src/proc/control/command.cpp | 11 ++++ src/proc/control/command.hpp | 5 ++ wiki/renderengine.html | 5 +- wiki/thinkPad.ichthyo.mm | 89 ++++++++++++++++++++++++++- 8 files changed, 188 insertions(+), 46 deletions(-) diff --git a/src/gui/interact/invocation-trail.hpp b/src/gui/interact/invocation-trail.hpp index c193f6868..d6765101a 100644 --- a/src/gui/interact/invocation-trail.hpp +++ b/src/gui/interact/invocation-trail.hpp @@ -22,10 +22,18 @@ /** @file invocation-trail.hpp - ** Abstraction: a tangible element of the User Interface. - ** Any such element is connected to the UIBus... + ** A command in preparation of being issued from the UI. + ** The actual persistent operations on the session model are defined + ** as DSL scripts acting on the session interface, and configured as a + ** _command prototype_. Typically these need to be enriched with at least + ** the actual subject to invoke this command on; many commands require + ** additional parameters, e.g. some time or colour value. These actual + ** invocation parameters need to be picked up from UI elements, and the + ** process of preparing and outfitting a generic command with these + ** actual values is tracked by an [InvocationTrail] handle. When + ** ready, finally this handle can be issued on any [BusTerm]. ** - ** @todo as of 1/2015 this is complete WIP-WIP-WIP + ** @todo as of 11/2015 this is complete WIP-WIP-WIP ** ** @see ////TODO_test usage example ** @@ -36,59 +44,61 @@ #define GUI_INTERACT_INVOCATION_TRAIL_H_ -#include "lib/error.hpp" -#include "gui/ctrl/bus-term.hpp" -#include "lib/idi/entry-id.hpp" -//#include "lib/symbol.hpp" -//#include "lib/util.hpp" +#include "proc/control/command.hpp" +#include "lib/diff/gen-node.hpp" -#include +#include #include namespace gui { namespace interact { - -// using lib::HashVal; -// using util::isnil; + + using lib::diff::GenNode; + using lib::diff::Rec; using std::string; /** - * Interface common to all UI elements of relevance for the Lumiera application. - * Any non-local and tangible interface interaction will at some point pass through - * this foundation element, which forms the joint and attachment to the UI backbone, - * which is the [UI-Bus][ui-bus.hpp]. Any tangible element acquires a distinct identity - * and has to be formed starting from an already existing bus nexus. - * - * @todo write type comment... + * A concrete command invocation in the state of preparation and argument binding. + * This value object is a tracking handle used within the UI to deal with establishing + * a command context, maybe to present the command within a menu or to picking up + * actual invocation parameters from the context. + * @remarks typically you don't create an InvocationTrail from scratch; rather + * you'll find it embedded into rules placed into a [InteractionStateManager]. + * The intention is to define it alongside with the command prototype. */ class InvocationTrail - : boost::noncopyable { - protected: - - Tangible(EntryID identity, ctrl::BusTerm nexus) - : uiBus_(nexus.attach(identity)) - { } + string cmdID_; public: - virtual ~Tangible(); ///< this is an interface + InvocationTrail(proc::control::Command prototype) + : cmdID_(prototype.getID()) + { } - void reset(); + GenNode bind (Rec&& cmdArgs) const + { + return GenNode(cmdID_, std::forward(cmdArgs)); + } - void slotExpand(); - void slotReveal(); + GenNode bang() const + { + return GenNode(cmdID_, FLAGS); + } - void noteMsg(); - void noteErr(); - void noteFlash(); - void noteMark(); + operator string() const + { + return "InvocationTrail cmd(\""+cmdID_+"\""; + } - protected: - virtual void doExpand() =0; - virtual void doReveal() =0; private: + + /** @todo unused as of 11/2015 + * some additional instantiation metadata + * could be passed alongside with the invocation. + */ + static const int FLAGS = 42; }; diff --git a/src/gui/model/tangible.cpp b/src/gui/model/tangible.cpp index f57e8bc9f..b2e5883a7 100644 --- a/src/gui/model/tangible.cpp +++ b/src/gui/model/tangible.cpp @@ -57,16 +57,33 @@ namespace model { + /** + * Prepare a command or action for actual invocation, once the execution context + * has been established. The action is not executed right away, but it is now ready + * and bound to the concrete arguments supplied with the [record][lib::diff::Rec]. + * @param prototype handle to a command instantiation, to be readied for invocation + * @param arguments suitable tuple of values, to be used to outfit the prototype + */ + void + Tangible::prepareCommand (InvocationTrail const& prototype, Rec&& arguments) + { + TODO ("invoke some hook for instrumentation?"); + uiBus_.act (prototype.bind(std::forward(arguments))); + } + /** - * - * @param id - * @return + * Actually trigger execution of an action or command. + * @param preparedAction handle pointing to a command definition, + * which needs to be outfitted with arguments and ready for invocation. */ - string - fun (string& id) + void + Tangible::issueCommand (InvocationTrail const& preparedAction) { - return "x"+id; + TODO ("invoke some hook for instrumentation?"); + uiBus_.act (prototype.bang()); } - + + + }} // namespace gui::model diff --git a/src/gui/model/tangible.hpp b/src/gui/model/tangible.hpp index 04049dcbb..c8439b35a 100644 --- a/src/gui/model/tangible.hpp +++ b/src/gui/model/tangible.hpp @@ -38,6 +38,7 @@ #include "lib/error.hpp" #include "gui/ctrl/bus-term.hpp" +#include "gui/interact/invocation-trail.hpp" #include "lib/idi/entry-id.hpp" //#include "lib/symbol.hpp" //#include "lib/util.hpp" @@ -67,8 +68,13 @@ namespace model { : boost::noncopyable { protected: + using interact::InvocationTrail; + using lib::diff::GenNode; + using lib::diff::Rec; + ctrl::BusTerm uiBus_; + Tangible(EntryID identity, ctrl::BusTerm nexus) : uiBus_(nexus.attach(identity)) { } @@ -78,6 +84,9 @@ namespace model { void reset(); + void prepareCommand (InvocationTrail const& prototype, Rec&& arguments); + void issueCommand (InvocationTrail const& preparedAction); + void slotExpand(); void slotReveal(); diff --git a/src/proc/control/command-closure.hpp b/src/proc/control/command-closure.hpp index 46a808209..11ea1fc68 100644 --- a/src/proc/control/command-closure.hpp +++ b/src/proc/control/command-closure.hpp @@ -178,6 +178,8 @@ namespace control { ////////////////////TODO the real access operations (e.g. for serialising) go here + /////////////////////////////////////////////////////////////TICKET #798 : we need to pick up arguments from a lib::diff::Record. + ostream& dump (ostream& output) const diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index bd4fd5d3f..9b0946eef 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -326,6 +326,17 @@ namespace control { } + Symbol + Command::getID() const + { + Symbol id = CommandRegistry::instance().findDefinition (*this); + if (!id) + throw error::State("Encountered a NIL command handle while expecting a bound one." + ,error::LUMIERA_ERROR_BOTTOM_VALUE); + return id; + } + + /** diagnostics: shows the commandID, if any, diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index ed865ce3a..980608c6d 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -133,6 +133,9 @@ namespace control { template Command& bindArg (Tuple const&); + /////////////////////////////////////////////////////////////TICKET #798 : we need a second overload to take the arguments as lib::diff::Record. + ///////////////////////////////////////////////////////////// : this needs to be built into the ParamAccessor within Closure (command-closure.hpp) + ExecResult operator() () ; ExecResult undo () ; @@ -171,6 +174,8 @@ namespace control { void duplicate_detected (Symbol) const; + Symbol getID() const; + operator string() const; friend bool operator== (Command const&, Command const&); friend bool operator< (Command const&, Command const&); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index e82a643a8..5fee35901 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -8371,7 +8371,7 @@ The UI-Bus is a ''Mediator'' -- impersonating the role of the //Model// and the 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.// -
+
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
 As a starting point, we know
 * there is a backbone structure known as the UI-Bus
@@ -8423,6 +8423,9 @@ We should note that these conventions of interchange lead to a recursive or ''se
 While the above definitions might seem more or less obvious and reasonable, there is one tiny detail, which -- on second thought -- unfolds into a fundamental decision to be taken. The point in question is //how we refer to a command.// More specifically: is referring to a command something generic, or is it rather something left to the actual implementing widget? In the first case, a generic foundation element has to provide some framework to deal with command definitions, whereas in the second case just a protected slot to pass on invocations from derived classes would be sufficient. This is a question of fundamental importance; subsidiarity has its merits, so once we forgo the opportunity to build from a generic pattern, local patterns will take over, while similarities and symmetries have to grow and wait to be discovered sometimes, if at all. This might actually not be a problem -- yet if you know Lumiera, you know that we tend to look at existing practice and draw fundamental conclusions, prior to acting.
 &rarr; InteractionControl
 &rarr; GuiCommandBinding
+
+!!!actual implementation of command invocation
+The {{{InvocationTrail}}} of an command is actually just a tag object, wrapping the command definition ID. In a first step, when the arguments can be closed, a {{{Record}}} with suitable bindings is created and wrapped into a {{{GenNode}}} corresponding to the command. This compound is sent over the UI-Bus, marking the command ready for execution. From this point on, just the {{{InvocationTrail}}} is passed to enable the trigger sites. When it is triggered, just a "bang!" message with the command ID is sent over the bus. An command instance can be re-used, as long as it is structurally the same as before, and as log as there is no possible collision with a similar, but differently parametrised instantiation process.
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 2bc2de68c..9fda46f65 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -247,7 +247,7 @@ - + @@ -260,6 +260,7 @@ + @@ -279,7 +280,7 @@ - + @@ -304,6 +305,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ die Alternative wäre, den Record mit allen Argumenten in den InvocationTrail zu packen. +

+

+ Dann würden wir diesen aber weiter versenden, um Aktivierungen zuzustellen. +

+

+ Das würde bedeuten, die Argumente x-fach zu kopieren (oder mich zu einem ref-counting-Mechanismus zwingen) +

+

+ +

+

+ Daher ist es besser, einmal, wenn die Argumente bekannt werden, diese zum Prototypen zu schicken +

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

+ Wichtig (offen): Instanz-Management +

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

+ Regel: nur was sich parallel entwickeln kann, +

+

+ muß auch geforkt werden +

+ + +
+ +
+
+