ardour
ui_config.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 1999-2014 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <iostream>
21 #include <sstream>
22 #include <unistd.h>
23 #include <cstdlib>
24 #include <cstdio> /* for snprintf, grrr */
25 
26 #include <glibmm/miscutils.h>
27 #include <glib/gstdio.h>
28 
29 #include "pbd/convert.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/xml++.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/error.h"
34 #include "pbd/stacktrace.h"
35 
36 #include "gtkmm2ext/rgb_macros.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 
40 
41 #include "ardour_ui.h"
42 #include "global_signals.h"
43 #include "ui_config.h"
44 
45 #include "i18n.h"
46 
47 using namespace std;
48 using namespace PBD;
49 using namespace ARDOUR;
50 using namespace ArdourCanvas;
51 
52 static const char* ui_config_file_name = "ui_config";
53 static const char* default_ui_config_file_name = "default_ui_config";
55 
56 static const double hue_width = 18.0;
57 
59  :
60 #undef UI_CONFIG_VARIABLE
61 #define UI_CONFIG_VARIABLE(Type,var,name,val) var (name,val),
62 #define CANVAS_FONT_VARIABLE(var,name) var (name),
63 #include "ui_config_vars.h"
64 #include "canvas_vars.h"
65 #undef UI_CONFIG_VARIABLE
67 
68  _dirty (false),
69  aliases_modified (false),
70  colors_modified (false),
71  modifiers_modified (false),
72  block_save (0)
73 {
74  _instance = this;
75 
76  load_state();
77 
79 
80  ParameterChanged.connect (sigc::mem_fun (*this, &UIConfiguration::parameter_changed));
81 
82  /* force GTK theme setting, so that loading an RC file will work */
83 
85 }
86 
88 {
89 }
90 
91 void
93 {
94  reset_gtk_theme ();
95 
96  /* In theory, one of these ought to work:
97 
98  gtk_rc_reparse_all_for_settings (gtk_settings_get_default(), true);
99  gtk_rc_reset_styles (gtk_settings_get_default());
100 
101  but in practice, neither of them do. So just reload the current
102  GTK RC file, which causes a reset of all styles and a redraw
103  */
104 
105  parameter_changed ("ui-rc-file");
106 }
107 
108 void
110 {
111  _dirty = true;
112 
113  if (param == "ui-rc-file") {
114  load_rc_file (true);
115  } else if (param == "color-file") {
116  load_color_theme ();
117  }
118 
119  save_state ();
120 }
121 
122 void
124 {
125  stringstream ss;
126 
127  ss << "gtk_color_scheme = \"" << hex;
128 
129  for (ColorAliases::iterator g = color_aliases.begin(); g != color_aliases.end(); ++g) {
130 
131  if (g->first.find ("gtk_") == 0) {
132  ColorAliases::const_iterator a = color_aliases.find (g->first);
133  const string gtk_name = g->first.substr (4);
134  ss << gtk_name << ":#" << std::setw (6) << setfill ('0') << (color (g->second) >> 8) << ';';
135  }
136  }
137 
138  ss << '"' << dec << endl;
139 
140  /* reset GTK color scheme */
141 
142  Gtk::Settings::get_default()->property_gtk_color_scheme() = ss.str();
143 }
144 
145 void
146 UIConfiguration::map_parameters (boost::function<void (std::string)>& functor)
147 {
148 #undef UI_CONFIG_VARIABLE
149 #define UI_CONFIG_VARIABLE(Type,var,Name,value) functor (Name);
150 #include "ui_config_vars.h"
151 #undef UI_CONFIG_VARIABLE
152 }
153 
154 int
156 {
157  std::string rcfile;
158  int ret = -1;
159 
161  XMLTree tree;
162 
163  info << string_compose (_("Loading default ui configuration file %1"), rcfile) << endmsg;
164 
165  if (!tree.read (rcfile.c_str())) {
166  error << string_compose(_("cannot read default ui configuration file \"%1\""), rcfile) << endmsg;
167  } else {
168  if (set_state (*tree.root(), Stateful::loading_state_version)) {
169  error << string_compose(_("default ui configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
170  } else {
171  _dirty = false;
172  ret = 0;
173  }
174  }
175 
176  } else {
177  warning << string_compose (_("Could not find default UI configuration file %1"), default_ui_config_file_name) << endmsg;
178  }
179 
180  if (ret == 0) {
181  /* reload color theme */
182  load_color_theme (false);
183  ARDOUR_UI_UTILS::ColorsChanged (); /* EMIT SIGNAL */
184  }
185 
186  return 0;
187 }
188 
189 int
191 {
192  std::string cfile;
193  string basename;
194  bool found = false;
195 
196  if (allow_own) {
197  basename = "my-";
198  basename += color_file.get();
199  basename += ".colors";
200 
201  if (find_file (ardour_config_search_path(), basename, cfile)) {
202  found = true;
203  }
204  }
205 
206  if (!found) {
207  basename = color_file.get();
208  basename += ".colors";
209 
210  if (find_file (ardour_config_search_path(), basename, cfile)) {
211  found = true;
212  }
213  }
214 
215  if (found) {
216 
217  XMLTree tree;
218 
219  info << string_compose (_("Loading color file %1"), cfile) << endmsg;
220 
221  if (!tree.read (cfile.c_str())) {
222  error << string_compose(_("cannot read color file \"%1\""), cfile) << endmsg;
223  return -1;
224  }
225 
226  if (set_state (*tree.root(), Stateful::loading_state_version)) {
227  error << string_compose(_("color file \"%1\" not loaded successfully."), cfile) << endmsg;
228  return -1;
229  }
230 
232  } else {
233  warning << string_compose (_("Color file %1 not found"), basename) << endmsg;
234  }
235 
236  return 0;
237 }
238 
239 int
241 {
242  XMLNode* root;
243  LocaleGuard lg (X_("C"));
244 
245  root = new XMLNode("Ardour");
246 
247  XMLNode* parent = new XMLNode (X_("Colors"));
248  for (Colors::const_iterator i = colors.begin(); i != colors.end(); ++i) {
249  XMLNode* node = new XMLNode (X_("Color"));
250  node->add_property (X_("name"), i->first);
251  stringstream ss;
252  ss << "0x" << setw (8) << setfill ('0') << hex << i->second;
253  node->add_property (X_("value"), ss.str());
254  parent->add_child_nocopy (*node);
255  }
256  root->add_child_nocopy (*parent);
257 
258  parent = new XMLNode (X_("ColorAliases"));
259  for (ColorAliases::const_iterator i = color_aliases.begin(); i != color_aliases.end(); ++i) {
260  XMLNode* node = new XMLNode (X_("ColorAlias"));
261  node->add_property (X_("name"), i->first);
262  node->add_property (X_("alias"), i->second);
263  parent->add_child_nocopy (*node);
264  }
265  root->add_child_nocopy (*parent);
266 
267  parent = new XMLNode (X_("Modifiers"));
268  for (Modifiers::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i) {
269  XMLNode* node = new XMLNode (X_("Modifier"));
270  node->add_property (X_("name"), i->first);
271  node->add_property (X_("modifier"), i->second.to_string());
272  parent->add_child_nocopy (*node);
273  }
274  root->add_child_nocopy (*parent);
275 
276  XMLTree tree;
277  std::string colorfile = Glib::build_filename (user_config_directory(), (string ("my-") + color_file.get() + ".colors"));
278 
279  tree.set_root (root);
280 
281  if (!tree.write (colorfile.c_str())){
282  error << string_compose (_("Color file %1 not saved"), colorfile) << endmsg;
283  return -1;
284  }
285 
286  return 0;
287 }
288 
289 int
291 {
292  bool found = false;
293 
294  std::string rcfile;
295 
297  XMLTree tree;
298  found = true;
299 
300  info << string_compose (_("Loading default ui configuration file %1"), rcfile) << endmsg;
301 
302  if (!tree.read (rcfile.c_str())) {
303  error << string_compose(_("cannot read default ui configuration file \"%1\""), rcfile) << endmsg;
304  return -1;
305  }
306 
307  if (set_state (*tree.root(), Stateful::loading_state_version)) {
308  error << string_compose(_("default ui configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
309  return -1;
310  }
311  }
312 
314  XMLTree tree;
315  found = true;
316 
317  info << string_compose (_("Loading user ui configuration file %1"), rcfile) << endmsg;
318 
319  if (!tree.read (rcfile)) {
320  error << string_compose(_("cannot read ui configuration file \"%1\""), rcfile) << endmsg;
321  return -1;
322  }
323 
324  if (set_state (*tree.root(), Stateful::loading_state_version)) {
325  error << string_compose(_("user ui configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
326  return -1;
327  }
328 
329  _dirty = false;
330  }
331 
332  if (!found) {
333  error << _("could not find any ui configuration file, canvas will look broken.") << endmsg;
334  }
335 
336  return 0;
337 }
338 
339 int
341 {
342 
343  if (_dirty) {
344  std::string rcfile = Glib::build_filename (user_config_directory(), ui_config_file_name);
345 
346  XMLTree tree;
347 
348  tree.set_root (&get_state());
349 
350  if (!tree.write (rcfile.c_str())){
351  error << string_compose (_("Config file %1 not saved"), rcfile) << endmsg;
352  return -1;
353  }
354 
355  _dirty = false;
356  }
357 
359 
360  if (store_color_theme ()) {
361  error << string_compose (_("Color file %1 not saved"), color_file.get()) << endmsg;
362  return -1;
363  }
364 
365  aliases_modified = false;
366  colors_modified = false;
367  modifiers_modified = false;
368  }
369 
370 
371  return 0;
372 }
373 
374 XMLNode&
376 {
377  XMLNode* root;
378  LocaleGuard lg (X_("C"));
379 
380  root = new XMLNode("Ardour");
381 
382  root->add_child_nocopy (get_variables ("UI"));
383  root->add_child_nocopy (get_variables ("Canvas"));
384 
385  if (_extra_xml) {
386  root->add_child_copy (*_extra_xml);
387  }
388 
389  return *root;
390 }
391 
392 XMLNode&
393 UIConfiguration::get_variables (std::string which_node)
394 {
395  XMLNode* node;
396  LocaleGuard lg (X_("C"));
397 
398  node = new XMLNode (which_node);
399 
400 #undef UI_CONFIG_VARIABLE
401 #undef CANVAS_FONT_VARIABLE
402 #define UI_CONFIG_VARIABLE(Type,var,Name,value) if (node->name() == "UI") { var.add_to_node (*node); }
403 #define CANVAS_FONT_VARIABLE(var,Name) if (node->name() == "Canvas") { var.add_to_node (*node); }
404 #include "ui_config_vars.h"
405 #include "canvas_vars.h"
406 #undef UI_CONFIG_VARIABLE
407 #undef CANVAS_FONT_VARIABLE
408 
409  return *node;
410 }
411 
412 int
413 UIConfiguration::set_state (const XMLNode& root, int /*version*/)
414 {
415  /* this can load a generic UI configuration file or a colors file */
416 
417  if (root.name() != "Ardour") {
418  return -1;
419  }
420 
421  Stateful::save_extra_xml (root);
422 
423  XMLNodeList nlist = root.children();
424  XMLNodeConstIterator niter;
425  XMLNode *node;
426 
427  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
428 
429  node = *niter;
430 
431  if (node->name() == "Canvas" || node->name() == "UI") {
432  set_variables (*node);
433 
434  }
435  }
436 
437  XMLNode* colors = find_named_node (root, X_("Colors"));
438 
439  if (colors) {
440  load_colors (*colors);
441  }
442 
443  XMLNode* aliases = find_named_node (root, X_("ColorAliases"));
444 
445  if (aliases) {
446  load_color_aliases (*aliases);
447  }
448 
449  XMLNode* modifiers = find_named_node (root, X_("Modifiers"));
450 
451  if (modifiers) {
452  load_modifiers (*modifiers);
453  }
454 
455  return 0;
456 }
457 
458 void
460 {
461  XMLNodeList const nlist = node.children();
462  XMLNodeConstIterator niter;
463  XMLProperty const *name;
464  XMLProperty const *alias;
465 
466  color_aliases.clear ();
467 
468  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
469  if ((*niter)->name() != X_("ColorAlias")) {
470  continue;
471  }
472  name = (*niter)->property (X_("name"));
473  alias = (*niter)->property (X_("alias"));
474 
475  if (name && alias) {
476  color_aliases.insert (make_pair (name->value(), alias->value()));
477  }
478  }
479 }
480 
481 void
483 {
484  XMLNodeList const nlist = node.children();
485  XMLNodeConstIterator niter;
486  XMLProperty const *name;
487  XMLProperty const *color;
488 
489  colors.clear ();
490 
491  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
492  if ((*niter)->name() != X_("Color")) {
493  continue;
494  }
495  name = (*niter)->property (X_("name"));
496  color = (*niter)->property (X_("value"));
497 
498  if (name && color) {
499  ArdourCanvas::Color c;
500  c = strtoul (color->value().c_str(), 0, 16);
501  colors.insert (make_pair (name->value(), c));
502  }
503  }
504 }
505 
506 void
508 {
509  PBD::LocaleGuard lg ("C");
510  XMLNodeList const nlist = node.children();
511  XMLNodeConstIterator niter;
512  XMLProperty const *name;
513  XMLProperty const *mod;
514 
515  modifiers.clear ();
516 
517  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
518  if ((*niter)->name() != X_("Modifier")) {
519  continue;
520  }
521 
522  name = (*niter)->property (X_("name"));
523  mod = (*niter)->property (X_("modifier"));
524 
525  if (name && mod) {
526  SVAModifier svam (mod->value());
527  modifiers.insert (make_pair (name->value(), svam));
528  }
529  }
530 }
531 
532 void
534 {
535 #undef UI_CONFIG_VARIABLE
536 #define UI_CONFIG_VARIABLE(Type,var,name,val) if (var.set_from_node (node)) { ParameterChanged (name); }
537 #define CANVAS_FONT_VARIABLE(var,name) if (var.set_from_node (node)) { ParameterChanged (name); }
538 #include "ui_config_vars.h"
539 #include "canvas_vars.h"
540 #undef UI_CONFIG_VARIABLE
541 #undef CANVAS_FONT_VARIABLE
542 }
543 
544 ArdourCanvas::SVAModifier
545 UIConfiguration::modifier (string const & name) const
546 {
547  Modifiers::const_iterator m = modifiers.find (name);
548  if (m != modifiers.end()) {
549  return m->second;
550  }
551  return SVAModifier ();
552 }
553 
554 ArdourCanvas::Color
555 UIConfiguration::color_mod (std::string const & colorname, std::string const & modifiername) const
556 {
557  return HSV (color (colorname)).mod (modifier (modifiername)).color ();
558 }
559 
560 ArdourCanvas::Color
561 UIConfiguration::color_mod (const ArdourCanvas::Color& color, std::string const & modifiername) const
562 {
563  return HSV (color).mod (modifier (modifiername)).color ();
564 }
565 
566 ArdourCanvas::Color
567 UIConfiguration::color (const std::string& name, bool* failed) const
568 {
569  ColorAliases::const_iterator e = color_aliases.find (name);
570 
571  if (failed) {
572  *failed = false;
573  }
574 
575  if (e != color_aliases.end ()) {
576  Colors::const_iterator rc = colors.find (e->second);
577  if (rc != colors.end()) {
578  return rc->second;
579  }
580  } else {
581  /* not an alias, try directly */
582  Colors::const_iterator rc = colors.find (name);
583  if (rc != colors.end()) {
584  return rc->second;
585  }
586  }
587 
588  if (!failed) {
589  /* only show this message if the caller wasn't interested in
590  the fail status.
591  */
592  cerr << string_compose (_("Color %1 not found"), name) << endl;
593  }
594 
595  if (failed) {
596  *failed = true;
597  }
598 
599  return rgba_to_color ((g_random_int()%256)/255.0,
600  (g_random_int()%256)/255.0,
601  (g_random_int()%256)/255.0,
602  0xff);
603 }
604 
605 Color
607 {
608  HSV hsv (c);
609  hsv.h = hue_width * (round (hsv.h/hue_width));
610  return hsv.color ();
611 }
612 
613 void
614 UIConfiguration::set_color (string const& name, ArdourCanvas::Color color)
615 {
616  Colors::iterator i = colors.find (name);
617  if (i == colors.end()) {
618  return;
619  }
620  i->second = color;
621  colors_modified = true;
622 
623  ARDOUR_UI_UTILS::ColorsChanged (); /* EMIT SIGNAL */
624 }
625 
626 void
627 UIConfiguration::set_alias (string const & name, string const & alias)
628 {
629  ColorAliases::iterator i = color_aliases.find (name);
630  if (i == color_aliases.end()) {
631  return;
632  }
633 
634  i->second = alias;
635  aliases_modified = true;
636 
637  ARDOUR_UI_UTILS::ColorsChanged (); /* EMIT SIGNAL */
638 }
639 
640 void
641 UIConfiguration::set_modifier (string const & name, SVAModifier svam)
642 {
643  Modifiers::iterator m = modifiers.find (name);
644 
645  if (m == modifiers.end()) {
646  return;
647  }
648 
649  m->second = svam;
650  modifiers_modified = true;
651 
652  ARDOUR_UI_UTILS::ColorsChanged (); /* EMIT SIGNAL */
653 }
654 
655 void
656 UIConfiguration::load_rc_file (bool themechange, bool allow_own)
657 {
658  string basename = ui_rc_file.get();
659  std::string rc_file_path;
660 
661  if (!find_file (ardour_config_search_path(), basename, rc_file_path)) {
662  warning << string_compose (_("Unable to find UI style file %1 in search path %2. %3 will look strange"),
663  basename, ardour_config_search_path().to_string(), PROGRAM_NAME)
664  << endmsg;
665  return;
666  }
667 
668  info << "Loading ui configuration file " << rc_file_path << endmsg;
669 
670  Gtkmm2ext::UI::instance()->load_rcfile (rc_file_path, themechange);
671 }
672 
673 
bool modifiers_modified
Definition: ui_config.h:111
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
Definition: ui_config.cc:567
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
void load_colors(XMLNode const &)
Definition: ui_config.cc:482
ArdourCanvas::SVAModifier modifier(const std::string &) const
Definition: ui_config.cc:545
Colors colors
Definition: ui_config.h:61
const std::string & value() const
Definition: xml++.h:159
int store_color_theme()
Definition: ui_config.cc:240
bool write() const
Definition: xml++.cc:147
const std::string & name() const
Definition: xml++.h:104
static const char * ui_config_file_name
Definition: ui_config.cc:52
bool aliases_modified
Definition: ui_config.h:109
XMLNode & get_state(void)
Definition: ui_config.cc:375
XMLNode * add_child_copy(const XMLNode &)
Definition: xml++.cc:363
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
#define CANVAS_FONT_VARIABLE(var, name)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
static const char * default_ui_config_file_name
Definition: ui_config.cc:53
void map_parameters(boost::function< void(std::string)> &)
Definition: ui_config.cc:146
bool find_file(const Searchpath &search_path, const string &filename, std::string &result)
Definition: file_utils.cc:187
void load_color_aliases(XMLNode const &)
Definition: ui_config.cc:459
Definition: xml++.h:55
static UI * instance()
Definition: gtk_ui.h:119
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
#define UI_CONFIG_VARIABLE(Type, var, name, val)
XMLNode * _extra_xml
Definition: stateful.h:109
LIBARDOUR_API std::string user_config_directory(int version=-1)
ColorAliases color_aliases
Definition: ui_config.h:62
#define X_(Text)
Definition: i18n.h:13
void set_color(const std::string &name, ArdourCanvas::Color)
Definition: ui_config.cc:614
XMLNode * set_root(XMLNode *n)
Definition: xml++.h:63
int load_rcfile(std::string, bool themechange=false)
Definition: gtk_ui.cc:140
void load_rc_file(bool themechange, bool allow_own=true)
Definition: ui_config.cc:656
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
static UIConfiguration * _instance
Definition: ui_config.h:113
void parameter_changed(std::string)
Definition: ui_config.cc:109
bool read()
Definition: xml++.h:71
LIBARDOUR_API XMLNode * find_named_node(const XMLNode &node, std::string name)
LIBARDOUR_API PBD::Searchpath ardour_config_search_path()
LIBPBD_API Transmitter info
bool colors_modified
Definition: ui_config.h:110
void colors_changed()
Definition: ui_config.cc:92
int load_defaults()
Definition: ui_config.cc:155
XMLProperty * add_property(const char *name, const std::string &value)
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
static const double hue_width
Definition: ui_config.cc:56
Definition: xml++.h:95
ArdourCanvas::Color color_mod(std::string const &color, std::string const &modifier) const
Definition: ui_config.cc:555
sigc::signal< void > ColorsChanged
Definition: debug.h:30
Modifiers modifiers
Definition: ui_config.h:63
void set_alias(std::string const &name, std::string const &alias)
Definition: ui_config.cc:627
sigc::signal< void, std::string > ParameterChanged
Definition: ui_config.h:78
int load_color_theme(bool allow_own=true)
Definition: ui_config.cc:190
ArdourCanvas::Color quantized(ArdourCanvas::Color) const
Definition: ui_config.cc:606
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
void set_variables(const XMLNode &)
Definition: ui_config.cc:533
void set_modifier(std::string const &, ArdourCanvas::SVAModifier svam)
Definition: ui_config.cc:641
XMLNode & get_variables(std::string)
Definition: ui_config.cc:393
void load_modifiers(XMLNode const &)
Definition: ui_config.cc:507
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void reset_gtk_theme()
Definition: ui_config.cc:123
int set_state(const XMLNode &, int version)
Definition: ui_config.cc:413
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
Definition: route_group.cc:50