X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Futils.cc;h=8cdf5e0b58650b3a04083b6d97308c2146e8da19;hb=79c918fd6aace3f5d94fe61973819574489ca755;hp=622cf62527cab2209f540848a7909f3eb2dd9ac6;hpb=29c378eecc4dc1c5340a2304a92acc8e0bffff09;p=ardour.git diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 622cf62527..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,50 +15,81 @@ 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 +#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; using namespace Glib; using namespace PBD; +using Gtkmm2ext::Keyboard; + +sigc::signal DPIReset; -ustring -fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses) +int +pixel_width (const string& str, Pango::FontDescription& font) { Label foo; Glib::RefPtr layout = foo.create_pango_layout (""); - ustring::size_type shorter_by = 0; - ustring txt; + + layout->set_font_description (font); + layout->set_text (str); + + int width, height; + Gtkmm2ext::get_ink_pixel_size (layout, width, height); + return width; +} + +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; layout->set_font_description (font); actual_width = 0; - ustring ustr = str; - ustring::iterator last = ustr.end(); + string ustr = str; + string::iterator last = ustr.end(); --last; /* now points at final entry */ txt = ustr; @@ -74,7 +105,7 @@ fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font actual_width = width; break; } - + ustr.erase (last--); shorter_by++; @@ -89,11 +120,62 @@ fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font return txt; } +/** 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) + */ + +std::pair +fit_to_pixels (cairo_t* cr, std::string name, double avail) +{ + /* XXX hopefully there exists a more efficient way of doing this */ + + bool abbreviated = false; + uint32_t width = 0; + + while (1) { + cairo_text_extents_t ext; + cairo_text_extents (cr, name.c_str(), &ext); + + if (ext.width < avail || name.length() <= 4) { + width = ext.width; + break; + } + + if (abbreviated) { + name = name.substr (0, name.length() - 4) + "..."; + } else { + name = name.substr (0, name.length() - 3) + "..."; + abbreviated = true; + } + } + + return std::make_pair (name, width); +} + + +/** 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); + } +} + + 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: @@ -111,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[] // @@ -163,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")) { @@ -179,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[] // @@ -210,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 @@ -221,7 +303,7 @@ get_canvas_points (string who, uint32_t npoints) return new ArdourCanvas::Points (npoints); } -Pango::FontDescription +Pango::FontDescription* get_font_for_style (string widgetname) { Gtk::Window window (WINDOW_TOPLEVEL); @@ -233,7 +315,21 @@ get_font_for_style (string widgetname) foobar.ensure_style(); style = foobar.get_style (); - return style->get_font(); + + 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 */ } uint32_t @@ -250,43 +346,44 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s } Gtk::Label foo; - + window->add (foo); foo.set_name (style); foo.ensure_style (); - - GtkRcStyle* waverc = foo.get_style()->gobj()->rc_style; - if (waverc) { + GtkRcStyle* rc = foo.get_style()->gobj()->rc_style; + + if (rc) { if (attr == "fg") { - r = waverc->fg[state].red / 257; - g = waverc->fg[state].green / 257; - b = waverc->fg[state].blue / 257; + 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 = waverc->fg[GTK_STATE_ACTIVE].red / 257; + a = rc->fg[GTK_STATE_ACTIVE].red / 257; } } else if (attr == "bg") { r = g = b = 0; - r = waverc->bg[state].red / 257; - g = waverc->bg[state].green / 257; - b = waverc->bg[state].blue / 257; + r = rc->bg[state].red / 257; + g = rc->bg[state].green / 257; + b = rc->bg[state].blue / 257; } else if (attr == "base") { - r = waverc->base[state].red / 257; - g = waverc->base[state].green / 257; - b = waverc->base[state].blue / 257; + r = rc->base[state].red / 257; + g = rc->base[state].green / 257; + b = rc->base[state].blue / 257; } else if (attr == "text") { - r = waverc->text[state].red / 257; - g = waverc->text[state].green / 257; - b = waverc->text[state].blue / 257; + 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 { @@ -294,7 +391,113 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s } } -bool + +Gdk::Color +color_from_style (string widget_style_name, int state, string attr) +{ + GtkStyle* style; + + 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 (attr == "fg") { + return Gdk::Color (&style->fg[state]); + } + + if (attr == "bg") { + return Gdk::Color (&style->bg[state]); + } + + if (attr == "light") { + return Gdk::Color (&style->light[state]); + } + + if (attr == "dark") { + return Gdk::Color (&style->dark[state]); + } + + if (attr == "mid") { + return Gdk::Color (&style->mid[state]); + } + + if (attr == "text") { + return Gdk::Color (&style->text[state]); + } + + 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"); +} + +Glib::RefPtr +gc_from_style (string widget_style_name, int state, string attr) +{ + GtkStyle* style; + + 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; + Glib::RefPtr ret = Gdk::GC::create(); + ret->set_rgb_fg_color(Gdk::Color("red")); + return ret; + } + + if (attr == "fg") { + return Glib::wrap(style->fg_gc[state]); + } + + if (attr == "bg") { + return Glib::wrap(style->bg_gc[state]); + } + + if (attr == "light") { + return Glib::wrap(style->light_gc[state]); + } + + if (attr == "dark") { + return Glib::wrap(style->dark_gc[state]); + } + + if (attr == "mid") { + return Glib::wrap(style->mid_gc[state]); + } + + if (attr == "text") { + return Glib::wrap(style->text_gc[state]); + } + + if (attr == "base") { + return Glib::wrap(style->base_gc[state]); + } + + if (attr == "text_aa") { + return Glib::wrap(style->text_aa_gc[state]); + } + + error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg; + Glib::RefPtr ret = Gdk::GC::create(); + ret->set_rgb_fg_color(Gdk::Color("red")); + return ret; +} + + +bool canvas_item_visible (ArdourCanvas::Item* item) { return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false; @@ -306,32 +509,119 @@ set_color (Gdk::Color& c, int rgb) c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256); } +bool +relay_key_press (GdkEventKey* ev, Gtk::Window* win) +{ + if (!key_press_focus_accelerator_handler (*win, ev)) { + return PublicEditor::instance().on_key_press_event(ev); + } else { + return true; + } +} + +bool +forward_key_press (GdkEventKey* ev) +{ + return PublicEditor::instance().on_key_press_event(ev); +} + +#ifdef GTKOSX +static guint +osx_keyval_without_alt (guint accent_keyval) +{ + switch (accent_keyval) { + case GDK_oe: + return GDK_q; + case GDK_registered: + return GDK_r; + case GDK_dagger: + return GDK_t; + case GDK_yen: + return GDK_y; + case GDK_diaeresis: + return GDK_u; + case GDK_oslash: + return GDK_o; + case GDK_Greek_pi: + return GDK_p; + case GDK_leftdoublequotemark: + return GDK_bracketleft; + case GDK_leftsinglequotemark: + return GDK_bracketright; + case GDK_guillemotleft: + return GDK_backslash; + case GDK_aring: + return GDK_a; + case GDK_ssharp: + return GDK_s; + case GDK_partialderivative: + return GDK_d; + case GDK_function: + return GDK_f; + case GDK_copyright: + return GDK_g; + case GDK_abovedot: + return GDK_h; + case GDK_notsign: + return GDK_l; + case GDK_ellipsis: + return GDK_semicolon; + case GDK_ae: + return GDK_apostrophe; + case GDK_Greek_OMEGA: + return GDK_z; + case GDK_ccedilla: + return GDK_c; + case GDK_radical: + return GDK_v; + case GDK_integral: + return GDK_b; + case GDK_mu: + return GDK_m; + case GDK_lessthanequal: + return GDK_comma; + case GDK_greaterthanequal: + return GDK_period; + case GDK_division: + return GDK_slash; + default: + break; + } + + return GDK_VoidSymbol; +} +#endif + bool key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) { GtkWindow* win = window.gobj(); GtkWidget* focus = gtk_window_get_focus (win); bool special_handling_of_unmodified_accelerators = false; - -#undef DEBUG_ACCELERATOR_HANDLING -#ifdef DEBUG_ACCELERATOR_HANDLING - bool debug = (getenv ("ARDOUR_DEBUG_ACCELERATOR_HANDLING") != 0); -#endif + bool allow_activating = true; if (focus) { - if (GTK_IS_ENTRY(focus)) { + if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) { special_handling_of_unmodified_accelerators = true; - } - } + } + } -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " focus is an entry ? " - << special_handling_of_unmodified_accelerators - << endl; +#ifdef GTKOSX + /* should this be universally true? */ + if (Keyboard::some_magic_widget_has_focus ()) { + allow_activating = false; } #endif + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n", + win, + ev->keyval, + ev->state, + special_handling_of_unmodified_accelerators, + Keyboard::some_magic_widget_has_focus(), + allow_activating)); + /* This exists to allow us to override the way GTK handles key events. The normal sequence is: @@ -341,18 +631,18 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) the focus widget and/or focus chain The problem with this is that if the accelerators include - keys without modifiers, such as the space bar or the + keys without modifiers, such as the space bar or the letter "e", then pressing the key while typing into a text entry widget results in the accelerator being activated, instead of the desired letter appearing in the text entry. There is no good way of fixing this, but this - represents a compromise. The idea is that + represents a compromise. The idea is that key events involving modifiers (not Shift) get routed into the activation pathway first, then get propagated to the focus widget if necessary. - + If the key event doesn't involve modifiers, we deliver to the focus widget first, thus allowing it to get "normal text" without interference @@ -363,6 +653,22 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) all "normal text" accelerators. */ +#ifdef GTKOSX + if (!special_handling_of_unmodified_accelerators) { + if (ev->state & GDK_MOD1_MASK) { + /* we're not in a text entry or "magic focus" widget so we don't want OS X "special-character" + text-style handling of alt-. change the keyval back to what it would be without + the alt key. this way, we see -v rather than -radical and so on. + */ + guint keyval_without_alt = osx_keyval_without_alt (ev->keyval); + + if (keyval_without_alt != GDK_VoidSymbol) { + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Remapped %1 to %2\n", gdk_keyval_name (ev->keyval), gdk_keyval_name (keyval_without_alt))); + ev->keyval = keyval_without_alt; + } + } + } +#endif if (!special_handling_of_unmodified_accelerators) { @@ -371,104 +677,114 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) it does allow. */ - int ret = false; + uint32_t fakekey = ev->keyval; - switch (ev->keyval) { - case GDK_Up: - ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_uparrow, GdkModifierType(ev->state)); - break; + if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) { + if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) { + return true; + } + } + } - case GDK_Down: - ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_downarrow, GdkModifierType(ev->state)); - break; + /* consider all relevant modifiers but not LOCK or SHIFT */ - case GDK_Right: - ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_rightarrow, GdkModifierType(ev->state)); - break; + guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); - case GDK_Left: - ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_leftarrow, GdkModifierType(ev->state)); - break; + if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) { - default: - break; - } + /* no special handling or there are modifiers in effect: accelerate first */ - if (ret) { - return true; + DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); + + if (allow_activating) { + if (gtk_window_activate_key (win, ev)) { + return true; + } } - } - - if (!special_handling_of_unmodified_accelerators || - ev->state & (Gdk::MOD1_MASK| - Gdk::MOD3_MASK| - Gdk::MOD4_MASK| - Gdk::MOD5_MASK| - Gdk::CONTROL_MASK)) { - /* no special handling or modifiers in effect: accelerate first */ + DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tactivate, then propagate\n"; - } -#endif - if (!gtk_window_activate_key (win, ev)) { - return gtk_window_propagate_key_event (win, ev); - } else { -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tnot handled\n"; - } -#endif - return true; - } + return gtk_window_propagate_key_event (win, ev); } - + /* no modifiers, propagate first */ - -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tactivate, then propagate\n"; - } -#endif - if (!gtk_window_propagate_key_event (win, ev)) { - return gtk_window_activate_key (win, ev); - } + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n"); -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tnot handled\n"; + if (!gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n"); + if (allow_activating) { + return gtk_window_activate_key (win, ev); + } + + } else { + DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n"); + return true; } -#endif + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n"); return true; } -Glib::RefPtr +Glib::RefPtr get_xpm (std::string name) { if (!xpm_map[name]) { - xpm_map[name] = Gdk::Pixbuf::create_from_file (ARDOUR::find_data_file(name, "pixmaps")); + + SearchPath spath(ARDOUR::ardour_search_path()); + spath += ARDOUR::system_data_search_path(); + + spath.add_subdirectory_to_paths("pixmaps"); + + sys::path data_file_path; + + if(!find_file_in_search_path (spath, name, data_file_path)) { + fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg; + } + + try { + xpm_map[name] = Gdk::Pixbuf::create_from_file (data_file_path.to_string()); + } catch(const Glib::Error& e) { + warning << "Caught Glib::Error: " << e.what() << endmsg; + } } - - return (xpm_map[name]); + + return xpm_map[name]; } -Glib::RefPtr -get_icon (const char* cname) +std::string +get_icon_path (const char* cname) { string name = cname; name += X_(".png"); - string path = ARDOUR::find_data_file (name, "icons"); + SearchPath spath(ARDOUR::ardour_search_path()); + spath += ARDOUR::system_data_search_path(); + + spath.add_subdirectory_to_paths("icons"); - if (path.empty()) { + sys::path data_file_path; + + if (!find_file_in_search_path (spath, name, data_file_path)) { fatal << string_compose (_("cannot find icon image for %1"), name) << endmsg; - /*NOTREACHED*/ } - return Gdk::Pixbuf::create_from_file (path); + return data_file_path.to_string(); +} + +Glib::RefPtr +get_icon (const char* cname) +{ + Glib::RefPtr img; + try { + img = Gdk::Pixbuf::create_from_file (get_icon_path (cname)); + } catch (const Gdk::PixbufError &e) { + cerr << "Caught PixbufError: " << e.what() << endl; + } catch (...) { + g_message("Caught ... "); + } + + return img; } string @@ -480,22 +796,22 @@ longest (vector& strings) vector::iterator longest = strings.begin(); string::size_type longest_length = (*longest).length(); - + vector::iterator i = longest; ++i; while (i != strings.end()) { - + string::size_type len = (*i).length(); - + if (len > longest_length) { longest = i; longest_length = len; - } - + } + ++i; } - + return *longest; } @@ -539,64 +855,69 @@ key_is_legal_for_numeric_entry (guint keyval) case GDK_Left: case GDK_Right: return true; - + default: break; } return false; } +void +set_pango_fontsize () +{ + long val = ARDOUR::Config->get_font_scale(); + + /* FT2 rendering - used by GnomeCanvas, sigh */ + pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_for_display(), val/1024, val/1024); -ustring -short_path (ustring path, uint32_t target_characters) + /* Cairo rendering, in case there is any */ + + pango_cairo_font_map_set_resolution ((PangoCairoFontMap*) pango_cairo_font_map_get_default(), val/1024); +} + +void +reset_dpi () { - ustring::size_type last_sep; - ustring::size_type len = path.length(); - const char separator = '/'; + long val = ARDOUR::Config->get_font_scale(); + set_pango_fontsize (); + /* Xft rendering */ - if (len <= target_characters) { - return path; - } + gtk_settings_set_long_property (gtk_settings_get_default(), + "gtk-xft-dpi", val, "ardour"); + DPIReset();//Emit Signal +} - if ((last_sep = path.find_last_of (separator)) == ustring::npos) { +void +resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height) +{ + Glib::RefPtr screen = window->get_screen (); + Gdk::Rectangle monitor_rect; + screen->get_monitor_geometry (0, monitor_rect); - /* just a filename, but its too long anyway */ + int const w = std::min (int (monitor_rect.get_width() * 0.8), max_width); + int const h = std::min (int (monitor_rect.get_height() * 0.8), max_height); - if (target_characters > 3) { - return path.substr (0, target_characters - 3) + ustring ("..."); - } else { - /* stupid caller, just hand back the whole thing */ - return path; - } - } + window->resize (w, h); +} - if (len - last_sep >= target_characters) { - /* even the filename itself is too long */ +/** Replace _ with __ in a string; for use with menu item text to make underscores displayed correctly */ +string +escape_underscores (string const & s) +{ + string o; + string::size_type const N = s.length (); - if (target_characters > 3) { - return path.substr (last_sep+1, target_characters - 3) + ustring ("..."); + for (string::size_type i = 0; i < N; ++i) { + if (s[i] == '_') { + o += "__"; } else { - /* stupid caller, just hand back the whole thing */ - return path; + o += s[i]; } } - - uint32_t so_far = (len - last_sep); - uint32_t space_for = target_characters - so_far; - if (space_for >= 3) { - ustring res = "..."; - res += path.substr (last_sep - space_for); - return res; - } else { - /* remove part of the end */ - ustring res = "..."; - res += path.substr (last_sep - space_for, len - last_sep + space_for - 3); - res += "..."; - return res; - - } + return o; } +