decide upon the actual mechanics of command binding and invocation
This commit is contained in:
parent
42cec6d604
commit
2704ad4512
8 changed files with 188 additions and 46 deletions
|
|
@ -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 <boost/noncopyable.hpp>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
|
||||
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<Rec>(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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Rec>(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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ namespace control {
|
|||
template<typename TYPES>
|
||||
Command& bindArg (Tuple<TYPES> 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&);
|
||||
|
|
|
|||
|
|
@ -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.//</pre>
|
||||
</div>
|
||||
<div title="UI-Element" creator="Ichthyostega" modifier="Ichthyostega" created="201511210307" modified="201511272242" tags="GuiPattern design draft decision" changecount="16">
|
||||
<div title="UI-Element" creator="Ichthyostega" modifier="Ichthyostega" created="201511210307" modified="201511280638" tags="GuiPattern design draft decision" changecount="17">
|
||||
<pre>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.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ViewConnection" modifier="Ichthyostega" created="201105221854" modified="201501091154" tags="def Model SessionLogic" changecount="3">
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@
|
|||
<node CREATED="1448659283641" ID="ID_209203268" MODIFIED="1448659290276" TEXT="letztlich ein String"/>
|
||||
<node CREATED="1448659347728" ID="ID_508578010" MODIFIED="1448659355835" TEXT="Konstante bei der Command-Funktion"/>
|
||||
<node CREATED="1448659334058" ID="ID_683316035" MODIFIED="1448659340357" TEXT="Makro + Namenskonvention"/>
|
||||
<node CREATED="1448683561882" ID="ID_839961131" MODIFIED="1448683880173">
|
||||
<node CREATED="1448683561882" ID="ID_839961131" MODIFIED="1448691299107">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -260,6 +260,7 @@
|
|||
</html>
|
||||
</richcontent>
|
||||
<arrowlink COLOR="#81759f" DESTINATION="ID_1679641405" ENDARROW="Default" ENDINCLINATION="604;-108;" ID="Arrow_ID_1210299906" STARTARROW="None" STARTINCLINATION="702;0;"/>
|
||||
<arrowlink COLOR="#aaa9c1" DESTINATION="ID_1193936433" ENDARROW="Default" ENDINCLINATION="392;0;" ID="Arrow_ID_1338946264" STARTARROW="Default" STARTINCLINATION="392;0;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -279,7 +280,7 @@
|
|||
<node CREATED="1448683674443" ID="ID_1931753413" MODIFIED="1448683684206" TEXT="Einheitlichkeit gefährdet"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1448683454504" HGAP="26" ID="ID_510876193" MODIFIED="1448683468155" TEXT="API generisch">
|
||||
<node CREATED="1448683454504" HGAP="42" ID="ID_510876193" MODIFIED="1448691201766" TEXT="API generisch" VSHIFT="-1">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1448683636672" ID="ID_1485949406" MODIFIED="1448683647815" TEXT="verhindert Wildwuchs"/>
|
||||
<node CREATED="1448683475853" ID="ID_24599710" MODIFIED="1448683492586">
|
||||
|
|
@ -304,6 +305,90 @@
|
|||
<node CREATED="1448683525822" ID="ID_1395068730" MODIFIED="1448683529258" TEXT="Gesten"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1448691191042" HGAP="35" ID="ID_1710578352" MODIFIED="1448691205990" TEXT="Lebenszyklus" VSHIFT="-1">
|
||||
<font NAME="SansSerif" SIZE="13"/>
|
||||
<node CREATED="1448691210544" ID="ID_242337741" MODIFIED="1448691218906" TEXT="Command-Skript: im Code"/>
|
||||
<node CREATED="1448691219614" ID="ID_992447056" MODIFIED="1448691241647" TEXT="Bildungs-Regeln: ebenda">
|
||||
<node CREATED="1448691243259" ID="ID_692910736" MODIFIED="1448691256433" TEXT="Frage: wie injizieren">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1448691264512" ID="ID_1193936433" MODIFIED="1448691288828" TEXT="InvocationTrail erstellen">
|
||||
<linktarget COLOR="#aaa9c1" DESTINATION="ID_1193936433" ENDARROW="Default" ENDINCLINATION="392;0;" ID="Arrow_ID_1338946264" SOURCE="ID_839961131" STARTARROW="Default" STARTINCLINATION="392;0;"/>
|
||||
</node>
|
||||
<node CREATED="1448691315849" ID="ID_1198560195" MODIFIED="1448691320189" TEXT="Bindugs-Regel">
|
||||
<node CREATED="1448691343406" ID="ID_642235825" MODIFIED="1448691350558" TEXT="funktor"/>
|
||||
<node CREATED="1448691324304" ID="ID_1103199702" MODIFIED="1448691338522" TEXT="definiert Bezugs-Quellen"/>
|
||||
<node CREATED="1448691355340" ID="ID_724965495" MODIFIED="1448691465633" TEXT="liefert Record<GenNode>"/>
|
||||
</node>
|
||||
<node CREATED="1448691865257" ID="ID_1343859473" MODIFIED="1448691874244" TEXT="Command-Binding wird gesendet">
|
||||
<node CREATED="1448691954533" ID="ID_966334383" MODIFIED="1448691960295" TEXT="Performance">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1448691962068" ID="ID_1045203424" MODIFIED="1448691974575" TEXT="nicht "auf Verdacht" senden">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1448692020868" ID="ID_705436290" MODIFIED="1448692192462" TEXT="Begründung: kein Kopieren der Argumente">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
die Alternative wäre, den Record mit allen Argumenten in den InvocationTrail zu packen.
|
||||
</p>
|
||||
<p>
|
||||
Dann würden wir diesen aber weiter versenden, um Aktivierungen zuzustellen.
|
||||
</p>
|
||||
<p>
|
||||
Das würde bedeuten, die Argumente x-fach zu kopieren (oder mich zu einem ref-counting-Mechanismus zwingen)
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Daher ist es besser, <i>einmal</i>, wenn die Argumente bekannt werden, diese zum Prototypen zu schicken
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1448691875184" ID="ID_642935499" MODIFIED="1448691904352" TEXT="für die Invocation genügt dann die reine ID"/>
|
||||
<node CREATED="1448692196213" ID="ID_727542699" MODIFIED="1448692339433">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Wichtig <font color="#e10409">(offen)</font>: Instanz-Management
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1448692240015" ID="ID_58254695" MODIFIED="1448692245826" TEXT="es geht um Allokationen in Proc"/>
|
||||
<node CREATED="1448692247478" ID="ID_1199512787" MODIFIED="1448692258689" TEXT="jede Instanz == Eintrag in der Command-Registry"/>
|
||||
<node CREATED="1448692287329" ID="ID_1099768193" MODIFIED="1448692317249">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Regel: nur was sich parallel entwickeln kann,
|
||||
</p>
|
||||
<p>
|
||||
muß auch geforkt werden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue