From ed76151d14b70bb67f8ff9609dc3629ca73cdab7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 3 Oct 2017 00:57:23 +0200 Subject: [PATCH] UI-Coordinates: value representation finished and unit test PASS (#1106) --- src/gui/interact/ui-coord.hpp | 93 +++++++++++++++++++--------- tests/gui/interact/ui-coord-test.cpp | 59 +++++++++++++----- wiki/thinkPad.ichthyo.mm | 55 ++++++++++------ 3 files changed, 143 insertions(+), 64 deletions(-) diff --git a/src/gui/interact/ui-coord.hpp b/src/gui/interact/ui-coord.hpp index 77871d2ba..1361d09f8 100644 --- a/src/gui/interact/ui-coord.hpp +++ b/src/gui/interact/ui-coord.hpp @@ -60,7 +60,6 @@ #include #include #include -//#include namespace gui { @@ -68,7 +67,6 @@ namespace interact { namespace error = lumiera::error; -// using std::unique_ptr; using std::string; using lib::Literal; using lib::Symbol; @@ -95,28 +93,26 @@ namespace interact { extern Symbol UIC_CURRENT_WINDOW; ///< window spec to refer to the _current window_ @see view-locator.cpp extern Symbol UIC_ELIDED; ///< indicate that a component is elided or irrelevant here - + /** * Describe a location within the UI through structural/topological coordinates. * A UICoord specification is a sequence of Literal tokens, elaborating a path descending * through the hierarchy of UI elements down to the specific UI element to refer. - * - * @todo initial draft as of 9/2017 + * @see UICoord_test */ class UICoord : public lib::PathArray { - using PathAry = lib::PathArray; public: /** * UI-Coordinates can be created explicitly by specifying a sequence of Literal tokens, * which will be used to initialise and then normalise the underlying PathArray. * @warning Literal means _"literal"_ with guaranteed storage during the whole execution. - * @remarks - in case you need to construct some part, then use Symbol to _intern_ the - * resulting string into the global static SymbolTable. + * @remarks - in case you need to construct some part, then use \ref Symbol to _intern_ + * the resulting string into the global static SymbolTable. * - usually the Builder API leads to more readable definitions, * explicitly indicating the meaning of the coordinate's parts. */ @@ -124,8 +120,8 @@ namespace interact { explicit UICoord (ARGS&& ...args) : PathArray(std::forward (args)...) { } - UICoord (UICoord&&) = default; - UICoord (UICoord const&) = default; + UICoord (UICoord&&) = default; + UICoord (UICoord const&) = default; UICoord (UICoord& o) : UICoord((UICoord const&)o) { } UICoord& operator= (UICoord const&) = default; @@ -146,16 +142,14 @@ namespace interact { /** Builder: start definition of UI-Coordinates rooted in given window */ static Builder window (Literal windowID); - // convenience shortcuts to start a copy-builder.... - + //----- convenience shortcuts to start a copy-builder.... Builder persp (Literal perspectiveID) const; Builder view (Literal viewID) const; Builder tab (Literal tabID) const; Builder tab (uint tabIdx) const; Builder noTab () const; - // convenience shortcuts to start mutation on a copy... - + //----- convenience shortcuts to start mutation on a copy... Builder path (Literal pathDefinition) const; Builder append (Literal elmID) const; Builder prepend (Literal elmID) const; @@ -206,6 +200,24 @@ namespace interact { } + bool + isPresent (size_t idx) const + { + Literal* elm = unConst(this)->getPosition(idx); + return not isnil(elm) + and *elm != Symbol::ANY; + } + + + bool + isWildcard (size_t idx) const + { + Literal* elm = unConst(this)->getPosition(idx); + return elm + and *elm == Symbol::ANY; + } + + /** * Check if this coordinate spec can be seen as an extension * of the given parent coordinates and thus reaches further down @@ -231,7 +243,7 @@ namespace interact { and ( (*this)[idx]== parent[idx] or Symbol::ANY == parent[idx] or isnil (parent[idx]))) - ++idx; + ++idx; ENSURE (idx < subSiz); return idx == parSiz; @@ -264,7 +276,7 @@ namespace interact { if (empty()) return ""; size_t end = min (size(), UIC_PATH); - size_t pos = indexOf(*begin()); + size_t pos = indexOf (*begin()); if (pos >= end) return ""; // empty or path information only @@ -275,7 +287,7 @@ namespace interact { if (0 < pos) // incomplete UI-Coordinates (not anchored) buff += "?"; - for ( ; posgetPosition(UIC_PATH)}; + iterator elm = pathSeq(); if (isnil (*elm)) - { // irregular case : only a path fragment + { // irregular case : only a path fragment elm = this->begin(); buff += "?/"; } - for ( ; elm; ++elm) + for ( ; elm; ++elm ) buff += *elm + "/"; // chop off last delimiter @@ -326,6 +338,14 @@ namespace interact { return buff; } + /** iterative access to the path sequence section */ + iterator + pathSeq() const + { + return size()<= UIC_PATH? end() + : iterator{this, unConst(this)->getPosition(UIC_PATH)}; + } + private: /** @note Builder allowed to manipulate stored data */ @@ -382,7 +402,7 @@ namespace interact { while (string::npos != (last = sequence.find ('/', pos))) { elms.emplace_back (Symbol{sequence.substr(pos, last - pos)}); - pos = last + 1; + pos = last + 1; // delimiter stripped } sequence = sequence.substr(pos); if (not isnil (sequence)) @@ -391,7 +411,7 @@ namespace interact { setTailSequence (idx, elms); } - + /** replace the existing path information with the given elements * @note - storage will possibly be expanded to accommodate * - the individual path elements will be _interned_ as Symbol @@ -404,7 +424,7 @@ namespace interact { setTailSequence (size_t idx, std::vector& pathElms) { size_t cnt = pathElms.size(); - expandPosition (idx + cnt); + expandPosition (idx + cnt); // preallocate for (size_t i=0 ; i < cnt; ++i) setContent (expandPosition(idx + i), pathElms[i]); size_t end = size(); @@ -413,12 +433,14 @@ namespace interact { } - public: + public: /* ===== relational operators : equality and partial order ===== */ + friend bool operator== (UICoord const& l, UICoord const& r) { - return static_cast (l) == static_cast (r); + return static_cast (l) == static_cast (r); } + friend bool operator< (UICoord const& l, UICoord const& r) { @@ -433,6 +455,8 @@ namespace interact { + + /* === Builder API === */ class UICoord::Builder @@ -453,12 +477,14 @@ namespace interact { Builder& operator= (Builder &&) = delete; public: - /** @remark moving a builder instance is allowed */ + /** @remark moving a builder instance is acceptable */ Builder (Builder &&) = default; /* == Builder functions == */ + /** change UI coordinate spec to define it to be rooted within the given window + * @note this function allows to _undefine_ the window, thus creating an incomplete spec */ Builder window (Literal windowID) { @@ -555,18 +581,21 @@ namespace interact { UICoord::UICoord (Builder&& builder) : UICoord{std::move (builder.uic_)} { - PathAry::normalise(); + PathArray::normalise(); } - /** Builder: start definition of UI-Coordinates rooted in the `currentWindow` */ + /** @return an empty Builder allowing to define further parts; + * to finish the definition, cast / store it into + * UICoord, which itself is immutable. + */ inline UICoord::Builder UICoord::currentWindow() { return window (UIC_CURRENT_WINDOW); } - /** Builder: start definition of UI-Coordinates rooted in given window */ + /** @return aBuilder with just the windowID defined */ inline UICoord::Builder UICoord::window (Literal windowID) { @@ -574,6 +603,12 @@ namespace interact { } + /** @return a Builder holding a clone copy of the original UICoord, + * with the perspective information set to a new value. + * @remarks This Builder can then be used do set further parts + * independently of the original. When done, store it + * as new UICoord object. To achieve real mutation, + * assign it to the original variable. */ inline UICoord::Builder UICoord::persp (Literal perspectiveID) const { diff --git a/tests/gui/interact/ui-coord-test.cpp b/tests/gui/interact/ui-coord-test.cpp index 12c03b405..2e25b9a25 100644 --- a/tests/gui/interact/ui-coord-test.cpp +++ b/tests/gui/interact/ui-coord-test.cpp @@ -28,19 +28,13 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "gui/interact/ui-coord.hpp" -#include "lib/format-cout.hpp"/////////////////////////TODO RLY? #include "lib/format-util.hpp" -//#include "lib/idi/entry-id.hpp" -//#include "lib/diff/gen-node.hpp" #include "lib/util.hpp" #include using std::string; -//using lib::idi::EntryID; -//using lib::diff::GenNode; -//using util::isSameObject; using lib::Symbol; using util::isnil; using util::join; @@ -51,23 +45,21 @@ namespace gui { namespace interact { namespace test { -// using lumiera::error::LUMIERA_ERROR_WRONG_TYPE; using lumiera::error::LUMIERA_ERROR_INDEX_BOUNDS; using lumiera::error::LUMIERA_ERROR_LOGIC; - namespace { //Test fixture... - - }//(End)Test fixture + /******************************************************************************//** * @test verify the basic properties of topological UI coordinate specifications. - * - created as path-like sequence of components + * - created as path-like sequence of \ref Literal components * - provides a builder API for definition and mutation * - Normalisation and handling of missing parts * - access to UI coordinate components * - string representation * - comparisons + * - predicates * * @see ui-coord.hpp * @see path-array.hpp @@ -98,7 +90,7 @@ namespace test { UICoord uic{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"}; CHECK (not isnil (uic)); CHECK (8 == uic.size()); - // path is iterable + // coordinate sequence is iterable CHECK ("Γ-Δ-Θ-Ξ-Σ-Ψ-Φ-Ω" == join(uic,"-")); // indexed access @@ -111,7 +103,11 @@ namespace test { CHECK ("Φ" == uic[UIC_PATH+1]); // ...descending through local widgets CHECK ("Ω" == uic[UIC_PATH+2]); - // iteration of complete path matches index order + // sequential access to the path part + CHECK ("Ψ-Φ-Ω" == join(uic.pathSeq(),"-")); + CHECK ("Ψ/Φ/Ω" == uic.getPath()); + + // iteration of complete coordinates matches index order uint i=0; for (UICoord::iterator ii = uic.begin(); ii; ++ii, ++i) CHECK (uic[i] == *ii); @@ -182,7 +178,7 @@ namespace test { UICoord uic4 = uic3.persp("perspective"); CHECK (4 == uic4.size()); CHECK ("UI:?[perspective]-*.view" == string(uic4)); - + uic4 = uic3.append("tab"); CHECK (5 == uic4.size()); CHECK ("UI:?.view.tab" == string(uic4)); @@ -228,7 +224,7 @@ namespace test { CHECK ("UI:?/α/β/γ/δ/ε/λ/ον" == string(uic)); CHECK ("" == uic.getComp()); CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath()); - + // note: we built a partially empty path array... CHECK (12 == uic.size()); CHECK (Symbol::EMPTY == uic.getView()); @@ -371,6 +367,7 @@ namespace test { CHECK (UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ",nullptr) == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ")); CHECK (u11 == u1.path("Ψ/Φ/Ω//")); + CHECK (u11 != u1.path("//Ψ/Φ/Ω")); CHECK (u1 > u11); CHECK (u11 < u1 ); @@ -407,6 +404,38 @@ namespace test { CHECK (not nil.isExplicit()); CHECK (not nil.isComplete()); CHECK (not nil.isIncomplete()); // note fine point + + CHECK (not u1.isPresent(UIC_WINDOW)); + CHECK (not u1.isPresent(UIC_PERSP)); + CHECK (not u1.isPresent(UIC_PANEL)); + CHECK ( u1.isPresent(UIC_VIEW)); + CHECK ( u1.isPresent(UIC_TAB)); + CHECK (not u1.isPresent(UIC_PATH)); + CHECK (not u1.isPresent(UIC_PATH+1)); + + CHECK ( u2.isPresent(UIC_WINDOW)); + CHECK (not u2.isPresent(UIC_PERSP)); + CHECK ( u2.isPresent(UIC_PANEL)); + CHECK ( u2.isPresent(UIC_VIEW)); + CHECK ( u2.isPresent(UIC_TAB)); + CHECK (not u2.isPresent(UIC_PATH)); + CHECK (not u2.isPresent(UIC_PATH+1)); + + CHECK ( u3.isPresent(UIC_WINDOW)); + CHECK ( u3.isPresent(UIC_PERSP)); + CHECK ( u3.isPresent(UIC_PANEL)); + CHECK ( u3.isPresent(UIC_VIEW)); + CHECK ( u3.isPresent(UIC_TAB)); + CHECK (not u3.isPresent(UIC_PATH)); + CHECK (not u3.isPresent(UIC_PATH+1)); + + CHECK (not u2.isWildcard(UIC_WINDOW)); + CHECK ( u2.isWildcard(UIC_PERSP)); + CHECK (not u2.isWildcard(UIC_PANEL)); + CHECK (not u2.isWildcard(UIC_VIEW)); + CHECK (not u2.isWildcard(UIC_TAB)); + CHECK (not u2.isWildcard(UIC_PATH)); + CHECK (not u2.isWildcard(UIC_PATH+1)); } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 518ce256b..ddb45c11e 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -3825,8 +3825,8 @@ - - + + @@ -3924,19 +3924,22 @@ - - - - + + + + - - + + - - + + - - + + + + + @@ -3992,32 +3995,44 @@ - + + - + + + + + + + + + - + - + - + - + - + - + + + +