Timeline: now settle the drawing code with the insights gained thus far

Especially note the tricks we need to play in order to allow for (limited) usage of CSS3 box-shadows.
The reason is, all these CSS3 effects are rendered in one shot and combinend on the StyleContext::render_background() call
Thus we need to ensure that the background is properly aligned with the frames
This commit is contained in:
Fischlurch 2019-08-23 03:04:22 +02:00
parent fc5eaf857c
commit 346b5ae769
3 changed files with 134 additions and 45 deletions

View file

@ -119,15 +119,14 @@ namespace timeline {
int line_ = 0;
void
fillBackground (int height)
fillBackground (StyleC& style, int height)
{
style_->render_background (cox_
,visible_.b // left start of the rectangle
,line_ // top of the rectangle
,visible_.delta() // width of the area
,height // height to fill
);
line_ += height;
style->render_background (cox_
,visible_.b // left start of the rectangle
,line_ // top of the rectangle
,visible_.delta() // width of the area
,height // height to fill
);
}
public:
@ -144,12 +143,12 @@ namespace timeline {
: public AbstractTrackRenderer
{
/** paint the top of the track body area */
/** create spacing at the top of the track body area */
void
prelude() override
{
int topMargin = style_->get_margin().get_top();
fillBackground (topMargin);
line_ += topMargin;
}
/** finish painting the track body area
@ -158,45 +157,53 @@ namespace timeline {
coda (uint pad) override
{
int bottomPad = pad + style_->get_margin().get_bottom();
fillBackground (bottomPad);
line_ += bottomPad;
}
/** draw grounding of an overview/ruler track
* with the given height */
void
ruler (uint h) override
ruler (uint contentHeight) override
{
int marTop = styleR_->get_margin().get_top();
int marBot = styleR_->get_margin().get_bottom();
int padTop = styleR_->get_padding().get_top();
int padBot = styleR_->get_padding().get_bottom();
int frameT = styleR_->get_border().get_top();
int frameB = styleR_->get_border().get_bottom();
int heightWithFrame = contentHeight + padTop+padBot + frameT+frameB;
line_ += marTop;
fillBackground(styleR_, heightWithFrame);
styleR_->render_frame (cox_
,visible_.b
+20 ////////////////////////////////////////TODO: visual debugging
,line_
,visible_.delta()
,h + frameT + frameB
,heightWithFrame
);
styleR_->render_background (cox_
,visible_.b // Left Start Of The Rectangle
,line_+frameT // Top Of The Rectangle
,visible_.delta() // Width Of The Area
,h // Height To Fill
);
line_ += h + frameT + frameB;
line_ += heightWithFrame;
line_ += marBot;
}
/** render additional padding/gap */
/** insert additional padding/gap (typically below a ruler) */
void
gap (uint h) override
{
fillBackground (h);
line_ += h;
}
/** fill background of track content area
* with the given vertical extension */
void
content (uint h) override
content (uint contentHeight) override
{
fillBackground (h);
int padTop = style_->get_padding().get_top();
int padBot = style_->get_padding().get_bottom();
int heightWithPadding = contentHeight + padTop+padBot;
fillBackground (style_, heightWithPadding);
line_ += heightWithPadding;
}
/** paint opening slope to enter nested sub tracks
@ -204,14 +211,21 @@ namespace timeline {
void
open() override
{
// style_->context_save(); // <<<---does not work. Asked on SO: https://stackoverflow.com/q/57342478
style_->add_class (slopeClassName (1));
int slopeWidth = style_->get_border().get_top();
style_->render_frame (cox_
,visible_.b // left start of the rectangle
,line_ // top of the rectangle
,visible_.delta() // width of the area
,2*slopeWidth // height to fill
style_->render_frame_gap(cox_
,visible_.b
+25 ////////////////////////////////////////TODO: visual debugging
,line_
,visible_.delta()
,2*slopeWidth
//_______________________________we only need the top side of the frame
,Gtk::PositionType::POS_BOTTOM
,visible_.b
,visible_.e
);
// style_->context_restore(); // <<<---does not work...
style_->remove_class (slopeClassName(1));
line_ += slopeWidth;
}
@ -223,23 +237,22 @@ namespace timeline {
{
// style_->context_save(); // <<<---does not work. Asked on SO: https://stackoverflow.com/q/57342478
style_->add_class (slopeClassName(n));
style_->invalidate();
int slopeWidth = style_->get_border().get_bottom();
INFO(stage, "n=%d class=%s -->slopeWidth=%d", n, util::cStr(slopeClassName(n)), slopeWidth);
line_ -= slopeWidth; // set back to create room for the (invisible) top side of the frame
style_->render_frame_gap(cox_
,visible_.b
+20 ////////////////////////////////////////TODO: visual debugging
+30 ////////////////////////////////////////TODO: visual debugging
,line_
,visible_.delta()
,slopeWidth
* 5 ////////////////////////////////////////TODO: visual debugging
,2*slopeWidth
//_______________________________we only need the bottom side of the frame
,Gtk::PositionType::POS_TOP
,visible_.b
,visible_.e
);
// style_->context_restore(); // <<<---does not work...
style_->remove_class (slopeClassName(n));
line_ += slopeWidth;
line_ += 2*slopeWidth;
}
public:

View file

@ -3524,7 +3524,7 @@ In accordance with the Lumiera application architecture in general, the UI is no
<pre>A specially configured LumieraPlugin, which actually contains or loads the complete code of the (GTK)GUI, and additionally is linked dynamically against the application core lib. During the [[UI startup process|GuiStart]], loading of this Plugin is triggered from {{{main()}}}. Actually this causes spawning of the GTK event thread and execution of the GTK main loop.
</pre>
</div>
<div title="GuiTimelineDraw" creator="Ichthyostega" modifier="Ichthyostega" created="201904052156" modified="201908211521" tags="GuiPattern spec impl img draft" changecount="100">
<div title="GuiTimelineDraw" creator="Ichthyostega" modifier="Ichthyostega" created="201904052156" modified="201908230100" tags="GuiPattern spec impl img draft" changecount="103">
<pre>The presentation of the track body area relies on the [[Gtk::Layout &quot;canvas widget&quot;|GtkLayoutWidget]], thus allowing for a mixture of custom drawing with embedded custom Gtk widgets. The actual drawing routine is activated in response to the {{{on_draw}}} signal -- and invoking the inherited handler function will initiate the standard drawing for the embedded child widgets. This partitions the additional, specific drawing activities into a pre-widget drawing phase to prepare the background and framework structure of the track area, and a post-widget drawing phase to show all kinds of overlays, markers cursors and similar UI indicators. A nested structure of {{{TrackBody}}} objects serves as organisational device to structure these custom drawing activities in accordance with the nested structure of the track fork.
!Building a nested 3D structure
@ -3553,7 +3553,7 @@ Once the fundamental decision towards a 3D structure is taken, there still is so
* shading can indicate a //slope// up or down.
An immediate consequence to draw from this observation is that ~CSS3 effects are only of limited use for this purpose. They are more helpful to highlight compact and local structures, like a menu button, or some element or handle on the clips. We can (and likely will) use CSS shading for the [[track overview rulers|TrackRuler]] though. We possibly could use a slight inset box shadow within the actual track content area. However, it is rather pointless to use a box shadow to paint the nested track scope insets -- we rather need to rely on gradients and direct colour shading for that purpose.
Another consequence is that we do not need to apply an overall &quot;stacked boxes&quot; approach -- there is not much to gain from doing so (and we would do a lot of unnecessary filling operations, most of which will actually clipped away). For that reason, we define our ''track profile'' to represent a vertical //top-down drawing sweep.// Non the less, the actual colours and shades can be defined completely through CSS rules. To achieve this, we apply some tricks
Another consequence is that we do not need to apply an overall &quot;stacked boxes&quot; approach -- there is not much to gain from doing so (and we would do a lot of unnecessary filling operations, most of which will actually be clipped away). For that reason, we define our ''track profile'' to represent a vertical //top-down drawing sweep.// Non the less, the actual colours and shades can be defined completely through CSS rules. To achieve this, we apply some tricks
* we define //virtual widgets,// which are only used to match against selectors and pick up the attached CSS styles
** the virtual element {{{fork}}} represents &quot;a timeline track&quot;
** and a virtual {{{frame}}} element nested therein represents &quot;a ruler on top of a timeline track&quot;
@ -3564,11 +3564,18 @@ Another consequence is that we do not need to apply an overall &quot;stacked bo
*:* a {{{margin}}} at top will add additional space between consecutive tracks
*:* while the {{{padding}}} will be used within the track content area -- &lt;br/&gt; of course only in vertical direction, since the horizontal extension is ruled by the time position of elements within the track
*:* please note that {{{background}}} stylings apply to the //content area// and not the track space at a whole.
*:* especially a {{{box shadow}}} will be drawn when filling the background of the content area -- however, only an {{{inset}}} makes sense here,&lt;br/&gt;since a regular (outer) box shadow will be covered by consecutive drawing actions...
*;track ruler
*:attach rules to the selector{{{fork.timeline__fork frame.timeline__ruler}}}
*:* again the {{{border top}}} and {{{border bottom}}} settings will delimit the ruler form the other track content
*:* while {{{margin}}} and {{{padding}}} apply as usual outside and within the border
*:* here the {{{box shadow}}} will be drawn with the background -- however, only an {{{inset}}} makes sense here,&lt;br/&gt;since a regular (outer) box shadow will be covered by consecutive drawing actions, unless it sticks within the limits of the {{{margin}}}
*:* here the {{{box shadow}}} will be drawn with the background and aligned with the frame -- and again, only an {{{inset}}} really makes sense,&lt;br/&gt;while a regular (outer) box shadow must be small enough to stick within the limits of the {{{margin}}}
*;slopes
*:we use several classes to define the effect of consecutive nested frames forming a common slope; however, we perform this combination effect only 5 steps deep
*:* we use class {{{.track-slope--deep1}}} for a simple slope (inset by one nested level)
*:* class {{{.track-slope--deep2}}} for two consecutive nested steps combined. Note this only ever happens on closing (upward) slopes
*:* likewise class {{{.track-slope--deep3}}} for three and class {{{.track-slope--deep4}}} for four combined slopes
*:* finally, class {{{.track-slope--verydeep}}} is used for five and more combined upward (closing) slopes
Please note also that our drawing code operates in several ''passes''. First, a ''background'' pass is used to fill the area, then GTK is invoked recursively for any widgets on the dawing canvas, most notably the ''clips''. Then, a final ''overlay'' pass allows to paint range markers, selections and indicators on top.
</pre>

View file

@ -21912,6 +21912,9 @@
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1566406763774" ID="ID_764785834" MODIFIED="1566406772229" TEXT="verwende bisher Platzhalter-Konstanten">
<icon BUILTIN="flag-pink"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1566518895896" ID="ID_1389016008" MODIFIED="1566518921254" TEXT="Achtung: Margin+Padding gem&#xe4;&#xdf; Stylesheet mit ber&#xfc;cksichtigen">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1566406773325" ID="ID_1516897126" MODIFIED="1566406830389" TEXT="soll einmal aus dem systematischen UI-Modell bzw Session-Modell kommen">
<arrowlink COLOR="#5287c5" DESTINATION="ID_43593052" ENDARROW="Default" ENDINCLINATION="-197;439;" ID="Arrow_ID_350259030" STARTARROW="None" STARTINCLINATION="-244;0;"/>
<icon BUILTIN="bell"/>
@ -22723,7 +22726,11 @@
<node COLOR="#338800" CREATED="1554516928332" ID="ID_874621550" MODIFIED="1557498707230" TEXT="Verben definieren">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1554571992025" ID="ID_1074099376" MODIFIED="1557498707230" TEXT="Anwendung der Verben"/>
<node COLOR="#338800" CREATED="1554571992025" FOLDED="true" ID="ID_1074099376" MODIFIED="1566517833423" TEXT="Anwendung der Verben">
<icon BUILTIN="button_ok"/>
<node CREATED="1566517815129" ID="ID_914599141" MODIFIED="1566517824939" TEXT="Funktionsaufruf via VTable"/>
<node CREATED="1566517825863" ID="ID_1111586723" MODIFIED="1566517831729" TEXT="Argumente aus embedded Tuple"/>
</node>
<node COLOR="#338800" CREATED="1554516938851" ID="ID_1733864099" MODIFIED="1557498707230" TEXT="Verb-Sequenz speichern">
<icon BUILTIN="button_ok"/>
</node>
@ -22750,7 +22757,25 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1554517013770" ID="ID_1565362810" MODIFIED="1557498707230" TEXT="Verb-Sequenz konsolidieren"/>
<node CREATED="1554517013770" ID="ID_1565362810" MODIFIED="1557498707230" TEXT="Verb-Sequenz konsolidieren">
<node CREATED="1566517520897" ID="ID_1585833997" MODIFIED="1566517533715" TEXT="nur beim abschlie&#xdf;enden Slope"/>
<node CREATED="1566517544022" ID="ID_1083102048" MODIFIED="1566517598107" TEXT="f&#xfc;gt dem jeweils letzten hinzu">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...anstatt f&#252;r jeden schlie&#223;enden nested scope noch ein weiteres Verb hinzuzuf&#252;gen.
</p>
<p>
Damit werden effektiv die &quot;schlie&#223;enden Klammern&quot; in eine einzige zusammengefa&#223;t
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1554517023983" ID="ID_582840262" MODIFIED="1557498707230" TEXT="Verb-Sequenz interpretieren">
<node CREATED="1554517097141" ID="ID_1017084418" MODIFIED="1563118296821" TEXT="&#xdc;bersichts-Ruler handhaben">
<linktarget COLOR="#44437f" DESTINATION="ID_1017084418" ENDARROW="Default" ENDINCLINATION="1682;-201;" ID="Arrow_ID_187242024" SOURCE="ID_1267787629" STARTARROW="None" STARTINCLINATION="1913;158;"/>
@ -22890,6 +22915,23 @@
<node CREATED="1566401506391" ID="ID_116486175" MODIFIED="1566401506391" TEXT="BodyCanvasWidget::maybeRebuildLayout()"/>
<node COLOR="#338800" CREATED="1566401515511" ID="ID_1551253495" MODIFIED="1566406332332" TEXT="neue Funktion hierf&#xfc;r">
<icon BUILTIN="button_ok"/>
<node CREATED="1566517643320" ID="ID_30150585" MODIFIED="1566517660194" TEXT="fragt den TrackBody"/>
<node CREATED="1566517661707" ID="ID_1225415802" MODIFIED="1566517709271" TEXT="dieser summiert im Moment einfach nochmal">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
ist ineffizient, aber der Code ist so klarer
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1566517682169" ID="ID_1110086285" MODIFIED="1566517691543" TEXT="...so oft wird das nicht gebraucht">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
@ -23090,6 +23132,10 @@
<node CREATED="1563112611511" ID="ID_1116374684" MODIFIED="1563112636155" TEXT="man kann sich Margin/Padding besorgen">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1566518952575" ID="ID_183446100" MODIFIED="1566519139547" TEXT="mu&#xdf; die sinngem&#xe4;&#xdf; mit den vom TrackBody verwalteten Spannen verrechnen">
<arrowlink COLOR="#779be7" DESTINATION="ID_35592741" ENDARROW="Default" ENDINCLINATION="109;-329;" ID="Arrow_ID_66200016" STARTARROW="None" STARTINCLINATION="479;0;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node CREATED="1563636831797" ID="ID_506277754" MODIFIED="1563636834809" TEXT="Rahmen">
@ -23155,7 +23201,7 @@
</html></richcontent>
</node>
</node>
<node COLOR="#435e98" CREATED="1564932484393" ID="ID_1092949064" MODIFIED="1566401015548">
<node COLOR="#435e98" CREATED="1564932484393" ID="ID_1092949064" MODIFIED="1566519094002">
<richcontent TYPE="NODE"><html>
<head>
@ -23167,7 +23213,8 @@
</body>
</html>
</richcontent>
<arrowlink COLOR="#02ab84" DESTINATION="ID_840104433" ENDARROW="Default" ENDINCLINATION="1028;-57;" ID="Arrow_ID_77023730" STARTARROW="None" STARTINCLINATION="106;39;"/>
<arrowlink COLOR="#02ab84" DESTINATION="ID_840104433" ENDARROW="Default" ENDINCLINATION="1035;-107;" ID="Arrow_ID_77023730" STARTARROW="Default" STARTINCLINATION="106;39;"/>
<linktarget COLOR="#2b75cc" DESTINATION="ID_1092949064" ENDARROW="Default" ENDINCLINATION="286;83;" ID="Arrow_ID_1686979270" SOURCE="ID_57629359" STARTARROW="None" STARTINCLINATION="572;0;"/>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="yes"/>
<node CREATED="1566401020977" ID="ID_1373829097" MODIFIED="1566401070383" TEXT="siehe Definition im TiddlyWiki (&quot;#GuiTimelineDraw&quot;)"/>
@ -23459,8 +23506,16 @@
<arrowlink COLOR="#2ee773" DESTINATION="ID_1183787016" ENDARROW="Default" ENDINCLINATION="278;16;" ID="Arrow_ID_1462879108" STARTARROW="None" STARTINCLINATION="344;0;"/>
</node>
</node>
<node CREATED="1563636771101" ID="ID_273130535" MODIFIED="1564610460909" TEXT="kann die Rahmenst&#xe4;rke nicht manipulieren">
<node COLOR="#435e98" CREATED="1563636771101" ID="ID_273130535" MODIFIED="1566518058000" TEXT="kann die Rahmenst&#xe4;rke nicht manipulieren">
<arrowlink COLOR="#cb487a" DESTINATION="ID_155787836" ENDARROW="Default" ENDINCLINATION="86;-182;" ID="Arrow_ID_1682426231" STARTARROW="None" STARTINCLINATION="187;-5;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1566517976980" ID="ID_1144490151" MODIFIED="1566518051558" TEXT="L&#xf6;sung: CSS-Klassen verwenden">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1566517991290" ID="ID_139839934" MODIFIED="1566518025089" TEXT="eine fixe Anzahl">
<node CREATED="1566518027596" ID="ID_1002340632" MODIFIED="1566518034807" TEXT="eins zwei drei vier viele"/>
</node>
<node CREATED="1566518038233" ID="ID_160319279" MODIFIED="1566518048501" TEXT="auf der letzten Klasse stehenbleiben"/>
</node>
</node>
</node>
@ -23758,9 +23813,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1564610302597" ID="ID_840104433" MODIFIED="1564932647891" TEXT="sollte so zeichnen, da&#xdf; CSS3-Effekte wie box-shadow nutzbar sind">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1564610302597" ID="ID_840104433" MODIFIED="1566517956971" TEXT="sollte so zeichnen, da&#xdf; CSS3-Effekte wie box-shadow nutzbar sind">
<arrowlink COLOR="#5590d5" DESTINATION="ID_1444331441" ENDARROW="Default" ENDINCLINATION="-449;0;" ID="Arrow_ID_1759102712" STARTARROW="None" STARTINCLINATION="98;-3;"/>
<linktarget COLOR="#02ab84" DESTINATION="ID_840104433" ENDARROW="Default" ENDINCLINATION="1028;-57;" ID="Arrow_ID_77023730" SOURCE="ID_1092949064" STARTARROW="None" STARTINCLINATION="106;39;"/>
<linktarget COLOR="#02ab84" DESTINATION="ID_840104433" ENDARROW="Default" ENDINCLINATION="1035;-107;" ID="Arrow_ID_77023730" SOURCE="ID_1092949064" STARTARROW="Default" STARTINCLINATION="106;39;"/>
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1564932652482" ID="ID_1330271110" MODIFIED="1564934138367" TEXT="alle render_background mit vollst&#xe4;ndigem Rechteck versorgen">
<icon BUILTIN="flag-yellow"/>
@ -23806,6 +23861,20 @@
<node CREATED="1564955112027" ID="ID_1010819780" MODIFIED="1564955123894" TEXT="Integration in Zeichenvorgang insgesamt beachten"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1566518983355" ID="ID_35592741" MODIFIED="1566519139548" TEXT="Zusammenspiel zw. H&#xf6;he und CSS">
<linktarget COLOR="#779be7" DESTINATION="ID_35592741" ENDARROW="Default" ENDINCLINATION="109;-329;" ID="Arrow_ID_66200016" SOURCE="ID_183446100" STARTARROW="None" STARTINCLINATION="479;0;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1566518998190" ID="ID_284079883" MODIFIED="1566519017050" TEXT="Stylesheet bestimmt zus&#xe4;tzlichen Margin + Padding"/>
<node CREATED="1566519017878" ID="ID_30554429" MODIFIED="1566519029065" TEXT="diese m&#xfc;ssen mit den Werten im TrackBody verrechnet werden">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1566522092555" ID="ID_293262823" MODIFIED="1566522110192" TEXT="Konsequenz: TrackBody mu&#xdf; auch den Style abfragen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1566519037996" ID="ID_57629359" MODIFIED="1566519094001" TEXT="der zus&#xe4;tzliche Platz wird u.A. f&#xfc;r den box-shadow ben&#xf6;tigt">
<arrowlink COLOR="#2b75cc" DESTINATION="ID_1092949064" ENDARROW="Default" ENDINCLINATION="286;83;" ID="Arrow_ID_1686979270" STARTARROW="None" STARTINCLINATION="572;0;"/>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
</node>