X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Futils.cc;h=00e94b0dd96b6878584162b1eeb119d7567a8b7c;hb=300b484cf6ac14c15e365c4062345d64a61c4b18;hp=621cdb0dd9a9e90827aa801178b2e252a6cd9abf;hpb=b85b4d9e54caef0585d308ef3bffee21d0e5ae56;p=ardour.git diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 621cdb0dd9..00e94b0dd9 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -25,32 +25,35 @@ #include // for fontmap resolution control for GnomeCanvas #include +#include +#include #include +#include #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 "canvas/item.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; @@ -61,99 +64,6 @@ using Gtkmm2ext::Keyboard; sigc::signal DPIReset; -int -pixel_width (const string& str, Pango::FontDescription& font) -{ - Label foo; - Glib::RefPtr layout = foo.create_pango_layout (""); - - 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; - - string ustr = str; - string::iterator last = ustr.end(); - --last; /* now points at final entry */ - - txt = ustr; - - while (!ustr.empty()) { - - layout->set_text (txt); - - int width, height; - Gtkmm2ext::get_ink_pixel_size (layout, width, height); - - if (width < pixel_width) { - actual_width = width; - break; - } - - ustr.erase (last--); - shorter_by++; - - if (with_ellipses && shorter_by > 3) { - txt = ustr; - txt += "..."; - } else { - txt = ustr; - } - } - - 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. @@ -290,19 +200,7 @@ xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) return (savergb); } -ArdourCanvas::Points* -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 new ArdourCanvas::Points (npoints); -} - -Pango::FontDescription* +Pango::FontDescription get_font_for_style (string widgetname) { Gtk::Window window (WINDOW_TOPLEVEL); @@ -317,18 +215,18 @@ get_font_for_style (string widgetname) Glib::RefPtr layout = foobar.get_layout(); - PangoFontDescription *pfd = (PangoFontDescription *)pango_layout_get_font_description((PangoLayout *)layout->gobj()); + PangoFontDescription *pfd = const_cast (pango_layout_get_font_description(const_cast(layout->gobj()))); if (!pfd) { /* layout inherited its font description from a PangoContext */ - PangoContext* ctxt = (PangoContext*) pango_layout_get_context ((PangoLayout*) layout->gobj()); + PangoContext* ctxt = (PangoContext*) pango_layout_get_context (const_cast(layout->gobj())); pfd = pango_context_get_font_description (ctxt); - return new Pango::FontDescription (pfd, true); /* make a copy */ + return Pango::FontDescription (pfd); /* make a copy */ } - return new Pango::FontDescription (pfd, true); /* make a copy */ + return Pango::FontDescription (pfd); /* make a copy */ } uint32_t @@ -351,31 +249,31 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s foo.set_name (style); foo.ensure_style (); - GtkRcStyle* waverc = foo.get_style()->gobj()->rc_style; + GtkRcStyle* rc = foo.get_style()->gobj()->rc_style; - if (waverc) { + 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; @@ -390,116 +288,51 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s } } - -Gdk::Color -color_from_style (string widget_style_name, int state, string attr) +bool +rgba_p_from_style (string style, float *r, float *g, float *b, string attr, int state) { - 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]); - } + static Gtk::Window* window = 0; + assert (r && g && b); - if (attr == "bg") { - return Gdk::Color (&style->bg[state]); + if (window == 0) { + window = new Window (WINDOW_TOPLEVEL); } - if (attr == "light") { - return Gdk::Color (&style->light[state]); - } + Gtk::EventBox foo; - if (attr == "dark") { - return Gdk::Color (&style->dark[state]); - } + window->add (foo); - if (attr == "mid") { - return Gdk::Color (&style->mid[state]); - } + foo.set_name (style); + foo.ensure_style (); - if (attr == "text") { - return Gdk::Color (&style->text[state]); - } + GtkRcStyle* rc = foo.get_style()->gobj()->rc_style; - if (attr == "base") { - return Gdk::Color (&style->base[state]); + if (!rc) { + warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl; + return false; } - - if (attr == "text_aa") { - return Gdk::Color (&style->text_aa[state]); + if (attr == "fg") { + *r = rc->fg[state].red / 65535.0; + *g = rc->fg[state].green / 65535.0; + *b = rc->fg[state].blue / 65535.0; + } else if (attr == "bg") { + *r = rc->bg[state].red / 65535.0; + *g = rc->bg[state].green / 65535.0; + *b = rc->bg[state].blue / 65535.0; + } else if (attr == "base") { + *r = rc->base[state].red / 65535.0; + *g = rc->base[state].green / 65535.0; + *b = rc->base[state].blue / 65535.0; + } else if (attr == "text") { + *r = rc->text[state].red / 65535.0; + *g = rc->text[state].green / 65535.0; + *b = rc->text[state].blue / 65535.0; + } else { + return false; } - 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; + window->remove (); + return true; } void @@ -511,8 +344,14 @@ set_color (Gdk::Color& c, int rgb) bool relay_key_press (GdkEventKey* ev, Gtk::Window* win) { + PublicEditor& ed (PublicEditor::instance()); + if (!key_press_focus_accelerator_handler (*win, ev)) { - return PublicEditor::instance().on_key_press_event(ev); + if (&ed == 0) { + /* early key press in pre-main-window-dialogs, no editor yet */ + return false; + } + return ed.on_key_press_event(ev); } else { return true; } @@ -524,72 +363,34 @@ forward_key_press (GdkEventKey* ev) return PublicEditor::instance().on_key_press_event(ev); } -#ifdef GTKOSX -static guint -osx_keyval_without_alt (guint accent_keyval) +bool +emulate_key_event (Gtk::Widget* w, unsigned int 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; + GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET(w->gobj())); + GdkKeymap *keymap = gdk_keymap_get_for_display (display); + GdkKeymapKey *keymapkey = NULL; + gint n_keys; + + if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keymapkey, &n_keys)) return false; + if (n_keys !=1) { g_free(keymapkey); return false;} + + GdkEventKey ev; + ev.type = GDK_KEY_PRESS; + ev.window = gtk_widget_get_window(GTK_WIDGET(w->gobj())); + ev.send_event = FALSE; + ev.time = 0; + ev.state = 0; + ev.keyval = keyval; + ev.length = 0; + ev.string = const_cast (""); + ev.hardware_keycode = keymapkey[0].keycode; + ev.group = keymapkey[0].group; + g_free(keymapkey); + + forward_key_press(&ev); + ev.type = GDK_KEY_RELEASE; + return forward_key_press(&ev); } -#endif bool key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) @@ -598,12 +399,9 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) GtkWidget* focus = gtk_window_get_focus (win); bool special_handling_of_unmodified_accelerators = false; bool allow_activating = true; + /* consider all relevant modifiers but not LOCK or SHIFT */ + const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); -#undef DEBUG_ACCELERATOR_HANDLING -#ifdef DEBUG_ACCELERATOR_HANDLING - //bool debug = (getenv ("ARDOUR_DEBUG_ACCELERATOR_HANDLING") != 0); - bool debug=true; -#endif if (focus) { if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) { special_handling_of_unmodified_accelerators = true; @@ -611,24 +409,27 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) } #ifdef GTKOSX - /* should this be universally true? */ + /* at one time this appeared to be necessary. As of July 2012, it does not + appear to be. if it ever is necessar, figure out if it should apply + to all platforms. + */ +#if 0 if (Keyboard::some_magic_widget_has_focus ()) { - allow_activating = false; + allow_activating = false; } #endif - -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "Win = " << win << " Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " special handling ? " - << special_handling_of_unmodified_accelerators - << " magic widget focus ? " - << Keyboard::some_magic_widget_has_focus() - << " allow_activation ? " - << allow_activating - << endl; - } #endif + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 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, + focus)); + /* This exists to allow us to override the way GTK handles key events. The normal sequence is: @@ -660,101 +461,105 @@ 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) { -#ifdef DEBUG_ACCELERATOR_HANDLING - cerr << "Remapped " << gdk_keyval_name (ev->keyval) << " to " << gdk_keyval_name (keyval_without_alt) << endl; - -#endif ev->keyval = keyval_without_alt; - } - } - } -#endif - if (!special_handling_of_unmodified_accelerators) { + /* XXX note that for a brief moment, the conditional above + * included "|| (ev->state & mask)" so as to enforce the + * implication of special_handling_of_UNMODIFIED_accelerators. + * however, this forces any key that GTK doesn't allow and that + * we have an alternative (see next comment) for to be + * automatically sent through the accel groups activation + * pathway, which prevents individual widgets & canvas items + * from ever seeing it if is used by a key binding. + * + * specifically, this hid Ctrl-down-arrow from MIDI region + * views because it is also bound to an action. + * + * until we have a robust, clean binding system, this + * quirk will have to remain in place. + */ /* pretend that certain key events that GTK does not allow to be used as accelerators are actually something that - it does allow. + it does allow. but only where there are no modifiers. */ uint32_t fakekey = ev->keyval; if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) { - if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) { + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels\n", + ev->keyval, fakekey)); + + GdkModifierType mod = GdkModifierType (ev->state); + + mod = GdkModifierType (mod & gtk_accelerator_get_default_mod_mask()); +#ifdef GTKOSX + /* GTK on OS X is currently (February 2012) setting both + the Meta and Mod2 bits in the event modifier state if + the Command key is down. + + gtk_accel_groups_activate() does not invoke any of the logic + that gtk_window_activate_key() will that sorts out that stupid + state of affairs, and as a result it fails to find a match + for the key event and the current set of accelerators. + + to fix this, if the meta bit is set, remove the mod2 bit + from the modifier. this assumes that our bindings use Primary + which will have set the meta bit in the accelerator entry. + */ + if (mod & GDK_META_MASK) { + mod = GdkModifierType (mod & ~GDK_MOD2_MASK); + } +#endif + + if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, mod)) { + DEBUG_TRACE (DEBUG::Accelerators, "\taccel group activated by fakekey\n"); return true; } } } - /* consider all relevant modifiers but not LOCK or SHIFT */ - - guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); - if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) { /* no special handling or there are modifiers in effect: accelerate first */ -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tactivate, then propagate\n"; - } -#endif + DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 string:%4 hardware_keycode:%5 group:%6\n", + ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group)); if (allow_activating) { + DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n"); if (gtk_window_activate_key (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); return true; } + } else { + DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n"); } -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tnot accelerated, now propagate\n"; - } -#endif + DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); + return gtk_window_propagate_key_event (win, ev); } /* no modifiers, propagate first */ -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tpropagate, then activate\n"; - } -#endif - if (!gtk_window_propagate_key_event (win, ev)) { -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tpropagation didn't handle, so activate\n"; - } -#endif + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\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, "\tactivation skipped\n"); } } else { -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\thandled by propagate\n"; - } -#endif + DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n"); return true; } -#ifdef DEBUG_ACCELERATOR_HANDLING - if (debug) { - cerr << "\tnot handled\n"; - } -#endif + DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n"); return true; } @@ -763,19 +568,18 @@ get_xpm (std::string name) { if (!xpm_map[name]) { - SearchPath spath(ARDOUR::ardour_search_path()); - spath += ARDOUR::system_data_search_path(); + Searchpath spath(ARDOUR::ardour_data_search_path()); spath.add_subdirectory_to_paths("pixmaps"); - sys::path data_file_path; + std::string 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()); + xpm_map[name] = Gdk::Pixbuf::create_from_file (data_file_path); } catch(const Glib::Error& e) { warning << "Caught Glib::Error: " << e.what() << endmsg; } @@ -790,18 +594,17 @@ get_icon_path (const char* cname) string name = cname; name += X_(".png"); - SearchPath spath(ARDOUR::ardour_search_path()); - spath += ARDOUR::system_data_search_path(); + Searchpath spath(ARDOUR::ardour_data_search_path()); spath.add_subdirectory_to_paths("icons"); - sys::path data_file_path; + std::string 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; + fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg; } - return data_file_path.to_string(); + return data_file_path; } Glib::RefPtr @@ -813,7 +616,7 @@ get_icon (const char* cname) } catch (const Gdk::PixbufError &e) { cerr << "Caught PixbufError: " << e.what() << endl; } catch (...) { - g_message("Caught ... "); + error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg; } return img; @@ -850,11 +653,48 @@ longest (vector& strings) bool key_is_legal_for_numeric_entry (guint keyval) { + /* we assume that this does not change over the life of the process + */ + + static int comma_decimal = -1; + switch (keyval) { - case GDK_minus: - case GDK_plus: case GDK_period: case GDK_comma: + if (comma_decimal < 0) { + std::lconv* lc = std::localeconv(); + if (strchr (lc->decimal_point, ',') != 0) { + comma_decimal = 1; + } else { + comma_decimal = 0; + } + } + break; + default: + break; + } + + switch (keyval) { + case GDK_decimalpoint: + case GDK_KP_Separator: + return true; + + case GDK_period: + if (comma_decimal) { + return false; + } else { + return true; + } + break; + case GDK_comma: + if (comma_decimal) { + return true; + } else { + return false; + } + break; + case GDK_minus: + case GDK_plus: case GDK_0: case GDK_1: case GDK_2: @@ -901,7 +741,9 @@ set_pango_fontsize () /* FT2 rendering - used by GnomeCanvas, sigh */ - pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_for_display(), val/1024, val/1024); +#ifndef WIN32 + pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_new(), val/1024, val/1024); +#endif /* Cairo rendering, in case there is any */ @@ -952,40 +794,65 @@ escape_underscores (string const & s) return o; } -static void -adjustment_to_controllable (Gtk::Adjustment* adj, boost::weak_ptr wcont) +/** Replace < and > with < and > respectively to make < > display correctly in markup strings */ +string +escape_angled_brackets (string const & s) { - boost::shared_ptr cont = wcont.lock(); - - if (cont) { - double val = adj->get_value(); - if (val != cont->get_value()) { - cont->set_value (val); - } - } + string o = s; + boost::replace_all (o, "<", "<"); + boost::replace_all (o, ">", ">"); + return o; } -static void -controllable_to_adjustment (Gtk::Adjustment* adj, boost::weak_ptr wcont) +Gdk::Color +unique_random_color (list& used_colors) { - boost::shared_ptr cont = wcont.lock(); - - if (cont) { - float val = cont->get_value(); - - if (val != adj->get_value()) { - adj->set_value (val); - } - } + Gdk::Color newcolor; + + while (1) { + + double h, s, v; + + h = fmod (random(), 360.0); + s = (random() % 65535) / 65535.0; + v = (random() % 65535) / 65535.0; + + s = min (0.5, s); /* not too saturated */ + v = max (0.9, v); /* not too bright */ + newcolor.set_hsv (h, s, v); + + if (used_colors.size() == 0) { + used_colors.push_back (newcolor); + return newcolor; + } + + for (list::iterator i = used_colors.begin(); i != used_colors.end(); ++i) { + Gdk::Color c = *i; + float rdelta, bdelta, gdelta; + + rdelta = newcolor.get_red() - c.get_red(); + bdelta = newcolor.get_blue() - c.get_blue(); + gdelta = newcolor.get_green() - c.get_green(); + + if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) { + /* different enough */ + used_colors.push_back (newcolor); + return newcolor; + } + } + + /* XXX need throttle here to make sure we don't spin for ever */ + } } -void -control_link (ScopedConnectionList& scl, boost::shared_ptr c, Gtk::Adjustment& a) +string +rate_as_string (float r) { - boost::weak_ptr wc (c); - - a.signal_value_changed().connect (sigc::bind (sigc::ptr_fun (adjustment_to_controllable), &a, wc)); - c->Changed.connect (scl, MISSING_INVALIDATOR, boost::bind (controllable_to_adjustment, &a, wc), - gui_context()); + char buf[32]; + if (fmod (r, 1000.0f)) { + snprintf (buf, sizeof (buf), "%.1f kHz", r/1000.0); + } else { + snprintf (buf, sizeof (buf), "%.0f kHz", r/1000.0); + } + return buf; } -