ardour
utils.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 Paul Davis
3 
4  This program is free software; you an 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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23 
24 #include <pango/pangoft2.h> // for fontmap resolution control for GnomeCanvas
25 #include <pango/pangocairo.h> // for fontmap resolution control for GnomeCanvas
26 
27 #include <cstdlib>
28 #include <clocale>
29 #include <cstring>
30 #include <cctype>
31 #include <cmath>
32 #include <fstream>
33 #include <list>
34 #include <sys/stat.h>
35 #include <gtkmm/rc.h>
36 #include <gtkmm/window.h>
37 #include <gtkmm/combo.h>
38 #include <gtkmm/label.h>
39 #include <gtkmm/paned.h>
40 #include <gtk/gtkpaned.h>
41 #include <boost/algorithm/string.hpp>
42 
43 #include "pbd/file_utils.h"
44 
45 #include <gtkmm2ext/utils.h>
48 
49 #include "canvas/item.h"
50 #include "canvas/utils.h"
51 
52 #include "ardour_ui.h"
53 #include "debug.h"
54 #include "public_editor.h"
55 #include "keyboard.h"
56 #include "utils.h"
57 #include "i18n.h"
58 #include "rgb_macros.h"
59 #include "gui_thread.h"
60 
61 using namespace std;
62 using namespace Gtk;
63 using namespace Glib;
64 using namespace PBD;
66 
67 namespace ARDOUR_UI_UTILS {
68  sigc::signal<void> DPIReset;
69 }
70 
71 #ifdef PLATFORM_WINDOWS
72 #define random() rand()
73 #endif
74 
75 
81 void
82 ARDOUR_UI_UTILS::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s)
83 {
84  m.push_back (e);
85  if (!s) {
86  m.back().set_sensitive (false);
87  }
88 }
89 
90 
91 gint
92 ARDOUR_UI_UTILS::just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win)
93 {
94  win->hide ();
95  return 0;
96 }
97 
98 /* xpm2rgb copied from nixieclock, which bore the legend:
99 
100  nixieclock - a nixie desktop timepiece
101  Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
102 
103  and was released under the GPL.
104 */
105 
106 unsigned char*
107 ARDOUR_UI_UTILS::xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
108 {
109  static long vals[256], val;
110  uint32_t t, x, y, colors, cpp;
111  unsigned char c;
112  unsigned char *savergb, *rgb;
113 
114  // PARSE HEADER
115 
116  if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
117  error << string_compose (_("bad XPM header %1"), xpm[0])
118  << endmsg;
119  return 0;
120  }
121 
122  savergb = rgb = (unsigned char*) malloc (h * w * 3);
123 
124  // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
125  for (t = 0; t < colors; ++t) {
126  sscanf (xpm[t+1], "%c c #%lx", &c, &val);
127  vals[c] = val;
128  }
129 
130  // COLORMAP -> RGB CONVERSION
131  // Get low 3 bytes from vals[]
132  //
133 
134  const char *p;
135  for (y = h-1; y > 0; --y) {
136 
137  for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
138  val = vals[(int)*p++];
139  *(rgb+2) = val & 0xff; val >>= 8; // 2:B
140  *(rgb+1) = val & 0xff; val >>= 8; // 1:G
141  *(rgb+0) = val & 0xff; // 0:R
142  }
143  }
144 
145  return (savergb);
146 }
147 
148 unsigned char*
149 ARDOUR_UI_UTILS::xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
150 {
151  static long vals[256], val;
152  uint32_t t, x, y, colors, cpp;
153  unsigned char c;
154  unsigned char *savergb, *rgb;
155  char transparent;
156 
157  // PARSE HEADER
158 
159  if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
160  error << string_compose (_("bad XPM header %1"), xpm[0])
161  << endmsg;
162  return 0;
163  }
164 
165  savergb = rgb = (unsigned char*) malloc (h * w * 4);
166 
167  // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
168 
169  if (strstr (xpm[1], "None")) {
170  sscanf (xpm[1], "%c", &transparent);
171  t = 1;
172  } else {
173  transparent = 0;
174  t = 0;
175  }
176 
177  for (; t < colors; ++t) {
178  sscanf (xpm[t+1], "%c c #%lx", &c, &val);
179  vals[c] = val;
180  }
181 
182  // COLORMAP -> RGB CONVERSION
183  // Get low 3 bytes from vals[]
184  //
185 
186  const char *p;
187  for (y = h-1; y > 0; --y) {
188 
189  char alpha;
190 
191  for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
192 
193  if (transparent && (*p++ == transparent)) {
194  alpha = 0;
195  val = 0;
196  } else {
197  alpha = 255;
198  val = vals[(int)*p];
199  }
200 
201  *(rgb+3) = alpha; // 3: alpha
202  *(rgb+2) = val & 0xff; val >>= 8; // 2:B
203  *(rgb+1) = val & 0xff; val >>= 8; // 1:G
204  *(rgb+0) = val & 0xff; // 0:R
205  }
206  }
207 
208  return (savergb);
209 }
210 
225 Pango::FontDescription
227 {
228  Pango::FontDescription fd (name);
229 
230  if (fd.get_family().empty()) {
231  fd.set_family ("Sans");
232  }
233 
234  return fd;
235 }
236 
237 Pango::FontDescription
238 ARDOUR_UI_UTILS::get_font_for_style (string widgetname)
239 {
240  Gtk::Window window (WINDOW_TOPLEVEL);
241  Gtk::Label foobar;
242  Glib::RefPtr<Gtk::Style> style;
243 
244  window.add (foobar);
245  foobar.set_name (widgetname);
246  foobar.ensure_style();
247 
248  style = foobar.get_style ();
249 
250  Glib::RefPtr<const Pango::Layout> layout = foobar.get_layout();
251 
252  PangoFontDescription *pfd = const_cast<PangoFontDescription *> (pango_layout_get_font_description(const_cast<PangoLayout *>(layout->gobj())));
253 
254  if (!pfd) {
255 
256  /* layout inherited its font description from a PangoContext */
257 
258  PangoContext* ctxt = (PangoContext*) pango_layout_get_context (const_cast<PangoLayout*>(layout->gobj()));
259  pfd = pango_context_get_font_description (ctxt);
260  return Pango::FontDescription (pfd); /* make a copy */
261  }
262 
263  return Pango::FontDescription (pfd); /* make a copy */
264 }
265 
266 void
267 ARDOUR_UI_UTILS::set_color_from_rgb (Gdk::Color& c, uint32_t rgb)
268 {
269  /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
270  multiplying by 256.
271  */
272  c.set_rgb ((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
273 }
274 
275 void
276 ARDOUR_UI_UTILS::set_color_from_rgba (Gdk::Color& c, uint32_t rgba)
277 {
278  /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
279  multiplying by 256.
280  */
281  c.set_rgb ((rgba >> 24)*256, ((rgba & 0xff0000) >> 16)*256, ((rgba & 0xff00) >> 8)*256);
282 }
283 
284 uint32_t
286 {
287  /* since alpha value is not available from a Gdk::Color, it is
288  hardcoded as 0xff (aka 255 or 1.0)
289  */
290 
291  const uint32_t r = c.get_red_p () * 255.0;
292  const uint32_t g = c.get_green_p () * 255.0;
293  const uint32_t b = c.get_blue_p () * 255.0;
294  const uint32_t a = 0xff;
295 
296  return RGBA_TO_UINT (r,g,b,a);
297 }
298 
299 
300 bool
301 ARDOUR_UI_UTILS::relay_key_press (GdkEventKey* ev, Gtk::Window* win)
302 {
304 
305  if (!key_press_focus_accelerator_handler (*win, ev)) {
306  if (&ed == 0) {
307  /* early key press in pre-main-window-dialogs, no editor yet */
308  return false;
309  }
310  return ed.on_key_press_event(ev);
311  } else {
312  return true;
313  }
314 }
315 
316 bool
318 {
319  return PublicEditor::instance().on_key_press_event(ev);
320 }
321 
322 bool
323 ARDOUR_UI_UTILS::emulate_key_event (Gtk::Widget* w, unsigned int keyval)
324 {
325  GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET(w->gobj()));
326  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
327  GdkKeymapKey *keymapkey = NULL;
328  gint n_keys;
329 
330  if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keymapkey, &n_keys)) return false;
331  if (n_keys !=1) { g_free(keymapkey); return false;}
332 
333  GdkEventKey ev;
334  ev.type = GDK_KEY_PRESS;
335  ev.window = gtk_widget_get_window(GTK_WIDGET(w->gobj()));
336  ev.send_event = FALSE;
337  ev.time = 0;
338  ev.state = 0;
339  ev.keyval = keyval;
340  ev.length = 0;
341  ev.string = const_cast<gchar*> ("");
342  ev.hardware_keycode = keymapkey[0].keycode;
343  ev.group = keymapkey[0].group;
344  g_free(keymapkey);
345 
346  forward_key_press(&ev);
347  ev.type = GDK_KEY_RELEASE;
348  return forward_key_press(&ev);
349 }
350 
351 static string
353 {
354  string s;
355  if (state & GDK_SHIFT_MASK) {
356  s += "+SHIFT";
357  }
358  if (state & GDK_LOCK_MASK) {
359  s += "+LOCK";
360  }
361  if (state & GDK_CONTROL_MASK) {
362  s += "+CONTROL";
363  }
364  if (state & GDK_MOD1_MASK) {
365  s += "+MOD1";
366  }
367  if (state & GDK_MOD2_MASK) {
368  s += "+MOD2";
369  }
370  if (state & GDK_MOD3_MASK) {
371  s += "+MOD3";
372  }
373  if (state & GDK_MOD4_MASK) {
374  s += "+MOD4";
375  }
376  if (state & GDK_MOD5_MASK) {
377  s += "+MOD5";
378  }
379  if (state & GDK_BUTTON1_MASK) {
380  s += "+BUTTON1";
381  }
382  if (state & GDK_BUTTON2_MASK) {
383  s += "+BUTTON2";
384  }
385  if (state & GDK_BUTTON3_MASK) {
386  s += "+BUTTON3";
387  }
388  if (state & GDK_BUTTON4_MASK) {
389  s += "+BUTTON4";
390  }
391  if (state & GDK_BUTTON5_MASK) {
392  s += "+BUTTON5";
393  }
394  if (state & GDK_SUPER_MASK) {
395  s += "+SUPER";
396  }
397  if (state & GDK_HYPER_MASK) {
398  s += "+HYPER";
399  }
400  if (state & GDK_META_MASK) {
401  s += "+META";
402  }
403  if (state & GDK_RELEASE_MASK) {
404  s += "+RELEASE";
405  }
406 
407  return s;
408 }
409 bool
410 ARDOUR_UI_UTILS::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
411 {
412  GtkWindow* win = window.gobj();
413  GtkWidget* focus = gtk_window_get_focus (win);
414  bool special_handling_of_unmodified_accelerators = false;
415  bool allow_activating = true;
416  /* consider all relevant modifiers but not LOCK or SHIFT */
417  const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
418  GdkModifierType modifier = GdkModifierType (ev->state);
419  modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
421 
422  if (focus) {
423  if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
424  special_handling_of_unmodified_accelerators = true;
425  }
426  }
427 
428 #ifdef GTKOSX
429  /* at one time this appeared to be necessary. As of July 2012, it does not
430  appear to be. if it ever is necessar, figure out if it should apply
431  to all platforms.
432  */
433 #if 0
434  if (Keyboard::some_magic_widget_has_focus ()) {
435  allow_activating = false;
436  }
437 #endif
438 #endif
439 
440 
441  DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n",
442  win,
443  ev->keyval,
444  show_gdk_event_state (ev->state),
445  special_handling_of_unmodified_accelerators,
446  Keyboard::some_magic_widget_has_focus(),
447  allow_activating,
448  focus,
449  (focus ? gtk_widget_get_name (focus) : "no focus widget")));
450 
451  /* This exists to allow us to override the way GTK handles
452  key events. The normal sequence is:
453 
454  a) event is delivered to a GtkWindow
455  b) accelerators/mnemonics are activated
456  c) if (b) didn't handle the event, propagate to
457  the focus widget and/or focus chain
458 
459  The problem with this is that if the accelerators include
460  keys without modifiers, such as the space bar or the
461  letter "e", then pressing the key while typing into
462  a text entry widget results in the accelerator being
463  activated, instead of the desired letter appearing
464  in the text entry.
465 
466  There is no good way of fixing this, but this
467  represents a compromise. The idea is that
468  key events involving modifiers (not Shift)
469  get routed into the activation pathway first, then
470  get propagated to the focus widget if necessary.
471 
472  If the key event doesn't involve modifiers,
473  we deliver to the focus widget first, thus allowing
474  it to get "normal text" without interference
475  from acceleration.
476 
477  Of course, this can also be problematic: if there
478  is a widget with focus, then it will swallow
479  all "normal text" accelerators.
480  */
481 
482  if (!special_handling_of_unmodified_accelerators) {
483 
484 
485  /* XXX note that for a brief moment, the conditional above
486  * included "|| (ev->state & mask)" so as to enforce the
487  * implication of special_handling_of_UNMODIFIED_accelerators.
488  * however, this forces any key that GTK doesn't allow and that
489  * we have an alternative (see next comment) for to be
490  * automatically sent through the accel groups activation
491  * pathway, which prevents individual widgets & canvas items
492  * from ever seeing it if is used by a key binding.
493  *
494  * specifically, this hid Ctrl-down-arrow from MIDI region
495  * views because it is also bound to an action.
496  *
497  * until we have a robust, clean binding system, this
498  * quirk will have to remain in place.
499  */
500 
501  /* pretend that certain key events that GTK does not allow
502  to be used as accelerators are actually something that
503  it does allow. but only where there are no modifiers.
504  */
505 
506  uint32_t fakekey = ev->keyval;
507 
509  DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels\n",
510  ev->keyval, fakekey));
511 
512  DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tmodified modifier was %1\n", show_gdk_event_state (modifier)));
513 
514  if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, modifier)) {
515  DEBUG_TRACE (DEBUG::Accelerators, "\taccel group activated by fakekey\n");
516  return true;
517  }
518  }
519  }
520 
521  if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
522 
523  /* no special handling or there are modifiers in effect: accelerate first */
524 
525  DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
526  DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
527  ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
528 
529  if (allow_activating) {
530  DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
531  if (gtk_accel_groups_activate (G_OBJECT(win), ev->keyval, modifier)) {
532  DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
533  return true;
534  }
535  } else {
536  DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
537  }
538 
539  DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
540 
541  return gtk_window_propagate_key_event (win, ev);
542  }
543 
544  /* no modifiers, propagate first */
545 
546  DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
547 
548  if (!gtk_window_propagate_key_event (win, ev)) {
549  DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
550  if (allow_activating) {
551  return gtk_accel_groups_activate (G_OBJECT(win), ev->keyval, modifier);
552  } else {
553  DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
554  }
555 
556  } else {
557  DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
558  return true;
559  }
560 
561  DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
562  return true;
563 }
564 
565 Glib::RefPtr<Gdk::Pixbuf>
567 {
568  if (!xpm_map[name]) {
569 
571 
572  spath.add_subdirectory_to_paths("pixmaps");
573 
574  std::string data_file_path;
575 
576  if(!find_file (spath, name, data_file_path)) {
577  fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg;
578  }
579 
580  try {
581  xpm_map[name] = Gdk::Pixbuf::create_from_file (data_file_path);
582  } catch(const Glib::Error& e) {
583  warning << "Caught Glib::Error: " << e.what() << endmsg;
584  }
585  }
586 
587  return xpm_map[name];
588 }
589 
590 vector<string>
592 {
594  spath.add_subdirectory_to_paths ("icons");
595  vector<string> r;
596 
597  r.push_back (_("default"));
598 
599  for (vector<string>::iterator s = spath.begin(); s != spath.end(); ++s) {
600 
601  vector<string> entries;
602 
603  get_paths (entries, *s, false, false);
604 
605  for (vector<string>::iterator e = entries.begin(); e != entries.end(); ++e) {
606  if (Glib::file_test (*e, Glib::FILE_TEST_IS_DIR)) {
607  r.push_back (Glib::filename_to_utf8 (Glib::path_get_basename(*e)));
608  }
609  }
610  }
611 
612  return r;
613 }
614 
615 std::string
616 ARDOUR_UI_UTILS::get_icon_path (const char* cname, string icon_set, bool is_image)
617 {
618  std::string data_file_path;
619  string name = cname;
620 
621  if (is_image) {
622  name += X_(".png");
623  }
624 
626 
627  if (!icon_set.empty() && icon_set != _("default")) {
628 
629  /* add "icons/icon_set" but .. not allowed to add both of these at once */
630  spath.add_subdirectory_to_paths ("icons");
631  spath.add_subdirectory_to_paths (icon_set);
632 
633  find_file (spath, name, data_file_path);
634  } else {
635  spath.add_subdirectory_to_paths ("icons");
636  find_file (spath, name, data_file_path);
637  }
638 
639  if (is_image && data_file_path.empty()) {
640 
641  if (!icon_set.empty() && icon_set != _("default")) {
642  warning << string_compose (_("icon \"%1\" not found for icon set \"%2\", fallback to default"), cname, icon_set) << endmsg;
643  }
644 
646  def.add_subdirectory_to_paths ("icons");
647 
648  if (!find_file (def, name, data_file_path)) {
649  fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg;
650  abort(); /*NOTREACHED*/
651  }
652  }
653 
654  return data_file_path;
655 }
656 
657 Glib::RefPtr<Gdk::Pixbuf>
658 ARDOUR_UI_UTILS::get_icon (const char* cname, string icon_set)
659 {
660  Glib::RefPtr<Gdk::Pixbuf> img;
661  try {
662  img = Gdk::Pixbuf::create_from_file (get_icon_path (cname, icon_set));
663  } catch (const Gdk::PixbufError &e) {
664  cerr << "Caught PixbufError: " << e.what() << endl;
665  } catch (...) {
666  error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg;
667  }
668 
669  return img;
670 }
671 
672 namespace ARDOUR_UI_UTILS {
673 Glib::RefPtr<Gdk::Pixbuf>
674 get_icon (const char* cname)
675 {
676  Glib::RefPtr<Gdk::Pixbuf> img;
677  try {
678  img = Gdk::Pixbuf::create_from_file (get_icon_path (cname));
679  } catch (const Gdk::PixbufError &e) {
680  cerr << "Caught PixbufError: " << e.what() << endl;
681  } catch (...) {
682  error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg;
683  }
684 
685  return img;
686 }
687 }
688 
689 string
690 ARDOUR_UI_UTILS::longest (vector<string>& strings)
691 {
692  if (strings.empty()) {
693  return string ("");
694  }
695 
696  vector<string>::iterator longest = strings.begin();
697  string::size_type longest_length = (*longest).length();
698 
699  vector<string>::iterator i = longest;
700  ++i;
701 
702  while (i != strings.end()) {
703 
704  string::size_type len = (*i).length();
705 
706  if (len > longest_length) {
707  longest = i;
708  longest_length = len;
709  }
710 
711  ++i;
712  }
713 
714  return *longest;
715 }
716 
717 bool
719 {
720  /* we assume that this does not change over the life of the process
721  */
722 
723  static int comma_decimal = -1;
724 
725  switch (keyval) {
726  case GDK_period:
727  case GDK_comma:
728  if (comma_decimal < 0) {
729  std::lconv* lc = std::localeconv();
730  if (strchr (lc->decimal_point, ',') != 0) {
731  comma_decimal = 1;
732  } else {
733  comma_decimal = 0;
734  }
735  }
736  break;
737  default:
738  break;
739  }
740 
741  switch (keyval) {
742  case GDK_decimalpoint:
743  case GDK_KP_Separator:
744  return true;
745 
746  case GDK_period:
747  if (comma_decimal) {
748  return false;
749  } else {
750  return true;
751  }
752  break;
753  case GDK_comma:
754  if (comma_decimal) {
755  return true;
756  } else {
757  return false;
758  }
759  break;
760  case GDK_minus:
761  case GDK_plus:
762  case GDK_0:
763  case GDK_1:
764  case GDK_2:
765  case GDK_3:
766  case GDK_4:
767  case GDK_5:
768  case GDK_6:
769  case GDK_7:
770  case GDK_8:
771  case GDK_9:
772  case GDK_KP_Add:
773  case GDK_KP_Subtract:
774  case GDK_KP_Decimal:
775  case GDK_KP_0:
776  case GDK_KP_1:
777  case GDK_KP_2:
778  case GDK_KP_3:
779  case GDK_KP_4:
780  case GDK_KP_5:
781  case GDK_KP_6:
782  case GDK_KP_7:
783  case GDK_KP_8:
784  case GDK_KP_9:
785  case GDK_Return:
786  case GDK_BackSpace:
787  case GDK_Delete:
788  case GDK_KP_Enter:
789  case GDK_Home:
790  case GDK_End:
791  case GDK_Left:
792  case GDK_Right:
793  return true;
794 
795  default:
796  break;
797  }
798 
799  return false;
800 }
801 
802 void
804 {
805  long val = ARDOUR_UI::config()->get_font_scale();
806 
807  /* FT2 rendering - used by GnomeCanvas, sigh */
808 
809 #ifndef PLATFORM_WINDOWS
810  pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_new(), val/1024, val/1024);
811 #endif
812 
813  /* Cairo rendering, in case there is any */
814 
815  pango_cairo_font_map_set_resolution ((PangoCairoFontMap*) pango_cairo_font_map_get_default(), val/1024);
816 }
817 
818 void
820 {
821  long val = ARDOUR_UI::config()->get_font_scale();
823  /* Xft rendering */
824 
825  gtk_settings_set_long_property (gtk_settings_get_default(),
826  "gtk-xft-dpi", val, "ardour");
827  DPIReset();//Emit Signal
828 }
829 
830 void
831 ARDOUR_UI_UTILS::resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height)
832 {
833  Glib::RefPtr<Gdk::Screen> screen = window->get_screen ();
834  Gdk::Rectangle monitor_rect;
835  screen->get_monitor_geometry (0, monitor_rect);
836 
837  int const w = std::min (int (monitor_rect.get_width() * 0.8), max_width);
838  int const h = std::min (int (monitor_rect.get_height() * 0.8), max_height);
839 
840  window->resize (w, h);
841 }
842 
843 
845 string
846 ARDOUR_UI_UTILS::escape_underscores (string const & s)
847 {
848  string o;
849  string::size_type const N = s.length ();
850 
851  for (string::size_type i = 0; i < N; ++i) {
852  if (s[i] == '_') {
853  o += "__";
854  } else {
855  o += s[i];
856  }
857  }
858 
859  return o;
860 }
861 
863 string
865 {
866  string o = s;
867  boost::replace_all (o, "<", "&lt;");
868  boost::replace_all (o, ">", "&gt;");
869  return o;
870 }
871 
872 Gdk::Color
873 ARDOUR_UI_UTILS::unique_random_color (list<Gdk::Color>& used_colors)
874 {
875  Gdk::Color newcolor;
876 
877  while (1) {
878 
879  double h, s, v;
880 
881  h = fmod (random(), 360.0);
882  s = (random() % 65535) / 65535.0;
883  v = (random() % 65535) / 65535.0;
884 
885  s = min (0.5, s); /* not too saturated */
886  v = max (0.9, v); /* not too bright */
887  newcolor.set_hsv (h, s, v);
888 
889  if (used_colors.size() == 0) {
890  used_colors.push_back (newcolor);
891  return newcolor;
892  }
893 
894  for (list<Gdk::Color>::iterator i = used_colors.begin(); i != used_colors.end(); ++i) {
895  Gdk::Color c = *i;
896  float rdelta, bdelta, gdelta;
897 
898  rdelta = newcolor.get_red() - c.get_red();
899  bdelta = newcolor.get_blue() - c.get_blue();
900  gdelta = newcolor.get_green() - c.get_green();
901 
902  if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) {
903  /* different enough */
904  used_colors.push_back (newcolor);
905  return newcolor;
906  }
907  }
908 
909  /* XXX need throttle here to make sure we don't spin for ever */
910  }
911 }
912 
913 string
915 {
916  char buf[32];
917  if (fmod (r, 1000.0f)) {
918  snprintf (buf, sizeof (buf), "%.1f kHz", r/1000.0);
919  } else {
920  snprintf (buf, sizeof (buf), "%.0f kHz", r/1000.0);
921  }
922  return buf;
923 }
bool relay_key_press(GdkEventKey *ev, Gtk::Window *win)
Definition: utils.cc:301
Gdk::Color unique_random_color(std::list< Gdk::Color > &)
Definition: utils.cc:873
LIBPBD_API Transmitter fatal
unsigned char * xpm2rgba(const char **xpm, uint32_t &w, uint32_t &h)
Definition: utils.cc:149
static std::map< std::string, Glib::RefPtr< Gdk::Pixbuf > > xpm_map
Definition: utils.h:81
void resize_window_to_proportion_of_monitor(Gtk::Window *, int, int)
Definition: utils.cc:831
Pango::FontDescription sanitized_font(std::string const &)
Definition: utils.cc:226
bool emulate_key_event(Gtk::Widget *, unsigned int)
Definition: utils.cc:323
LIBGTKMM2EXT_API bool possibly_translate_mod_to_make_legal_accelerator(GdkModifierType &mod)
Definition: utils.cc:375
sigc::signal< void > DPIReset
Definition: utils.cc:68
Definition: ardour_ui.h:130
Pango::FontDescription get_font_for_style(std::string widgetname)
bool forward_key_press(GdkEventKey *ev)
Definition: utils.cc:317
bool key_press_focus_accelerator_handler(Gtk::Window &window, GdkEventKey *ev)
Definition: utils.cc:410
std::vector< std::string > get_icon_sets()
Definition: utils.cc:591
static string show_gdk_event_state(int state)
Definition: utils.cc:352
unsigned char * xpm2rgb(const char **xpm, uint32_t &w, uint32_t &h)
Definition: utils.cc:107
Representation of the interface of the Editor class.
static int N
Definition: signals_test.cc:27
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
guint modifier
void add_item_with_sensitivity(Gtk::Menu_Helpers::MenuList &, Gtk::Menu_Helpers::MenuElem, bool)
LIBPBD_API int replace_all(std::string &str, const std::string &target, const std::string &replacement)
Definition: strreplace.cc:24
bool find_file(const Searchpath &search_path, const string &filename, std::string &result)
Definition: file_utils.cc:187
void reset_dpi()
Definition: utils.cc:819
LIBPBD_TEMPLATE_MEMBER_API Searchpath & add_subdirectory_to_paths(const std::string &subdir)
Definition: search_path.cc:158
gint just_hide_it(GdkEventAny *, Gtk::Window *)
Definition: utils.cc:92
#define _(Text)
Definition: i18n.h:11
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
uint32_t gdk_color_to_rgba(Gdk::Color const &)
Definition: utils.cc:285
#define X_(Text)
Definition: i18n.h:13
void set_color_from_rgba(Gdk::Color &, uint32_t)
Definition: utils.cc:276
std::string longest(std::vector< std::string > &)
uint64_t Accelerators
Definition: debug.cc:30
std::string rate_as_string(float r)
Definition: utils.cc:914
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
void set_color_from_rgb(Gdk::Color &, uint32_t)
Definition: utils.cc:267
bool key_is_legal_for_numeric_entry(guint keyval)
Definition: utils.cc:718
void set_pango_fontsize()
Definition: utils.cc:803
LIBGTKMM2EXT_API bool possibly_translate_keyval_to_make_legal_accelerator(uint32_t &keyval)
Definition: utils.cc:399
static PublicEditor & instance()
const char * name
void get_paths(vector< string > &result, const Searchpath &paths, bool files_only, bool recurse)
Definition: file_utils.cc:144
static UIConfiguration * config()
Definition: ardour_ui.h:188
Definition: debug.h:30
Glib::RefPtr< Gdk::Pixbuf > get_xpm(std::string)
Definition: utils.cc:566
std::string get_icon_path(const char *, std::string icon_set=std::string(), bool is_image=true)
#define RGBA_TO_UINT(r, g, b, a)
Definition: rgb_macros.h:34
std::string escape_underscores(std::string const &)
LIBARDOUR_API PBD::Searchpath ardour_data_search_path()
Glib::RefPtr< Gdk::Pixbuf > get_icon(const char *cname)
Definition: utils.cc:674
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
std::string escape_angled_brackets(std::string const &)