diff --git a/src/common/ui-protocol.cpp b/src/common/ui-protocol.cpp index 8fa10ae16..aef3dc97d 100644 --- a/src/common/ui-protocol.cpp +++ b/src/common/ui-protocol.cpp @@ -57,6 +57,14 @@ namespace stage { const Symbol MARK_Warning{"Warning"}; const Symbol MARK_Message{"Message"}; + + /* ======== CSS selector names ======== */ + + const Symbol NODE_fork{"fork"}; + + const Symbol CLASS_timeline{"timeline"}; + + /** */ diff --git a/src/include/ui-protocol.hpp b/src/include/ui-protocol.hpp index 8ad85e1b6..c7c5c7039 100644 --- a/src/include/ui-protocol.hpp +++ b/src/include/ui-protocol.hpp @@ -97,5 +97,12 @@ namespace stage { extern const Symbol MARK_Message; + /* ======== CSS selector names ======== */ + + extern const Symbol NODE_fork; + + extern const Symbol CLASS_timeline; + + }// namespace stage #endif /*STAGE_INTERFACE_UI_PROTOCOL_H*/ diff --git a/src/stage/ctrl/ui-manager.cpp b/src/stage/ctrl/ui-manager.cpp index 8edcaf396..7ef614f28 100644 --- a/src/stage/ctrl/ui-manager.cpp +++ b/src/stage/ctrl/ui-manager.cpp @@ -190,4 +190,12 @@ namespace ctrl { } + void + UiManager::configureStyle (timeline::TimelineWidget const& timeline) + { + uiStyle_->prepareStyleContext (timeline); + } + + + }}// namespace stage::ctrl diff --git a/src/stage/ctrl/ui-manager.hpp b/src/stage/ctrl/ui-manager.hpp index eecb7cae6..524962c4e 100644 --- a/src/stage/ctrl/ui-manager.hpp +++ b/src/stage/ctrl/ui-manager.hpp @@ -59,7 +59,8 @@ namespace stage { class UiBus; -namespace workspace { class UIStyle; } +namespace workspace { class UiStyle; } +namespace timeline { class TimelineWidget; } namespace ctrl { using std::unique_ptr; @@ -146,6 +147,8 @@ namespace ctrl { void allowCloseWindow (bool yes); + void configureStyle (timeline::TimelineWidget const&); + private: }; diff --git a/src/stage/interact/interaction-director.cpp b/src/stage/interact/interaction-director.cpp index 9259a2946..81ff5f94c 100644 --- a/src/stage/interact/interaction-director.cpp +++ b/src/stage/interact/interaction-director.cpp @@ -364,6 +364,7 @@ namespace interact { .addTimeline ( anchorProxy.buildTimelineWidget (this->uiBus_)); + globalCtx_.uiManager_.configureStyle (*anchorProxy); return anchorProxy; } diff --git a/src/stage/timeline/timeline-layout.cpp b/src/stage/timeline/timeline-layout.cpp index 802f0b518..097f52ea4 100644 --- a/src/stage/timeline/timeline-layout.cpp +++ b/src/stage/timeline/timeline-layout.cpp @@ -57,30 +57,6 @@ namespace stage { namespace timeline { - namespace { /////////////////////////////////////////////////////////////////////////////////////TICKET #1168 : doesn't this rather belong into the global UiStyle manager? - void - provideStyleContextAdvice (Gtk::Widget const& anchorWidget) - { - lumiera::advice::Provision styleAdvice{"style(trackBody)"}; - - Gtk::WidgetPath path = anchorWidget.get_path(); - // build a "virtual" CSS node to represent the track scope - GType scopeNode = Gtk::Box::get_type(); - int pos = path.path_append_type (scopeNode); - // override the generic node name with a custom widget type - gtk_widget_path_iter_set_object_name (path.gobj(), pos, "TrackScope"); - // deliberately we don't invoke path.iter_set_name(pos, "id") add an #ID - path.iter_add_class(pos, "timeline"); - // for reference, see gtk_widget_path_append_for_widget() in in gtkwidget.c, line 16413 - - // create a new style context and configure it according to the defined path - PStyleContext style = Gtk::StyleContext::create(); - style->set_path (path); - // publish as Advice "style(trackBody)" - styleAdvice.setAdvice (style); - INFO (stage, "Body-CSS: path=%s", util::cStr (path.to_string())); ////////////////////////TICKET #1201 : this yields "paned:dir-ltr.horizontal box:dir-ltr.vertical TrackScope.timeline" - } - } @@ -94,8 +70,6 @@ namespace timeline { { topLevelContainer.add1 (headerPane_); topLevelContainer.add2 (bodyCanvas_); - - provideStyleContextAdvice (bodyCanvas_); } @@ -118,6 +92,13 @@ namespace timeline { signalStructureChange_(); // this _is_ such a change } + Gtk::WidgetPath + TimelineLayout::getBodyWidgetPath() const + { + return bodyCanvas_.get_path(); + } + + /* ==== Interface: LayoutManager===== */ diff --git a/src/stage/timeline/timeline-layout.hpp b/src/stage/timeline/timeline-layout.hpp index 068c57d9f..7ad186864 100644 --- a/src/stage/timeline/timeline-layout.hpp +++ b/src/stage/timeline/timeline-layout.hpp @@ -124,6 +124,9 @@ namespace timeline { /** @internal anchor the display of the root track into the two display panes */ void installRootTrack (TrackHeadWidget&,TrackBody&); + Gtk::WidgetPath getBodyWidgetPath() const; + + protected:/* ==== Interface: LayoutManager===== */ PixSpan getPixSpan() override; diff --git a/src/stage/timeline/timeline-widget.cpp b/src/stage/timeline/timeline-widget.cpp index 5d8a8f26e..2f6c2bde1 100644 --- a/src/stage/timeline/timeline-widget.cpp +++ b/src/stage/timeline/timeline-widget.cpp @@ -90,6 +90,12 @@ namespace timeline { { return control_->getName(); } + + Gtk::WidgetPath + TimelineWidget::getBodyWidgetPath() const + { + return layout_->getBodyWidgetPath(); + } diff --git a/src/stage/timeline/timeline-widget.hpp b/src/stage/timeline/timeline-widget.hpp index 5cfa4d379..794248261 100644 --- a/src/stage/timeline/timeline-widget.hpp +++ b/src/stage/timeline/timeline-widget.hpp @@ -145,6 +145,8 @@ namespace timeline { cuString getLabel() const override; + Gtk::WidgetPath getBodyWidgetPath() const; + public: /* ===== Signals ===== */ diff --git a/src/stage/workspace/ui-style.cpp b/src/stage/workspace/ui-style.cpp index 5d7101fa4..eb28d7da6 100644 --- a/src/stage/workspace/ui-style.cpp +++ b/src/stage/workspace/ui-style.cpp @@ -32,10 +32,13 @@ #include "stage/workspace/ui-style.hpp" +#include "stage/timeline/timeline-widget.hpp" #include "stage/config-keys.hpp" #include "lib/searchpath.hpp" #include "lib/util.hpp" +#include "include/ui-protocol.hpp" + #include #include @@ -68,6 +71,7 @@ namespace workspace { : Gtk::UIManager() , iconSearchPath_{Config::get (KEY_ICON_PATH)} , resourceSerachPath_{Config::get (KEY_UIRES_PATH)} + , styleAdvice_{"style(trackBody)"} { Glib::set_application_name (Config::get (KEY_TITLE)); @@ -101,6 +105,46 @@ namespace workspace { + /** + * @remarks some implementation notes.... + * - GTK defines for each widget a _widget path_, to describe the path + * of widget parent relationships down from the top-level window + * - this Gtk::WidgetPath is then used to match against CSS selectors of the GTK stylesheet, + * either the global system theme, or (with precedence) an application stylesheet (`lumiera.css`) + * - but the Gtk::StyleContext and (and should) also be used outside of the core GTK framework to + * carry out custom drawing tasks, which allows custom drawing to "blend in" with the desktop theme. + * - to support this usage, we construct a "virtual widget" and place it at a systematically correct + * position in the widget hierarchy, causing the corresponding style context to pick up the appropriate + * standard CSS definitions in effect at that point in the hierarchy. Moreover, users may (and shall) + * add custom styling rules in a way to match and affect this "virtual" CSS node. + * - the resulting Gtk::StyleContext is constructed only once, at initialisation. It is used from drawing + * code "deep down" within the TimelineWidget's implementation. The [Advice System](\ref advice.hpp) + * allows to pass such information without the need of a direct relation between provider and consumer. + * - for technical reference how to manage and populate GTK WidgetPath nodes, see the implementation + * of the C-function `gtk_widget_path_append_for_widget()` in in GTK 3.x, gtkwidget.c, line 16413 + */ + void + UiStyle::prepareStyleContext (timeline::TimelineWidget const& timeline) + { + // the first Timeline triggers initialisation + if (styleAdvice_.isGiven()) return; + + Gtk::WidgetPath path = timeline.getBodyWidgetPath(); + GType scopeNode = Gtk::Box::get_type(); + int pos = path.path_append_type (scopeNode); // build a "virtual" CSS node to represent the track scope + + gtk_widget_path_iter_set_object_name (path.gobj(), pos, NODE_fork); // override the generic node name with a custom widget type "fork" + path.iter_add_class(pos, cuString{CLASS_timeline}); // decorate this CSS node with a CSS class ".timeline" (distinguish it from asset bins) + // deliberately we *do not* invoke path.iter_set_name(pos, "id") to add an #ID + PStyleContext style = Gtk::StyleContext::create(); // create a new style context and configure it according to the path defined thus far + style->set_path (path); + styleAdvice_.setAdvice (style); // publish as Advice "style(trackBody)" + INFO (stage, "Body-CSS: path=%s", util::cStr (path.to_string())); ////////////////////////TICKET #1201 : this yields "paned:dir-ltr.horizontal box:dir-ltr.vertical TrackScope.timeline" + } + + + + Cairo::RefPtr UiStyle::readStyleColourProperty (Gtk::Widget& widget ,const gchar * property_name diff --git a/src/stage/workspace/ui-style.hpp b/src/stage/workspace/ui-style.hpp index fd933ac26..6b6c311e4 100644 --- a/src/stage/workspace/ui-style.hpp +++ b/src/stage/workspace/ui-style.hpp @@ -37,6 +37,7 @@ #define STAGE_WORKSPACE_UI_STYLE_H #include "stage/gtk-base.hpp" +#include "common/advice.hpp" #include "lib/nocopy.hpp" #include @@ -47,6 +48,7 @@ namespace stage { namespace model { class Project; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle namespace controller { class Controller; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle + namespace timeline { class TimelineWidget; } class UiBus; @@ -54,6 +56,9 @@ namespace workspace { using std::string; + using StyleAdvice = lumiera::advice::Provision; + + /** @@ -70,6 +75,8 @@ namespace workspace { string iconSearchPath_; string resourceSerachPath_; + StyleAdvice styleAdvice_; + public: /** The registered icon size for giant 48x48 px icons. @@ -102,6 +109,23 @@ namespace workspace { */ void setTheme (string const& stylesheetName); + /** + * Use the existing TimelineWidget's GTK-WidgetPath to establish a systematic + * CSS styling context, which can be used for theming and styling of Lumiera's + * custom UI elements within the timeline display. Especially, this allows us + * to anchor those custom elements at a dedicated point in the hierarchy, the + * way it is visible for CSS selectors. Thus, either standard CSS rules and + * inheritance take effect on our custom elements, or the GTK stylesheet + * may add dedicated style rules for elements within the timeline display, + * most notably the system of nested scopes in the track fork and the + * display of clips and overlays. + * + * Especially the following selector path can be used + * - `paned.timeline-page > body.timeline > fork.timeline` + */ + void prepareStyleContext (timeline::TimelineWidget const&); + + /** * A utility function which reads a colour style from the GTK Style. * @param widget The widget to load the style out of. diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9927c04ea..e9690993e 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -21534,11 +21534,12 @@ - + + - + @@ -21607,7 +21608,7 @@ - + @@ -21634,13 +21635,15 @@ - + + + - + @@ -21652,8 +21655,9 @@ + - + @@ -21674,6 +21678,7 @@ + @@ -21685,7 +21690,7 @@ - + @@ -21716,14 +21721,46 @@ - - - - - + - + + + + + + + + + +

+ ...d.h. dann aus dem InteractionDirector heraus +

+

+ -- ja dann kann man auch gleich direkt an den UiManager delegieren! +

+ + +
+ +
+
+ + + + + + +

+ 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 +

+ + +
+ +
+ +