Merge branch 'master' into windows+cc
[ardour.git] / gtk2_ardour / utils.cc
index 692ae05a094a4b20604ab12e380b74c2280e51e9..00e94b0dd96b6878584162b1eeb119d7567a8b7c 100644 (file)
 #include <pango/pangocairo.h> // for fontmap resolution control for GnomeCanvas
 
 #include <cstdlib>
+#include <clocale>
+#include <cstring>
 #include <cctype>
+#include <cmath>
 #include <fstream>
 #include <list>
 #include <sys/stat.h>
-#include <libart_lgpl/art_misc.h>
 #include <gtkmm/rc.h>
 #include <gtkmm/window.h>
 #include <gtkmm/combo.h>
@@ -42,8 +44,8 @@
 
 #include <gtkmm2ext/utils.h>
 #include "ardour/rc_configuration.h"
-
 #include "ardour/filesystem_paths.h"
+#include "canvas/item.h"
 
 #include "ardour_ui.h"
 #include "debug.h"
@@ -52,7 +54,6 @@
 #include "utils.h"
 #include "i18n.h"
 #include "rgb_macros.h"
-#include "canvas_impl.h"
 #include "gui_thread.h"
 
 using namespace std;
@@ -199,18 +200,6 @@ 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
 get_font_for_style (string widgetname)
 {
@@ -226,13 +215,13 @@ get_font_for_style (string widgetname)
 
        Glib::RefPtr<const Pango::Layout> layout = foobar.get_layout();
 
-       PangoFontDescription *pfd = (PangoFontDescription *)pango_layout_get_font_description((PangoLayout *)layout->gobj());
+       PangoFontDescription *pfd = const_cast<PangoFontDescription *> (pango_layout_get_font_description(const_cast<PangoLayout *>(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<PangoLayout*>(layout->gobj()));
                pfd =  pango_context_get_font_description (ctxt);
                return Pango::FontDescription (pfd); /* make a copy */
        }
@@ -300,9 +289,50 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s
 }
 
 bool
-canvas_item_visible (ArdourCanvas::Item* item)
+rgba_p_from_style (string style, float *r, float *g, float *b, string attr, int state)
 {
-       return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false;
+       static Gtk::Window* window = 0;
+       assert (r && g && b);
+
+       if (window == 0) {
+               window = new Window (WINDOW_TOPLEVEL);
+       }
+
+       Gtk::EventBox foo;
+
+       window->add (foo);
+
+       foo.set_name (style);
+       foo.ensure_style ();
+
+       GtkRcStyle* rc = foo.get_style()->gobj()->rc_style;
+
+       if (!rc) {
+               warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
+               return false;
+       }
+       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;
+       }
+
+       window->remove ();
+       return true;
 }
 
 void
@@ -314,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;
        }
@@ -327,6 +363,35 @@ forward_key_press (GdkEventKey* ev)
         return PublicEditor::instance().on_key_press_event(ev);
 }
 
+bool
+emulate_key_event (Gtk::Widget* w, unsigned int keyval)
+{
+       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<gchar*> ("");
+       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);
+}
+
 bool
 key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
 {
@@ -459,9 +524,13 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
                /* no special handling or there are modifiers in effect: accelerate first */
 
                 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 {
@@ -499,7 +568,7 @@ get_xpm (std::string name)
 {
        if (!xpm_map[name]) {
 
-               SearchPath spath(ARDOUR::ardour_data_search_path());
+               Searchpath spath(ARDOUR::ardour_data_search_path());
 
                spath.add_subdirectory_to_paths("pixmaps");
 
@@ -525,7 +594,7 @@ get_icon_path (const char* cname)
        string name = cname;
        name += X_(".png");
 
-       SearchPath spath(ARDOUR::ardour_data_search_path());
+       Searchpath spath(ARDOUR::ardour_data_search_path());
 
        spath.add_subdirectory_to_paths("icons");
 
@@ -547,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;
@@ -584,11 +653,48 @@ longest (vector<string>& 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:
@@ -635,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 */
 
@@ -703,15 +811,15 @@ unique_random_color (list<Gdk::Color>& used_colors)
 
        while (1) {
 
-               /* avoid neon/glowing tones by limiting them to the
-                  "inner section" (paler) of a color wheel/circle.
-               */
+               double h, s, v;
 
-               const int32_t max_saturation = 48000; // 65535 would open up the whole color wheel
+               h = fmod (random(), 360.0);
+               s = (random() % 65535) / 65535.0;
+               v = (random() % 65535) / 65535.0;
 
-               newcolor.set_red (random() % max_saturation);
-               newcolor.set_blue (random() % max_saturation);
-               newcolor.set_green (random() % max_saturation);
+               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);
@@ -727,6 +835,7 @@ unique_random_color (list<Gdk::Color>& used_colors)
                        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;
                        }
@@ -735,3 +844,15 @@ unique_random_color (list<Gdk::Color>& used_colors)
                /* XXX need throttle here to make sure we don't spin for ever */
        }
 }
+
+string 
+rate_as_string (float r)
+{
+       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;
+}