new PBD::DEBUG API changes for Waves backend
[ardour.git] / libs / gtkmm2ext / utils.cc
index 1fec597fbaf562bf0aecde5c39f12a0b850dde89..6efa95ac1a36e83ae57ea703a386d4ddf2f5a439 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include <map>
+#include <algorithm>
 
 #include <gtk/gtkpaned.h>
 #include <gtk/gtk.h>
@@ -42,6 +43,7 @@ Gtkmm2ext::init (const char* localedir)
 {
 #ifdef ENABLE_NLS
        (void) bindtextdomain(PACKAGE, localedir);
+       (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
 #endif
 }
 
@@ -57,9 +59,9 @@ Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
 }
 
 void
-get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
-                              int& width,
-                              int& height)
+Gtkmm2ext::get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
+                          int& width,
+                          int& height)
 {
        layout->get_pixel_size (width, height);
 }
@@ -75,6 +77,51 @@ Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *
        w.set_size_request(width + hpadding, height + vpadding);
 }
 
+/** Set width request to display given text, and height to display anything.
+    This is useful for setting many widgets to the same height for consistency. */
+void
+Gtkmm2ext::set_size_request_to_display_given_text_width (Gtk::Widget& w,
+                                                         const gchar* htext,
+                                                         gint         hpadding,
+                                                         gint         vpadding)
+{
+       static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+       w.ensure_style ();
+
+       int hwidth, hheight;
+       get_pixel_size (w.create_pango_layout (htext), hwidth, hheight);
+
+       int vwidth, vheight;
+       get_pixel_size (w.create_pango_layout (vtext), vwidth, vheight);
+
+       w.set_size_request(hwidth + hpadding, vheight + vpadding);
+}
+
+void
+Gtkmm2ext::set_height_request_to_display_any_text (Gtk::Widget& w, gint vpadding)
+{
+       static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+       w.ensure_style ();
+
+       int width, height;
+       get_pixel_size (w.create_pango_layout (vtext), width, height);
+
+       w.set_size_request(-1, height + vpadding);
+}
+
+void
+Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, std::string const & text,
+                                                  gint hpadding, gint vpadding)
+{
+       int width, height;
+       w.ensure_style ();
+       
+       get_pixel_size (w.create_pango_layout (text), width, height);
+       w.set_size_request(width + hpadding, height + vpadding);
+}
+
 void
 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, 
                                                   const std::vector<std::string>& strings,
@@ -113,6 +160,33 @@ Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w,
        w.set_size_request(width_max + hpadding, height_max + vpadding);
 }
 
+/** This version specifies horizontal padding in text to avoid assumptions
+    about font size.  Should be used anywhere padding is used to avoid text,
+    like combo boxes. */
+void
+Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget&                    w,
+                                                   const std::vector<std::string>& strings,
+                                                   const std::string&              hpadding,
+                                                   gint                            vpadding)
+{
+       int width_max = 0;
+       int height_max = 0;
+       w.ensure_style ();
+
+       for (vector<string>::const_iterator i = strings.begin(); i != strings.end(); ++i) {
+               int width, height;
+               get_pixel_size (w.create_pango_layout (*i), width, height);
+               width_max = max(width_max,width);
+               height_max = max(height_max, height);
+       }
+
+       int pad_width;
+       int pad_height;
+       get_pixel_size (w.create_pango_layout (hpadding), pad_width, pad_height);
+
+       w.set_size_request(width_max + pad_width, height_max + vpadding);
+}
+
 static inline guint8
 demultiply_alpha (guint8 src,
                   guint8 alpha)
@@ -129,11 +203,11 @@ demultiply_alpha (guint8 src,
        return alpha ? ((guint (src) << 8) - src) / alpha : 0;
 }
 
-static void
-convert_bgra_to_rgba (guint8 const* src,
-                     guint8*       dst,
-                     int           width,
-                     int           height)
+void
+Gtkmm2ext::convert_bgra_to_rgba (guint8 const* src,
+                                guint8*       dst,
+                                int           width,
+                                int           height)
 {
        guint8 const* src_pixel = src;
        guint8*       dst_pixel = dst;
@@ -233,6 +307,39 @@ Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& str
        }
 }
 
+void
+Gtkmm2ext::get_popdown_strings (Gtk::ComboBoxText& cr, std::vector<std::string>& strings)
+{
+       strings.clear ();
+       Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
+       if (!m) {
+               return;
+       }
+       for(Gtk::TreeModel::iterator i = m->children().begin(); i != m->children().end(); ++i) {
+               Glib::ustring txt;
+               (*i)->get_value(0, txt);
+               strings.push_back (txt);
+       }
+}
+
+bool
+Gtkmm2ext::contains_value (Gtk::ComboBoxText& cr, const std::string text)
+{
+       std::vector<std::string> s;
+       get_popdown_strings (cr, s);
+       return (std::find (s.begin(), s.end(), text) != s.end());
+}
+
+bool
+Gtkmm2ext::set_active_text_if_present (Gtk::ComboBoxText& cr, const std::string text)
+{
+       if (contains_value(cr, text)) {
+               cr.set_active_text (text);
+               return true;
+       }
+       return false;
+}
+
 GdkWindow*
 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
 {
@@ -264,6 +371,30 @@ Gtkmm2ext::detach_menu (Gtk::Menu& menu)
        }
 }
 
+bool
+Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator (GdkModifierType& mod)
+{
+#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
+       return true;
+}
+
 bool
 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
 {
@@ -574,6 +705,18 @@ Gtkmm2ext::pixel_width (const string& str, Pango::FontDescription& font)
        return width;
 }
 
+void
+Gtkmm2ext::pixel_size (const string& str, Pango::FontDescription& font, int& width, int& height)
+{
+       Gtk::Label foo;
+       Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
+
+       layout->set_font_description (font);
+       layout->set_text (str);
+
+       Gtkmm2ext::get_ink_pixel_size (layout, width, height);
+}
+
 #if 0
 string
 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
@@ -681,3 +824,114 @@ Gtkmm2ext::disable_tooltips ()
        gtk_rc_parse_string ("gtk-enable-tooltips = 0");
 }
 
+bool
+Gtkmm2ext::event_inside_widget_window (Gtk::Widget& widget, GdkEvent* ev)
+{
+        gdouble evx, evy;
+
+        if (!gdk_event_get_root_coords (ev, &evx, &evy)) {
+                return false;
+        }
+        
+        gint wx;
+        gint wy;
+        gint width, height, depth;
+        gint x, y;
+
+        Glib::RefPtr<Gdk::Window> widget_window = widget.get_window();
+
+        widget_window->get_geometry (x, y, width, height, depth);
+        widget_window->get_root_origin (wx, wy);
+        
+        if ((evx >= wx && evx < wx + width) && 
+            (evy >= wy && evy < wy + height)) {
+                return true;
+        } 
+
+        return false;
+}
+
+const char*
+Gtkmm2ext::event_type_string (int event_type)
+{
+       switch (event_type) {
+       case GDK_NOTHING:
+               return "nothing";
+       case GDK_DELETE:
+               return "delete";
+       case GDK_DESTROY:
+               return "destroy";
+       case GDK_EXPOSE:
+               return "expose";
+       case GDK_MOTION_NOTIFY:
+               return "motion_notify";
+       case GDK_BUTTON_PRESS:
+               return "button_press";
+       case GDK_2BUTTON_PRESS:
+               return "2button_press";
+       case GDK_3BUTTON_PRESS:
+               return "3button_press";
+       case GDK_BUTTON_RELEASE:
+               return "button_release";
+       case GDK_KEY_PRESS:
+               return "key_press";
+       case GDK_KEY_RELEASE:
+               return "key_release";
+       case GDK_ENTER_NOTIFY:
+               return "enter_notify";
+       case GDK_LEAVE_NOTIFY:
+               return "leave_notify";
+       case GDK_FOCUS_CHANGE:
+               return "focus_change";
+       case GDK_CONFIGURE:
+               return "configure";
+       case GDK_MAP:
+               return "map";
+       case GDK_UNMAP:
+               return "unmap";
+       case GDK_PROPERTY_NOTIFY:
+               return "property_notify";
+       case GDK_SELECTION_CLEAR:
+               return "selection_clear";
+       case GDK_SELECTION_REQUEST:
+               return "selection_request";
+       case GDK_SELECTION_NOTIFY:
+               return "selection_notify";
+       case GDK_PROXIMITY_IN:
+               return "proximity_in";
+       case GDK_PROXIMITY_OUT:
+               return "proximity_out";
+       case GDK_DRAG_ENTER:
+               return "drag_enter";
+       case GDK_DRAG_LEAVE:
+               return "drag_leave";
+       case GDK_DRAG_MOTION:
+               return "drag_motion";
+       case GDK_DRAG_STATUS:
+               return "drag_status";
+       case GDK_DROP_START:
+               return "drop_start";
+       case GDK_DROP_FINISHED:
+               return "drop_finished";
+       case GDK_CLIENT_EVENT:
+               return "client_event";
+       case GDK_VISIBILITY_NOTIFY:
+               return "visibility_notify";
+       case GDK_NO_EXPOSE:
+               return "no_expose";
+       case GDK_SCROLL:
+               return "scroll";
+       case GDK_WINDOW_STATE:
+               return "window_state";
+       case GDK_SETTING:
+               return "setting";
+       case GDK_OWNER_CHANGE:
+               return "owner_change";
+       case GDK_GRAB_BROKEN:
+               return "grab_broken";
+       case GDK_DAMAGE:
+               return "damage";
+       }
+
+       return "unknown";
+}