In the end, I used the profile building pass to also calculate and sum up the vertical offsets.
Seems to be the only sane approach to get really precise values, since adjacent
upwards slopes can be combined at various places (and I do not want to use the
actual drawing code for this calculation)
need to investigate and probably need to store per track offset values
already while building the track profile. The primary reason for the
observed discrepancy seems to be the rather flexible combination of
slope borders.
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
seemingly, the Box with PACK_SHRINK allocates a zero height to the rulerCanvas initally,
which is correct at that point, since the widgets are not yet realised.
However, when we later set_size() on the rulerCanvas, the enclosing Box should reflow.
It does indeed if the child widget is a button or something similar, however,
somehow this reflowing does not work when we set_size on the canvas.
A workaround is to place a new set_size_request().
TODO: do this more precisely, and only on the rulerCanvas. To the contrary,
the mainCanvas is placed into a scolling-pane and thus does not need a size-Request.
Moreover, the latter automatically communicates with the hadjustment() / vadjustment() of
the enclosing scrollbars.
as can be verified with the debugger, it sets the correct sizes now.
And it is called only once (unless the content size actually changes).
TODO: however, the visible display of the GTK widgets is not adjusted
- CSS3 effects like box-shadow are applied with the StyleContext::render_background() function
* first, an outset box-shadow is rendered _outside_ the box given as parameter to `render_background()`
* then the box is filled with the background colour
* and last, an inset box-shadow is rendered _inside_ the area of a would-be border,
without rendering the border itself.
* consequently we can not shade the border itself and we can not shade the content
Indeed I had missed to connect the new "free standing" StyleContext to
some Gdk::Screen, typically the default screen (connected to the current
top level window). But seemingly this was not really necessary, since,
somehow magically, the style context must have connected itself to some
screen, otherwise it wouldn't be able to access the CSS cascade.
Anyhow, fixing this omission does not resolve our problem.
Nor does any combination of re-connecting, invalidating etc.
I poked around in the GTK (C) code a lot, but could not spot any obvious
missing initialisation step. To much magic around here. Without massive
debugging into GTK internals, I don't see any way to further this
investigation. And, moreover there is a viable workaround
(namely to set and remove the classes explicitly, which works as intended)
I posted a question on Stackoverflow and for now
I'll file this topic as "inconclusive"
https://stackoverflow.com/q/57342478
Note however, we will not plaster our UI code and CSS with mangled-out selectors
on each and every single element. This is what cascading was meant to be used for.
DONE
- can now control the border size through a set of modifier classes
OPEN
- but context_save()/restore() does not work; seem to loose all styling
- not clear how to deal with CSS3 effects like box-shadow
Within the timeline drawing code, adding a class to the Gtk::StyleContext on the fly seemingly did not work.
Now we're doing basically the same here in this small Gtk test application,
and it does not work either :-)
- add a separate dummy Gtk::Frame widget
- apply custom styling to that frame, by virtue of a CSS class '.experiment'
- pick up the Gtk::StyleContext of that testFrame
- use this style context to draw a custom frame onto the canvas
- control extension of that custom frame through the top margin of testFrame
...to find out about GTK's implementation of some aspects of CSS
through Gtk::StyleContext and friends
Basically this is a clone of the existing gtk-canvas-experiment application
...somehow does not yet work as intended...
- unable to control the border-width from code
- Gtk::StyleContext::add_class(name) does not seem to have any effect
The population message is just made up, in order to create more interesting structures
in the UI and so to further the development of the timeline display.
For the actual structure I choose to mirror my example drawing in draw/UI-TimelineLayout-1.png
which is also used in the TiddlyWiki, on the #GuiTimelineView tiddler
https://lumiera.org/wiki/renderengine.html#GuiTimelineView
We can add our custom classes to custom widgets, and we can set the
widget name, which can be used as #id selector from CSS
Unfortunately we can not set the main CSS node name for CustomWidgets defined through GTKmm (C++)
The latter is only possible when deriving the custom widget in plain-C, which is quite tedious.
On a second thought, this limitation is not so severe as it might seem, because
most of the time you actually do *not* want to change the CSS node name,
because you want to match against existing rules in the theme (e.g. box, or paned)
The actual case here would have been an exception to this rule, since here
it would be nice to anchor the whole custom timeline drawing in an "body.timeline" element
NOTE: Current state for the selector path is now:
window.background box.vertical box[2/3].horizontal widget[2/2] widget paned.vertical widget box.vertical notebook[1/1].frame paned.horizontal.timeline-page box.vertical.timeline.timeline-body fork.timeline
...and perform the initialisation once, when attaching the first timeline to the UI
Now our code produces the following Gtk::WidgetPath (note the last node, which our code added)
window:backdrop:dir-ltr.background box:backdrop:dir-ltr.vertical box:backdrop:dir-ltr[2/3].horizontal widget:backdrop:dir-ltr[2/2] widget:backdrop:dir-ltr paned:backdrop:dir-ltr.vertical widget:backdrop:dir-ltr box:backdrop:dir-ltr.vertical notebook:backdrop:dir-ltr[1/1].frame paned:backdrop:dir-ltr.horizontal box:backdrop:dir-ltr.vertical fork.timeline
For context: The »Advice System« was coined a long time ago, in 2010,
based on the vague impression that it might be useful for that kind of application
we are about to build here. And, as can be expected, none of the usage situations
envisioned at that time was brought to bear. Non the less, the facility came in
handy at times, precisely because it is cross-cutting and allows to pass
information without imposing any systematic relationship between the
communication partners.
And now we've got again such a situation.
The global style manager in the UI has to build a virtual CSS path,
which is needed by drawing code somewhere deep down, and we absolutely
do not want to pass a reference to the style manager over 20 recursive calls.
The alternatives would be
(1) to turn the style manager into a public service
(2) to have a static access function somewhere
(3) to use a global variable.
For rationale, (1) would be overblown, because we do not actually request
a service to do work for us, rather we need some global piece of information.
(2) would be equivalent to (1), just more confusing. And (3) is basically
what the Advice system does, with the added benefit of a clear-cut service
access point and a well defined lifecycle.
This changeset adds the ability to check if actual Advice has been published,
which allows us to invoke the (possibly expensive) GTK path building and
style context building code only once.
- at some (yet to be defined) location, a virtual WidgetPath is constructed
and used to build a Gtk::StyleContext in accordance to the curren CSS
- within the drawing routine, we use Lumiera's Advice-System to access this info
...when rendering this part, which shall be always visible.
And the rest of the profile needs to be rendered into a second canvas,
which is placed within a pane with scrollbar.
Implemented as a statefull iterator filter
TODO:
- actual draw operations not yet implemented
- find a way how to select the prelude / body part of the track profile
This is a consequence of subsuming the timeline ruler under the concept of an overview track
the template lib::PolymorphicValue seemingly picked the wrong
implementation strategy for "virtual copy support": In fact it is possible
to use the optimal strategy here, since our interface inherits from CloneSupport,
yet the metaprogramming logic picked the mix-in-adapter (which requires one additional "slot"
of storage plus a dynamic_cast at runtime).
The reason for this malfunction was the fact that we used META_DETECT_FUNCTION
to detect the presence of a clone-support-function. This is not correct, since
it can only detect a function in the *same* class, not an inherited function.
Thus, switching to META_DETECT_FUNCTION_NAME solves this problem
Well, this solution has some downsides, but since I intend to rewrite the
whole virtual copy support (#1197) anyway, I'll deem this acceptable for now
TODO / WIP: still some diagnostics code to clean up, plus a better solution for the EmptyBase
...which, in the end, can even be considered the more logical design choice,
since the "verb visitor" is a more elaborated and sophisiticated Verb-Token,
adding the special twist of embedded storage for variable function arguments