X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Futils.cc;h=e96137ee2c41306cb9959f7b8bdde4ff7608cc55;hb=a4664d68c031c77c5e436fe97a92005b7d2019d8;hp=5e5534222e174a71b700de94dab63b99d4d7a905;hpb=3845af6ce92ef15637ffb09410f442e7b4a104c3;p=ardour.git diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 5e5534222e..e96137ee2c 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2003 Paul Davis + Copyright (C) 2003 Paul Davis 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 @@ -36,7 +36,7 @@ #include #include "ardour/configuration.h" -#include "ardour/configuration.h" +#include "ardour/rc_configuration.h" #include "ardour/filesystem_paths.h" @@ -47,12 +47,13 @@ #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; @@ -99,7 +100,7 @@ fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font actual_width = width; break; } - + ustr.erase (last--); shorter_by++; @@ -128,7 +129,7 @@ fit_to_pixels (cairo_t* cr, std::string name, double avail) bool abbreviated = false; uint32_t width = 0; - + while (1) { cairo_text_extents_t ext; cairo_text_extents (cr, name.c_str(), &ext); @@ -187,9 +188,9 @@ 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; @@ -197,13 +198,13 @@ xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h) } 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[] // @@ -240,7 +241,7 @@ xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h) } savergb = rgb = (unsigned char*) malloc (h * w * 4); - + // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION if (strstr (xpm[1], "None")) { @@ -255,7 +256,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[] // @@ -311,17 +312,17 @@ get_font_for_style (string widgetname) 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 */ } @@ -340,12 +341,12 @@ 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) { @@ -353,7 +354,7 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s r = waverc->fg[state].red / 257; g = waverc->fg[state].green / 257; b = waverc->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; @@ -377,7 +378,7 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s } window->remove (); - + if (state == Gtk::STATE_NORMAL && rgba) { return (uint32_t) RGBA_TO_UINT(r,g,b,a); } else { @@ -491,7 +492,7 @@ gc_from_style (string widget_style_name, int state, string attr) } -bool +bool canvas_item_visible (ArdourCanvas::Item* item) { return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false; @@ -503,12 +504,6 @@ set_color (Gdk::Color& c, int rgb) c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256); } -#ifdef GTKOSX -extern "C" { - gboolean gdk_quartz_possibly_forward (GdkEvent*); -} -#endif - bool relay_key_press (GdkEventKey* ev, Gtk::Window* win) { @@ -519,6 +514,79 @@ relay_key_press (GdkEventKey* ev, Gtk::Window* win) } } +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) { @@ -535,8 +603,8 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) if (focus) { if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) { special_handling_of_unmodified_accelerators = true; - } - } + } + } #ifdef GTKOSX /* should this be universally true? */ @@ -547,7 +615,7 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) #ifdef DEBUG_ACCELERATOR_HANDLING if (debug) { - cerr << "Win = " << win << " Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " special handling ? " + 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() @@ -566,18 +634,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 @@ -588,6 +656,24 @@ 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) { @@ -602,17 +688,6 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) { return true; } - -#ifdef GTKOSX - if (allow_activating) { - int oldval = ev->keyval; - ev->keyval = fakekey; - if (gdk_quartz_possibly_forward ((GdkEvent*) ev)) { - return true; - } - ev->keyval = oldval; - } -#endif } } @@ -631,11 +706,6 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) #endif if (allow_activating) { -#ifdef GTKOSX - if (gdk_quartz_possibly_forward ((GdkEvent*) ev)) { - return true; - } -#endif if (gtk_window_activate_key (win, ev)) { return true; } @@ -648,9 +718,9 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) #endif return gtk_window_propagate_key_event (win, ev); } - + /* no modifiers, propagate first */ - + #ifdef DEBUG_ACCELERATOR_HANDLING if (debug) { cerr << "\tpropagate, then activate\n"; @@ -664,15 +734,9 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) #endif if (allow_activating) { - -#ifdef GTKOSX - if (gdk_quartz_possibly_forward ((GdkEvent*) ev)) { - return true; - } -#endif return gtk_window_activate_key (win, ev); - } - + } + } else { #ifdef DEBUG_ACCELERATOR_HANDLING if (debug) { @@ -690,22 +754,22 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) return true; } -Glib::RefPtr +Glib::RefPtr get_xpm (std::string name) { if (!xpm_map[name]) { 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) { @@ -736,7 +800,7 @@ get_icon_path (const char* cname) return data_file_path.to_string(); } -Glib::RefPtr +Glib::RefPtr get_icon (const char* cname) { Glib::RefPtr img; @@ -760,22 +824,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; } @@ -819,7 +883,7 @@ key_is_legal_for_numeric_entry (guint keyval) case GDK_Left: case GDK_Right: return true; - + default: break; } @@ -836,7 +900,7 @@ set_pango_fontsize () pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_for_display(), val/1024, val/1024); /* Cairo rendering, in case there is any */ - + pango_cairo_font_map_set_resolution ((PangoCairoFontMap*) pango_cairo_font_map_get_default(), val/1024); } @@ -862,35 +926,79 @@ possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval) case GDK_ISO_Left_Tab: fakekey = GDK_nabla; break; - + case GDK_Up: fakekey = GDK_uparrow; break; - + case GDK_Down: fakekey = GDK_downarrow; break; - + case GDK_Right: fakekey = GDK_rightarrow; break; - + case GDK_Left: fakekey = GDK_leftarrow; break; - + + case GDK_Return: + fakekey = GDK_3270_Enter; + break; + + case GDK_KP_Enter: + fakekey = GDK_F35; + break; + default: break; } - + if (fakekey != GDK_VoidSymbol) { keyval = fakekey; return true; - } + } return false; } - + +uint32_t +possibly_translate_legal_accelerator_to_real_key (uint32_t keyval) +{ + switch (keyval) { + case GDK_nabla: + return GDK_Tab; + break; + + case GDK_uparrow: + return GDK_Up; + break; + + case GDK_downarrow: + return GDK_Down; + break; + + case GDK_rightarrow: + return GDK_Right; + break; + + case GDK_leftarrow: + return GDK_Left; + break; + + case GDK_3270_Enter: + return GDK_Return; + + case GDK_F35: + return GDK_KP_Enter; + break; + } + + return keyval; +} + + inline guint8 convert_color_channel (guint8 src, @@ -907,7 +1015,7 @@ convert_bgra_to_rgba (guint8 const* src, { guint8 const* src_pixel = src; guint8* dst_pixel = dst; - + for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { @@ -918,8 +1026,113 @@ convert_bgra_to_rgba (guint8 const* src, dst_pixel[2] = convert_color_channel (src_pixel[0], src_pixel[3]); dst_pixel[3] = src_pixel[3]; - + dst_pixel += 4; src_pixel += 4; } } + +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); + + int const w = std::min (monitor_rect.get_width(), max_width) * 0.8; + int const h = std::min (monitor_rect.get_height(), max_height) * 0.8; + + window->resize (w, h); +} + +Glib::RefPtr +pixbuf_from_ustring(const ustring& name, Pango::FontDescription* font, int clip_width, int clip_height, Gdk::Color fg) +{ + static Glib::RefPtr* empty_pixbuf = 0; + + if (name.empty()) { + if (empty_pixbuf == 0) { + empty_pixbuf = new Glib::RefPtr; + *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height); + } + return *empty_pixbuf; + } + + Glib::RefPtr buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height); + + cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height); + cairo_t* cr = cairo_create (surface); + cairo_text_extents_t te; + + cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0); + cairo_select_font_face (cr, font->get_family().c_str(), + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, font->get_size() / Pango::SCALE); + cairo_text_extents (cr, name.c_str(), &te); + + cairo_move_to (cr, 0.5, 0.5 - te.height / 2 - te.y_bearing + clip_height / 2); + cairo_show_text (cr, name.c_str()); + + convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height); + + cairo_destroy(cr); + cairo_surface_destroy(surface); + + return buf; +} + +/** 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 (); + + for (string::size_type i = 0; i < N; ++i) { + if (s[i] == '_') { + o += "__"; + } else { + o += s[i]; + } + } + + return o; +} + +static void +adjustment_to_controllable (Gtk::Adjustment* adj, boost::weak_ptr wcont) +{ + boost::shared_ptr cont = wcont.lock(); + + if (cont) { + double val = adj->get_value(); + if (val != cont->get_value()) { + cont->set_value (val); + } + } +} + +static void +controllable_to_adjustment (Gtk::Adjustment* adj, boost::weak_ptr wcont) +{ + boost::shared_ptr cont = wcont.lock(); + + if (cont) { + float val = cont->get_value(); + + if (val != adj->get_value()) { + adj->set_value (val); + } + } +} + +void +control_link (ScopedConnectionList& scl, boost::shared_ptr c, Gtk::Adjustment& a) +{ + 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()); +} +