diff options
author | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
---|---|---|
committer | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
commit | 209d967b1bb80a9735d690d8f4f0455ecb9970ca (patch) | |
tree | 9d76ddcd7c1ac9d91bb2b1a33d31b66ce4ded5de /gtk2_ardour/utils.cc | |
parent | e4b9aed743fc765219ac775905a221c017c88fba (diff) |
Initial import of gtk2_ardour.
git-svn-id: svn://localhost/trunk/ardour2@24 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/utils.cc')
-rw-r--r-- | gtk2_ardour/utils.cc | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc new file mode 100644 index 0000000000..4a023b8ad9 --- /dev/null +++ b/gtk2_ardour/utils.cc @@ -0,0 +1,520 @@ +/* + Copyright (C) 2003 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <cstdlib> +#include <cctype> +#include <libart_lgpl/art_misc.h> +#include <gtk--/window.h> +#include <gtk--/combo.h> +#include <gtk--/label.h> +#include <gtk--/paned.h> +#include <gtk/gtkpaned.h> + +#include <gtkmmext/utils.h> + +#include "ardour_ui.h" +#include "utils.h" +#include "i18n.h" +#include "rgb_macros.h" + +using namespace std; +using namespace Gtk; + +string +short_version (string orig, string::size_type target_length) +{ + /* this tries to create a recognizable abbreviation + of "orig" by removing characters until we meet + a certain target length. + + note that we deliberately leave digits in the result + without modification. + */ + + + string::size_type pos; + + /* remove white-space and punctuation, starting at end */ + + while (orig.length() > target_length) { + if ((pos = orig.find_last_of (_("\"\n\t ,<.>/?:;'[{}]~`!@#$%^&*()_-+="))) == string::npos) { + break; + } + orig.replace (pos, 1, ""); + } + + /* remove lower-case vowels, starting at end */ + + while (orig.length() > target_length) { + if ((pos = orig.find_last_of (_("aeiou"))) == string::npos) { + break; + } + orig.replace (pos, 1, ""); + } + + /* remove upper-case vowels, starting at end */ + + while (orig.length() > target_length) { + if ((pos = orig.find_last_of (_("AEIOU"))) == string::npos) { + break; + } + orig.replace (pos, 1, ""); + } + + /* remove lower-case consonants, starting at end */ + + while (orig.length() > target_length) { + if ((pos = orig.find_last_of (_("bcdfghjklmnpqrtvwxyz"))) == string::npos) { + break; + } + orig.replace (pos, 1, ""); + } + + /* remove upper-case consonants, starting at end */ + + while (orig.length() > target_length) { + if ((pos = orig.find_last_of (_("BCDFGHJKLMNPQRTVWXYZ"))) == string::npos) { + break; + } + orig.replace (pos, 1, ""); + } + + /* whatever the length is now, use it */ + + return orig; +} + +string +fit_to_pixels (string str, int32_t pixel_width, Gdk_Font& font) +{ + gint width; + gint lbearing; + gint rbearing; + gint ascent; + gint descent; + + int namelen = str.length(); + char cstr[namelen+1]; + strcpy (cstr, str.c_str()); + + while (namelen) { + + gdk_string_extents (font, + cstr, + &lbearing, + &rbearing, + &width, + &ascent, + &descent); + + if (width < (pixel_width)) { + break; + } + + --namelen; + cstr[namelen] = '\0'; + + } + + return cstr; +} + +int +atoi (const string& s) +{ + return atoi (s.c_str()); +} + +double +atof (const string& s) +{ + return atof (s.c_str()); +} + +void +strip_whitespace_edges (string& str) +{ + string::size_type i; + string::size_type len; + string::size_type s; + + len = str.length(); + + for (i = 0; i < len; ++i) { + if (isgraph (str[i])) { + break; + } + } + + s = i; + + for (i = len - 1; i >= 0; --i) { + if (isgraph (str[i])) { + break; + } + } + + str = str.substr (s, (i - s) + 1); +} + +vector<string> +internationalize (const char **array) +{ + vector<string> v; + + for (uint32_t i = 0; array[i]; ++i) { + v.push_back (_(array[i])); + } + + return v; +} + +gint +just_hide_it (GdkEventAny *ev, Gtk::Window *win) +{ + ARDOUR_UI::instance()->allow_focus (false); + win->hide_all (); + return TRUE; +} + +void +allow_keyboard_focus (bool yn) +{ + ARDOUR_UI::instance()->allow_focus (yn); +} + +/* xpm2rgb copied from nixieclock, which bore the legend: + + nixieclock - a nixie desktop timepiece + Copyright (C) 2000 Greg Ercolano, erco@3dsite.com + + and was released under the GPL. +*/ + +unsigned char* +xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h) +{ + static long vals[256], val; + uint32_t t, x, y, colors, cpp; + unsigned char c; + unsigned char *savergb, *rgb; + + // PARSE HEADER + + if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) { + error << compose (_("bad XPM header %1"), xpm[0]) + << endmsg; + return 0; + } + + savergb = rgb = (unsigned char*)art_alloc (h * w * 3); + + // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION + for (t = 0; t < colors; ++t) { + sscanf (xpm[t+1], "%c c #%lx", &c, &val); + vals[c] = val; + } + + // COLORMAP -> RGB CONVERSION + // Get low 3 bytes from vals[] + // + + const char *p; + for (y = h-1; y > 0; --y) { + + for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) { + val = vals[(int)*p++]; + *(rgb+2) = val & 0xff; val >>= 8; // 2:B + *(rgb+1) = val & 0xff; val >>= 8; // 1:G + *(rgb+0) = val & 0xff; // 0:R + } + } + + return (savergb); +} + +unsigned char* +xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) +{ + static long vals[256], val; + uint32_t t, x, y, colors, cpp; + unsigned char c; + unsigned char *savergb, *rgb; + char transparent; + + // PARSE HEADER + + if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) { + error << compose (_("bad XPM header %1"), xpm[0]) + << endmsg; + return 0; + } + + savergb = rgb = (unsigned char*)art_alloc (h * w * 4); + + // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION + + if (strstr (xpm[1], "None")) { + sscanf (xpm[1], "%c", &transparent); + t = 1; + } else { + transparent = 0; + t = 0; + } + + for (; t < colors; ++t) { + sscanf (xpm[t+1], "%c c #%lx", &c, &val); + vals[c] = val; + } + + // COLORMAP -> RGB CONVERSION + // Get low 3 bytes from vals[] + // + + const char *p; + for (y = h-1; y > 0; --y) { + + char alpha; + + for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) { + + if (transparent && (*p++ == transparent)) { + alpha = 0; + val = 0; + } else { + alpha = 255; + val = vals[(int)*p]; + } + + *(rgb+3) = alpha; // 3: alpha + *(rgb+2) = val & 0xff; val >>= 8; // 2:B + *(rgb+1) = val & 0xff; val >>= 8; // 1:G + *(rgb+0) = val & 0xff; // 0:R + } + } + + return (savergb); +} + +GtkCanvasPoints* +get_canvas_points (string who, uint32_t npoints) +{ + // cerr << who << ": wants " << npoints << " canvas points" << endl; +#ifdef TRAP_EXCESSIVE_POINT_REQUESTS + if (npoints > (uint32_t) gdk_screen_width() + 4) { + abort (); + } +#endif + return gtk_canvas_points_new (npoints); +} + +int +channel_combo_get_channel_count (Gtk::Combo& combo) +{ + string str = combo.get_entry()->get_text(); + int chns; + + if (str == _("mono")) { + return 1; + } else if (str == _("stereo")) { + return 2; + } else if ((chns = atoi (str)) != 0) { + return chns; + } else { + return 0; + } +} + +static int32_t +int_from_hex (char hic, char loc) +{ + int hi; /* hi byte */ + int lo; /* low byte */ + + hi = (int) hic; + + if( ('0'<=hi) && (hi<='9') ) { + hi -= '0'; + } else if( ('a'<= hi) && (hi<= 'f') ) { + hi -= ('a'-10); + } else if( ('A'<=hi) && (hi<='F') ) { + hi -= ('A'-10); + } + + lo = (int) loc; + + if( ('0'<=lo) && (lo<='9') ) { + lo -= '0'; + } else if( ('a'<=lo) && (lo<='f') ) { + lo -= ('a'-10); + } else if( ('A'<=lo) && (lo<='F') ) { + lo -= ('A'-10); + } + + return lo + (16 * hi); +} + +void +url_decode (string& url) +{ + string::iterator last; + string::iterator next; + + for (string::iterator i = url.begin(); i != url.end(); ++i) { + if ((*i) == '+') { + *i = ' '; + } + } + + if (url.length() <= 3) { + return; + } + + last = url.end(); + + --last; /* points at last char */ + --last; /* points at last char - 1 */ + + for (string::iterator i = url.begin(); i != last; ) { + + if (*i == '%') { + + next = i; + + url.erase (i); + + i = next; + ++next; + + if (isxdigit (*i) && isxdigit (*next)) { + /* replace first digit with char */ + *i = int_from_hex (*i,*next); + ++i; /* points at 2nd of 2 digits */ + url.erase (i); + } + } else { + ++i; + } + } +} + +string +get_font_for_style (string widgetname) +{ + Gtk::Label foobar; + + foobar.set_name (widgetname); + foobar.ensure_style(); + + if (foobar.get_style() == 0 || foobar.get_style()->gtkobj()->rc_style == 0 || foobar.get_style()->gtkobj()->rc_style->font_name == 0) { + return "fixed"; + } + + string str = foobar.get_style()->gtkobj()->rc_style->font_name; + + if (str.empty()) { + return "fixed"; // standard X Window fallback font + } else { + return str; + } +} +gint +pane_handler (GdkEventButton* ev, Gtk::Paned* pane) +{ + if (ev->window != Gtkmmext::get_paned_handle (*pane)) { + return FALSE; + } + + if (Keyboard::is_delete_event (ev)) { + + gint pos; + gint cmp; + + pos = Gtkmmext::gtk_paned_get_position (pane->gtkobj()); + + if (dynamic_cast<VPaned*>(pane)) { + cmp = pane->height(); + } else { + cmp = pane->width(); + } + + /* we have to use approximations here because we can't predict the + exact position or sizes of the pane (themes, etc) + */ + + if (pos < 10 || abs (pos - cmp) < 10) { + + /* already collapsed: restore it (note that this is cast from a pointer value to int, which is tricky on 64bit */ + + pane->set_position ((gint64) pane->get_data ("rpos")); + + } else { + + int collapse_direction; + + /* store the current position */ + + pane->set_data ("rpos", (gpointer) pos); + + /* collapse to show the relevant child in full */ + + collapse_direction = (gint64) pane->get_data ("collapse-direction"); + + if (collapse_direction) { + pane->set_position (1); + } else { + if (dynamic_cast<VPaned*>(pane)) { + pane->set_position (pane->height()); + } else { + pane->set_position (pane->width()); + } + } + } + + return TRUE; + } + + return FALSE; +} +uint32_t +rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a) +{ + Gtk::Label foo; + + foo.set_name (style); + foo.ensure_style (); + + GtkRcStyle* waverc = foo.get_style()->gtkobj()->rc_style; + + if (waverc) { + r = waverc->fg[GTK_STATE_NORMAL].red / 257; + g = waverc->fg[GTK_STATE_NORMAL].green / 257; + b = waverc->fg[GTK_STATE_NORMAL].blue / 257; + + /* what a hack ... "a" is for "active" */ + + a = waverc->fg[GTK_STATE_ACTIVE].red / 257; + + } else { + warning << compose (_("missing RGBA style for \"%1\""), style) << endl; + } + + return (uint32_t) RGBA_TO_UINT(r,g,b,a); +} |