Timeline: consider how to integrate the drawing code

...which leads to a specific twist here; while in the simple version
we still could hope to get away with a simple uniform uint argument,
the situation has changed altogether now. The canvas has turned into
some generic component, since it is instantiated two times, onece for
the time ruler and once for the actual body content. Thus all of the
specifics of the drawing code need to be pushed into a new, dedicated
renderer component. And this more or less forces us to pass all the
actual presentation variations through the invocation arguments of
the visitor.

So we're now off again for a digression, we need a more generalised visitor
This commit is contained in:
Fischlurch 2019-04-14 15:38:57 +02:00
parent 7ee0baa241
commit ec9b2388da
9 changed files with 467 additions and 56 deletions

View file

@ -1,5 +1,5 @@
/*
OPAQUE-HOLDER.hpp - buffer holding an object inline while hiding the concrete type
OPAQUE-HOLDER.hpp - buffer holding an object inline while hiding the concrete type
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
@ -35,7 +35,7 @@
** exposes a neutral interface, the inner container keeps track of the actual
** type by means of a vtable. OpaqueHolder is built on top of InPlaceAnyHolder
** additionally to support a "common base interface" and re-access of the
** embedded object through this interface. For this to work, all of the
** embedded object through this interface. For this to work, all of the
** stored types need to be derived from this common base interface.
** OpaqueHolder then may be even used like a smart-ptr, exposing this
** base interface. To the contrary, InPlaceAnyHolder has lesser requirements
@ -59,7 +59,7 @@
**
** @see opaque-holder-test.cpp
** @see function-erasure.hpp usage example
** @see variant.hpp
** @see variant.hpp
*/
@ -118,7 +118,7 @@ namespace lib {
/* ==== Policy classes controlling re-Access ==== */
/**
* Standard policy for accessing the contents via
* Standard policy for accessing the contents via
* a common base class interface. Using this policy
* causes static or dynamic casts or direct conversion
* to be employed as appropriate.
@ -134,7 +134,7 @@ namespace lib {
{
SUB* oPtr = &obj;
BA* asBase = util::AccessCasted<BA*>::access (oPtr);
if (asBase)
if (asBase)
return asBase;
throw error::Logic ("Unable to convert concrete object to Base interface"
@ -146,13 +146,13 @@ namespace lib {
/**
* Alternative policy for accessing the contents without
* a common interface; use this policy if the intention is
* to use OpaqueHolder with a family of similar classes,
* \em without requiring all of them to be derived from
* a common base class. (E.g. std::function objects).
* to use OpaqueHolder with a family of similar classes,
* _without requiring all of them_ to be derived from
* a _common base_ class. (E.g. std::function objects).
* In this case, the "Base" type will be defined to void*
* As a consequence, we loose all type information and
* no conversions are possible on re-access. You need
* to know the \em exact type to get back at the object.
* to know the _exact_ type to get back at the object.
*/
struct InPlaceAnyHolder_unrelatedTypes
{
@ -180,7 +180,7 @@ namespace lib {
* as a template parameter. InPlaceAnyHolder may be created empty
* or cleared afterwards, and this #empty() state may be detected
* at runtime. In a similar vein, when the stored object has a
* \c bool validity check, this can be accessed though #isValid().
* `bool` validity check, this can be accessed though #isValid().
* Moreover `!empty() && isValid()` may be tested as by `bool`
* conversion of the Holder object. The whole compound
* is copyable if and only if the contained object is copyable.
@ -327,7 +327,7 @@ namespace lib {
void
killBuffer()
killBuffer()
{
buff().~Buffer();
}
@ -378,7 +378,7 @@ namespace lib {
InPlaceAnyHolder()
{
{
make_emptyBuff();
}
@ -396,7 +396,7 @@ namespace lib {
InPlaceAnyHolder&
operator= (InPlaceAnyHolder const& ref)
{
if (!isSameObject (*this, ref))
if (not isSameObject (*this, ref))
{
killBuffer();
try
@ -416,8 +416,8 @@ namespace lib {
InPlaceAnyHolder&
operator= (SUB const& newContent)
{
if ( empty()
|| !isSameObject (*buff().getBase(), newContent)
if (empty()
or not isSameObject (*buff().getBase(), newContent)
)
{
killBuffer();
@ -511,7 +511,7 @@ namespace lib {
* - when knowing the exact type to access, the templated #get might be an option
* - the empty state of the container and a `isValid()` on the target may be checked
* - a combination of both is available as a `bool` check on the OpaqueHolder instance.
*
*
* For using OpaqueHolder, several *assumptions* need to be fulfilled
* - any instance placed into OpaqueHolder is below the specified maximum size
* - the caller cares for thread safety. No concurrent get calls while in mutation!
@ -555,7 +555,7 @@ namespace lib {
return *InPlaceHolder::buff().getBase();
}
BA*
BA*
operator-> () const
{
ASSERT (!InPlaceHolder::empty());
@ -577,7 +577,7 @@ namespace lib {
* allows to place new objects there. It has no way to keep track of the
* actual object living currently in the buffer. Thus, using InPlaceBuffer
* requires the placed class(es) themselves to maintain their lifecycle,
* and especially it is mandatory for the base class to provide a
* and especially it is mandatory for the base class to provide a
* virtual dtor. On the other hand, just the (alignment rounded)
* storage for the object(s) placed into the buffer is required.
* @remarks as a complement, PlantingHandle may be used on APIs to offer
@ -652,7 +652,7 @@ namespace lib {
static auto embedType() { return (SUB*) nullptr; }
/** Abbreviation for placement new */
/** Abbreviation for placement new */
template<class TY, typename...ARGS>
TY&
create (ARGS&& ...args)
@ -681,7 +681,7 @@ namespace lib {
return getObj();
}
BA*
BA*
operator-> () const
{
return &getObj();

View file

@ -1,5 +1,5 @@
/*
POLYMORPHIC-VALUE.hpp - building opaque polymorphic value objects
POLYMORPHIC-VALUE.hpp - building opaque polymorphic value objects
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
@ -77,38 +77,38 @@
** of these virtual functions can be assumed to know the real type and thus be
** able to invoke the correct copy ctor or assignment operator. For this to
** work, the interface needs to expose those copy and clone operations somehow
** as virtual functions. There are two alternatives to get at this point:
** as virtual functions. There are two alternatives to fulfil this requirement:
** - in the general case, the common base interface doesn't expose such operations.
** Thus we need to <i>mix in</i> an additional \em management interface; this
** can be done by \em subclassing the desired implementation type, because
** Thus we need to _mix in_ an additional _management_ interface; this
** can be done by _subclassing_ the desired implementation type, because
** this concrete type is irrelevant after finishing the placement constructor.
** In order to re-access this management interface, so to be able to invoke
** the copy or clone operations, we need to do an elaborate re-cast operation,
** first going down to the leaf type and then back up into the mixed-in
** management interface. Basically this operation is performed by using
** a \c dynamic_cast<CopyAPI&>(bufferContents)
** a `dynamic_cast<CopyAPI&>(bufferContents)`
** - but when the used client types provide some collaboration and implement
** this management interface either directly on the API or as an immediate
** sub-interface, then this copy/management interface is located within the
** direct inheritance chain and can be reached by a simple \c static_cast.
** direct inheritance chain and can be reached by a simple `static_cast`.
** Indeed, as we're just using a different meaning of the VTable, only a
** single indirection (virtual function call) is required at runtime in
** this case to invoke the copy ctor or assignment operator.
** Thus, in this latter (optimal) case, the fact that PolymorphicValue allows
** to conceal the actual implementation type comes with zero runtime overhead,
** compared with direct usage of a family of polymorphic types (with VTable).
** compared to direct usage of a family of polymorphic types (with VTable).
**
** So, how can the implementation of copy or assignment know the actual type
** to be copied? Basically we exploit the fact that the actual instance lives
** in an opaque buffer within the "outer" container. More specifically, \em we
** in an opaque buffer within the "outer" container. More specifically, _we_
** place it into that buffer -- thus we're able to control the actual type used.
** This way, the actual copy operations reside in an Adapter type, which lives
** at the absolute leaf end of the inheritance chain. It even inherits from
** the "implementation type" specified by the client. Thus, within the
** context of the copy operation, we know all the concrete types.
** context of the copy operation, we know all the concrete types.
**
**
** \par using polymorphic value objects
** # using polymorphic value objects
**
** To start with, we need a situation where polymorphic treatment and type erasure
** might be applicable. That is, we use a public API, and only that, in any client
@ -140,7 +140,7 @@
** - define the implementation types to inherit from the public API
** - implement the mentioned factory function, based on the static build
** PolymorphicValue#build functions, using the actual implementation type
** as parameter.
** as parameter.
**
** @see polymorphic-value-test.cpp
** @see opaque-holder.hpp other similar opaque inline buffer templates
@ -171,12 +171,12 @@ namespace lib {
/**
* Interface for active support of copy operations
* by the embedded client objects. When inserted into the
* inheritance chain \em above the concrete implementation objects,
* inheritance chain _above_ the concrete implementation objects,
* PolymorphicValue is able to perform copy operations trivially and
* without any \c dynamic_cast and other run time overhead besides a
* without any `dynamic_cast` and other run time overhead besides a
* simple indirection through the VTable. To enable this support, the
* implementation objects should inherit from \c CopySupport<Interface>
* (where \c Interface would be the public API for all these embedded
* implementation objects should inherit from `CopySupport<Interface>`
* (where `Interface` would be the public API for all these embedded
* implementation objects).
* Alternatively, it's also possible to place this CopySupport API as parent
* to the public API (it might even be completely absent, but then you'd need
@ -251,7 +251,7 @@ namespace lib {
struct AssignmentPolicy
{
template<class IMP>
static void
static void
assignEmbedded(IMP& dest,IMP const& src)
{
dest = src;
@ -269,7 +269,7 @@ namespace lib {
struct AssignmentPolicy<API, enable_if< allow_Clone_but_no_Copy<API> >>
{
template<class IMP>
static void
static void
assignEmbedded(IMP&,IMP const&)
{
throw error::Logic("attempt to overwrite unmodifiable value");
@ -286,7 +286,7 @@ namespace lib {
* level of the concrete implementation class and later on
* accessed through a \c dynamic_cast
*/
template <class TY, class YES = void>
template <class TY, class YES = void>
struct Trait
{
typedef CopySupport<TY,EmptyBase> CopyAPI;
@ -306,10 +306,10 @@ namespace lib {
/**
* Special case when the embedded types support copying
* on the API level, e.g. there is a sub-API exposing a \c cloneInto
* on the API level, e.g. there is a sub-API exposing a `cloneInto`
* function. In this case, the actual implementation classes can be
* instantiated as-is and the copy operations can be accessed by a
* simple \c static_cast without runtime overhead.
* simple `static_cast` without runtime overhead.
*/
template <class TY>
struct Trait<TY, enable_if< exposes_CloneFunction<TY> >>
@ -348,8 +348,8 @@ namespace lib {
* buffer through a builder function; later, this buffer may be copied
* and passed on without knowing the actual contained type.
*
* For using PolymorphicValue, several \b assumptions need to be fulfilled
* - any instance placed into OpaqueHolder is below the specified maximum size
* For using PolymorphicValue, several *assumptions* need to be fulfilled
* - any instance placed into the opaque buffer is below the specified maximum size
* - the caller cares for thread safety. No concurrent get calls while in mutation!
*
* @warning when a create or copy-into operation fails with exception, the whole
@ -366,8 +366,8 @@ namespace lib {
typedef polyvalue::Trait<CPY> _Traits;
typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
typedef typename _Traits::Assignment _AssignmentPolicy;
enum{
siz = storage + _Traits::ADMIN_OVERHEAD
enum{
siz = storage + _Traits::ADMIN_OVERHEAD
};
@ -420,14 +420,14 @@ namespace lib {
/**
* Implementation Helper: supporting copy operations.
* Implementation Helper: add support for copy operations.
* Actually instances of this Adapter template are placed
* into the internal buffer, such that they both inherit
* from the desired implementation type and the copy
* from the desired implementation type and the copy
* support interface. The implementation of the
* concrete copy operations is provided here
* forwarding to the copy operations
* of the implementation object.
* as forwarding to the copy operations
* of the implementation object.
*/
template<class IMP>
class Adapter
@ -446,7 +446,7 @@ namespace lib {
REQUIRE (INSTANCEOF (Adapter, &targetBase));
Adapter& target = static_cast<Adapter&> (targetBase);
_AssignmentPolicy::assignEmbedded(target,*this);
} // forward to assignment operator
} // forward to assignment operator
public: /* == forwarding ctor to implementation type == */

View file

@ -63,7 +63,7 @@ namespace lib {
/**
* Action token implemented by double dispatch to a handler function,
* as defined in the "receiver" interface (parameter \c REC).
* as defined in the "receiver" interface (parameter `REC`).
* The token is typically part of a DSL and can be applied
* to a concrete receiver subclass.
* @tparam REC the type receiving the verb invocations

136
src/lib/verb-visitor.hpp Normal file
View file

@ -0,0 +1,136 @@
/*
VERB-VISITOR.hpp - double dispatch to arbitrary functions on a common interface
Copyright (C) Lumiera.org
2019, Hermann Vosseler <Ichthyostega@web.de>
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 verb-visitor.hpp
** A specific double dispatch variation for function invocation.
** While the classic visitor invokes a common `handle` function with varying arguments,
** here we allow for pre-binding of arbitrary functions on an interface with individual
** suitable arguments. Yet similar to the classic visitor, the actual receiver can be a
** subclass of the target interface, which causes the _second_ indirection in the dispatch
** chain. Since the actually distinguishing factor is not so much a type, but a specific
** operation, we refer to the delayed invocation handles created by this binding as
** _verb token_ on a _receiver_ object (which is the concrete visitor).
**
** This setup is an extension or derivative of the [generic verb token](\ref verb-token-hpp)
** used for the diff system and similar applications; likewise the intended usage is to establish
** a language comprised of several abstract actions ("verbs"), but to allow the concrete operation
** to be supplied later, at application time, and within a different code context. The most notable
** use case is for the drawing of track contents in the user interface, where this pattern allows
** the separation of actual drawing code from the nested track controller structure.
**
** @see [drawing on the track canvas](\ref body-canvas-widget.cpp)
** @see VerbVisitorDispatch_test
**
*/
#ifndef LIB_VERB_VISITOR_H
#define LIB_VERB_VISITOR_H
#include "lib/symbol.hpp"
#include "lib/util.hpp"
#include <utility>
#include <string>
#include <array>
namespace lib {
using std::string;
/**
* Action token implemented by double dispatch to a handler function,
* as defined in the "receiver" interface (parameter \c REC).
* The token is typically part of a DSL and can be applied
* to a concrete receiver subclass.
* @tparam REC the type receiving the verb invocations
* @tparam SIG signature of the actual verb function, expected
* to exist on the receiver (REC) interface
* @remarks while the included ID Literal is mostly for diagnostics,
* it also serves as identity for comparisons. Conceptually what
* we want is to compare the function "offset", but this leads
* into relying on implementation defined behaviour.
* @note the #VERB macro simplifies definition of actual tokens
*/
template<class REC, class SIG>
class VerbToken;
template<class REC, class RET, typename... ARGS>
class VerbToken<REC, RET(ARGS...)>
{
public:
typedef RET (REC::*Handler) (ARGS...);
private:
Handler handler_;
Literal token_;
public:
RET
applyTo (REC& receiver, ARGS&& ...args)
{
REQUIRE ("NIL" != token_);
return (receiver.*handler_)(std::forward<ARGS>(args)...);
}
VerbToken(Handler handlerFunction, Literal token)
: handler_(handlerFunction)
, token_(token)
{ }
VerbToken()
: handler_{}
, token_("NIL")
{ }
/* default copyable */
operator string() const
{
return string(token_);
}
Literal const&
getID()
{
return token_;
}
/** equality of VerbToken, based on equality of the #token_ Literal
* @remarks member pointers to virtual functions aren't comparable, for good reason
*/
bool operator== (VerbToken const& o) const { return token_ == o.token_; }
bool operator!= (VerbToken const& o) const { return token_ != o.token_; }
};
#define VERB(RECEIVER, FUN) VERB_##FUN (&RECEIVER::FUN, STRINGIFY(FUN))
} // namespace lib
#endif /*LIB_VERB_VISITOR_H*/

View file

@ -160,8 +160,8 @@ namespace timeline {
BodyCanvasWidget::BodyCanvasWidget (DisplayManager& displayManager)
: Gtk::Box{Gtk::ORIENTATION_VERTICAL}
, contentArea_{}
, rulerCanvas_{std::function<Renderer&()>(), std::function<Renderer&()>()} ///////////TODO dummy placeholder factories.... need to build the real thing
, mainCanvas_{std::function<Renderer&()>(), std::function<Renderer&()>()}
, rulerCanvas_{std::function<Renderer&(CairoC)>(), std::function<Renderer&(CairoC)>()} ///////////TODO dummy placeholder factories.... need to build the real thing
, mainCanvas_{std::function<Renderer&(CairoC)>(), std::function<Renderer&(CairoC)>()}
, layout_{displayManager}
, profile_{}
, rootBody_{nullptr}

View file

@ -71,6 +71,8 @@
namespace stage {
namespace timeline {
using CairoC = Cairo::RefPtr<Cairo::Context> const&;
class DisplayManager;
class TrackBody;
class TimelineCanvas;
@ -87,7 +89,7 @@ namespace timeline {
class TimelineCanvas
: public Gtk::Layout
{
using _RenderFactory = std::function<Renderer&()>;
using _RenderFactory = std::function<Renderer&(CairoC)>;
_RenderFactory getGroundingRenderer_;
_RenderFactory getOverlayRenderer_;

View file

@ -118,7 +118,7 @@ namespace test{
/***********************************************************************//**
/**********************************************************************//**
* @test Demonstration/Concept: dispatch a specific function
* based on the given verbs of an embedded custom language.
* Actually what we want to achieve here is a specific form

View file

@ -0,0 +1,195 @@
/*
VerbVisitorDispatch(Test) - Setup to dispatch to arbitrary functions on a receiver interface
Copyright (C) Lumiera.org
2019, Hermann Vosseler <Ichthyostega@web.de>
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 verb-visitor-dispatch-test.cpp
** Demonstrate the extended concept of a _verb language_ based on double dispatch.
** @see body-canvas-widget.hpp
*/
#include "lib/test/run.hpp"
#include "lib/verb-visitor.hpp"
#include "lib/format-string.hpp"
#include "lib/format-cout.hpp"
#include <string>
#include <vector>
using std::string;
using util::_Fmt;
using std::vector;
namespace lib {
namespace test{
class Receiver
{
public:
virtual ~Receiver() { } ///< this is an interface
virtual string woof() =0;
virtual string honk() =0;
virtual string moo() =0;
virtual string meh() =0;
};
namespace {
const string BEGINNING("silence");
using Verb = VerbToken<Receiver, string(void)>;
using VerbSeq = vector<Verb>;
Verb VERB(Receiver, woof);
Verb VERB(Receiver, honk);
Verb VERB(Receiver, moo);
Verb VERB(Receiver, meh);
}
/**
* a receiver of verb-tokens,
* which renders them verbosely
*/
class VerboseRenderer
: public Receiver
{
string woof() { return "Woof-Woof!"; }
string honk() { return "Honk-Honk!"; }
string moo() { return "Moo-Moo!"; }
string meh() { return "Meh!"; }
};
/**
* Statefull receiver of verb-tokens.
*/
class RecollectingReceiver
: public Receiver
{
string verb_;
_Fmt fmt_;
string
buildResultTerm (string nextToken)
{
string resultExpression (fmt_ % verb_ % nextToken);
verb_ = nextToken;
return resultExpression;
}
string woof() { return buildResultTerm (VERB_woof); }
string honk() { return buildResultTerm (VERB_honk); }
string moo() { return buildResultTerm (VERB_moo); }
string meh() { return buildResultTerm (VERB_meh); }
public:
RecollectingReceiver()
: verb_(BEGINNING)
, fmt_("%s followed by %s")
{ }
};
/***********************************************************************//**
* @test Demonstration/Concept: dispatch a specific function
* based on the given verbs of an embedded custom language.
* Actually what we want to achieve here is a specific form
* of double dispatch; thus the implementation relies on a
* variation of the visitor pattern.
*
* @see DiffListApplication_test
*/
class VerbVisitorDispatch_test : public Test
{
virtual void
run (Arg)
{
VerbSeq tokens = build_test_feed();
render_verbose (tokens);
verify_dispatch (tokens);
}
/** prepare a sequence of verbs
* for the actual tests to work on */
VerbSeq
build_test_feed()
{
return {
VERB_woof,
VERB_honk,
VERB_moo,
VERB_meh
};
}
/** @test demonstrate the dispatching
* based on the concrete verb token.
* Here the implementation just prints
* the name of the invoked verb
*/
void
render_verbose (VerbSeq tokens)
{
VerboseRenderer receiver;
for (Verb verb : tokens)
cout << "consuming " << verb
<< " -> '"
<< verb.applyTo(receiver)
<< "'\n";
}
/** @test verify the correct individual dispatch
* through a computation specific for the given verb
*/
void
verify_dispatch (VerbSeq tokens)
{
RecollectingReceiver receiver;
string previous = BEGINNING;
for (Verb verb : tokens)
{
CHECK (previous+" followed by "+string(verb) == verb.applyTo(receiver));
previous = string(verb);
}
}
};
/** Register this test class... */
LAUNCHER (VerbVisitorDispatch_test, "unit common");
}} // namespace lib::test

View file

@ -19578,7 +19578,7 @@
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1555080572765" ID="ID_577805455" MODIFIED="1555080639983" TEXT="im Detail etwas komplexer...">
<node CREATED="1555080572765" ID="ID_577805455" MODIFIED="1555198544043" TEXT="im Detail etwas komplexer...">
<richcontent TYPE="NOTE"><html>
<head>
@ -19599,6 +19599,7 @@
</body>
</html>
</richcontent>
<linktarget COLOR="#a9b4c1" DESTINATION="ID_577805455" ENDARROW="Default" ENDINCLINATION="146;-10;" ID="Arrow_ID_228489961" SOURCE="ID_447173098" STARTARROW="Default" STARTINCLINATION="110;0;"/>
</node>
</node>
</node>
@ -19608,6 +19609,83 @@
<node CREATED="1555082703199" ID="ID_81861736" MODIFIED="1555082709649" TEXT="oben f&#xfc;r den Time-Ruler"/>
<node CREATED="1555082710728" ID="ID_676334326" MODIFIED="1555082731805" TEXT="unten f&#xfc;r die Track-Struktur"/>
</node>
<node CREATED="1555198475915" ID="ID_216668392" MODIFIED="1555198483009" TEXT="Koordinieren der draw-Aktivit&#xe4;t">
<node CREATED="1555198484257" ID="ID_447173098" MODIFIED="1555198544043" TEXT="Problem: Aufteilung">
<arrowlink DESTINATION="ID_577805455" ENDARROW="Default" ENDINCLINATION="146;-10;" ID="Arrow_ID_228489961" STARTARROW="Default" STARTINCLINATION="110;0;"/>
<node CREATED="1555198495266" ID="ID_118142711" MODIFIED="1555198505789" TEXT="was kommt in den (immer sichtbaren) oberen Teil?"/>
<node CREATED="1555198558887" ID="ID_1718337163" MODIFIED="1555198578064" TEXT="Beide Canvas-Instanzen verwenden das gleiche Koordinatensystem">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1555198633466" ID="ID_780787053" MODIFIED="1555198646314" TEXT="Auf Interpretieren des Struktur-Profils zur&#xfc;ckgef&#xfc;hrt">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247298877" ID="ID_1739468610" MODIFIED="1555247319224" TEXT="das mu&#xdf; dann aber verallgemeinert wertden">
<icon BUILTIN="yes"/>
<node CREATED="1555247361420" ID="ID_1263829263" MODIFIED="1555247495149" TEXT="warum?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
weil Verallgemeinern einer einzigen Aktion
</p>
<p>
stets besser ist, als repetitives aufdoppeln und variieren
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1555247377809" ID="ID_281745763" MODIFIED="1555247439373" TEXT="Erwartete Anforderungen...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<ul>
<li>
content renderer
</li>
<li>
vom speziellen Track abh&#228;ngige Bereichsmarkierungen
</li>
<li>
lokale und spezielle Overlays sind zu zeichnen
</li>
</ul>
</body>
</html>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247320686" ID="ID_1896093043" MODIFIED="1555247351638" TEXT="brauche Visitor mit flexiblen Argumenten">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1555247502178" ID="ID_297247554" MODIFIED="1555247730526" TEXT="Anforderung">
<icon BUILTIN="yes"/>
<node CREATED="1555247509182" ID="ID_184476156" MODIFIED="1555247526066" TEXT="funktioniert genauso wie Visitor im Diff, mit Verb-Tokens"/>
<node CREATED="1555247526934" ID="ID_679986589" MODIFIED="1555247540296" TEXT="aber jedes Verb nimmt andere Argumente"/>
<node CREATED="1555247545556" ID="ID_425297916" MODIFIED="1555247558405" TEXT="brauche in-Place Storage (wie ein union)"/>
<node CREATED="1555247559370" ID="ID_1379389656" MODIFIED="1555247576787" TEXT="soll insgesamt typsicher bleiben"/>
<node CREATED="1555247580247" ID="ID_54654021" MODIFIED="1555247599368" TEXT="aber nur 2 Indirektionen (double dispatch)"/>
</node>
<node CREATED="1555247609372" ID="ID_984933888" MODIFIED="1555247727312" TEXT="Konzept/Ansatz">
<icon BUILTIN="idea"/>
<node CREATED="1555247614626" ID="ID_279811814" MODIFIED="1555247631405" TEXT="das Verb-Token mit einem Union-Argument verwenden"/>
<node CREATED="1555247635823" ID="ID_893471557" MODIFIED="1555247654952" TEXT="und dieses Setup in einen Adapter / Builder verpacken"/>
<node CREATED="1555247665396" ID="ID_1210108422" MODIFIED="1555247677598" TEXT="vermutlich werden Lambdas eine Rolle spielen"/>
<node CREATED="1555247678988" ID="ID_1615700205" MODIFIED="1555247695891" TEXT="aber ich m&#xf6;chte Heap-Storage vermeiden"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247704342" ID="ID_929740643" MODIFIED="1555247723589" TEXT="Entwurf/Test">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247713060" ID="ID_1159666241" MODIFIED="1555247718108" TEXT="proof-of-concept">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1555247744121" ID="ID_1280520595" MODIFIED="1555247751428" TEXT="ausgehend von Kopie des VerbToken"/>
<node CREATED="1555247757037" ID="ID_1249615365" MODIFIED="1555247774360" TEXT="(optional) vielleicht letztlich in eine L&#xf6;sung verschmelzen?"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1555084648375" ID="ID_483631091" MODIFIED="1555084698950" TEXT="organisiert das Struktur-Profil">
<arrowlink COLOR="#2e66db" DESTINATION="ID_1659558780" ENDARROW="Default" ENDINCLINATION="-889;0;" ID="Arrow_ID_1691760775" STARTARROW="None" STARTINCLINATION="828;0;"/>
</node>
@ -19842,7 +19920,7 @@
</node>
</node>
<node CREATED="1554480402297" ID="ID_1456965488" MODIFIED="1554480404805" TEXT="wie?">
<node CREATED="1542388995969" ID="ID_343346390" MODIFIED="1542389006282" TEXT="konkreter Ablauf">
<node CREATED="1542388995969" ID="ID_343346390" MODIFIED="1555197135775" TEXT="Ablauf-Plan">
<icon BUILTIN="idea"/>
<node CREATED="1542389054873" ID="ID_1270989660" MODIFIED="1542389072647" TEXT="Ausl&#xf6;ser: draw-Signal an Canvas">
<icon BUILTIN="full-1"/>