ViewSpec: decide how to cast the types for building the DSL

we'll use a typedef to represent the default case
and provide the level within the UI-Tree as template parameter for the generic case

This avoids wrapping each definition into a builder function, which will be
the same function for 99% of the cases, and it looks rather compact and natural
for the default case, while still retaining genericity.

Another alternative would have been to inject the Tree-level at the invocation;
but doing so feels more like magic for me.
This commit is contained in:
Fischlurch 2018-02-24 04:25:41 +01:00
parent 41b8d12b66
commit 69f87e994c
3 changed files with 224 additions and 22 deletions

View file

@ -121,7 +121,7 @@ namespace interact {
* It takes a _viewID_ as argument, which actually is more of a typeID to designate
* the kind of view or UI widget, which shall be attached at or retrieved from the
* location resolved through the LocationRule. The latter is essentially what is
* embedded within the Locator functor
* embedded within the Locator functor.
*/
using Locator = std::function<UICoord(Literal)>;
@ -130,32 +130,41 @@ namespace interact {
* A specification to describe the desired location of a component view within the Lumiera UI.
* ViewSpec is basically a set of [UI coordinates](\ref UICoord), with the additional possibility
* of specifying several alternatives, with the intention to pick the first applicable one.
*
* @todo initial draft as of 9/2017
* @tparam depth the level in the tree addressed by this locator
* @remarks Locator is build from a DSL expression, which is basically a UICoord::Builder.
* This coordinate spec describes a sequence of several places where to locate
* the UI-Element in question. The template parameter clarifies if we're talking
* about windows here, or panels or views. The latter is the [default case](\ref ViewSpec).
*/
class ViewSpec
template<size_t depth>
class LocatorSpec
: public Locator
{
public:
ViewSpec(UICoord coordinates)
LocatorSpec(UICoord coordinates)
: Locator([](Literal componentID) -> UICoord
{
UNIMPLEMENTED ("resolve a view spec to yield explicit UI coordinates");
})
{
UNIMPLEMENTED ("build a view spec from explicitly given UI coordinates");
}
/** shortcut to allow initialisation from UI-Coordinate builder expression */
ViewSpec(UICoord::Builder&& coordinates)
: ViewSpec{UICoord(std::move (coordinates))}
LocatorSpec(UICoord::Builder&& coordinates)
: LocatorSpec{UICoord(std::move (coordinates))}
{ }
UICoord
operator() (Literal componentID)
{
UNIMPLEMENTED ("resolve a view spec to yield explicit UI coordinates");
}
private:
};
/**
* A specification to describe the desired location of a component view within the Lumiera UI.
* ViewSpec is basically a set of [UI coordinates](\ref UICoord), with the additional possibility
* of specifying several alternatives, with the intention to pick the first applicable one.
*/
using ViewSpec = LocatorSpec<UIC_VIEW>;
/**
* Allocator is a functor to resolve a given, desired location of a view within the UI, resulting

View file

@ -2838,7 +2838,7 @@ Command instances are like prototypes -- thus each additional level of different
see the description in &amp;rarr; CommandSetup
</pre>
</div>
<div title="GuiComponentView" creator="Ichthyostega" modifier="Ichthyostega" created="201709021521" modified="201802160224" tags="def GuiPattern design" changecount="50">
<div title="GuiComponentView" creator="Ichthyostega" modifier="Ichthyostega" created="201709021521" modified="201802240154" tags="def GuiPattern design" changecount="51">
<pre>//A view within the UI, featuring some component of relevance to »the model«.//
While any UI is comprised of numerous widgets acting as //view of something,// only some of those views play the prominent role to act as //building block component// of the user interface.
Such UI component views exhibit some substantial traits
@ -2858,7 +2858,7 @@ Here, //Allocation// means
The classical example to verify this definition is the //allocation of viewers:// when starting playback of a new media item, we &quot;need a viewer&quot; to show it. But we can not just create yet another viewer window -- rather we're bound to allocate one of the possible &quot;viewer slots&quot;. In fact this is a configurable property of the UI layout employed; sometimes some people need the limitation to one single viewer entity (which might even be external, routed to a beamer or monitor), while other ones request the classical editor layout with two viewer windows side by side, while yet different working styles might exploit a limited set of viewers allocated in stack- or round-robin style.
!View access
The global access point to component views is the {{{ViewLocator}}} within InteractionDirector, which exposes a generic access- and management API to
The global access point to component views is the ViewLocator within InteractionDirector, which exposes a generic access- and management API to
* get (possibly create) some view of given type
* get (possibly create) a view with specific identity
* destroy a specific view
@ -3730,7 +3730,7 @@ Especially the focus navigation entails the use of some kind of ubiquitous [[coo
</pre>
</div>
<div title="InteractionDirector" creator="Ichthyostega" modifier="Ichthyostega" created="201702102146" modified="201801132336" tags="def design GuiPattern" changecount="27">
<div title="InteractionDirector" creator="Ichthyostega" modifier="Ichthyostega" created="201702102146" modified="201802240129" tags="def design GuiPattern" changecount="28">
<pre>//the top-level controller within the UI.//
In Lumiera, the structures of the model within the [[Session]] (the so called HighLevelModel) are mapped onto corresponding [[tangible UI entities|UI-Element]], which serve as a front-end to represent those entities towards the user. Within this model, there is a //conceptual root node// -- which logically corresponds to the session itself. This [[root element in model|ModelRootMO]] links together the actual top-level entities, which are the (multiple) timelines, together with the asset management and defaults and rules configuration within the session.
@ -3752,6 +3752,7 @@ The InteractionDirector is part of the model, and thus we have to distinguish be
:* the SpotLocator is what is &quot;moved&quot; when the [[Spot]] of current activity moves
:* the FocusTracker is responsible for //detecting changes in current selection and focus.//
:* the [[Navigator]] is a special controller to handle moving the SpotLocator within the UI tree topology
:* the ViewLocator serves for any kind of high-level, abstracted access to [[component views|GuiComponentView]] and location resolution.
!Collaborations
* several global actions are exposed here, like opening the session and creating a new timeline.&lt;br/&gt;Such operations are typically bound into menu and action buttons, and in turn invoke [[commands|CommandHandling]] into the Session
@ -4288,7 +4289,7 @@ The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangibl
In the case at hand, the basic building block of the Lumiera UI, the {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying a concrete diff sequence embedded in the message with the help of a {{{DiffApplicator&lt;DiffMutable&gt;}}}, based on the TreeMutator exposed.</pre>
</div>
<div title="Navigator" creator="Ichthyostega" modifier="Ichthyostega" created="201710132354" modified="201712170155" tags="spec decision draft GuiPattern" changecount="21">
<div title="Navigator" creator="Ichthyostega" modifier="Ichthyostega" created="201710132354" modified="201802240130" tags="spec decision draft GuiPattern" changecount="23">
<pre>//Service to navigate through the UI as generic structure.//
The Navigator is a component maintained by the InteractionDirector, and the actual implementation is backed by several facilities of the GuiTopLevel. It serves as foundation to treat the UI as a topological network of abstracted locations, represented as [[UI-Coordinates|UICoord]]. This design, together with the UI-Bus helps to reduce coupling within the UI implementation, since it enables to //get somewhere// and reach //some place// -- without the necessity to rely on concrete widget implementation structure.
@ -4312,6 +4313,10 @@ In the current situation ({{red{10/2017}}}), before engaging into the actual imp
:* or to get //just some instance// of a view identified by type
;WorkSite navication
:move the Spot to some other place in the UI known by its [[UI-Coordinates|UICoord]]
!!!{{red{Update 2/2018:}}} changed responsibilities
Elaboration on the topic of »View Allocation« caused some minor architectural rearrangements.
* Navigator became a pure information service (read-only), working on an abstracted view of the UI through [[UI coordinates|UICoord]]
* the ViewLocator became service point for any high-level access to GuiComponentView elements
!!!Requirements clarified
From these use cases we conclude that the actual requirements for a Navigator component are less than one might expect.
@ -9846,6 +9851,14 @@ Establishing a ~ViewConnection is prerequisite for creating or attaching an Play
View connections are part of the model and thus persistent. They can be created explicitly, or just derived by //allocating a viewer.// And a new view connection can push aside (and thus &quot;break&quot;) an existing one from another timeline or model element. When a view connection is //broken,// any associated PlayProcess needs to be terminated (this is a blocking operation). Thus, at any time, there can be only one active view connection to a given viewer or output sink; here &quot;active&quot; means, that a PlayController has been hooked up, and the connection is ready for playback or rendering. But on the other hand, nothing prevents a timeline (or similar model object) to maintain multiple view connections -- consequently the actual playback position behaves as if associated with the view connection; it has only meaning with respect to this specific connection. An obvious example is that you may play back, without interfering with an ongoing render.
</pre>
</div>
<div title="ViewLocator" creator="Ichthyostega" modifier="Ichthyostega" created="201802240138" modified="201802240150" tags="spec decision draft GuiPattern" changecount="6">
<pre>//access and location of [[component views|GuiComponentView]] as abstracted from actual UI widgets.//
The ViewLocator is a close sibling and mutually interdependent with the [[Navigator]] -- the primary difference being the uniform, completely symbolic representation by [[UI-tree topology|UICoord]], as exposed through the latter, which precludes //immediate manipulation.// The ViewLocator likewise presents an abstracted view, but oriented towards individual components, which it allows to locate, allocate and expose by direct reference as UI-Element.
!Rules based handling by kind-of-view
A small selection of //relevant UI elements// can in fact be located &quot;by-type&quot;, relying on a configuration in the form of //locating rules...// &amp;rarr; elaborated in more detail [[here|GuiComponentView]].
This access mechanism allows to act on &quot;the primary one of that kind&quot;, possibly creating a new instance on demand -- such UI elements are not to be confused with the model entities they expose for user interaction; typically they can either be re-linked or re-bound to a specific entity, or they are able to handle multiple model connections in separate tabs within the view (e.g. several [[Timelines|GuiTimelineView]]).</pre>
</div>
<div title="ViewerAsset" modifier="Ichthyostega" created="201105230116" modified="201105232228" tags="Model spec">
<pre>A [[structural Asset|StructAsset]] corresponding to a Viewer element in the GUI.

View file

@ -10223,13 +10223,193 @@
<node CREATED="1519358000671" ID="ID_49826255" MODIFIED="1519358015345" TEXT="Aufruf mit Typ-ID-Argument"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1519358138988" ID="ID_1481930885" MODIFIED="1519358147156" TEXT="Problem: DSL-Mechanik">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1519358138988" ID="ID_1481930885" MODIFIED="1519442424308" TEXT="DSL-Mechanik">
<icon BUILTIN="pencil"/>
<node CREATED="1519358154386" ID="ID_1810798001" MODIFIED="1519358201550" TEXT="Allocator wird durch Zuweisen der AlocSpec generiert">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1519358178623" ID="ID_517547970" MODIFIED="1519358197549" TEXT="beim Locator fehlt ein entsprechendes Gegenst&#xfc;ck">
<icon BUILTIN="flag-pink"/>
<node CREATED="1519358178623" ID="ID_517547970" MODIFIED="1519442398323" TEXT="beim Locator fehlt ein entsprechendes Gegenst&#xfc;ck">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1519359156410" ID="ID_1786241256" MODIFIED="1519359162713" TEXT="Idee">
<icon BUILTIN="idea"/>
<node CREATED="1519359176855" ID="ID_853060191" MODIFIED="1519359192777">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
der <i>Level</i>&#160;im UI ist noch offen
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1519359193821" ID="ID_588596170" MODIFIED="1519359234665" STYLE="fork" TEXT="das k&#xf6;nnte Argument eines Builders sein"/>
<node CREATED="1519359239735" ID="ID_988890391" MODIFIED="1519442391464" TEXT="konkret......">
<node CREATED="1519438604809" ID="ID_313142617" MODIFIED="1519438615852" TEXT="L&#xf6;sevorgang mu&#xdf; den Ziel-Level kennen"/>
<node CREATED="1519438617271" ID="ID_1310079168" MODIFIED="1519438673926">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<i>fast immer</i>&#160;ist das aber UIC_VIEW
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
im Moment f&#228;llt mir &#252;berhaupt keine Ausnahme ein
</p>
<p>
aber man soll niemals nie sagen;
</p>
<p>
</p>
<p>
jedenfalls ist der LocationSolver komplett generisch geschrieben,
</p>
<p>
w&#228;re ja auch d&#228;mlich, den auf einen Level festzunageln
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1519439848624" ID="ID_1356890401" MODIFIED="1519440019400">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
kann man den Level <i>erschlie&#223;en?</i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="button_cancel"/>
<node CREATED="1519439872572" ID="ID_1387780581" MODIFIED="1519439914138" TEXT="fast, aber leider nein">
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1519439893089" ID="ID_350245814" MODIFIED="1519440011427" TEXT="nicht wenn alle Pattern gleich lang sind">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
es ist nicht klar, ob die pattern bereits das fragliche View-Element mit einschlie&#223;en,
</p>
<p>
oder ob das View-Element noch angeh&#228;ngt werden soll. Diese Variation ist essentiell,
</p>
<p>
um Regeln auszudr&#252;cken, die explizit nur eine schon existierende UI-Komponente greifen
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="info"/>
</node>
</node>
<node CREATED="1519440039302" ID="ID_779685706" MODIFIED="1519442729591" TEXT="folglich...">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1519440044629" ID="ID_433141744" MODIFIED="1519442714991" TEXT="mu&#xdf; der Level entweder aus der DSL kommen">
<icon BUILTIN="button_cancel"/>
</node>
<node CREATED="1519440054651" ID="ID_1512334426" MODIFIED="1519442712213" TEXT="oder er mu&#xdf; &#xfc;ber den Typ gecodet sein">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1519442682549" ID="ID_1285145089" MODIFIED="1519442708878" TEXT="oder explizit beim Aufruf mitgegeben">
<icon BUILTIN="button_cancel"/>
</node>
</node>
</node>
</node>
<node CREATED="1519437341366" ID="ID_1400629217" MODIFIED="1519437344737" TEXT="Alternativen">
<node CREATED="1519437362523" ID="ID_1967120024" MODIFIED="1519440122737" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
auto locate = matchView(
</p>
<p>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;panel(&quot;blah&quot;)
</p>
<p>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;or currentWindow().panel(&quot;blubb&quot;).create() )
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="button_cancel"/>
</node>
<node CREATED="1519437509655" ID="ID_241024117" MODIFIED="1519442360056" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
LocatorSpec&lt;UIC_VIEW&gt; locate = panel(&quot;blah&quot;)
</p>
<p>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;or currentWindow().panel(&quot;blubb&quot;).create()
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1519437756333" ID="ID_565391583" MODIFIED="1519440134474" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
ViewSpec locate = panel(&quot;blah&quot;)
</p>
<p>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;or currentWindow().panel(&quot;blubb&quot;).create()
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1519440138712" ID="ID_861550710" MODIFIED="1519440299158" TEXT="Entscheidung">
<icon BUILTIN="yes"/>
<node CREATED="1519440157310" ID="ID_1912054433" MODIFIED="1519440166344" TEXT="ziehe die letzte Variante als Standard-Fall vor">
<node CREATED="1519440168660" ID="ID_1954754744" MODIFIED="1519440288338" TEXT="weil sie am unscheinbarsten ist">
<icon BUILTIN="ksmiletris"/>
</node>
<node CREATED="1519440271318" ID="ID_436275698" MODIFIED="1519440283871" TEXT="auch wenn dadurch die Definitionen etwas schief werden">
<icon BUILTIN="smily_bad"/>
</node>
</node>
<node CREATED="1519440180978" ID="ID_42017722" MODIFIED="1519440194012" TEXT="die vorletzte Variante ist die eigentliche Definition">
<node CREATED="1519440198016" ID="ID_650838793" MODIFIED="1519440207306" TEXT="und ViewSpec ein Typ-Alias"/>
<node CREATED="1519440208487" ID="ID_1465224504" MODIFIED="1519440222184" TEXT="analog f&#xfc;r PanelSpec, WindowSpec"/>
</node>
<node CREATED="1519440250849" ID="ID_800018525" MODIFIED="1519440267084" TEXT="die Asymetrie in der DSL-Definition nehme ich in Kauf">
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node CREATED="1519355735012" ID="ID_241646491" MODIFIED="1519355793090" TEXT="wo entsteht die LocationRule?">