Introduce predefined constants for magic IDs in UI communication
...these magical strings are already spreading dangerously throughout the code base
PS: also fixup for c6b8811af0 (broken whitespace in test definition)
This commit is contained in:
parent
08ed6e1ee8
commit
9894542bf9
20 changed files with 258 additions and 98 deletions
|
|
@ -150,7 +150,7 @@ namespace gui {
|
|||
ERROR_LOG_AND_IGNORE (guifacade, "trigger shutdown of the GUI");
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
checkRunningState () noexcept override
|
||||
{
|
||||
return bool(facade);
|
||||
|
|
@ -210,15 +210,6 @@ namespace gui {
|
|||
{
|
||||
return bool(facade);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace gui
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
62
src/common/ui-protocol.cpp
Normal file
62
src/common/ui-protocol.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
UiProtocol - magic keys used for communication with the Lumiera UI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2018, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
/** @file ui-protocol.cpp
|
||||
** Storage for key constants and basic definitions used for interfacing with the GUI.
|
||||
*/
|
||||
|
||||
//#include "gui/gtk-base.hpp" /////////////////////TODO necessary?
|
||||
#include "include/ui-protocol.hpp"
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
const Symbol META_kind{"kind"};
|
||||
|
||||
const Symbol TYPE_Fork{"Fork"};
|
||||
const Symbol TYPE_Clip{"Clip"};
|
||||
const Symbol TYPE_Marker{"Marker"};
|
||||
const Symbol TYPE_Channel{"Channel"};
|
||||
const Symbol TYPE_Effect{"Effect"};
|
||||
|
||||
const Symbol ATTR_name{"name"};
|
||||
const Symbol ATTR_fork{"fork"};
|
||||
|
||||
|
||||
/* ======== UI-Element protocol ======== */
|
||||
|
||||
const Symbol MARK_reset{"reset"};
|
||||
const Symbol MARK_clearErr{"clearErr"};
|
||||
const Symbol MARK_clearMsg{"clearMsg"};
|
||||
const Symbol MARK_expand{"expand"};
|
||||
const Symbol MARK_reveal{"reveal"};
|
||||
const Symbol MARK_Flash{"Flash"};
|
||||
const Symbol MARK_Error{"Error"};
|
||||
const Symbol MARK_Warning{"Warning"};
|
||||
const Symbol MARK_Message{"Message"};
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
}// namespace gui
|
||||
|
|
@ -147,7 +147,7 @@ namespace ctrl {
|
|||
virtual void
|
||||
doMark (GenNode const& stateMark) override
|
||||
{
|
||||
if (stateMark.idi.getSym() == "Warning")
|
||||
if (stateMark.idi.getSym() == MARK_Warning)
|
||||
getWidget().addWarn (stateMark.data.get<string>());
|
||||
else
|
||||
// forward to default handler
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include "gui/ctrl/bus-term.hpp"
|
||||
#include "gui/ctrl/state-manager.hpp"
|
||||
#include "gui/ctrl/state-map-grouping-storage.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -174,14 +175,14 @@ namespace ctrl {
|
|||
void
|
||||
recordState (ID uiElm, StateMark stateMark)
|
||||
{
|
||||
if ("reset" == stateMark.idi.getSym())
|
||||
if (MARK_reset == stateMark.idi.getSym())
|
||||
storage_.clearState (uiElm);
|
||||
else
|
||||
if ("clearErr" == stateMark.idi.getSym())
|
||||
storage_.clearProperty (uiElm, "Error");
|
||||
if (MARK_clearErr == stateMark.idi.getSym())
|
||||
storage_.clearProperty (uiElm, string{MARK_Error});
|
||||
else
|
||||
if ("clearMsg" == stateMark.idi.getSym())
|
||||
storage_.clearProperty (uiElm, "Message");
|
||||
if (MARK_clearMsg == stateMark.idi.getSym())
|
||||
storage_.clearProperty (uiElm, string{MARK_Message});
|
||||
else
|
||||
storage_.record (uiElm, stateMark);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "gui/ctrl/bus-term.hpp"
|
||||
#include "gui/model/tangible.hpp"
|
||||
#include "proc/cmd.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "include/gui-notification-facade.h"
|
||||
#include "lib/scoped-ptrvect.hpp"
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
|
|
@ -225,12 +226,12 @@ namespace dialog {
|
|||
trig_4_.set_tooltip_markup (_("trigger Proc-command, which in turn\n"
|
||||
"sends an <b>state mark</b> message, using\n"
|
||||
"the message action-ID from the combobox"));
|
||||
actionID_.append ("Flash");
|
||||
actionID_.append ("revealYourself");
|
||||
actionID_.append ("clearErr");
|
||||
actionID_.append ("clearMsg");
|
||||
actionID_.append ("expand");
|
||||
actionID_.append ("reset");
|
||||
actionID_.append (cuString{MARK_Flash});
|
||||
actionID_.append (cuString{MARK_reveal});
|
||||
actionID_.append (cuString{MARK_clearErr});
|
||||
actionID_.append (cuString{MARK_clearMsg});
|
||||
actionID_.append (cuString{MARK_expand});
|
||||
actionID_.append (cuString{MARK_reset});
|
||||
actionID_.set_active(1);
|
||||
actionID_.set_tooltip_markup("select the specific action-ID\n"
|
||||
"when sending a <b>mark</b> message.\n"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
**
|
||||
** The base class of all [tangible UI elements](\ref Tangible) provides a default implementation
|
||||
** for these generic interaction mechanisms: It offers slots to connect UI signals against, and
|
||||
** it understands the \em `mark` messages `"expand"` and `"revealYourself"`. These are implemented
|
||||
** it understands the \em `mark` messages `"expand"` and `"reveal"`. These are implemented
|
||||
** by delegating to the \ref Expander and \ref Revealer functors respectively. Moreover, this
|
||||
** default implementation automatically detects a resulting state change and emits an appropriate
|
||||
** \em `note` message on the UI-Bus, so to make those state changes persistent. However, in order
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "gui/model/tangible.hpp"
|
||||
#include "gui/model/widget.hpp"
|
||||
#include "gui/model/controller.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
|
||||
|
||||
|
|
@ -60,7 +61,7 @@ namespace model {
|
|||
Tangible::reset()
|
||||
{
|
||||
if (this->doReset())
|
||||
uiBus_.note (GenNode{"reset", true});
|
||||
uiBus_.note (GenNode{string{MARK_reset}, true});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -82,7 +83,7 @@ namespace model {
|
|||
Tangible::clearErr()
|
||||
{
|
||||
if (this->doClearErr())
|
||||
uiBus_.note (GenNode{"clearErr", true});
|
||||
uiBus_.note (GenNode{string{MARK_clearErr}, true});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ namespace model {
|
|||
Tangible::clearMsg()
|
||||
{
|
||||
if (this->doClearMsg())
|
||||
uiBus_.note (GenNode{"clearMsg", true});
|
||||
uiBus_.note (GenNode{string{MARK_clearMsg}, true});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -125,7 +126,7 @@ namespace model {
|
|||
Tangible::markMsg (string message)
|
||||
{
|
||||
if (this->doMsg (message))
|
||||
uiBus_.note (GenNode{"Message", message});
|
||||
uiBus_.note (GenNode{string{MARK_Message}, message});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -136,7 +137,7 @@ namespace model {
|
|||
Tangible::markErr (string error)
|
||||
{
|
||||
if (this->doErr (error))
|
||||
uiBus_.note (GenNode("Error", error));
|
||||
uiBus_.note (GenNode{string{MARK_Error}, error});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -156,7 +157,7 @@ namespace model {
|
|||
Tangible::slotExpand()
|
||||
{
|
||||
if (this->doExpand(true))
|
||||
uiBus_.note (GenNode("expand", true));
|
||||
uiBus_.note (GenNode{string{MARK_expand}, true});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -168,7 +169,7 @@ namespace model {
|
|||
Tangible::slotCollapse()
|
||||
{
|
||||
if (this->doExpand(false))
|
||||
uiBus_.note (GenNode("expand", false));
|
||||
uiBus_.note (GenNode{string{MARK_expand}, false});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -192,9 +193,9 @@ namespace model {
|
|||
* Cause the element to be brought into sight.
|
||||
* This is a generic Slot to connect UI signals against;
|
||||
* the same action can also be triggered by sending a **mark**
|
||||
* message over the UI-Bus with the symbol "`revealYourself`".
|
||||
* message over the UI-Bus with the symbol "`reveal`".
|
||||
* @note this is an optional feature and requires the actual widget or controller
|
||||
* either to override the ::doRevealYourself() extension point, or to
|
||||
* either to override the ::doReveal() extension point, or to
|
||||
* [install a suitable closure](\ref installRevealer()). Typically this
|
||||
* is not in itself a persistent state change; however, it might incur
|
||||
* expanding some widgets, which is recorded as persistent UI state.
|
||||
|
|
@ -207,7 +208,7 @@ namespace model {
|
|||
void
|
||||
Tangible::slotReveal()
|
||||
{
|
||||
this->doRevealYourself();
|
||||
this->doReveal();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -217,7 +218,7 @@ namespace model {
|
|||
* explicitly to enable this functionality.
|
||||
*/
|
||||
void
|
||||
Tangible::doRevealYourself()
|
||||
Tangible::doReveal()
|
||||
{
|
||||
if (reveal_.canReveal())
|
||||
reveal_();
|
||||
|
|
@ -245,13 +246,13 @@ namespace model {
|
|||
void
|
||||
Tangible::mark (GenNode const& stateMark)
|
||||
{
|
||||
if (stateMark.idi.getSym() == "Flash")
|
||||
if (stateMark.idi.getSym() == MARK_Flash)
|
||||
this->doFlash();
|
||||
else
|
||||
if (stateMark.idi.getSym() == "Error")
|
||||
if (stateMark.idi.getSym() == MARK_Error)
|
||||
this->markErr (stateMark.data.get<string>());
|
||||
else
|
||||
if (stateMark.idi.getSym() == "Message")
|
||||
if (stateMark.idi.getSym() == MARK_Message)
|
||||
this->markMsg (stateMark.data.get<string>());
|
||||
else
|
||||
this->doMark(stateMark);
|
||||
|
|
@ -267,10 +268,10 @@ namespace model {
|
|||
* It is up to the concrete element to give this a tangible meaning, e.g. a track
|
||||
* might switch to detail view and a clip might reveal attached effects.
|
||||
* - *reset* restores the element to the hard wired default, by invoking `doReset()`
|
||||
* - *revealYourself* prompts the element to take the necessary actions to bring
|
||||
* itself into view. There is no requirement for an element to even implement
|
||||
* this call, but those which do typically know some kind of _"parent object"_
|
||||
* to forward this request, by invoking `doReveal(myID)` on this parent.
|
||||
* - *reveal* prompts the element to take the necessary actions to bring itself
|
||||
* into view. There is no requirement for an element to even implement this call,
|
||||
* but those which do typically know some kind of _"parent object"_ to forward
|
||||
* this request, by invoking `doReveal(myID)` on this parent.
|
||||
* For instance, a clip might ask the enclosing track, which in turn might
|
||||
* call the enclosing timeline display for help, resulting in a scroll action
|
||||
* to bring the clip into sight.
|
||||
|
|
@ -280,23 +281,23 @@ namespace model {
|
|||
void
|
||||
Tangible::doMark (GenNode const& stateMark)
|
||||
{
|
||||
if (stateMark.idi.getSym() == "expand")
|
||||
if (stateMark.idi.getSym() == MARK_expand)
|
||||
{
|
||||
if (this->doExpand (stateMark.data.get<bool>()))
|
||||
uiBus_.note (GenNode("expand", true)); // possibly reentrant (yet harmless)
|
||||
uiBus_.note (GenNode(string{MARK_expand}, true)); // possibly reentrant (yet harmless)
|
||||
}
|
||||
else
|
||||
if (stateMark.idi.getSym() == "reset")
|
||||
if (stateMark.idi.getSym() == MARK_reset)
|
||||
this->reset();
|
||||
else
|
||||
if (stateMark.idi.getSym() == "clearMsg")
|
||||
if (stateMark.idi.getSym() == MARK_clearMsg)
|
||||
this->clearMsg();
|
||||
else
|
||||
if (stateMark.idi.getSym() == "clearErr")
|
||||
if (stateMark.idi.getSym() == MARK_clearErr)
|
||||
this->clearErr();
|
||||
else
|
||||
if (stateMark.idi.getSym() == "revealYourself")
|
||||
this->doRevealYourself();
|
||||
if (stateMark.idi.getSym() == MARK_reveal)
|
||||
this->doReveal();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ namespace model {
|
|||
virtual bool doClearMsg() =0;
|
||||
virtual bool doClearErr() =0;
|
||||
virtual bool doExpand (bool yes);
|
||||
virtual void doRevealYourself();
|
||||
virtual void doReveal ();
|
||||
|
||||
virtual bool doMsg (string) =0;
|
||||
virtual bool doErr (string) =0;
|
||||
|
|
@ -287,9 +287,9 @@ namespace model {
|
|||
/**
|
||||
* Configure the (optional) functionality to bring the UI-Element into sight.
|
||||
* @param how_to_uncover_the_element a lambda or function<void()> to actually cause the necessary actions.
|
||||
* @note unless this setup function is invoked, the "`revealYourself`" functionality remains disabled.
|
||||
* @note unless this setup function is invoked, the "`reveal`" functionality remains disabled.
|
||||
* Typically this setup will be done by an owning parent container, binding to some internals
|
||||
* and also recursively invoking the "`revealYourself`" action on the container.
|
||||
* and also recursively invoking the "`reveal`" action on the container.
|
||||
*/
|
||||
inline void
|
||||
Tangible::installRevealer (Revealer::RevealeItFun how_to_uncover_the_element)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
#include "gui/ctrl/ui-dispatcher.hpp"
|
||||
#include "gui/notification-service.hpp"
|
||||
#include "gui/interact/wizard.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
|
||||
#include "lib/diff/mutation-message.hpp"
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
|
|
@ -113,7 +114,7 @@ namespace gui {
|
|||
markNote (errorLogID, text);
|
||||
break;
|
||||
case NOTE_WARN:
|
||||
mark (errorLogID, GenNode{"Warning", text});
|
||||
mark (errorLogID, GenNode{string{MARK_Warning}, text});
|
||||
break;
|
||||
default:
|
||||
throw lumiera::error::Logic (_Fmt{"UI Notification with invalid severity %d encountered. "
|
||||
|
|
@ -124,14 +125,14 @@ namespace gui {
|
|||
void
|
||||
NotificationService::markError (ID uiElement, string const& text)
|
||||
{
|
||||
dispatchMsg (uiElement, GenNode{"Error", text});
|
||||
dispatchMsg (uiElement, GenNode{string{MARK_Error}, text});
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationService::markNote (ID uiElement, string const& text)
|
||||
{
|
||||
dispatchMsg (uiElement, GenNode{"Message", text});
|
||||
dispatchMsg (uiElement, GenNode{string{MARK_Message}, text});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
|
||||
#include "gui/gtk-base.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "gui/timeline/clip-presenter.hpp"
|
||||
#include "gui/timeline/marker-widget.hpp"
|
||||
|
||||
|
|
@ -94,7 +95,7 @@ namespace timeline {
|
|||
.attach (collection(markers_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Marker"
|
||||
return "Marker" == spec.data.recordType();
|
||||
return TYPE_Marker == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PMarker const& elm) -> bool
|
||||
{
|
||||
|
|
@ -113,7 +114,7 @@ namespace timeline {
|
|||
.attach (collection(effects_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Effect"
|
||||
return "Effect" == spec.data.recordType();
|
||||
return TYPE_Effect == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PEffect const& elm) -> bool
|
||||
{
|
||||
|
|
@ -132,7 +133,7 @@ namespace timeline {
|
|||
.attach (collection(channels_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Channel"
|
||||
return "Channel" == spec.data.recordType();
|
||||
return TYPE_Channel == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PChannel const& elm) -> bool
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
|
||||
#include "gui/gtk-base.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "gui/timeline/marker-widget.hpp"
|
||||
|
||||
//#include "gui/ui-bus.hpp"
|
||||
|
|
@ -82,11 +83,11 @@ namespace timeline {
|
|||
{
|
||||
buffer.create (
|
||||
TreeMutator::build()
|
||||
.change("name", [&](string val)
|
||||
.change(ATTR_name, [&](string val)
|
||||
{
|
||||
name_ = val;
|
||||
})
|
||||
.change("kind", [&](string val)
|
||||
.change(META_kind, [&](string val)
|
||||
{
|
||||
if (val == "LOOP") kind_ = LOOP;
|
||||
else kind_ = MARK;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
|
||||
#include "gui/gtk-base.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "gui/timeline/timeline-controller.hpp"
|
||||
#include "gui/timeline/track-presenter.hpp"
|
||||
#include "gui/timeline/marker-widget.hpp"
|
||||
|
|
@ -155,12 +156,12 @@ namespace timeline {
|
|||
target->buildMutator (buff); // - delegate to child to build nested TreeMutator
|
||||
return true;
|
||||
}))
|
||||
.mutateAttrib("fork", [&](TreeMutator::Handle buff)
|
||||
.mutateAttrib(ATTR_fork, [&](TreeMutator::Handle buff)
|
||||
{ // »Attribute Mutator« : how enter an object field as nested scope
|
||||
REQUIRE (fork_);
|
||||
fork_->buildMutator(buff);
|
||||
})
|
||||
.change("name", [&](string val)
|
||||
.change(ATTR_name, [&](string val)
|
||||
{ // »Attribute Setter« : how assign a new value to some object field
|
||||
name_ = val;
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
|
||||
#include "gui/gtk-base.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "gui/timeline/track-presenter.hpp"
|
||||
#include "gui/timeline/clip-presenter.hpp"
|
||||
#include "gui/timeline/marker-widget.hpp"
|
||||
|
|
@ -104,7 +105,7 @@ namespace timeline {
|
|||
.attach (collection(markers_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Marker"
|
||||
return "Marker" == spec.data.recordType();
|
||||
return TYPE_Marker == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PMarker const& elm) -> bool
|
||||
{
|
||||
|
|
@ -123,7 +124,7 @@ namespace timeline {
|
|||
.attach (collection(clips_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Clip"
|
||||
return "Clip" == spec.data.recordType();
|
||||
return TYPE_Clip == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PClip const& elm) -> bool
|
||||
{
|
||||
|
|
@ -142,7 +143,7 @@ namespace timeline {
|
|||
.attach (collection(subFork_)
|
||||
.isApplicableIf ([&](GenNode const& spec) -> bool
|
||||
{ // »Selector« : require object-like sub scope with type-field "Fork"
|
||||
return "Fork" == spec.data.recordType();
|
||||
return TYPE_Fork == spec.data.recordType();
|
||||
})
|
||||
.matchElement ([&](GenNode const& spec, PFork const& elm) -> bool
|
||||
{
|
||||
|
|
|
|||
93
src/include/ui-protocol.hpp
Normal file
93
src/include/ui-protocol.hpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
UI-PROTOCOL.h - magic keys used for communication with the Lumiera UI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2018, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file ui-protocol.hpp
|
||||
** Hard wired key constants and basic definitions for communication with the GUI.
|
||||
** The Lumiera UI is connected to the application core via message oriented interfaces,
|
||||
** running an asynchronous communication protocol.
|
||||
** - the [UI-Bus](\ref ui-bus.hpp) allows for some specific kinds of messages to be
|
||||
** sent either "upstream" (towards the CoreService) or "downstream" to individual
|
||||
** [UI-Elements](\ref gui::model::Tangible) known by ID.
|
||||
** - these ["tangible interface elements"](\ref tangible.hpp) themselves define a
|
||||
** basic set of actions and "state mark" messages, known as the "element protocol"
|
||||
** - and changes to the structure of tangible elements exposed through the UI are
|
||||
** conducted by pushing up [»diff messages«](\ref mutation-message.hpp) into the
|
||||
** UI via UI-Bus. These messages need to comply to an underlying structural
|
||||
** model of elements to be edited within the session and exposed for GUI
|
||||
** manipulation. This is referred to as "Session Model Scheme"
|
||||
**
|
||||
** These protocols are basically _implementation defined_ conventions and not
|
||||
** rigorously formalised. To a large extent, they are guided by the types and
|
||||
** corresponding API interfaces. However, since the lumiera session allows for
|
||||
** quite flexible structures, these protocols are kept open for local extensions.
|
||||
** At various levels, magic ID-Values are used to initiate specific interactions.
|
||||
** This header supplies the hard wired key constants and IDs thereby employed.
|
||||
**
|
||||
** @see common/ui-protocol.cpp (translation unit backing those constants)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUI_INTERFACE_UI_PROTOCOL_H
|
||||
#define GUI_INTERFACE_UI_PROTOCOL_H
|
||||
|
||||
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
|
||||
namespace Glib {
|
||||
//class ustring; /////////////////////////////TODO needed?
|
||||
}
|
||||
namespace gui {
|
||||
|
||||
//using lib::Literal;
|
||||
using lib::Symbol;
|
||||
//using cuString = const Glib::ustring;
|
||||
|
||||
|
||||
extern const Symbol META_kind;
|
||||
|
||||
extern const Symbol TYPE_Fork;
|
||||
extern const Symbol TYPE_Clip;
|
||||
extern const Symbol TYPE_Marker;
|
||||
extern const Symbol TYPE_Channel;
|
||||
extern const Symbol TYPE_Effect;
|
||||
|
||||
extern const Symbol ATTR_name;
|
||||
extern const Symbol ATTR_fork;
|
||||
|
||||
|
||||
/* ======== UI-Element protocol ======== */
|
||||
|
||||
extern const Symbol MARK_reset;
|
||||
extern const Symbol MARK_clearErr;
|
||||
extern const Symbol MARK_clearMsg;
|
||||
extern const Symbol MARK_expand;
|
||||
extern const Symbol MARK_reveal;
|
||||
extern const Symbol MARK_Flash;
|
||||
extern const Symbol MARK_Error;
|
||||
extern const Symbol MARK_Warning;
|
||||
extern const Symbol MARK_Message;
|
||||
|
||||
|
||||
}// namespace gui
|
||||
#endif /*GUI_INTERFACE_UI_PROTOCOL_H*/
|
||||
|
|
@ -33,7 +33,8 @@
|
|||
** Such an architecture allows for tight cooperation between strictly separated
|
||||
** components, without the need of a fixed, predefined and shared data structure.
|
||||
**
|
||||
** \par Basic Assumptions
|
||||
** # Basic Assumptions
|
||||
**
|
||||
** While the \em linearisation folds knowledge about the underlying data structure
|
||||
** down into the actual diff, we deliberately assume that the data to be diffed is
|
||||
** \em structured data. Moreover, we'll assume implicitly that this data is \em typed,
|
||||
|
|
@ -44,7 +45,8 @@
|
|||
** send the actual content data this way, or to serve as redundancy to verify
|
||||
** proper application of the changes at the diff receiver downstream.
|
||||
**
|
||||
** \par Solution Pattern
|
||||
** # Solution Pattern
|
||||
**
|
||||
** The representation of this linearised diff language relies on a specialised form
|
||||
** of the <b>visitor pattern</b>: We assume the vocabulary of the diff language to be
|
||||
** relatively fixed, while the actual effect when consuming the stream of diff tokens
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "proc/cmd.hpp"
|
||||
#include "proc/control/command-def.hpp"
|
||||
//#include "proc/mobject/session.hpp"
|
||||
#include "include/ui-protocol.hpp" //////////////////////////////////////////////////////////////TICKET #1140 : verify if this include is required
|
||||
#include "include/gui-notification-facade.h"
|
||||
#include "gui/interact/wizard.hpp" //////////////////////////////////////////////////////////////TICKET #1140 : include needed temporarily
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
|
|
@ -54,6 +55,7 @@ using gui::NOTE_INFO;
|
|||
using gui::NOTE_WARN;
|
||||
using gui::NOTE_ERROR;
|
||||
using gui::NotifyLevel;
|
||||
using gui::MARK_expand;
|
||||
using gui::GuiNotification;
|
||||
using lib::diff::GenNode;
|
||||
//using util::cStr;
|
||||
|
|
@ -214,8 +216,8 @@ COMMAND_DEFINITION (test_meta_markAction)
|
|||
{
|
||||
ID errorLogID = gui::interact::Wizard::getErrorLogID();
|
||||
GuiNotification::facade().mark (errorLogID
|
||||
,actionID=="expand"? GenNode{actionID, isYes(message)}
|
||||
: GenNode{actionID, message});
|
||||
,actionID==MARK_expand? GenNode{actionID, isYes(message)}
|
||||
: GenNode{actionID, message});
|
||||
})
|
||||
.captureUndo ([](string actionID, string message) -> string
|
||||
{
|
||||
|
|
|
|||
|
|
@ -705,8 +705,8 @@ TEST "util: sanitised identifier" UtilSanitizedIdentifier_test <<END
|
|||
out-lit: 'Word' --> 'Word'
|
||||
out-lit: 'a Sentence' --> 'a_Sentence'
|
||||
out-lit: 'trailing Withespace
|
||||
out-lit: ' --> 'trailing_Withespace'
|
||||
out-lit: 'with a lot
|
||||
out-lit: ' --> 'trailing_Withespace'
|
||||
out-lit: 'with a lot
|
||||
out-lit: of Whitespace' --> 'with_a_lot_of_Whitespace'
|
||||
out-lit: 'with"much (punctuation)[]!' --> 'withmuch_(punctuation)'
|
||||
out-lit: '§&Ω%€ leading garbage' --> 'leading_garbage'
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
/** @test configure a handler for the (optional) "revealYourself" functionality.
|
||||
/** @test configure a handler for the (optional) "reveal yourself" functionality.
|
||||
* We install a lambda to supply the actual implementation action, which can then
|
||||
* either be triggered by a signal/slot invocation, or by sending a "state mark".
|
||||
*/
|
||||
|
|
@ -494,7 +494,7 @@ namespace test {
|
|||
|
||||
bool revealed = false;
|
||||
mock.installRevealer([&]()
|
||||
{ // NOTE: our mock "implementation" of the revealYourself functionality
|
||||
{ // NOTE: our mock "implementation" of the »reveal yourself« functionality
|
||||
mock.slotExpand(); // explicitly prompts the element to expand itself,
|
||||
revealed = true; // and then via closure sets a flag we can verify.
|
||||
});
|
||||
|
|
@ -504,7 +504,7 @@ namespace test {
|
|||
CHECK (true == revealed);
|
||||
CHECK (mock.isExpanded());
|
||||
CHECK (mock.verifyEvent("create","target")
|
||||
.beforeCall("revealYourself")
|
||||
.beforeCall("reveal")
|
||||
.beforeCall("expand").arg(true)
|
||||
.beforeEvent("expanded"));
|
||||
|
||||
|
|
@ -515,28 +515,28 @@ namespace test {
|
|||
|
||||
// second test: the same can be achieved via UI-Bus message...
|
||||
revealed = false;
|
||||
auto stateMark = GenNode{"revealYourself", 47}; // (payload argument irrelevant)
|
||||
auto stateMark = GenNode{"reveal", 47}; // (payload argument irrelevant)
|
||||
auto& uiBus = gui::test::Nexus::testUI();
|
||||
CHECK (nexusLog.ensureNot("revealYourself"));
|
||||
CHECK (nexusLog.ensureNot("reveal"));
|
||||
|
||||
uiBus.mark (targetID, stateMark); // send the state mark message to reveal the element
|
||||
|
||||
CHECK (true == revealed);
|
||||
CHECK (mock.verifyMark("revealYourself", 47)
|
||||
CHECK (mock.verifyMark("reveal", 47)
|
||||
.afterEvent("expanded")
|
||||
.beforeCall("revealYourself")
|
||||
.beforeCall("reveal")
|
||||
.beforeCall("expand").arg(true));
|
||||
|
||||
CHECK (nexusLog.verifyCall("mark").arg(targetID, stateMark)
|
||||
.after("handling state-mark")
|
||||
.before("revealYourself")
|
||||
.before("reveal")
|
||||
.beforeEvent("delivered mark"));
|
||||
|
||||
// Note the fine point: the target element /was/ already expanded
|
||||
// and thus there is no second "expanded" event, nor is there a
|
||||
// second state mark emitted into the UI-Bus...
|
||||
CHECK (mock.ensureNot("expanded")
|
||||
.afterCall("revealYourself")
|
||||
.afterCall("reveal")
|
||||
.afterEvent("expanded"));
|
||||
CHECK (nexusLog.ensureNot("note")
|
||||
.afterCall("mark").arg(targetID, stateMark)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "lib/sync.hpp"
|
||||
#include "lib/sync-classlock.hpp"
|
||||
#include "backend/thread-wrapper.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "gui/ctrl/bus-term.hpp"
|
||||
#include "gui/ctrl/state-manager.hpp"
|
||||
#include "proc/control/command.hpp"
|
||||
|
|
@ -190,8 +191,8 @@ namespace test {
|
|||
CHECK (nexusLog.verifyCall("note").on("TestNexus").arg(elmID, "GenNode-ID(\"expand\")-DataCap|«bool»|true"));
|
||||
|
||||
// send a state mark down to the mock element
|
||||
gui::test::Nexus::testUI().mark (elmID, GenNode("Flash", 23));
|
||||
CHECK (nexusLog.verifyCall("mark").on("TestNexus").arg(elmID, "Flash")
|
||||
gui::test::Nexus::testUI().mark (elmID, GenNode(string{MARK_Flash}, 23));
|
||||
CHECK (nexusLog.verifyCall("mark").on("TestNexus").arg(elmID, MARK_Flash)
|
||||
.beforeEvent("TestNexus", "mark to bID-zeitgeist"));
|
||||
CHECK (elmLog.verifyCall("doFlash").on("zeitgeist"));
|
||||
|
||||
|
|
@ -202,9 +203,9 @@ namespace test {
|
|||
CHECK (nexusLog.verifyCall("routeDetach").on("TestNexus").arg(elmID)
|
||||
.beforeEvent("TestNexus", "removed route to bID-zeitgeist"));
|
||||
|
||||
gui::test::Nexus::testUI().mark (elmID, GenNode("Flash", 88));
|
||||
gui::test::Nexus::testUI().mark (elmID, GenNode({MARK_Flash}, 88));
|
||||
CHECK (nexusLog.verify("removed route to bID-zeitgeist")
|
||||
.beforeCall("mark").on("TestNexus").arg(elmID, "Flash")
|
||||
.beforeCall("mark").on("TestNexus").arg(elmID, MARK_Flash)
|
||||
.beforeEvent("warn","discarding mark to unknown bID-zeitgeist"));
|
||||
CHECK (elmLog.ensureNot("Flash")
|
||||
.afterEvent("destroy","zeitgeist"));
|
||||
|
|
@ -367,8 +368,8 @@ namespace test {
|
|||
CHECK (not mockB.isTouched());
|
||||
CHECK (not mockC.isTouched());
|
||||
|
||||
uiBus.mark (alpha, GenNode{"Message", "Centauri"});
|
||||
uiBus.mark (bravo, GenNode{"Flash", true});
|
||||
uiBus.mark (alpha, GenNode{"Message", "Centauri"});
|
||||
uiBus.mark (bravo, GenNode{"Flash", true});
|
||||
uiBus.mark (charly, GenNode{"Message", "Delta"});
|
||||
uiBus.mark (charly, GenNode{"Error", "Echo"});
|
||||
|
||||
|
|
@ -497,8 +498,8 @@ namespace test {
|
|||
auto& stateManager = gui::test::Nexus::getMockStateManager();
|
||||
CHECK (stateManager.currentState(alpha, "expand") == GenNode("expand", false ));
|
||||
CHECK (stateManager.currentState(bravo, "expand") == GenNode("expand", true ));
|
||||
CHECK (stateManager.currentState(charly, "expand") == Ref::NO);
|
||||
CHECK (stateManager.currentState(charly, "Error") == GenNode("Error", "Echo")); // sticky error state was recorded
|
||||
CHECK (stateManager.currentState(charly,"expand") == Ref::NO);
|
||||
CHECK (stateManager.currentState(charly, "Error") == GenNode("Error", "Echo")); // sticky error state was recorded
|
||||
|
||||
// reset error state(s)
|
||||
uiBus.markAll (GenNode{"clearErr", true});
|
||||
|
|
@ -509,9 +510,9 @@ namespace test {
|
|||
|
||||
CHECK (stateManager.currentState(alpha, "expand") == GenNode("expand", false ));
|
||||
CHECK (stateManager.currentState(bravo, "expand") == GenNode("expand", true ));
|
||||
CHECK (stateManager.currentState(charly, "expand") == Ref::NO);
|
||||
CHECK (stateManager.currentState(charly, "Error") == Ref::NO); // sticky error state was cleared,
|
||||
// because charly sent a clearErr state mark notification back
|
||||
CHECK (stateManager.currentState(charly,"expand") == Ref::NO);
|
||||
CHECK (stateManager.currentState(charly, "Error") == Ref::NO); // sticky error state was cleared,
|
||||
// because charly sent a clearErr state mark notification back
|
||||
|
||||
// send global sweeping reset
|
||||
uiBus.markAll (GenNode{"reset", true});
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "include/ui-protocol.hpp"
|
||||
#include "lib/test/event-log.hpp"
|
||||
#include "gui/model/tangible.hpp"
|
||||
#include "lib/diff/record.hpp"
|
||||
|
|
@ -126,7 +127,7 @@ namespace test{
|
|||
virtual bool
|
||||
doReset() override
|
||||
{
|
||||
log_.call(this->identify(), "reset");
|
||||
log_.call(this->identify(), string{MARK_reset});
|
||||
if (virgin_)
|
||||
return false; // there was nothing to reset
|
||||
|
||||
|
|
@ -134,22 +135,22 @@ namespace test{
|
|||
message_ = "";
|
||||
expanded_ = false;
|
||||
virgin_ = true;
|
||||
log_.event("reset");
|
||||
log_.event(string{MARK_reset});
|
||||
return true; // we did indeed reset something
|
||||
} // and thus a state mark should be captured
|
||||
|
||||
virtual bool
|
||||
doExpand (bool yes) override
|
||||
{
|
||||
log_.call(this->identify(), "expand", yes);
|
||||
log_.call(this->identify(), string{MARK_expand}, yes);
|
||||
return Tangible::doExpand (yes);
|
||||
}
|
||||
|
||||
virtual void
|
||||
doRevealYourself() override
|
||||
doReveal() override
|
||||
{
|
||||
log_.call(this->identify(), "revealYourself");
|
||||
Tangible::doRevealYourself(); // NOTE: without specific configuration this is NOP
|
||||
log_.call(this->identify(), string{MARK_reveal});
|
||||
Tangible::doReveal(); // NOTE: without specific configuration this is NOP
|
||||
}
|
||||
|
||||
virtual bool
|
||||
|
|
|
|||
Loading…
Reference in a new issue