Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
ui-style.cpp
Go to the documentation of this file.
1/*
2 UiStyle - manage coherent UI styling
3
4 Copyright (C)
5 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
6 2017, Hermann Vosseler <Ichthyostega@web.de>
7
8  **Lumiera** is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by the
10  Free Software Foundation; either version 2 of the License, or (at your
11  option) any later version. See the file COPYING for further details.
12
13* *****************************************************************/
14
15
28#include "stage/config-keys.hpp"
29#include "lib/searchpath.hpp"
30#include "lib/file.hpp"
31#include "lib/util.hpp"
32
33#include <gtkmm/stylecontext.h>
34
35using Gtk::IconSize;
36using Gtk::IconFactory;
37
38
39
40namespace stage {
41namespace workspace {
42
43 IconSize UiStyle::GiantIconSize = Gtk::ICON_SIZE_INVALID;
44 IconSize UiStyle::MenuIconSize = Gtk::ICON_SIZE_INVALID;
45
46
47
48
58 : Gtk::UIManager()
59 , iconSearchPath_{Config::get (KEY_ICON_PATH)}
60 , resourceSerachPath_{Config::get (KEY_UIRES_PATH)}
61 , styleAdviceTrackBody_{"style(trackBody)"}
62 , styleAdviceTrackRuler_{"style(trackRuler)"}
63 {
64 Glib::set_application_name (Config::get (KEY_TITLE));
65
68
70 }
71
72
73
74 void
75 UiStyle::setTheme (string const& stylesheetName)
76 {
77 auto screen = Gdk::Screen::get_default();
78 auto css_provider = Gtk::CssProvider::create();
79 try
80 {
81 css_provider->load_from_path (lib::resolveModulePath (stylesheetName, resourceSerachPath_));
84 }
85 catch(Glib::Error const& failure)
86 {
87 WARN (stage, "Failure while loading stylesheet '%s': %s", cStr(stylesheetName), cStr(failure.what()));
88 }
89
90 Gtk::StyleContext::add_provider_for_screen (screen, css_provider,
91 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
92 }
93
94
95
114 void
116 {
117 // the first Timeline triggers initialisation
118 if (styleAdviceTrackBody_.isGiven()) return;
119
120 Gtk::WidgetPath path = timeline.getBodyWidgetPath();
121 GType scopeNode = Gtk::Box::get_type();
122 int pos = path.path_append_type (scopeNode); // build a "virtual" CSS node to represent the track scope
123
124 gtk_widget_path_iter_set_object_name (path.gobj(), pos, NODE_fork); // override the generic node name with a custom widget type "fork"
125 path.iter_add_class(pos, CLASS_timeline_fork); // decorate this CSS node with a CSS class ".timeline__fork" (distinguish it from asset bins)
126 // deliberately we *do not* invoke path.iter_set_name(pos, "id") to add an #ID
127 for (int i=0; i<pos; ++i) // reset any state flags accidentally set (resulting in pseudo classes like ":backdrop")
128 gtk_widget_path_iter_set_state(path.gobj(), i, GTK_STATE_FLAG_NORMAL);
129 PStyleContext style = Gtk::StyleContext::create(); // create a new style context and configure it according to the path defined thus far
130 style->set_screen(Gdk::Screen::get_default());
131 style->set_path (path);
132 styleAdviceTrackBody_.setAdvice (style); // publish as Advice "style(trackBody)"
133
134 pos = path.path_append_type (scopeNode); // append another nested "virtual" CSS node to represent the a ruler track
135 gtk_widget_path_iter_set_object_name (path.gobj(), pos, NODE_frame); // ...but this time we explicitly use the conventional Name "frame" (hard wired default by GTK)
136 // note: the node is deliberately left as 'frame' to pick up existing styling
137 path.iter_add_class(pos, CLASS_timeline_ruler); // decorate with CSS class ".timeline__ruler" to identify position within the system
138 style = Gtk::StyleContext::create(); // create another style context...
139 style->set_path (path); // ...for this nested path. (Note: Gtk takes a copy of the path, see gtk_style_context_set_path(), line 1120)
140 styleAdviceTrackRuler_.setAdvice (style); // publish as Advice "style(trackRuler)"
141 }
142
143
144
145
146 Cairo::RefPtr<Cairo::SolidPattern>
148 ,const gchar * property_name
149 ,guint16 red, guint16 green, guint16 blue)
150 {
151 REQUIRE (property_name);
152
153 // TODO: Can we get rid of the GdkColor completely here?
155 GdkColor *color;
156 gtk_widget_style_get(widget.gobj(), property_name, &color, NULL);
157
158 Cairo::RefPtr<Cairo::SolidPattern> pattern;
159 // Did the colour load successfully?
160 if (color != NULL)
161 {
162 pattern = Cairo::SolidPattern::create_rgb ( (double)color->red / 0xFFFF,
163 (double)color->green / 0xFFFF,
164 (double)color->blue / 0xFFFF);
165 }
166 else
167 {
168 WARN (stage, "%s style value failed to load", property_name);
169
170 pattern = Cairo::SolidPattern::create_rgb ( red, green, blue );
171 }
172
173 return pattern;
174 }
175
176
177 void
179 {
180 if(GiantIconSize == Gtk::ICON_SIZE_INVALID)
181 GiantIconSize = IconSize::register_new ("giant", 48, 48);
182 if(MenuIconSize == Gtk::ICON_SIZE_INVALID)
183 MenuIconSize = IconSize::register_new ("menu", 16, 16);
184 }
185
186
191 void
193 {
194 Glib::RefPtr<IconFactory> factory = Gtk::IconFactory::create();
195
196 addStockIconSet(factory, "panel-assets", "panel_assets", _("_Assets"));
197 addStockIconSet(factory, "panel-play", "panel_play", _("_Play"));
198 addStockIconSet(factory, "panel-viewer", "panel_viewer", _("_Viewer"));
199 addStockIconSet(factory, "panel-infobox", "panel_infobox", _("_InfoBox"));
200 addStockIconSet(factory, "panel-timeline", "panel_timeline",_("_Timeline"));
201 addStockIconSet(factory, "panel-timeline", "panel_timeline_obsolete",_("_ZombieTimeline"));
202
203 addStockIconSet(factory, "window-new" ,"new_window" ,_("New _Window"));
204
205 addStockIconSet(factory, "placement" ,ICON_placement ,_("_Placement"));
206 addStockIconSet(factory, "arrow-hand" ,ICON_arrow_hand_menu ,_("_Menu"));
207 addStockIconSet(factory, "arrow-hand" ,ICON_arrow_hand_down ,_("_Expand"));
208 addStockIconSet(factory, "arrow-hand" ,ICON_arrow_hand_up ,_("_Collapse"));
209
210 addStockIconSet(factory, "tool-arrow", "tool_arrow", _("_Arrow"));
211 addStockIconSet(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam"));
212
213 addStockIconSet(factory, "track-disabled", "track_disabled",_("Track Disabled"));
214 addStockIconSet(factory, "track-enabled", "track_enabled", _("Track Enabled"));
215 addStockIconSet(factory, "track-locked", "track_locked", _("Track Locked"));
216 addStockIconSet(factory, "track-unlocked", "track_unlocked",_("Track Unlocked"));
217
218 factory->add_default(); //Add factory to list of factories.
219 }
220
221
222 bool
223 UiStyle::addStockIconSet (Glib::RefPtr<IconFactory> const& factory
224 ,Literal iconName
225 ,Literal id
226 ,Literal label)
227 {
228 Glib::RefPtr<Gtk::IconSet> icon_set = Gtk::IconSet::create();
229 cuString uIconName{iconName}, uLabel{label}; // even while we're just passing through a C-string to GTK,
230 // unfortunately Glib::ustring wraps a std::string
231
232 // Load all the sizes, wildcarding the largest icon to be loaded
233 bool found{false};
234 found |= addStockIcon (icon_set, uIconName, GiantIconSize, not found);
235 found |= addStockIcon (icon_set, uIconName, Gtk::ICON_SIZE_BUTTON, not found);
236 found |= addStockIcon (icon_set, uIconName, Gtk::ICON_SIZE_MENU, not found);
237 found |= addStockIcon (icon_set, uIconName, Gtk::ICON_SIZE_LARGE_TOOLBAR, not found);
238 found |= addStockIcon (icon_set, uIconName, MenuIconSize, not found);
239
240 if (not found)
241 {
242 // No icons were loaded
243 ERROR (stage, "Unable to load icon '%s'", iconName);
244 return false;
245 }
246
247 // Add the icon set to the icon factory
248 const Gtk::StockID stock_id(id);
249 factory->add(stock_id, icon_set);
250 Gtk::Stock::add(Gtk::StockItem(stock_id, uLabel));
251 return true;
252 }
253
254
255 bool
256 UiStyle::addStockIcon (Glib::RefPtr<Gtk::IconSet> const& icon_set
257 ,cuString& icon_name
258 ,Gtk::IconSize size
259 ,bool wildcard)
260 {
261 // Try the icon theme
262 if (addThemeIconSource(icon_set, icon_name, size, wildcard))
263 return true;
264
265 // Try to resolve the icon via the configured search path
267 for (auto const& location : iconLocations)
268 if (addNonThemeIconSource (icon_set
269 ,location
270 ,icon_name
271 ,size
272 ,wildcard))
273 return true;
274
275 return false; // icon not found
276 }
277
278
279 bool
280 UiStyle::addThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
281 ,cuString& icon_name
282 ,Gtk::IconSize size
283 ,bool wildcard)
284 {
285 // Get the size
286 int width = 0, height = 0;
287 if(!IconSize::lookup(size, width, height))
288 return false;
289 REQUIRE(width > 0);
290
291 // Try to load the icon
292 Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
293 REQUIRE(theme);
294
296 Gtk::IconInfo info = theme->lookup_icon(icon_name, width, (Gtk::IconLookupFlags)0);
297
298 if (!info) return false; // unable to resolve Icon
299
300 cuString path(info.get_filename());
301 return addStockIconFromPath(path, icon_set, size, wildcard);
302 }
303
304
305 bool
306 UiStyle::addNonThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
307 ,cuString& base_dir
308 ,cuString& icon_name
309 ,Gtk::IconSize size
310 ,bool wildcard)
311 {
312 // Get the size
313 int width = 0, height = 0;
314 if(!IconSize::lookup(size, width, height))
315 return false;
316 REQUIRE(width > 0);
317
318 // Try to load the icon
319 cuString path(Glib::ustring::compose("%1/%2x%3/%4.png",
320 base_dir, width, height, icon_name));
321 return addStockIconFromPath(path, icon_set, size, wildcard);
322 }
323
324
325 bool
327 ,Glib::RefPtr<Gtk::IconSet> const& icon_set
328 ,Gtk::IconSize size
329 ,bool wildcard)
330 {
331 if (not fs::exists (path)) return false;
332
333 try {
334 Gtk::IconSource source;
335 source.set_pixbuf(Gdk::Pixbuf::create_from_file(path));
336 source.set_size_wildcarded(wildcard);
337 source.set_size(size);
338
339 icon_set->add_source(source);
340
341 return true;
342 }
343
344 catch(Glib::Exception const& ex)
345 {
346 WARN (stage, "Failure when accessing icon '%s'. Problem: %s", cStr(path), cStr(ex.what()));
347 return false;
348 }
349 }
350
351
352
353}}// namespace stage::workspace
Inline string literal.
Definition symbol.hpp:78
Helper: Access a path Specification as a sequence of filesystem Paths.
C++ wrapper for convenient access to the Lumiera config system.
static string get(lib::Literal key)
void setAdvice(AD const &pieceOfAdvice)
Definition advice.hpp:274
Core timeline display (custom widget).
Gtk::WidgetPath getBodyWidgetPath() const
StyleAdvice styleAdviceTrackRuler_
Definition ui-style.hpp:72
bool addStockIcon(Glib::RefPtr< Gtk::IconSet > const &icon_set, cuString &icon_name, Gtk::IconSize size, bool wildcard)
Loads an icon, searching standard icon locations, and adds it to an icon set.
Definition ui-style.cpp:256
static Gtk::IconSize GiantIconSize
The registered icon size for giant 48x48 px icons.
Definition ui-style.hpp:80
bool addThemeIconSource(Glib::RefPtr< Gtk::IconSet > const &icon_set, cuString &icon_name, Gtk::IconSize size, bool wildcard)
Loads an icon from a the icon theme.
Definition ui-style.cpp:280
StyleAdvice styleAdviceTrackBody_
Definition ui-style.hpp:71
bool addStockIconFromPath(string path, Glib::RefPtr< Gtk::IconSet > const &icon_set, Gtk::IconSize size, bool wildcard)
Loads an icon from a specific path and adds it to an icon set.
Definition ui-style.cpp:326
static Cairo::RefPtr< Cairo::SolidPattern > readStyleColourProperty(Gtk::Widget &widget, const gchar *property_name, guint16 red, guint16 green, guint16 blue)
A utility function which reads a colour style from the GTK Style.
Definition ui-style.cpp:147
bool addNonThemeIconSource(Glib::RefPtr< Gtk::IconSet > const &icon_set, cuString &base_dir, cuString &icon_name, Gtk::IconSize size, bool wildcard)
Loads an icon from a non theme set.
Definition ui-style.cpp:306
UiStyle()
Set up a coherent theming and styling for the application.
Definition ui-style.cpp:57
void prepareStyleContext(timeline::TimelineWidget const &)
Use the existing TimelineWidget's GTK-WidgetPath to establish a systematic CSS styling context,...
Definition ui-style.cpp:115
void registerStockItems()
Registers application stock items: icons and labels associated with IDs.
Definition ui-style.cpp:192
static Gtk::IconSize MenuIconSize
The registered icon size for giant 16x16 px icons.
Definition ui-style.hpp:86
void setTheme(string const &stylesheetName)
Sets the theme to use for the Lumiera GUI.
Definition ui-style.cpp:75
bool addStockIconSet(Glib::RefPtr< Gtk::IconFactory > const &factory, Literal iconName, Literal id, Literal label)
Adds an icon (in different sizes) to the icon factory.
Definition ui-style.cpp:223
Definition of access keys for global UI configuration.
Includes the C++ Filesystem library and provides some convenience helpers.
#define _(String)
Definition gtk-base.hpp:68
return NULL
Definition llist.h:586
string resolveModulePath(fs::path moduleName, string searchPath)
helper to establish the location to search for loadable modules, configuration files,...
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
Literal KEY_STYLESHEET
Literal KEY_TITLE
Literal ICON_arrow_hand_up
Literal KEY_UIRES_PATH
Glib::RefPtr< Gtk::StyleContext > PStyleContext
Definition gtk-base.hpp:95
Literal KEY_ICON_PATH
Literal ICON_arrow_hand_menu
const uString cuString
Definition gtk-base.hpp:93
Literal ICON_placement
const Symbol NODE_frame
cuString CLASS_timeline_fork
Literal ICON_arrow_hand_down
cuString CLASS_timeline_ruler
const Symbol NODE_fork
Helpers to handle directory search paths.
Definition of access keys for uniform UI styling.
CStr cStr(std::string const &rendered)
convenience shortcut: forced conversion to c-String via string.
Definition symbol.hpp:60
This file defines the core component of the Lumiera GUI.
Service for global theming and style related concerns.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...