X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Futils.cc;h=8cdf5e0b58650b3a04083b6d97308c2146e8da19;hb=ad942b104a80c74c689e0c1b5c016d1870850830;hp=448f1b57fefbe796e2fc46ec87a40bd0dbe58fe4;hpb=5c819462b8f146b25a7dbe2c948a8407e7c5dbbb;p=ardour.git diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 448f1b57fe..8cdf5e0b58 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -1,7 +1,7 @@ /* - Copyright (C) 2003 Paul Davis + Copyright (C) 2003 Paul Davis - This program is free software; you can redistribute it and/or modify + This program is free software; you an 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. @@ -15,180 +15,167 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif + +#include // for fontmap resolution control for GnomeCanvas +#include // for fontmap resolution control for GnomeCanvas + #include #include +#include +#include #include +#include #include #include #include #include #include +#include "pbd/file_utils.h" + #include +#include "ardour/configuration.h" +#include "ardour/rc_configuration.h" + +#include "ardour/filesystem_paths.h" #include "ardour_ui.h" +#include "debug.h" +#include "public_editor.h" #include "keyboard.h" #include "utils.h" #include "i18n.h" #include "rgb_macros.h" #include "canvas_impl.h" +#include "gui_thread.h" using namespace std; using namespace Gtk; -using namespace sigc; - -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. +using namespace Glib; +using namespace PBD; +using Gtkmm2ext::Keyboard; - note that we deliberately leave digits in the result - without modification. - */ +sigc::signal DPIReset; +int +pixel_width (const string& str, Pango::FontDescription& font) +{ + Label foo; + Glib::RefPtr layout = foo.create_pango_layout (""); - string::size_type pos; + layout->set_font_description (font); + layout->set_text (str); - /* remove white-space and punctuation, starting at end */ + int width, height; + Gtkmm2ext::get_ink_pixel_size (layout, width, height); + return width; +} - while (orig.length() > target_length) { - if ((pos = orig.find_last_of (_("\"\n\t ,<.>/?:;'[{}]~`!@#$%^&*()_-+="))) == string::npos) { - break; - } - orig.replace (pos, 1, ""); - } +string +fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses) +{ + Label foo; + Glib::RefPtr layout = foo.create_pango_layout (""); + string::size_type shorter_by = 0; + string txt; - /* remove lower-case vowels, starting at end */ + layout->set_font_description (font); - while (orig.length() > target_length) { - if ((pos = orig.find_last_of (_("aeiou"))) == string::npos) { - break; - } - orig.replace (pos, 1, ""); - } + actual_width = 0; - /* remove upper-case vowels, starting at end */ + string ustr = str; + string::iterator last = ustr.end(); + --last; /* now points at final entry */ - while (orig.length() > target_length) { - if ((pos = orig.find_last_of (_("AEIOU"))) == string::npos) { - break; - } - orig.replace (pos, 1, ""); - } + txt = ustr; - /* remove lower-case consonants, starting at end */ + while (!ustr.empty()) { - while (orig.length() > target_length) { - if ((pos = orig.find_last_of (_("bcdfghjklmnpqrtvwxyz"))) == string::npos) { - break; - } - orig.replace (pos, 1, ""); - } + layout->set_text (txt); - /* remove upper-case consonants, starting at end */ + int width, height; + Gtkmm2ext::get_ink_pixel_size (layout, width, height); - while (orig.length() > target_length) { - if ((pos = orig.find_last_of (_("BCDFGHJKLMNPQRTVWXYZ"))) == string::npos) { + if (width < pixel_width) { + actual_width = width; break; } - orig.replace (pos, 1, ""); - } - /* whatever the length is now, use it */ - - return orig; -} + ustr.erase (last--); + shorter_by++; -string -fit_to_pixels (const string & str, int pixel_width, const string & font) -{ - Label foo; - int width; - int height; - Pango::FontDescription fontdesc (font); - - int namelen = str.length(); - char cstr[namelen+1]; - strcpy (cstr, str.c_str()); - - while (namelen) { - Glib::RefPtr layout = foo.create_pango_layout (cstr); - - layout->set_font_description (fontdesc); - layout->get_pixel_size (width, height); - - if (width < (pixel_width)) { - break; + if (with_ellipses && shorter_by > 3) { + txt = ustr; + txt += "..."; + } else { + txt = ustr; } - - --namelen; - cstr[namelen] = '\0'; - } - return cstr; + return txt; } -int -atoi (const string& s) -{ - return atoi (s.c_str()); -} +/** Try to fit a string into a given horizontal space by ellipsizing it. + * @param cr Cairo context in which the text will be plotted. + * @param name Text. + * @param avail Available horizontal space. + * @return (Text, possibly ellipsized) and (horizontal size of text) + */ -double -atof (const string& s) +std::pair +fit_to_pixels (cairo_t* cr, std::string name, double avail) { - return atof (s.c_str()); -} + /* XXX hopefully there exists a more efficient way of doing this */ -void -strip_whitespace_edges (string& str) -{ - string::size_type i; - string::size_type len; - string::size_type s; + bool abbreviated = false; + uint32_t width = 0; - len = str.length(); + while (1) { + cairo_text_extents_t ext; + cairo_text_extents (cr, name.c_str(), &ext); - for (i = 0; i < len; ++i) { - if (isgraph (str[i])) { + if (ext.width < avail || name.length() <= 4) { + width = ext.width; break; } - } - - s = i; - for (i = len - 1; i >= 0; --i) { - if (isgraph (str[i])) { - break; + if (abbreviated) { + name = name.substr (0, name.length() - 4) + "..."; + } else { + name = name.substr (0, name.length() - 3) + "..."; + abbreviated = true; } } - str = str.substr (s, (i - s) + 1); + return std::make_pair (name, width); } -vector -internationalize (const char **array) -{ - vector v; - for (uint32_t i = 0; array[i]; ++i) { - v.push_back (_(array[i])); +/** Add an element to a menu, settings its sensitivity. + * @param m Menu to add to. + * @param e Element to add. + * @param s true to make sensitive, false to make insensitive + */ +void +add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) +{ + m.push_back (e); + if (!s) { + m.back().set_sensitive (false); } - - return v; } + gint -just_hide_it (GdkEventAny *ev, Gtk::Window *win) +just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win) { - win->hide_all (); - return TRUE; + win->hide (); + return 0; } /* xpm2rgb copied from nixieclock, which bore the legend: @@ -206,23 +193,23 @@ xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h) 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 << string_compose (_("bad XPM header %1"), xpm[0]) << endmsg; return 0; } - savergb = rgb = (unsigned char*)art_alloc (h * w * 3); - + savergb = rgb = (unsigned char*) malloc (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[] // @@ -258,8 +245,8 @@ xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) return 0; } - savergb = rgb = (unsigned char*)art_alloc (h * w * 4); - + savergb = rgb = (unsigned char*) malloc (h * w * 4); + // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION if (strstr (xpm[1], "None")) { @@ -274,7 +261,7 @@ xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) sscanf (xpm[t+1], "%c c #%lx", &c, &val); vals[c] = val; } - + // COLORMAP -> RGB CONVERSION // Get low 3 bytes from vals[] // @@ -305,7 +292,7 @@ xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) } ArdourCanvas::Points* -get_canvas_points (string who, uint32_t npoints) +get_canvas_points (string /*who*/, uint32_t npoints) { // cerr << who << ": wants " << npoints << " canvas points" << endl; #ifdef TRAP_EXCESSIVE_POINT_REQUESTS @@ -316,211 +303,621 @@ get_canvas_points (string who, uint32_t npoints) return new ArdourCanvas::Points (npoints); } -int -channel_combo_get_channel_count (Gtk::ComboBoxText& combo) +Pango::FontDescription* +get_font_for_style (string widgetname) { - string str = combo.get_active_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; + Gtk::Window window (WINDOW_TOPLEVEL); + Gtk::Label foobar; + Glib::RefPtr style; + + window.add (foobar); + foobar.set_name (widgetname); + foobar.ensure_style(); + + style = foobar.get_style (); + + Glib::RefPtr layout = foobar.get_layout(); + + PangoFontDescription *pfd = (PangoFontDescription *)pango_layout_get_font_description((PangoLayout *)layout->gobj()); + + if (!pfd) { + + /* layout inherited its font description from a PangoContext */ + + PangoContext* ctxt = (PangoContext*) pango_layout_get_context ((PangoLayout*) layout->gobj()); + pfd = pango_context_get_font_description (ctxt); + return new Pango::FontDescription (pfd, true); /* make a copy */ } + + return new Pango::FontDescription (pfd, true); /* make a copy */ } -static int32_t -int_from_hex (char hic, char loc) +uint32_t +rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, string attr, int state, bool rgba) { - 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); + /* In GTK+2, styles aren't set up correctly if the widget is not + attached to a toplevel window that has a screen pointer. + */ + + static Gtk::Window* window = 0; + + if (window == 0) { + window = new Window (WINDOW_TOPLEVEL); + } + + Gtk::Label foo; + + window->add (foo); + + foo.set_name (style); + foo.ensure_style (); + + GtkRcStyle* rc = foo.get_style()->gobj()->rc_style; + + if (rc) { + if (attr == "fg") { + r = rc->fg[state].red / 257; + g = rc->fg[state].green / 257; + b = rc->fg[state].blue / 257; + + /* what a hack ... "a" is for "active" */ + if (state == Gtk::STATE_NORMAL && rgba) { + a = rc->fg[GTK_STATE_ACTIVE].red / 257; + } + } else if (attr == "bg") { + r = g = b = 0; + r = rc->bg[state].red / 257; + g = rc->bg[state].green / 257; + b = rc->bg[state].blue / 257; + } else if (attr == "base") { + r = rc->base[state].red / 257; + g = rc->base[state].green / 257; + b = rc->base[state].blue / 257; + } else if (attr == "text") { + r = rc->text[state].red / 257; + g = rc->text[state].green / 257; + b = rc->text[state].blue / 257; + } + } else { + warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl; + } + + window->remove (); + + if (state == Gtk::STATE_NORMAL && rgba) { + return (uint32_t) RGBA_TO_UINT(r,g,b,a); + } else { + return (uint32_t) RGB_TO_UINT(r,g,b); + } } -void -url_decode (string& url) + +Gdk::Color +color_from_style (string widget_style_name, int state, string attr) { - string::iterator last; - string::iterator next; + GtkStyle* style; - for (string::iterator i = url.begin(); i != url.end(); ++i) { - if ((*i) == '+') { - *i = ' '; - } + style = gtk_rc_get_style_by_paths (gtk_settings_get_default(), + widget_style_name.c_str(), + 0, G_TYPE_NONE); + + if (!style) { + error << string_compose (_("no style found for %1, using red"), style) << endmsg; + return Gdk::Color ("red"); } - if (url.length() <= 3) { - return; + if (attr == "fg") { + return Gdk::Color (&style->fg[state]); } - last = url.end(); + if (attr == "bg") { + return Gdk::Color (&style->bg[state]); + } - --last; /* points at last char */ - --last; /* points at last char - 1 */ + if (attr == "light") { + return Gdk::Color (&style->light[state]); + } - for (string::iterator i = url.begin(); i != last; ) { + if (attr == "dark") { + return Gdk::Color (&style->dark[state]); + } - if (*i == '%') { + if (attr == "mid") { + return Gdk::Color (&style->mid[state]); + } - next = i; + if (attr == "text") { + return Gdk::Color (&style->text[state]); + } - 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; - } + if (attr == "base") { + return Gdk::Color (&style->base[state]); + } + + if (attr == "text_aa") { + return Gdk::Color (&style->text_aa[state]); } + + error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg; + return Gdk::Color ("red"); } -Pango::FontDescription -get_font_for_style (string widgetname) +Glib::RefPtr +gc_from_style (string widget_style_name, int state, string attr) { - Gtk::Window window (WINDOW_TOPLEVEL); - Gtk::Label foobar; - Glib::RefPtr