From 22bc2167f92f0ef9d4011a2a75f97df621293fec Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 22 Mar 2020 16:37:58 +0100 Subject: [PATCH] Relative-Hook: prepare to split the abstraction into two levels Level-1 : generic attachment into some kind of view Level-2 : attachment by coordinates onto some kind of canvas --- src/stage/model/canvas-hook.hpp | 219 ++++++++++++++++++++++++++++++++ src/stage/model/view-hook.hpp | 27 +++- wiki/thinkPad.ichthyo.mm | 84 +++++++++++- 3 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 src/stage/model/canvas-hook.hpp diff --git a/src/stage/model/canvas-hook.hpp b/src/stage/model/canvas-hook.hpp new file mode 100644 index 000000000..052ec2f82 --- /dev/null +++ b/src/stage/model/canvas-hook.hpp @@ -0,0 +1,219 @@ +/* + CANVAS-HOOK.hpp - abstracted attachment to a canvas with free positioning + + Copyright (C) Lumiera.org + 2020, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file canvas-hook.hpp + ** Specialised (abstracted) presentation context with positioning by coordinates. + ** This extends the generic abstraction of a ViewHook, and works in a similar way, + ** in close collaboration with the corresponding CanvasHooked entity (abstraction). + ** Elements relying on those abstractions maintain an attachment to "their view", + ** while remaining agnostic about the view's implementation details. But the key + ** point with this extended abstraction is that elements can be placed onto a + ** coordinate system or canvas, and they can be moved to a different position. + ** A CanvasHooked element is basically a decorator directly attached to the + ** element, adding automatic detachment on destruction, similar to a smart-ptr. + ** So the "hooked" widget will live within the common allocation, together with + ** its attachment; the whole arrangement must be set up at construction time + ** - the combined `CanvasHooked` must be non-copyable, since it can be expected + ** for the canvas to store some pointer to the attached widget. + ** - moreover, the canvas/presentation need to be available and activated when + ** constructing the widget(s) due to the interwoven lifecycle. + ** - and, most notably, the presentation/canvas (the ViewHook) must be arranged to + ** outlive the attached widgets, since they call back on destruction. + ** In the typical usage situation these points can be ensured naturally by housing + ** the widgets in some detail data structure owned by the top level presentation frame. + ** + ** @see ViewHook_test + ** + */ + + +#ifndef STAGE_MODEL_CANVAS_HOOK_H +#define STAGE_MODEL_CANVAS_HOOK_H + +#include "lib/time/timevalue.hpp" +#include "lib/nocopy.hpp" +#include "lib/util.hpp" + +#include + + +namespace stage { +namespace model { + + using lib::time::Time; + + + + /** + * Interface to represent _"some presentation layout entity",_ + * with the ability to _attach_ widgets (managed elsewhere), to + * relocate those widgets to another position, and to re-establish + * a different sequence of the widgets (whatever this means). + * @remark some typical examples for the kind of collaboration modelled here: + * - a _canvas widget,_ (e.g. `Gtk::Layout`), allowing to attach + * child widgets at specific positions, together with custom drawing. + * - a tree or grid control, allowing to populate some row with a given widget. + * @warning please ensure the ViewHook outlives any attached ViewHooked. + */ + template + class ViewHook + { + public: + virtual ~ViewHook() { } ///< this is an interface + + virtual void hook (WID& widget, int xPos=0, int yPos=0) =0; + virtual void move (WID& widget, int xPos, int yPos) =0; + virtual void remove (WID& widget) =0; + virtual void rehook (WID& widget) noexcept =0; + + template + void reOrder (IT newOrder); + + struct Pos + { + ViewHook& view; + int x,y; + }; + + Pos + hookedAt (int x, int y) + { + return Pos{*this, x,y}; + } + + /** build the "construction hook" for a \ref ViewHooked element, + * which is to be attached to some timeline canvas view. + * @param start anchor point / nominal start point of the element + * @param downshift (optional) vertical shift down from the baseline + * @return opaque registration argument for the ViewHooked ctor */ + Pos + hookedAt (Time start, int downshift=0) + { + return hookedAt (translateTimeToPixels (start), downshift); + } + + /** Anchor point to build chains of related View Hooks */ + virtual ViewHook& + getAnchorHook() noexcept + { + return *this; + } + + protected: + /** extension point for time axis zoom management. */ + int translateTimeToPixels (Time) const =0; + }; + + + + /** + * A widget attached onto a display canvas or similar central presentation context. + * This decorator inherits from the widget to be attached, i.e. the widget itself becomes + * embedded; moreover, the attachment is immediately performed at construction time and + * managed automatically thereafter. When the `ViewHooked` element goes out of scope, it is + * automatically detached from presentation. With the help of ViewHooked, a widget (or similar + * entity) may control some aspects of its presentation placement, typically the coordinates + * on some kind of _canvas_ (-> `Gtk::Layout`), while remaining agnostic regarding the + * implementation details of the canvas and its placement thereon. + * + * The prominent example of a `ViewHooked` element is the stage::timeline::DisplayFrame, maintained + * by the TrackPresenter within the timeline UI. This connection entity allows to place ClipWidget + * elements into the appropriate display region for this track, without exposing the actual + * stage::timeline::BodyCanvasWidget to each and every Clip or Label widget. + * + * @tparam WID type of the embedded widget, which is to be hooked-up into the view/canvas. + * @remark since ViewHooked represents one distinct attachment to some view or canvas, + * is has a clear-cut identity and thus may be moved, but not copied. + * @warning since ViewHooked entities call back into the ViewHook on destruction, + * the latter still needs to be alive at that point. Which basically means + * you must ensure the ViewHooked "Widgets" are destroyed prior to the "Canvas". + */ + template + class ViewHooked + : public WID + , util::NonCopyable + { + using View = ViewHook; + + View* view_; + + public: + template + ViewHooked (View& view, ARGS&& ...args) + : WID{std::forward(args)...} + , view_{&view} + { + view_->hook (*this); + } + template + ViewHooked (typename View::Pos viewPos, ARGS&& ...args) + : WID{std::forward(args)...} + , view_{&viewPos.view} + { + view_->hook (*this, viewPos.x, viewPos.y); + } + + ~ViewHooked() noexcept + { + try { + if (view_) + view_->remove (*this); + } + ERROR_LOG_AND_IGNORE (progress, "Detaching of ViewHooked widgets from the presentation") + } + + void + moveTo (int xPos, int yPos) + { + view_->move (*this, xPos,yPos); + } + }; + + + + /** + * re-attach elements in a given, new order. + * @param newOrder a Lumiera Forward Iterator to yield a reference to + * all attached elements, and in the new order to be established. + * @remark this operation becomes relevant, when "attaching an element" also + * constitutes some kind of arrangement in the visual presentation, like + * e.g. a stacking order, or by populating some table cells in sequence. + * The expected semantics is for this operation to detach each given element, + * and then immediately re-attach it _at the "beginning"_ (whatever this means). + * The element as such, and all associated presentation entities are not destroyed, + * but continue to exist with the same identity (and possibly all signal wirings). + * Just they now appear as if attached with the new ordering. + */ + template + template + void + ViewHook::reOrder (IT newOrder) + { + for (ViewHooked& existingHook : newOrder) + this->rehook (existingHook); + } + + + +}}// namespace stage::model +#endif /*STAGE_MODEL_CANVAS_HOOK_H*/ diff --git a/src/stage/model/view-hook.hpp b/src/stage/model/view-hook.hpp index f26d190f6..0dda6a816 100644 --- a/src/stage/model/view-hook.hpp +++ b/src/stage/model/view-hook.hpp @@ -35,9 +35,12 @@ ** modelled by a smart-handle stage::timeline::ViewHooked, which -- on destruction -- ** automatically detaches the widget from the presentation. ** - ** As it turns out in practice, such a "hooked" widget will never exist apart from its - ** attachment. Consequently, we locate the widget within the smart-handle itself, thus - ** tightly linking together the lifecycle of the widget and the presentation attachment. + ** As it turns out in practice, we get two flavours or _view attachment:_ + ** - Widgets just somehow placed into a grid or widget layout + ** - Widgets attached to a canvas with positioning by coordinates + ** Moreover, such a "hooked" widget will never exist apart from its attachment. + ** Consequently, we locate the widget within the smart-handle itself, thus tightly + ** linking together the lifecycle of the widget and the presentation attachment. ** However, this combined memory layout incurs some liabilities: ** - the combined `ViewHooked` must be non-copyable, since it can be expected ** for the canvas to store some pointer to the attached widget. @@ -56,6 +59,7 @@ #ifndef STAGE_MODEL_VIEW_HOOK_H #define STAGE_MODEL_VIEW_HOOK_H +#include "lib/time/timevalue.hpp" #include "lib/nocopy.hpp" #include "lib/util.hpp" @@ -65,6 +69,8 @@ namespace stage { namespace model { + using lib::time::Time; + /** @@ -104,12 +110,27 @@ namespace model { return Pos{*this, x,y}; } + /** build the "construction hook" for a \ref ViewHooked element, + * which is to be attached to some timeline canvas view. + * @param start anchor point / nominal start point of the element + * @param downshift (optional) vertical shift down from the baseline + * @return opaque registration argument for the ViewHooked ctor */ + Pos + hookedAt (Time start, int downshift=0) + { + return hookedAt (translateTimeToPixels (start), downshift); + } + /** Anchor point to build chains of related View Hooks */ virtual ViewHook& getAnchorHook() noexcept { return *this; } + + protected: + /** extension point for time axis zoom management. */ + int translateTimeToPixels (Time) const =0; }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index addc340c5..831338776 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -19174,8 +19174,9 @@ - + + @@ -19188,6 +19189,29 @@ + + + + + + + + + + + + + + + + +

+ erleichtert das Testen +

+ + +
+
@@ -21891,6 +21915,8 @@ + + @@ -22024,6 +22050,51 @@ + + + + + + + + + +

+ da weit über den Code verstreut +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -22036,7 +22107,7 @@
- + @@ -22048,6 +22119,7 @@ + @@ -27690,7 +27762,13 @@ - + + + + + + +