From bdf3351f5576c0f291b6ed157c4726b2079616ff Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 8 Nov 2019 20:49:37 +0100 Subject: [PATCH] ClipDisplay: basic implementation of ViewHook helper --- src/lib/iter-chain-search.hpp | 2 +- src/lib/iter-tree-explorer.hpp | 6 +- src/lib/util.hpp | 28 ++-- src/stage/model/view-hook.hpp | 78 ++++++---- tests/51-gui-model.tests | 5 + tests/library/iter-tree-explorer-test.cpp | 2 +- tests/stage/model/view-hook-test.cpp | 89 +++++++----- wiki/thinkPad.ichthyo.mm | 167 +++++++++++++++++----- 8 files changed, 267 insertions(+), 110 deletions(-) diff --git a/src/lib/iter-chain-search.hpp b/src/lib/iter-chain-search.hpp index 084a24851..f24d34937 100644 --- a/src/lib/iter-chain-search.hpp +++ b/src/lib/iter-chain-search.hpp @@ -259,7 +259,7 @@ namespace iter { { addStep ([predicate{forward (filterPredicate)}] (Filter& filter) - { // manipulte current filter configuration + { // manipulate current filter configuration filter.setNewFilter (predicate); }); return move(*this); diff --git a/src/lib/iter-tree-explorer.hpp b/src/lib/iter-tree-explorer.hpp index e28be857a..781030e41 100644 --- a/src/lib/iter-tree-explorer.hpp +++ b/src/lib/iter-tree-explorer.hpp @@ -1591,15 +1591,15 @@ namespace lib { * * This function starts a *Builder* expression. It picks up the given source, * which can be something "sequence-like" or "iterable", and will automatically - * wrapped and adapted. + * be wrapped and adapted. * - from a STL container, we retrieve a pair of STL iterators (`begin()`, `end()`) * - a "Lumiera Forward Iterator" is copied or moved into the wrapper and used as - * data source, pulling results on demand until exhaustion + * data source, when pulling results on demand, until exhaustion * - a _State Core_ object is copied or moved into the wrapper and adapted to * be iterated as "Lumiera Forward Iterator". Any object with suitable extension * points and behaviour can be used, as explained [here](\ref lib::IterStateWrapper). * - * The resulting TreeExplorer instance can be directly used as "Lumiera Forward Iterator". + * The resulting TreeExplorer instance can directly be used as "Lumiera Forward Iterator". * However, typically you might want to invoke the builder functions to configure further * processing steps in a processing pipeline... * - to [filter](\ref TreeExplorer::filter) the results with a predicate (functor) diff --git a/src/lib/util.hpp b/src/lib/util.hpp index 493c25caa..f83b70ec1 100644 --- a/src/lib/util.hpp +++ b/src/lib/util.hpp @@ -29,7 +29,7 @@ ** separate headers. ** @warning be sure to understand the ramifications of including _anything_ here... ** @see util-coll.hpp - ** @see uitl-foreach.hpp + ** @see util-foreach.hpp ** @see util-quant.hpp */ @@ -137,20 +137,20 @@ namespace util { inline bool isnil (const CONT* pContainer) { - return !pContainer || pContainer->empty(); + return !pContainer or pContainer->empty(); } template inline bool isnil (CONT* pContainer) { - return !pContainer || pContainer->empty(); + return !pContainer or pContainer->empty(); } inline bool isnil (const char* pCStr) { - return !pCStr || !(*pCStr); + return !pCStr or !(*pCStr); } @@ -235,6 +235,15 @@ namespace util { return end != std::find(begin,end, val); } + /** use (and exhaust) a »Lumiera Forward Iterator« for linear search */ + template + inline bool + linearSearch (IT iter, typename IT::value_type const& val) + { + IT end{}; + return end != std::find (std::move (iter), end, val); + } + /** fetch value from a Map, or return a default if not found */ template inline typename MAP::mapped_type @@ -281,8 +290,8 @@ namespace util { /** remove all elements fulfilling a given predicate * from a (sorted) set. * @return true if anything has been removed. */ - template - bool remove_if (SET& set, PRD test) + template + bool remove_if (SET& set, FUN test) { typedef typename SET::iterator Itor; bool found = false; @@ -291,7 +300,8 @@ namespace util { Itor pos = begin; while (pos!=end) { - if (!test (*pos)) ++pos; + if (not test(*pos)) + ++pos; else { found = true; @@ -378,14 +388,14 @@ namespace util { * - leading and trailing whitespace is ignored * @throws lumiera::error::Invalid for any other text content */ - bool boolVal(string const&); + bool boolVal (string const&); /** check the given text if it can be interpreted as affirmative answer (bool `true`). * @remarks this function just fishes for the known `true` tokens and interprets * all other content as `false`, including empty strings. Never throws. */ - bool isYes(string const&) noexcept; + bool isYes (string const&) noexcept; diff --git a/src/stage/model/view-hook.hpp b/src/stage/model/view-hook.hpp index dc589ad81..46abb5b32 100644 --- a/src/stage/model/view-hook.hpp +++ b/src/stage/model/view-hook.hpp @@ -46,23 +46,29 @@ #ifndef STAGE_MODEL_VIEW_HOOK_H #define STAGE_MODEL_VIEW_HOOK_H -//#include "stage/gtk-base.hpp" -//#include "lib/symbol.hpp" +#include "lib/nocopy.hpp" #include "lib/util.hpp" -//#include -//#include -//#include - - namespace stage { namespace model { -// using lib::Literal; -// using util::isnil; -// using std::forward; - + + template + class ViewHook; + + template + class ViewHookable + { + public: + virtual ~ViewHookable() { } ///< this is an interface + + virtual ViewHook hook (ELM& elm, int xPos, int yPos) =0; + virtual void move (ELM& elm, int xPos, int yPos) =0; + virtual void remove (ELM& elm) noexcept =0; + }; + + /** * Abstracted attachment onto a display canvas or similar central presentation context. @@ -76,30 +82,52 @@ namespace model { * elements into the appropriate display region for this track, without exposing the actual * stage::timeline::BodyCanvasWidget to each and every Clip or Label widget. * - * @todo WIP-WIP as of 4/2019 - * @todo the number of pinned elements should be a member field, instead of sneaking it into the prelude element... + * @remark since ViewHook represents one distinct attachment to some view or canvas, + * is has a clear-cut identity and thus may be moved, but not copied. + * @todo WIP-WIP as of 11/2019 */ template class ViewHook + : util::MoveOnly { - public: + using View = ViewHookable; + + ELM* widget_; + View& view_; + + public: + ViewHook (ELM& elm, View& view) + : widget_{&elm} + , view_{view} + { } + + ViewHook (ViewHook&& existing) + : widget_{nullptr} + , view_{existing.view_} + { + std::swap (widget_, existing.widget_); + } + + ~ViewHook() noexcept + { + if (widget_) + view_.remove (*widget_); + } + ELM& operator* () const { - UNIMPLEMENTED ("mart-ptr like access to the attached Element"); + return *widget_; + } + + void + moveTo (int xPos, int yPos) + { + view_.move (*widget_, xPos,yPos); } }; - /** - */ -//inline void -//TrackProfile::performWith () -//{ -//} - - - -}}// namespace model::timeline +}}// namespace stage::model #endif /*STAGE_MODEL_VIEW_HOOK_H*/ diff --git a/tests/51-gui-model.tests b/tests/51-gui-model.tests index 5af25ff0a..d5dc9b401 100644 --- a/tests/51-gui-model.tests +++ b/tests/51-gui-model.tests @@ -22,6 +22,11 @@ return: 0 END +TEST "managed canvas attachment" ViewHook_test < //#include -#include +#include using util::isSameObject; using util::contains; -using util::isnil; +//using util::isnil; //using std::make_unique; //using std::move; -using std::vector; +//using std::vector; +using std::forward_list; namespace stage{ @@ -50,52 +52,64 @@ namespace test { namespace { // Test fixture... -// template struct DummyWidget -// : public sigc::trackable { int x = rand() % 100; int y = rand() % 100; + int i = rand(); // "identity" friend bool operator== (DummyWidget const& wa, DummyWidget const& wb) { return wa.x == wb.x - and wa.y == wb.y; + and wa.y == wb.y + and wa.i == wb.i; } }; using WidgetViewHook = ViewHook; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1201 : TODO actually implement this generic for ViewHook - template - class ViewHookable - { - public: - virtual ~ViewHookable() { } ///< this is an interface - - virtual ViewHook hook (ELM& elm, int xPos, int yPos) =0; - }; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1201 : TODO actually implement this generic for ViewHook - + + + class FakeCanvas : public ViewHookable { - vector widgets_; + struct Attachment + { + DummyWidget& widget; + int posX, posY; + }; + forward_list widgets_; void addDummy(DummyWidget& widget, int x, int y) { - UNIMPLEMENTED ("add widget at given position"); + widgets_.push_front (Attachment{widget, x,y}); + } + + auto + allWidgets() const + { + return lib::treeExplore(widgets_) + .transform([](Attachment const& entry) + { + return entry.widget; + }); } public: - using const_reference = DummyWidget const&; - using const_iterator = vector::const_iterator; - bool empty() const { return widgets_.empty(); } - const_iterator begin() const { return widgets_.begin(); } - const_iterator end() const { return widgets_.end(); } + bool + empty() const + { + return widgets_.empty(); + } + + bool + testContains (DummyWidget const& someWidget) + { + return util::linearSearch (allWidgets(), someWidget); + } /* === Interface ViewHookable === */ @@ -104,8 +118,19 @@ namespace test { hook (DummyWidget& elm, int xPos, int yPos) override { addDummy(elm, xPos,yPos); - TODO ("actually do something to hook it up..."); - return WidgetViewHook{}; + return WidgetViewHook{elm, *this}; + } + + void + move (DummyWidget& elm, int xPos, int yPos) override + { + UNIMPLEMENTED ("move it"); + } + + void + remove (DummyWidget& elm) noexcept override + { + widgets_.remove_if ([&](Attachment const& a) { return a.widget == elm; }); } }; } @@ -138,13 +163,13 @@ namespace test { FakeCanvas canvas; DummyWidget widget; { - WidgetViewHook hook = canvas.hook(widget, widget.x, widget.y); + WidgetViewHook hook = canvas.hook (widget, widget.x, widget.y); CHECK (isSameObject (*hook, widget)); - CHECK (contains (canvas, widget)); - CHECK (not isnil (canvas)); + CHECK (canvas.testContains (widget)); + CHECK (not canvas.empty()); }// hook goes out of scope... - CHECK (not contains (canvas, widget)); - CHECK (isnil (canvas)); + CHECK (not canvas.testContains (widget)); + CHECK (canvas.empty()); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index dd9280630..9c26595fb 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -18282,8 +18282,7 @@ Das bedeutet: viele Kind-Widgets werden auf diesem Canvas platziert und müssen daher mit ihm interagieren

- - + @@ -18294,9 +18293,9 @@ - - - + + + @@ -18309,8 +18308,7 @@ Allerdings lebt der erzeugte Kind-ViewHook danach eigenständig und es gibt keine weitere Beziehung

- -
+
@@ -18329,8 +18327,7 @@ Erläuterung: man könnte auf die Idee kommen, die vier notwendigen Operationen auf dem Ziel durch Lambdas zu verkapseln. Wenn man dann aber nicht aufpaßt, resultiert das in einer Closure für jedes dieser vier Lamdas, und diese Closure hält zumindest einen Pointer auf das Zielobjekt. Der Vorteil eines solchen Ansatzes wäre natürlich, daß der konkrete Typ von Quelle und Ziel aus der Definition des ViewHook verschwindet (allerdings auch nur, wenn diese Lambdas in std::function-Objekte gewickelt sind)

- - +
@@ -18354,8 +18351,7 @@ - - + @@ -18365,6 +18361,57 @@ + + + + + + + + + + + +

+ "the children of your friends ain't your friends" +

+ + +
+
+ + + + + + +

+ ...sonst müßte man das Einfügen als eine weitere (protected)-Operation auf dem ViewHookable ausdrücken und könnte dann die Erzeugung des ViewHook fest in den ViewHookable ABC implementieren.... +

+ + +
+
+
+ + + + + + + + + + + + + + + + + + +
@@ -20046,8 +20093,7 @@ ermöglicht (abstrahierten) Zugang zum Canvas über einen ViewHook

- - +
@@ -22014,8 +22060,7 @@ Kein Wunder daß die meisten UIs aus Sicht des Programmierers ein Albtraum sind

- - + @@ -22032,8 +22077,7 @@ Abstraktion: ViewHook (->Canvas)

- - + @@ -24621,7 +24665,7 @@ - + @@ -24631,7 +24675,7 @@ - + @@ -39426,7 +39470,8 @@ - + + @@ -39463,7 +39508,7 @@ - + @@ -39611,7 +39656,7 @@ - + @@ -39709,7 +39754,7 @@ - + @@ -39739,7 +39784,7 @@ - + @@ -39776,7 +39821,7 @@ - + @@ -40124,7 +40169,7 @@ - + @@ -40200,7 +40245,7 @@ - + @@ -40311,7 +40356,7 @@ - + @@ -40522,7 +40567,7 @@ - + @@ -40595,7 +40640,7 @@ - + @@ -40845,7 +40890,7 @@ - + @@ -40985,7 +41030,7 @@ - + @@ -41097,7 +41142,7 @@ - + @@ -41170,7 +41215,7 @@ - + @@ -41374,7 +41419,7 @@ - + @@ -41504,7 +41549,7 @@ - + @@ -41827,6 +41872,10 @@ + + + + @@ -41855,6 +41904,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • + kein allgemeines Such-Framework bauen! +
  • +
  • + den Begriff des "Containers" knapp halten: was keine const_reference bietet, ist kein Container +
  • +
+ + +
+ +
+
+
@@ -42020,7 +42110,7 @@ - + @@ -50413,8 +50503,7 @@ !!!!!11!!

- - +