From 04424fb8df18692766ddd46903326ef6696c5db4 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 31 Aug 2018 19:52:24 +0200 Subject: [PATCH] UiElement: code and document the functor components --- src/gui/model/expander-revealer.hpp | 132 +++++++++++++++++++++++----- wiki/thinkPad.ichthyo.mm | 21 +++-- 2 files changed, 125 insertions(+), 28 deletions(-) diff --git a/src/gui/model/expander-revealer.hpp b/src/gui/model/expander-revealer.hpp index d61fc3857..c2d7b435e 100644 --- a/src/gui/model/expander-revealer.hpp +++ b/src/gui/model/expander-revealer.hpp @@ -23,11 +23,37 @@ /** @file expander-revealer.hpp ** Helper components to implement some standard UI-element actions by installing a functor. + ** The protocol for operating UI elements connected to the [UI-Bus](\ref ui-bus.hpp) includes + ** some generic operations, which need to be concretised for each actual usage situation. + ** Moreover, there are many situations where implementing those actions does not make + ** much sense, and thus they need to be treated as optional. + ** - some widgets or elements can be expanded or collapsed, to show more information + ** or to save screen real estate. Such widgets also expose an _expansion_ state. + ** - sometimes it is necessary to bring a given widget into sight, be it to show + ** the effect of some processing, or be it to indicate an error situation. ** - ** ## Interactions + ** ## Usage in the default implementation + ** + ** The base class of all [tangible UI elements](\ref Tangible) provides a default implementation + ** for these generic interaction mechanism: It offers slots to connect UI signals against, and + ** it understands the _`mark`_ messages "`expand`" and "`revealYourself`". 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 + ** _`note`_ message on the UI-Bus, so to make those state changes persistent. However, in order + ** to supply an concrete implementation, depending on the circumstances, either the widget itself + ** or a parent container holding the element needs to install lambdas into those functor holders, + ** to detail what actually needs to be done. E.g. it is quite common to implement the "expand" + ** functionality by wrapping the widget into a `Gtk::Expander`. Which effectively means that + ** the widget itself is not able to expand itself, since this `Gtk::Expander` container widget + ** lives within the parent widget to hold the element. So this parent needs to install a + ** lambda when establishing the child element, and bind it to the `Gtk::Expander::set_expanded` + ** property, and the corresponding `Gtk::Expander::get_expanded` to retrieve the current + ** _expansion state_. However, to the contrary, some widgets do implement their _expansion state_ + ** all by themselves, e.g. by switching the presentation layout. Those widgets will have to + ** install an appropriate Expander functor within their constructor. ** ** @see [UI-Element protocol](\ref tangible.hpp) - ** @see \ref BusTerm_test + ** @see [usage example](\ref error-log-display.hpp) ** */ @@ -37,54 +63,118 @@ #include "lib/error.hpp" -//#include "lib/idi/entry-id.hpp" -//#include "lib/symbol.hpp" #include -//#include -//#include +#include namespace gui { namespace model { - -// using std::string; -// using lib::Symbol; + + using std::move; /** * Functor component to support the default implementation of expanding/collapsing. + * It is built based on closures (lambdas) to explicate how to detect the expansion + * state of the widget in question and how actively to expand or collapse it. + * A default constructed Expander disables this feature -- which can be detected + * through the #canExpand() function. */ class Expander { - public: - protected: + using ProbeFun = std::function; + using ChangeFun = std::function; - - Expander() - { } + ProbeFun probeState_; + ChangeFun changeState_; public: + Expander() { } + Expander(ProbeFun detectCurrExpansionState, ChangeFun expand_collapse) + : probeState_{move (detectCurrExpansionState)} + , changeState_{move (expand_collapse)} + { + ENSURE (canExpand()); + } - protected: + bool + canExpand() const + { + return bool{probeState_} + and bool{changeState_}; + } + + operator bool() const + { + REQUIRE (canExpand()); + return probeState_(); + } + + bool + operator() (bool shallExpand) + { + REQUIRE (canExpand()); + bool currState = probeState_(); + if (currState != shallExpand) + changeState_(shallExpand); + return currState; + } + + /* === alternate "expressive" API === */ + bool + expand (bool yes =true) + { + return this->operator() (yes); + } + + bool + collapse() + { + return expand (false); + } + + bool + isExpanded() const + { + return bool{*this}; + } }; + /** * Functor component to support the default implementation of revealing an UI-Element. + * It is built based on a closure (lambda) detailing what actually to do in order + * to bring a given UI element into sight. A default constructed Revealer disables + * this feature, which can be detected through the #canReveal() function. */ class Revealer { - public: - protected: + using RevealeItFun = std::function; - - Revealer() - { } + RevealeItFun revealIt_; public: + Revealer() { } + Revealer(RevealeItFun how_to_uncover_the_element) + : revealIt_{move (how_to_uncover_the_element)} + { + ENSURE (canReveal()); + } - protected: + bool + canReveal() const + { + return bool{revealIt_}; + } + + void + operator()() + { + REQUIRE (canReveal()); + revealIt_(); + } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index f3f2a9ee7..92feff65a 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -1779,7 +1779,7 @@ - + @@ -1789,6 +1789,7 @@

der Parent-Container ist für das expand/collapse zuständig

+ @@ -1917,15 +1918,15 @@
- + - - - + + + - - + + @@ -1941,6 +1942,9 @@ + + + @@ -2015,6 +2019,9 @@ + + +