2 Copyright (C) 2003 Paul Davis
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.
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.
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.
23 #include <libart_lgpl/art_misc.h>
24 #include <gtkmm/window.h>
25 #include <gtkmm/combo.h>
26 #include <gtkmm/label.h>
27 #include <gtkmm/paned.h>
28 #include <gtk/gtkpaned.h>
30 #include <gtkmm2ext/utils.h>
32 #include "ardour_ui.h"
35 #include "rgb_macros.h"
41 short_version (string orig, string::size_type target_length)
43 /* this tries to create a recognizable abbreviation
44 of "orig" by removing characters until we meet
45 a certain target length.
47 note that we deliberately leave digits in the result
52 string::size_type pos;
54 /* remove white-space and punctuation, starting at end */
56 while (orig.length() > target_length) {
57 if ((pos = orig.find_last_of (_("\"\n\t ,<.>/?:;'[{}]~`!@#$%^&*()_-+="))) == string::npos) {
60 orig.replace (pos, 1, "");
63 /* remove lower-case vowels, starting at end */
65 while (orig.length() > target_length) {
66 if ((pos = orig.find_last_of (_("aeiou"))) == string::npos) {
69 orig.replace (pos, 1, "");
72 /* remove upper-case vowels, starting at end */
74 while (orig.length() > target_length) {
75 if ((pos = orig.find_last_of (_("AEIOU"))) == string::npos) {
78 orig.replace (pos, 1, "");
81 /* remove lower-case consonants, starting at end */
83 while (orig.length() > target_length) {
84 if ((pos = orig.find_last_of (_("bcdfghjklmnpqrtvwxyz"))) == string::npos) {
87 orig.replace (pos, 1, "");
90 /* remove upper-case consonants, starting at end */
92 while (orig.length() > target_length) {
93 if ((pos = orig.find_last_of (_("BCDFGHJKLMNPQRTVWXYZ"))) == string::npos) {
96 orig.replace (pos, 1, "");
99 /* whatever the length is now, use it */
105 fit_to_pixels (string str, int32_t pixel_width, Gdk_Font& font)
113 int namelen = str.length();
114 char cstr[namelen+1];
115 strcpy (cstr, str.c_str());
119 gdk_string_extents (font,
127 if (width < (pixel_width)) {
132 cstr[namelen] = '\0';
140 atoi (const string& s)
142 return atoi (s.c_str());
146 atof (const string& s)
148 return atof (s.c_str());
152 strip_whitespace_edges (string& str)
155 string::size_type len;
160 for (i = 0; i < len; ++i) {
161 if (isgraph (str[i])) {
168 for (i = len - 1; i >= 0; --i) {
169 if (isgraph (str[i])) {
174 str = str.substr (s, (i - s) + 1);
178 internationalize (const char **array)
182 for (uint32_t i = 0; array[i]; ++i) {
183 v.push_back (_(array[i]));
190 just_hide_it (GdkEventAny *ev, Gtk::Window *win)
192 ARDOUR_UI::instance()->allow_focus (false);
198 allow_keyboard_focus (bool yn)
200 ARDOUR_UI::instance()->allow_focus (yn);
203 /* xpm2rgb copied from nixieclock, which bore the legend:
205 nixieclock - a nixie desktop timepiece
206 Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
208 and was released under the GPL.
212 xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
214 static long vals[256], val;
215 uint32_t t, x, y, colors, cpp;
217 unsigned char *savergb, *rgb;
221 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
222 error << string_compose (_("bad XPM header %1"), xpm[0])
227 savergb = rgb = (unsigned char*)art_alloc (h * w * 3);
229 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
230 for (t = 0; t < colors; ++t) {
231 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
235 // COLORMAP -> RGB CONVERSION
236 // Get low 3 bytes from vals[]
240 for (y = h-1; y > 0; --y) {
242 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
243 val = vals[(int)*p++];
244 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
245 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
246 *(rgb+0) = val & 0xff; // 0:R
254 xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
256 static long vals[256], val;
257 uint32_t t, x, y, colors, cpp;
259 unsigned char *savergb, *rgb;
264 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
265 error << string_compose (_("bad XPM header %1"), xpm[0])
270 savergb = rgb = (unsigned char*)art_alloc (h * w * 4);
272 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
274 if (strstr (xpm[1], "None")) {
275 sscanf (xpm[1], "%c", &transparent);
282 for (; t < colors; ++t) {
283 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
287 // COLORMAP -> RGB CONVERSION
288 // Get low 3 bytes from vals[]
292 for (y = h-1; y > 0; --y) {
296 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
298 if (transparent && (*p++ == transparent)) {
306 *(rgb+3) = alpha; // 3: alpha
307 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
308 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
309 *(rgb+0) = val & 0xff; // 0:R
317 get_canvas_points (string who, uint32_t npoints)
319 // cerr << who << ": wants " << npoints << " canvas points" << endl;
320 #ifdef TRAP_EXCESSIVE_POINT_REQUESTS
321 if (npoints > (uint32_t) gdk_screen_width() + 4) {
325 return gnome_canvas_points_new (npoints);
329 channel_combo_get_channel_count (Gtk::Combo& combo)
331 string str = combo.get_entry()->get_text();
334 if (str == _("mono")) {
336 } else if (str == _("stereo")) {
338 } else if ((chns = atoi (str)) != 0) {
346 int_from_hex (char hic, char loc)
348 int hi; /* hi byte */
349 int lo; /* low byte */
353 if( ('0'<=hi) && (hi<='9') ) {
355 } else if( ('a'<= hi) && (hi<= 'f') ) {
357 } else if( ('A'<=hi) && (hi<='F') ) {
363 if( ('0'<=lo) && (lo<='9') ) {
365 } else if( ('a'<=lo) && (lo<='f') ) {
367 } else if( ('A'<=lo) && (lo<='F') ) {
371 return lo + (16 * hi);
375 url_decode (string& url)
377 string::iterator last;
378 string::iterator next;
380 for (string::iterator i = url.begin(); i != url.end(); ++i) {
386 if (url.length() <= 3) {
392 --last; /* points at last char */
393 --last; /* points at last char - 1 */
395 for (string::iterator i = url.begin(); i != last; ) {
406 if (isxdigit (*i) && isxdigit (*next)) {
407 /* replace first digit with char */
408 *i = int_from_hex (*i,*next);
409 ++i; /* points at 2nd of 2 digits */
419 get_font_for_style (string widgetname)
423 foobar.set_name (widgetname);
424 foobar.ensure_style();
426 if (foobar.get_style() == 0 || foobar.get_style()->gobj()->rc_style == 0 || foobar.get_style()->gobj()->rc_style->font_name == 0) {
430 string str = foobar.get_style()->gobj()->rc_style->font_name;
433 return "fixed"; // standard X Window fallback font
439 pane_handler (GdkEventButton* ev, Gtk::Paned* pane)
441 if (ev->window != Gtkmm2ext::get_paned_handle (*pane)) {
445 if (Keyboard::is_delete_event (ev)) {
450 pos = Gtkmm2ext::gtk_paned_get_position (pane->gobj());
452 if (dynamic_cast<VPaned*>(pane)) {
453 cmp = pane->get_height();
455 cmp = pane->get_width();
458 /* we have to use approximations here because we can't predict the
459 exact position or sizes of the pane (themes, etc)
462 if (pos < 10 || abs (pos - cmp) < 10) {
464 /* already collapsed: restore it (note that this is cast from a pointer value to int, which is tricky on 64bit */
466 pane->set_position ((gint64) pane->get_data ("rpos"));
470 int collapse_direction;
472 /* store the current position */
474 pane->set_data ("rpos", (gpointer) pos);
476 /* collapse to show the relevant child in full */
478 collapse_direction = (gint64) pane->get_data ("collapse-direction");
480 if (collapse_direction) {
481 pane->set_position (1);
483 if (dynamic_cast<VPaned*>(pane)) {
484 pane->set_position (pane->get_height());
486 pane->set_position (pane->get_width());
497 rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a)
501 foo.set_name (style);
504 GtkRcStyle* waverc = foo.get_style()->gobj()->rc_style;
507 r = waverc->fg[Gtk::STATE_NORMAL].red / 257;
508 g = waverc->fg[Gtk::STATE_NORMAL].green / 257;
509 b = waverc->fg[Gtk::STATE_NORMAL].blue / 257;
511 /* what a hack ... "a" is for "active" */
513 a = waverc->fg[GTK_STATE_ACTIVE].red / 257;
516 warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
519 return (uint32_t) RGBA_TO_UINT(r,g,b,a);
523 decorate (Gtk::Window& w, Gdk::WMDecoration d)
525 w.get_window().set_decorations (d);