From e33eae729b77c429a2767c9355e76efc25ae8de0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 23 Mar 2020 04:16:10 +0100 Subject: [PATCH] Relative-Hook: complete refactoring down to tracks and clips (see #1213) ...and the result was very much worth the effort, leading to more focused and cleaner code. - all the concerns of moving widgets and translating coordinates are now confined to the second abstraction layer (CanvasHook) - while the ViewHook now deals exclusively with attachment, detachment and reordering of attachment sequence --- src/stage/model/canvas-hook.hpp | 7 ++ src/stage/model/view-hook.hpp | 9 +-- src/stage/timeline/body-canvas-widget.cpp | 11 +++ src/stage/timeline/body-canvas-widget.hpp | 10 ++- src/stage/timeline/clip-presenter.cpp | 4 +- src/stage/timeline/clip-presenter.hpp | 4 +- src/stage/timeline/clip-widget.cpp | 22 ++--- src/stage/timeline/clip-widget.hpp | 8 +- src/stage/timeline/display-manager.hpp | 21 +++-- src/stage/timeline/timeline-layout.cpp | 19 +---- src/stage/timeline/timeline-layout.hpp | 18 ++--- src/stage/timeline/track-body.cpp | 9 +-- src/stage/timeline/track-body.hpp | 8 +- src/stage/timeline/track-head-widget.cpp | 9 +-- src/stage/timeline/track-head-widget.hpp | 8 +- src/stage/timeline/track-presenter.hpp | 12 +-- tests/stage/model/canvas-hook-test.cpp | 87 ++------------------ tests/stage/model/view-hook-test.cpp | 98 +++-------------------- wiki/thinkPad.ichthyo.mm | 73 ++++++++++++----- 19 files changed, 157 insertions(+), 280 deletions(-) diff --git a/src/stage/model/canvas-hook.hpp b/src/stage/model/canvas-hook.hpp index 65923ab71..6a12ebdf5 100644 --- a/src/stage/model/canvas-hook.hpp +++ b/src/stage/model/canvas-hook.hpp @@ -85,6 +85,13 @@ namespace model { virtual void hook (WID& widget, int xPos, int yPos) =0; virtual void move (WID& widget, int xPos, int yPos) =0; + /** Anchor point to build chains of related View Hooks */ + virtual CanvasHook& + getAnchorHook() noexcept + { + return *this; + } + struct Pos { CanvasHook& view; diff --git a/src/stage/model/view-hook.hpp b/src/stage/model/view-hook.hpp index 27726d865..378f16dc8 100644 --- a/src/stage/model/view-hook.hpp +++ b/src/stage/model/view-hook.hpp @@ -92,13 +92,6 @@ namespace model { template void reOrder (IT newOrder); - - /** Anchor point to build chains of related View Hooks */ - virtual ViewHook& - getAnchorHook() noexcept - { - return *this; - } }; @@ -176,7 +169,7 @@ namespace model { void ViewHook::reOrder (IT newOrder) { - for (ViewHooked& existingHook : newOrder) + for (WID& existingHook : newOrder) this->rehook (existingHook); } diff --git a/src/stage/timeline/body-canvas-widget.cpp b/src/stage/timeline/body-canvas-widget.cpp index 09865be6b..e6cef4140 100644 --- a/src/stage/timeline/body-canvas-widget.cpp +++ b/src/stage/timeline/body-canvas-widget.cpp @@ -83,6 +83,11 @@ namespace timeline { using CairoC = PCairoContext const&; using StyleC = PStyleContext const&; + namespace { /////////////////////////////////////////////////////TICKET #1213 : use proper zoom handling instead of dummy constants!! + const int TODO_px_per_second = 25; + const int TODO_px_per_microtick = TODO_px_per_second / Time::SCALE; + } /////////////////////////////////////////////////////TICKET #1213 : (END) get rid of these dummy constants!! + namespace { // details of track background painting const int INITIAL_TIMERULER_HEIGHT_px = 30; @@ -569,6 +574,12 @@ namespace timeline { getCanvas(yPos).move (widget, xPos, yPos); } + int + BodyCanvasWidget::translateTimeToPixels (Time startTimePoint) const + { + return TODO_px_per_microtick * _raw(startTimePoint); //////////TICKET #1213 : delegate zoom handling to the display manager (field #layout_) !! + } + /** respond to the DisplayEvaluation pass. * @remark assuming that each track has already established it own vertical space requirement, * thereby placing the extension values into TrackBody::contentHeight_ diff --git a/src/stage/timeline/body-canvas-widget.hpp b/src/stage/timeline/body-canvas-widget.hpp index a08471c33..a6a5b12d0 100644 --- a/src/stage/timeline/body-canvas-widget.hpp +++ b/src/stage/timeline/body-canvas-widget.hpp @@ -77,7 +77,7 @@ #include "stage/gtk-base.hpp" #include "stage/timeline/track-profile.hpp" #include "stage/timeline/display-evaluation.hpp" -#include "stage/model/view-hook.hpp" +#include "stage/model/canvas-hook.hpp" //#include "lib/util.hpp" @@ -90,6 +90,8 @@ namespace stage { namespace timeline { + using lib::time::Time; + using CairoC = Cairo::RefPtr const&; class DisplayManager; @@ -142,7 +144,7 @@ namespace timeline { */ class BodyCanvasWidget : public Gtk::Box - , public model::ViewHook + , public model::CanvasHook , public LayoutElement { DisplayManager& layout_; @@ -168,13 +170,15 @@ namespace timeline { return contentArea_.get_vadjustment(); } - protected: /* ==== Interface: ViewHook ===== */ + protected: /* ==== Interface: CanvasHook ===== */ void hook (Gtk::Widget&, int xPos=0, int yPos=0) override; void move (Gtk::Widget&, int xPos, int yPos) override; void remove (Gtk::Widget&) override; void rehook (Gtk::Widget&) noexcept override; + int translateTimeToPixels (Time) const override; + protected: /* ==== Interface: LayoutElement ===== */ void establishLayout (DisplayEvaluation&) override; diff --git a/src/stage/timeline/clip-presenter.cpp b/src/stage/timeline/clip-presenter.cpp index 7bd477a91..59a5b344e 100644 --- a/src/stage/timeline/clip-presenter.cpp +++ b/src/stage/timeline/clip-presenter.cpp @@ -70,7 +70,7 @@ namespace timeline { * @param view (abstracted) canvas or display framework to attach this clip to * @param offsetX offset relative to the start of the track ///////////////////////////////TICKET #1213 : translation time->offset should be built into the ViewHook!!! */ - ClipPresenter::ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetViewHook& view, optional offsetX) + ClipPresenter::ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetHook& view, optional offsetX) : Controller{identity, nexus} , channels_{} , effects_{} @@ -172,7 +172,7 @@ namespace timeline { ClipDelegate::switchAppearance (this->widget_, defaultAppearance); } - WidgetViewHook& + WidgetHook& ClipPresenter::getClipContentCanvas() { UNIMPLEMENTED ("how to create and wire an embedded canvas for the clip contents/effects"); diff --git a/src/stage/timeline/clip-presenter.hpp b/src/stage/timeline/clip-presenter.hpp index d376b617a..ca6ca10e9 100644 --- a/src/stage/timeline/clip-presenter.hpp +++ b/src/stage/timeline/clip-presenter.hpp @@ -94,7 +94,7 @@ namespace timeline { static const ClipDelegate::Appearance defaultAppearance = ClipDelegate::COMPACT; public: - ClipPresenter (ID, ctrl::BusTerm&, WidgetViewHook&, optional offsetX); + ClipPresenter (ID, ctrl::BusTerm&, WidgetHook&, optional offsetX); ~ClipPresenter(); @@ -121,7 +121,7 @@ namespace timeline { */ void resetAppearanceStyle(); - WidgetViewHook& getClipContentCanvas(); + WidgetHook& getClipContentCanvas(); }; diff --git a/src/stage/timeline/clip-widget.cpp b/src/stage/timeline/clip-widget.cpp index a821491b2..6cd5be8e1 100644 --- a/src/stage/timeline/clip-widget.cpp +++ b/src/stage/timeline/clip-widget.cpp @@ -75,34 +75,36 @@ namespace timeline { namespace {// details of concrete clip appearance styles... - + + using WidgetHook = model::CanvasHook; + using HookedWidget = model::CanvasHooked; ///////////////////////////////////////////TICKET #1211 : need preliminary placeholder clip widget for timeline layout + class ClipData : public ClipDelegate , util::NonCopyable { - WidgetViewHook& display_; + WidgetHook& display_; /* === Interface ClipDelegate === */ public: - ClipData(WidgetViewHook& displayAnchor) + ClipData(WidgetHook& displayAnchor) : ClipDelegate{} , display_{displayAnchor} { } }; - using ViewHookedWidget = model::ViewHooked; ///////////////////////////////////////////TICKET #1211 : need preliminary placeholder clip widget for timeline layout class ClipWidget - : public ViewHookedWidget + : public HookedWidget , public ClipDelegate , util::NonCopyable { /* === Interface ClipDelegate === */ public: - ClipWidget(WidgetViewHook& displayAnchor, int x, int y, uString clipName) - : ViewHookedWidget{displayAnchor.hookedAt(x,y), clipName} + ClipWidget(WidgetHook::Pos hookPoint, uString clipName) + : HookedWidget{hookPoint, clipName} , ClipDelegate{} { } }; @@ -114,16 +116,16 @@ namespace timeline { /* === Appearance Style state transitions === */ ClipDelegate::Appearance - ClipDelegate::switchAppearance (PDelegate& manager, Appearance desired, WidgetViewHook* newView) + ClipDelegate::switchAppearance (PDelegate& manager, Appearance desired, WidgetHook* newView) { UNIMPLEMENTED ("clip appearance style state management"); } ClipDelegate::Appearance - ClipDelegate::buildDelegate (PDelegate& manager, WidgetViewHook& view, optional startOffsetX) ////////////////TICKET #1213 : translation time->offset should be built into the ViewHook!!! + ClipDelegate::buildDelegate (PDelegate& manager, WidgetHook& view, optional startOffsetX) ////////////////TICKET #1213 : translation time->offset should be built into the ViewHook!!! { if (startOffsetX) - manager.reset (new ClipWidget{view, *startOffsetX, defaultOffsetY, defaultName}); + manager.reset (new ClipWidget{view.hookedAt(*startOffsetX, defaultOffsetY), defaultName}); else manager.reset (new ClipData{view}); } diff --git a/src/stage/timeline/clip-widget.hpp b/src/stage/timeline/clip-widget.hpp index cbc0f483e..f08ec0f9d 100644 --- a/src/stage/timeline/clip-widget.hpp +++ b/src/stage/timeline/clip-widget.hpp @@ -102,7 +102,7 @@ #define STAGE_TIMELINE_CLIP_WIDGET_H #include "stage/gtk-base.hpp" -#include "stage/model/view-hook.hpp" +#include "stage/model/canvas-hook.hpp" //#include "lib/util.hpp" @@ -118,7 +118,7 @@ namespace timeline { using std::string; - using WidgetViewHook = model::ViewHook; + using WidgetHook = model::CanvasHook; class ClipDelegate; using PDelegate = std::unique_ptr; @@ -167,12 +167,12 @@ namespace timeline { */ static Appearance switchAppearance (PDelegate& manager, Appearance desired =PENDING, - WidgetViewHook* newView =nullptr); + WidgetHook* newView =nullptr); /** build the initial presentation widget on construction, using a minimally * viable appearance style. This is the first incantation of #switchAppearance. */ - static Appearance buildDelegate (PDelegate& manager, WidgetViewHook& view, + static Appearance buildDelegate (PDelegate& manager, WidgetHook& view, std::optional startOffsetX); ///////////////////////TICKET #1213 : translation time->offset should be built into the ViewHook!!! private:/* ===== Internals ===== */ diff --git a/src/stage/timeline/display-manager.hpp b/src/stage/timeline/display-manager.hpp index 6a3f49d72..0ae4baf2f 100644 --- a/src/stage/timeline/display-manager.hpp +++ b/src/stage/timeline/display-manager.hpp @@ -65,7 +65,7 @@ namespace timeline { using util::max; - using model::ViewHooked; + using lib::time::Time; class TrackHeadWidget; class TrackBody; @@ -75,10 +75,10 @@ namespace timeline { * when attaching or moving Widgets on the shared canvas. */ template - class ViewRefHook - : public model::ViewHook + class RelativeCanvasHook + : public model::CanvasHook { - model::ViewHook& refHook_; + model::CanvasHook& refHook_; /* ==== Interface: ViewHook ===== */ @@ -108,7 +108,7 @@ namespace timeline { } /** allow to build a derived ViewRefHook with different offset */ - model::ViewHook& + model::CanvasHook& getAnchorHook() noexcept override { return this->refHook_; @@ -118,8 +118,15 @@ namespace timeline { virtual int hookAdjX (int xPos) =0; virtual int hookAdjY (int yPos) =0; + /** delegating default implementation for timeline zoom */ + int + translateTimeToPixels (Time startTimePoint) const override + { + return refHook_.hookedAt(startTimePoint).x; + } + public: - ViewRefHook(model::ViewHook& baseHook) + RelativeCanvasHook(model::CanvasHook& baseHook) : refHook_{baseHook.getAnchorHook()} { } }; @@ -144,7 +151,7 @@ namespace timeline { virtual model::ViewHook& getHeadHook() =0; virtual model::ViewHook& getBodyHook() =0; - virtual model::ViewHook& getClipHook() =0; + virtual model::CanvasHook& getClipHook() =0; }; diff --git a/src/stage/timeline/timeline-layout.cpp b/src/stage/timeline/timeline-layout.cpp index 037a41fcf..c3b9ca6ec 100644 --- a/src/stage/timeline/timeline-layout.cpp +++ b/src/stage/timeline/timeline-layout.cpp @@ -135,16 +135,14 @@ namespace timeline { /* ==== Interface: ViewHook ===== */ void - TimelineLayout::hook (TrackHeadWidget& head, int xPos, int yPos) + TimelineLayout::hook (TrackHeadWidget& head) { - REQUIRE (xPos==0 && yPos==0, "arbitrary positioning of sub-Tracks contradicts the concept of track-profile."); ///TODO remove that API headerPane_.installForkRoot (head); } void - TimelineLayout::hook (TrackBody& body, int xPos, int yPos) + TimelineLayout::hook (TrackBody& body) { - REQUIRE (xPos==0 && yPos==0, "arbitrary positioning of sub-Tracks contradicts the concept of track-profile."); ///TODO remove that API bodyCanvas_.installForkRoot (body); // detect changes of the track structure @@ -179,18 +177,5 @@ namespace timeline { } - void - TimelineLayout::move (TrackHeadWidget& head, int xPos, int yPos) - { - NOTREACHED ("ViewHooked: not supported -- refactor?"); - } - - void - TimelineLayout::move (TrackBody& body, int xPos, int yPos) - { - NOTREACHED ("ViewHooked: not supported -- refactor?"); - } - - }}// namespace stage::timeline diff --git a/src/stage/timeline/timeline-layout.hpp b/src/stage/timeline/timeline-layout.hpp index 89f944dc9..03d608e96 100644 --- a/src/stage/timeline/timeline-layout.hpp +++ b/src/stage/timeline/timeline-layout.hpp @@ -87,7 +87,7 @@ #include "stage/timeline/display-evaluation.hpp" #include "stage/timeline/header-pane-widget.hpp" #include "stage/timeline/body-canvas-widget.hpp" -#include "stage/model/view-hook.hpp" +#include "stage/model/canvas-hook.hpp" //#include "lib/util.hpp" @@ -143,19 +143,17 @@ namespace timeline { model::ViewHook& getHeadHook() override { return *this; }; model::ViewHook& getBodyHook() override { return *this; }; - model::ViewHook& getClipHook() override { return bodyCanvas_; }; + model::CanvasHook& getClipHook() override { return bodyCanvas_; }; protected: /* ==== Interface: ViewHook ===== */ - void hook (TrackHeadWidget&, int xPos=0, int yPos=0) override; - void move (TrackHeadWidget&, int xPos, int yPos) override; - void remove (TrackHeadWidget&) override; - void rehook (TrackHeadWidget&) noexcept override; + void hook (TrackHeadWidget&) override; + void remove (TrackHeadWidget&) override; + void rehook (TrackHeadWidget&) noexcept override; - void hook (TrackBody&, int xPos=0, int yPos=0) override; - void move (TrackBody&, int xPos, int yPos) override; - void remove (TrackBody&) override; - void rehook (TrackBody&) noexcept override; + void hook (TrackBody&) override; + void remove (TrackBody&) override; + void rehook (TrackBody&) noexcept override; private:/* ===== Internals ===== */ diff --git a/src/stage/timeline/track-body.cpp b/src/stage/timeline/track-body.cpp index 6b1d051d2..c4d030ebc 100644 --- a/src/stage/timeline/track-body.cpp +++ b/src/stage/timeline/track-body.cpp @@ -95,21 +95,14 @@ namespace timeline { /* ==== Interface: ViewHook ===== */ void - TrackBody::hook (TrackBody& subBody, int xPos, int yPos) + TrackBody::hook (TrackBody& subBody) { - REQUIRE (xPos==0 && yPos==0, "arbitrary positioning of TrackBody contradicts the concept of track-profile."); ///TODO remove that API subTracks_.push_back (&subBody); // notify presentation code of the changed structure subBody.signalStructureChange_ = signalStructureChange_; signalStructureChange_(); // this _is_ such a change } - - void - TrackBody::move (TrackBody& subBody, int xPos, int yPos) - { - NOTREACHED ("woot?? can we even move a sub-TrackBody????"); - } void TrackBody::remove (TrackBody& subBody) diff --git a/src/stage/timeline/track-body.hpp b/src/stage/timeline/track-body.hpp index e80a7c81b..864f66d0a 100644 --- a/src/stage/timeline/track-body.hpp +++ b/src/stage/timeline/track-body.hpp @@ -41,6 +41,7 @@ #define STAGE_TIMELINE_TRACK_BODY_H #include "stage/gtk-base.hpp" +#include "stage/model/view-hook.hpp" #include "stage/timeline/ruler-track.hpp" #include "stage/timeline/display-manager.hpp" @@ -125,10 +126,9 @@ namespace timeline { /* ==== Interface: ViewHook ===== */ - void hook (TrackBody&, int xPos=0, int yPos=0) override; - void move (TrackBody&, int xPos, int yPos) override; - void remove (TrackBody&) override; - void rehook (TrackBody&) noexcept override; + void hook (TrackBody&) override; + void remove (TrackBody&) override; + void rehook (TrackBody&) noexcept override; /* ===== Internals ===== */ /** diff --git a/src/stage/timeline/track-head-widget.cpp b/src/stage/timeline/track-head-widget.cpp index 5a2783e7b..87a8be7ca 100644 --- a/src/stage/timeline/track-head-widget.cpp +++ b/src/stage/timeline/track-head-widget.cpp @@ -131,17 +131,10 @@ namespace timeline { /* ==== Interface: ViewHook ===== */ void - TrackHeadWidget::hook (TrackHeadWidget& subHead, int xPos, int yPos) + TrackHeadWidget::hook (TrackHeadWidget& subHead) { - REQUIRE (xPos==0 && yPos==0, "selection of arbitrary row not yet implemented"); attachSubFork (subHead); } - - void - TrackHeadWidget::move (TrackHeadWidget& subHead, int xPos, int yPos) - { - NOTREACHED ("woot?? can we even move a sub-TrackHead????"); - } void TrackHeadWidget::remove (TrackHeadWidget& subHead) diff --git a/src/stage/timeline/track-head-widget.hpp b/src/stage/timeline/track-head-widget.hpp index 12844d7dc..a7cc74dcb 100644 --- a/src/stage/timeline/track-head-widget.hpp +++ b/src/stage/timeline/track-head-widget.hpp @@ -61,7 +61,6 @@ namespace stage { namespace timeline { using ID = ctrl::BusTerm::ID; - using model::ViewHooked; /** * Header pane control area corresponding to a Track with nested child Tracks. @@ -81,10 +80,9 @@ namespace timeline { /* ==== Interface: ViewHook ===== */ - void hook (TrackHeadWidget&, int xPos=0, int yPos=0) override; - void move (TrackHeadWidget&, int xPos, int yPos) override; - void remove (TrackHeadWidget&) override; - void rehook (TrackHeadWidget&) noexcept override; + void hook (TrackHeadWidget&) override; + void remove (TrackHeadWidget&) override; + void rehook (TrackHeadWidget&) noexcept override; public: TrackHeadWidget(); diff --git a/src/stage/timeline/track-presenter.hpp b/src/stage/timeline/track-presenter.hpp index abc06b736..8d7194c3f 100644 --- a/src/stage/timeline/track-presenter.hpp +++ b/src/stage/timeline/track-presenter.hpp @@ -141,10 +141,10 @@ namespace timeline { class DisplayFrame : util::NonCopyable , public DisplayViewHooks - , public ViewRefHook + , public RelativeCanvasHook { - ViewHooked head_; - ViewHooked body_; + model::ViewHooked head_; + model::ViewHooked body_; /* === extended Interface for relative view hook === */ @@ -155,11 +155,11 @@ namespace timeline { model::ViewHook& getHeadHook() override { return head_; }; model::ViewHook& getBodyHook() override { return body_; }; - model::ViewHook& getClipHook() override { return *this; }; + model::CanvasHook& getClipHook() override { return *this; }; public: DisplayFrame (DisplayViewHooks& displayAnchor) - : ViewRefHook{displayAnchor.getClipHook()} + : RelativeCanvasHook{displayAnchor.getClipHook()} , head_{displayAnchor.getHeadHook()} , body_{displayAnchor.getBodyHook()} { } @@ -259,7 +259,7 @@ namespace timeline { { uint x = rand() % 50; uint y = 0; - Gtk::Button* butt = Gtk::manage (new ViewHooked{display_.hookedAt(x,y), TODO_trackName_}); + Gtk::Button* butt = Gtk::manage (new model::CanvasHooked{display_.hookedAt(x,y), TODO_trackName_}); butt->signal_clicked().connect( [butt]{ cout << "|=="<get_label()<show(); diff --git a/tests/stage/model/canvas-hook-test.cpp b/tests/stage/model/canvas-hook-test.cpp index 05c11556d..862d07741 100644 --- a/tests/stage/model/canvas-hook-test.cpp +++ b/tests/stage/model/canvas-hook-test.cpp @@ -123,24 +123,8 @@ namespace test { and pos->posY == y_expected; } - /** verify our internal sequence matches the given one */ - template - bool - testContainsSequence (IT refSeq) - { - // NOTE the implementation twist of using a std::forward_list, - // which causes reversed order of our internal elements - lib::IterStack ids; - for (auto& entry : widgets_) - ids.push (entry.widget.i); - for ( ; refSeq and ids; ++refSeq, ++ids) - if (refSeq->i != *ids) break; - return isnil(refSeq) - and isnil(ids); - } - - /* === Interface ViewHook === */ + /* === Interface CanvasHook === */ void hook (DummyWidget& elm, int xPos, int yPos) override @@ -208,39 +192,22 @@ namespace test { virtual void run (Arg) { - verify_standardUsage(); - verify_multiplicity(); + attach2canvas(); relocateWidget(); - reOrderHooked(); } - /** @test the standard use case is to hook up a widget to a canvas for display. + /** @test attach several widgets with distinct coordinates + * and verify automated detaching on destruction. */ void - verify_standardUsage() - { - FakeCanvas canvas; - CHECK (canvas.empty()); - { - HookedWidget widget{canvas.hookedAt(0,0) }; - CHECK (canvas.testContains (widget.i)); - CHECK (not canvas.empty()); - }// hook goes out of scope... - CHECK (canvas.empty()); - } - - - /** @test each hooking has a distinct identity and is managed on its own. - */ - void - verify_multiplicity() + attach2canvas() { FakeCanvas canvas; CHECK (canvas.empty()); HookedWidget widget{canvas.hookedAt(1,1)}; - CHECK (canvas.testContains (widget.i)); + CHECK (canvas.testVerifyPos (widget, 1,1)); CHECK (not canvas.empty()); int someID; @@ -249,6 +216,8 @@ namespace test { someID = otherWidget.i; CHECK (canvas.testContains (someID)); CHECK (canvas.testContains (widget.i)); + CHECK (canvas.testVerifyPos (widget, 1,1)); + CHECK (canvas.testVerifyPos (otherWidget, 2,2)); }// hook goes out of scope... CHECK (not canvas.testContains (someID)); CHECK (canvas.testContains (widget.i)); @@ -292,46 +261,6 @@ namespace test { CHECK (canvas.testVerifyPos (w1, x1,y1)); CHECK (canvas.testVerifyPos (w3, x3,y3)); } - - - /** @test a mechanism to re-attach elements in changed order. - * @remarks this test looks somewhat convoluted, because `ViewHooked` is defined - * to be non-copyable (for good reason, since we can assume that the canvas - * somehow maintains a pointer to each widget added, so we can not allow the - * attached widgets to move in memory). However, in practice the "order sequence" - * is typically defined as a delegating iterator over some sequence of model elements, - * which themselves are managed as a STL container of `std::unique_ptr`; thus it is - * very much possible to alter the sequence of the model elements, without actually - * touching the memory location of the slave widgets used for presentation. - */ - void - reOrderHooked() - { - using Widgets = lib::ScopedCollection; - using OrderIdx = vector; - - FakeCanvas canvas; // WARNING: Canvas must outlive the widgets! - - // create 20 (random) widgets and hook them onto the canvas - Widgets widgets{20}; - OrderIdx orderIdx; - for (uint i=0; i<20; ++i) - orderIdx.push_back (& widgets.emplace(canvas.hookedAt(0,1))); - - // helper: use the orderIdx to generate sequence of widget refs (not pointers) - auto orderSequence = [&] { return lib::ptrDeref(eachElm(orderIdx)); }; - - CHECK (canvas.testContainsSequence (eachElm(widgets))); - CHECK (canvas.testContainsSequence (orderSequence())); - - // now lets assume the relevant order of the widgets has been altered - shuffle (orderIdx.begin(),orderIdx.end(), std::random_device()); - CHECK (not canvas.testContainsSequence (orderSequence())); - - // so we need to re-construct the canvas attachments in the new order - canvas.reOrder (orderSequence()); - CHECK (canvas.testContainsSequence (orderSequence())); - } }; diff --git a/tests/stage/model/view-hook-test.cpp b/tests/stage/model/view-hook-test.cpp index 80393912c..92c7315e5 100644 --- a/tests/stage/model/view-hook-test.cpp +++ b/tests/stage/model/view-hook-test.cpp @@ -33,8 +33,8 @@ #include "lib/iter-adapter-stl.hpp" #include "lib/util.hpp" +#include #include -#include #include #include @@ -43,9 +43,8 @@ using util::isnil; using util::contains; using util::isSameObject; using lib::iter_stl::eachElm; -using std::vector; -using std::forward_list; using std::shuffle; +using std::vector; namespace stage{ @@ -73,21 +72,15 @@ namespace test { class FakeCanvas : public ViewHook { - struct Attachment - { - DummyWidget& widget; - int posX, posY; - }; - forward_list widgets_; - + std::list widgets_; auto allWidgetIDs() const { return lib::treeExplore(widgets_) - .transform([](Attachment const& entry) + .transform([](DummyWidget const& entry) { - return entry.widget.i; + return entry.i; }); } @@ -96,7 +89,7 @@ namespace test { { return std::find_if (widgets_.begin() ,widgets_.end() - , [&](Attachment const& a) { return a.widget == someWidget; }); + , [&](DummyWidget const& widget) { return widget == someWidget; }); } public: @@ -113,26 +106,12 @@ namespace test { return util::linearSearch (allWidgetIDs(), someWidgetID); } - bool - testVerifyPos (DummyWidget const& someWidget, int x_expected, int y_expected) - { - auto end = widgets_.end(); - auto pos = findEntry (someWidget); - return pos != end - and pos->posX == x_expected - and pos->posY == y_expected; - } - /** verify our internal sequence matches the given one */ template bool testContainsSequence (IT refSeq) { - // NOTE the implementation twist of using a std::forward_list, - // which causes reversed order of our internal elements - lib::IterStack ids; - for (auto& entry : widgets_) - ids.push (entry.widget.i); + auto ids = allWidgetIDs(); for ( ; refSeq and ids; ++refSeq, ++ids) if (refSeq->i != *ids) break; return isnil(refSeq) @@ -143,27 +122,15 @@ namespace test { /* === Interface ViewHook === */ void - hook (DummyWidget& elm, int xPos, int yPos) override + hook (DummyWidget& elm) override { - widgets_.push_front (Attachment{elm, xPos,yPos}); - } - - void - move (DummyWidget& elm, int xPos, int yPos) override - { - auto end = widgets_.end(); - auto pos = findEntry (elm); - if (pos != end) - { - pos->posX = xPos; - pos->posY = yPos; - } + widgets_.push_back (elm); } void remove (DummyWidget& elm) override { - widgets_.remove_if ([&](Attachment const& a) { return a.widget == elm; }); + widgets_.remove_if ([&](auto const& widget) { return widget == elm; }); } @@ -172,9 +139,9 @@ namespace test { { auto pos = findEntry (existingHook); REQUIRE (pos != widgets_.end(), "the given iterator must yield previously hooked-up elements"); - Attachment existing{*pos}; - this->remove (existing.widget); - this->hook (existing.widget, existing.posX,existing.posY); + DummyWidget& widget{*pos}; + this->remove (widget); + this->hook (widget); } }; } @@ -202,7 +169,6 @@ namespace test { { verify_standardUsage(); verify_multiplicity(); - relocateWidget(); reOrderHooked(); } @@ -248,44 +214,6 @@ namespace test { } - /** @test hook a widget at a specific position and then later - * relocate it on the canvas through the ViewHook front-end. - */ - void - relocateWidget() - { - int x1 = rand() % 100; - int y1 = rand() % 100; - int x2 = rand() % 100; - int y2 = rand() % 100; - int x3 = rand() % 100; - int y3 = rand() % 100; - - FakeCanvas canvas; - HookedWidget w1{canvas.hookedAt(x1,y1)}; - HookedWidget w3{canvas.hookedAt(x3,y3)}; - - int id2; - { - HookedWidget w2{canvas.hookedAt(x2,y2)}; - id2 = w2.i; - CHECK (canvas.testContains (id2)); - CHECK (canvas.testVerifyPos (w2, x2,y2)); - - int newX = ++x2; - int newY = --y2; - w2.moveTo (newX,newY); - - CHECK (canvas.testVerifyPos (w2, newX,newY)); - CHECK (canvas.testVerifyPos (w1, x1,y1)); - CHECK (canvas.testVerifyPos (w3, x3,y3)); - } - CHECK (not canvas.testContains (id2)); - CHECK (canvas.testVerifyPos (w1, x1,y1)); - CHECK (canvas.testVerifyPos (w3, x3,y3)); - } - - /** @test a mechanism to re-attach elements in changed order. * @remarks this test looks somewhat convoluted, because `ViewHooked` is defined * to be non-copyable (for good reason, since we can assume that the canvas diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 2cce3cce3..4e3ffdef9 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -791,6 +791,13 @@

+ + + + + + + @@ -19174,10 +19181,10 @@ - + - - + + @@ -19213,8 +19220,8 @@ - - + + @@ -19224,19 +19231,23 @@ - - + + - - + + - - + + - - + + + + + + @@ -22097,8 +22108,8 @@ - - + + @@ -22106,11 +22117,14 @@ - + - - - + + + + + + @@ -27943,7 +27957,8 @@ - + + @@ -27991,6 +28006,13 @@ + + + + + + + @@ -28159,7 +28181,8 @@ - + + @@ -28259,7 +28282,7 @@ - + @@ -28270,12 +28293,18 @@

+
+ + + + +