state mark handling within the base element: unit test PASS

...and I made the decision *not* to consider any kind of
generic properties for now. YAGNI.

UI coding is notorious spaghetti code.
No point in fighting that, it is just the way it is,
because somewhere you're bound to get concrete, hands-on.
This commit is contained in:
Fischlurch 2016-02-12 01:31:51 +01:00
parent e4a57e27d2
commit 26d0f50e47
4 changed files with 138 additions and 5 deletions

View file

@ -33,6 +33,7 @@
#include "gui/model/tangible.hpp"
#include "gui/model/widget.hpp"
#include "gui/model/controller.hpp"
#include "lib/diff/gen-node.hpp"
namespace gui {
@ -129,5 +130,38 @@ namespace model {
}
/**
* default implementation and catch-all handler for receiving »state mark« messages.
* Such messages serve either to cause a presentation state effect specific to this
* element, or they are used to re-play a former state change to restore some
* specific UI state captured within a past working session. Events handled here:
* - *expand* with a `bool` argument calls the `doExpand(bool)` virtual function.
* 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.
* 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.
* @note this is a default implementation for a virtual function declared _abstract_
* with the intention for derived classes to tail-call this default handler.
*/
void
Tangible::doMark (GenNode const& stateMark)
{
if (stateMark.idi.getSym() == "expand")
this->doExpand (stateMark.data.get<bool>());
else
if (stateMark.idi.getSym() == "reset")
this->doReset();
else
if (stateMark.idi.getSym() == "revealYourself")
this->doRevealYourself();
}
}} // namespace gui::model

View file

@ -441,7 +441,43 @@ namespace test {
.beforeCall("note").arg(targetID, GenNode{"expand", false})
.before("handling state-mark"));
////////////////////////////////////////////////////////////TODO: WIP
// Second part: replay of a state mark via UI-Bus....
auto stateMark = GenNode{"expand", true};
auto& uiBus = gui::test::Nexus::testUI();
CHECK (not mock.isExpanded());
CHECK (mock.ensureNot("mark"));
uiBus.mark (targetID, stateMark);
CHECK (nexusLog.verifyCall("mark").arg(targetID, stateMark)
.before("delivered mark to "+string(targetID)).arg(stateMark));
CHECK (mock.verifyMark("expand", "true")
.beforeCall("expand").arg(true)
.beforeEvent("expanded"));
CHECK (mock.isExpanded());
CHECK (mock.isTouched());
// the default handler defined in model::Tangible
// already supports some rather generic state changes,
// like e.g. a reset to the element's default state.
// Note that the actual implementation doReset()
// is a virtual function, here implemented in MockElm.
uiBus.mark (targetID, GenNode{"reset", true});
// note: payload is irrelevant for "reset" mark
// and we're back to pristine state...
CHECK (not mock.isTouched());
CHECK (not mock.isExpanded());
CHECK (mock.verifyMark("reset", "true")
.afterEvent("expanded")
.beforeCall("reset")
.beforeEvent("reset"));
cout << "____Event-Log_________________\n"
<< util::join(mock.getLog(), "\n")
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
@ -449,7 +485,6 @@ namespace test {
cout << "____Nexus-Log_________________\n"
<< util::join(nexusLog, "\n")
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
////////////////////////////////////////////////////////////TODO: WIP
}
@ -472,16 +507,16 @@ namespace test {
CHECK (mock.ensureNot("Message"));
// now send a "Flash" mark via UI-Bus....
uiBus.mark(targetID, GenNode{"Flash", true });
uiBus.mark (targetID, GenNode{"Flash", true });
CHECK (mock.verifyMark("Flash"));
CHECK (mock.ensureNot("Error"));
CHECK (mock.ensureNot("Message"));
uiBus.mark(targetID, GenNode{"Error", "getting serious"});
uiBus.mark (targetID, GenNode{"Error", "getting serious"});
CHECK (mock.verifyMark("Error", "serious"));
uiBus.mark(targetID, GenNode{"Message", "by mistake"});
uiBus.mark (targetID, GenNode{"Message", "by mistake"});
CHECK (mock.verifyMark("Message", "mistake"));
CHECK (mock.verify("target")

View file

@ -170,6 +170,9 @@ namespace test{
log_.call (this->identify(), "doMark", mark);
cout << this->identify() << " <-- state-mark = "<< mark <<endl;
log_.note ("type=mark", "ID="+mark.idi.getSym(), mark);
// forward to default handler
Tangible::doMark (mark);
}

View file

@ -211,6 +211,49 @@
<node CREATED="1448659792782" ID="ID_1547056651" MODIFIED="1448659801312" TEXT="r&#xe4;umliche Navigation"/>
<node CREATED="1448659824337" ID="ID_1734858009" MODIFIED="1448659829865" TEXT="Markierungen"/>
</node>
<node CREATED="1455236472002" FOLDED="true" HGAP="49" ID="ID_952544600" MODIFIED="1455236890661" TEXT="generische Eigenschaften" VSHIFT="15">
<icon BUILTIN="button_cancel"/>
<node CREATED="1455236491432" ID="ID_1268644179" MODIFIED="1455236569787" TEXT="Idee">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1455236501719" HGAP="35" ID="ID_540888754" MODIFIED="1455236634083" TEXT="man k&#xf6;nnte Eigenschaften konfigurieren" VSHIFT="2"/>
<node CREATED="1455236512373" ID="ID_211355731" MODIFIED="1455236518680" TEXT="jede Eigenschaft h&#xe4;tte">
<node CREATED="1455236519677" ID="ID_1698754255" MODIFIED="1455236521384" TEXT="Namen"/>
<node CREATED="1455236522020" ID="ID_404018073" MODIFIED="1455236526855" TEXT="slot"/>
<node CREATED="1455236527443" ID="ID_45035009" MODIFIED="1455236537118" TEXT="passende &#xbb;state mark&#xab;"/>
<node CREATED="1455236537802" ID="ID_1419063243" MODIFIED="1455236554532" TEXT="handler-funktor"/>
<node CREATED="1455236554927" ID="ID_772542993" MODIFIED="1455236563746" TEXT="installiert sich in generischen handler"/>
</node>
<node CREATED="1455236573173" HGAP="72" ID="ID_466911779" MODIFIED="1455236591000" TEXT="Bewertung" VSHIFT="16">
<icon BUILTIN="yes"/>
<node CREATED="1455236781242" ID="ID_674694140" MODIFIED="1455236787861" TEXT="k&#xf6;nnte interessant sein f&#xfc;r Diff"/>
<node CREATED="1455236788424" ID="ID_1507269502" MODIFIED="1455236848778" TEXT="aber gegen das Grundkonzept">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
ich wollte explizit kein generisch-introspektives UI,
</p>
<p>
weil das die Tendenz hat, sich zu einem Framework auszuwachsen.
</p>
<p>
F&#252;r die UI-Programmierung mu&#223; man Spaghetticode akzeptieren.
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1455236851592" ID="ID_1599276883" MODIFIED="1455236859119" TEXT="YAGNI">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1455236869405" ID="ID_1141383110" MODIFIED="1455236874756" TEXT="sp&#xe4;ter">
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
</node>
<node CREATED="1448658696638" ID="ID_1235910089" MODIFIED="1448658704649" TEXT="slots">
<node CREATED="1451177440022" ID="ID_1603816152" MODIFIED="1451177686811" TEXT="expand">
@ -280,6 +323,24 @@
</html></richcontent>
</node>
<node CREATED="1451177719577" ID="ID_1175980404" MODIFIED="1451177726636" TEXT="wie finde ich den Vater..."/>
<node CREATED="1455236368345" ID="ID_1490676072" MODIFIED="1455236414978" TEXT="besser">
<icon BUILTIN="yes"/>
<node CREATED="1455236382183" ID="ID_983670310" MODIFIED="1455236392849" TEXT="Einstiegspunkt: revealYourself"/>
<node CREATED="1455236393861" ID="ID_1638665625" MODIFIED="1455236410123">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
support ist <i>optional</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1455236418290" ID="ID_1765760054" MODIFIED="1455236435380" TEXT="dieses ruft parent.reveal(myID)"/>
</node>
</node>
</node>
<node CREATED="1448658726090" FOLDED="true" ID="ID_37610818" MODIFIED="1454978057481" TEXT="Commands">