Code

Automatically add shortcuts to tooltips
authorJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Mon, 6 Sep 2010 17:32:05 +0000 (19:32 +0200)
committerJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Mon, 6 Sep 2010 17:32:05 +0000 (19:32 +0200)
src/interface.cpp
src/interface.h
src/shortcuts.cpp
src/shortcuts.h
src/verbs.cpp
src/verbs.h
src/widgets/button.cpp
src/widgets/toolbox.cpp

index 6dc29288f638db312cafa6c901359c5614dc57af..d66a14dbf43176ab18584cb8eff72a843ba408b8 100644 (file)
@@ -456,85 +456,12 @@ sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
 
 } // end of sp_ui_menu_append_item()
 
-/**
-\brief  a wrapper around gdk_keyval_name producing (when possible) characters, not names
- */
-static gchar const *
-sp_key_name(guint keyval)
-{
-    /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
-       simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
-    gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
-
-    if      (!strcmp(n, "asciicircum"))  return "^";
-    else if (!strcmp(n, "parenleft"  ))  return "(";
-    else if (!strcmp(n, "parenright" ))  return ")";
-    else if (!strcmp(n, "plus"       ))  return "+";
-    else if (!strcmp(n, "minus"      ))  return "-";
-    else if (!strcmp(n, "asterisk"   ))  return "*";
-    else if (!strcmp(n, "KP_Multiply"))  return "*";
-    else if (!strcmp(n, "Delete"     ))  return "Del";
-    else if (!strcmp(n, "Page_Up"    ))  return "PgUp";
-    else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
-    else if (!strcmp(n, "grave"      ))  return "`";
-    else if (!strcmp(n, "numbersign" ))  return "#";
-    else if (!strcmp(n, "bar"        ))  return "|";
-    else if (!strcmp(n, "slash"      ))  return "/";
-    else if (!strcmp(n, "exclam"     ))  return "!";
-    else if (!strcmp(n, "percent"    ))  return "%";
-    else return n;
-}
-
-
-/**
- * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
- * \param c Points to a buffer at least 256 bytes long.
- */
-void
-sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
-{
-    /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
-     * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
-     * Will probably need to change sp_shortcut_invoke callers.
-     *
-     * The existing gtk_label_new_with_mnemonic call can be replaced with
-     * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
-     * gtk_label_set_text_with_mnemonic(lbl, str).
-     */
-    static GtkAccelLabelClass const &accel_lbl_cls
-        = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
-
-    struct { unsigned test; char const *name; } const modifier_tbl[] = {
-        { SP_SHORTCUT_SHIFT_MASK,   accel_lbl_cls.mod_name_shift   },
-        { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
-        { SP_SHORTCUT_ALT_MASK,     accel_lbl_cls.mod_name_alt     }
-    };
-
-    gchar *p = c;
-    gchar *end = p + 256;
-
-    for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
-        if ((shortcut & modifier_tbl[i].test)
-            && (p < end))
-        {
-            p += g_snprintf(p, end - p, "%s%s",
-                            modifier_tbl[i].name,
-                            accel_lbl_cls.mod_separator);
-        }
-    }
-    if (p < end) {
-        p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
-    }
-    end[-1] = '\0';  // snprintf doesn't guarantee to nul-terminate the string.
-}
-
 void
 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
 {
     SPAction     *action;
     unsigned int shortcut;
     gchar        *s;
-    gchar        key[256];
     gchar        *atitle;
 
     action = verb->get_action(NULL);
@@ -548,11 +475,12 @@ sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
     g_free(atitle);
 
     shortcut = sp_shortcut_get_primary(verb);
-    if (shortcut) {
+    if (shortcut!=GDK_VoidSymbol) {
+        gchar* key = sp_shortcut_get_label(shortcut);
         s = g_stpcpy(s, " (");
-        sp_ui_shortcut_string(shortcut, key);
         s = g_stpcpy(s, key);
         s = g_stpcpy(s, ")");
+        g_free(key);
     }
 }
 
@@ -582,9 +510,8 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::
         if (!action) return NULL;
 
         shortcut = sp_shortcut_get_primary(verb);
-        if (shortcut) {
-            gchar c[256];
-            sp_ui_shortcut_string(shortcut, c);
+        if (shortcut!=GDK_VoidSymbol) {
+            gchar* c = sp_shortcut_get_label(shortcut);
             GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
             GtkWidget *const name_lbl = gtk_label_new("");
             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
@@ -600,6 +527,7 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::
                 item = gtk_image_menu_item_new();
             }
             gtk_container_add((GtkContainer *) item, hb);
+            g_free(c);
         } else {
             if (radio) {
                 item = gtk_radio_menu_item_new (group);
@@ -754,9 +682,8 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *
     SPAction *action = (verb) ? verb->get_action(view) : 0;
     GtkWidget *item = gtk_check_menu_item_new();
 
-    if (verb && shortcut) {
-        gchar c[256];
-        sp_ui_shortcut_string(shortcut, c);
+    if (verb && shortcut!=GDK_VoidSymbol) {
+        gchar* c = sp_shortcut_get_label(shortcut);
 
         GtkWidget *hb = gtk_hbox_new(FALSE, 16);
 
@@ -775,6 +702,7 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *
         gtk_widget_show_all(hb);
 
         gtk_container_add((GtkContainer *) item, hb);
+        g_free(c);
     } else {
         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
index 099fdd27712950324c09f548bdb629a5f69de0bc..3900350bd59f75490c09cf4b64f14bc31e4d449b 100644 (file)
@@ -69,8 +69,6 @@ void sp_ui_dialog_title_string (Inkscape::Verb * verb, gchar* c);
 void sp_ui_error_dialog (const gchar * message);
 bool sp_ui_overwrite_file (const gchar * filename);
 
-void sp_ui_shortcut_string (unsigned int shortcut, gchar* c);
-
 #endif
 
 /*
index 7d0f3747d044153a9a56f64af47551491b15d4a6..d02ef6e4890026610674d396048d9bf565d61898 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <gdk/gdkkeys.h>
 #include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
 
 #include "helper/action.h"
 #include "io/sys.h"
@@ -202,10 +203,33 @@ unsigned int
 sp_shortcut_get_primary(Inkscape::Verb *verb)
 {
     if (!primary_shortcuts) sp_shortcut_init();
-    return (unsigned int)GPOINTER_TO_INT(g_hash_table_lookup(primary_shortcuts,
-                                                             (gpointer)(verb)));
+    gpointer value;
+    if (g_hash_table_lookup_extended(primary_shortcuts, (gpointer)(verb), NULL, &value)) {
+        return (unsigned int)GPOINTER_TO_INT(value);
+    } else {
+        return GDK_VoidSymbol;
+    }
 }
 
+gchar* sp_shortcut_get_label (unsigned int shortcut)
+{
+    // The comment below was copied from the function sp_ui_shortcut_string in interface.cpp (which was subsequently removed)
+    /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
+     * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
+     * Will probably need to change sp_shortcut_invoke callers.
+     *
+     * The existing gtk_label_new_with_mnemonic call can be replaced with
+     * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
+     * gtk_label_set_text_with_mnemonic(lbl, str).
+     */
+    if (shortcut==GDK_VoidSymbol) return 0;
+    return gtk_accelerator_get_label(
+        shortcut&(~SP_SHORTCUT_MODIFIER_MASK),static_cast<GdkModifierType>(
+        ((shortcut&SP_SHORTCUT_SHIFT_MASK)?GDK_SHIFT_MASK:0) |
+        ((shortcut&SP_SHORTCUT_CONTROL_MASK)?GDK_CONTROL_MASK:0) |
+        ((shortcut&SP_SHORTCUT_ALT_MASK)?GDK_MOD1_MASK:0)
+        ));
+}
 
 /*
   Local Variables:
index 5119851c9c79390438628df49332c0a154d4feb6..3fa0927138078abebd24d635a58d94913d5aeec0 100644 (file)
@@ -24,12 +24,14 @@ namespace Inkscape {
 #define SP_SHORTCUT_SHIFT_MASK (1 << 24)
 #define SP_SHORTCUT_CONTROL_MASK (1 << 25)
 #define SP_SHORTCUT_ALT_MASK (1 << 26)
+#define SP_SHORTCUT_MODIFIER_MASK (SP_SHORTCUT_SHIFT_MASK|SP_SHORTCUT_CONTROL_MASK|SP_SHORTCUT_ALT_MASK)
 
 /* Returns true if action was performed */
 bool sp_shortcut_invoke (unsigned int shortcut, Inkscape::UI::View::View *view);
 
 Inkscape::Verb * sp_shortcut_get_verb (unsigned int shortcut);
-unsigned int sp_shortcut_get_primary (Inkscape::Verb * verb);
+unsigned int sp_shortcut_get_primary (Inkscape::Verb * verb); // Returns GDK_VoidSymbol if no shortcut is found.
+char* sp_shortcut_get_label (unsigned int shortcut); // Returns the human readable form of the shortcut (or NULL), for example Shift+Ctrl+F. Free the returned string with g_free.
 
 #endif
 
index c2af399c543a6df412ca91f4264c6a6146f8b6cb..6ba0aa562a6912d65015190277bada40c3bf3e56 100644 (file)
@@ -63,6 +63,7 @@
 #include "selection-chemistry.h"
 #include "seltrans.h"
 #include "shape-editor.h"
+#include "shortcuts.h"
 #include "sp-flowtext.h"
 #include "sp-guide.h"
 #include "splivarot.h"
@@ -334,7 +335,7 @@ Verb::VerbIDTable Verb::_verb_ids;
     in the \c _verbs hashtable which is indexed by the \c code.
 */
 Verb::Verb(gchar const *id, gchar const *name, gchar const *tip, gchar const *image) :
-    _actions(NULL), _id(id), _name(name), _tip(tip), _image(image)
+    _actions(NULL), _id(id), _name(name), _tip(tip), _full_tip(0), _image(image)
 {
     static int count = SP_VERB_LAST;
 
@@ -358,6 +359,8 @@ Verb::~Verb(void)
         delete _actions;
     }
 
+    if (_full_tip) g_free(_full_tip);
+
     return;
 }
 
@@ -631,7 +634,20 @@ Verb::sensitive(SPDocument *in_doc, bool in_sensitive)
 gchar const *
 Verb::get_tip (void)
 {
-       return _(_tip);
+    if (!_tip) return 0;
+    unsigned int shortcut = sp_shortcut_get_primary(this);
+    if (shortcut!=_shortcut || !_full_tip) {
+        if (_full_tip) g_free(_full_tip);
+        _shortcut = shortcut;
+        gchar* shortcutString = sp_shortcut_get_label(shortcut);
+        if (shortcutString) {
+            _full_tip = g_strdup_printf("%s (%s)", _(_tip), shortcutString);
+            g_free(shortcutString);
+        } else {
+               _full_tip = g_strdup(_(_tip));
+        }
+    }
+    return _full_tip;
 }
 
 void
index 7c04ba3f6be9c39000b88f23d251bc2159e3a3f5..16d4d795a618d525369d1e5d96d3111a112aad9f 100644 (file)
@@ -339,6 +339,8 @@ private:
     gchar const * _name;
     /** \brief Tooltip for the verb. */
     gchar const * _tip;
+    gchar * _full_tip; // includes shortcut
+    unsigned int _shortcut;
     /** \brief Name of the image that represents the verb. */
     gchar const * _image;
     /** \brief Unique numerical representation of the verb.  In most cases
@@ -409,7 +411,7 @@ public:
          gchar const * name,
          gchar const * tip,
          gchar const * image) :
-        _actions(NULL), _id(id), _name(name), _tip(tip), _image(image), _code(code), _default_sensitive(true) {
+        _actions(NULL), _id(id), _name(name), _tip(tip), _full_tip(0), _image(image), _code(code), _default_sensitive(true) {
         _verbs.insert(VerbTable::value_type(_code, this));
         _verb_ids.insert(VerbIDTable::value_type(_id, this));
     }
index 6769fa389d9f1889e29f24e925053f0adb3d8f0f..aa32a9d9101f727cf063e6c19bf7f18afa80e0bd 100644 (file)
@@ -27,6 +27,8 @@
 #include "shortcuts.h"
 #include "interface.h"
 
+#include <gdk/gdkkeysyms.h>
+
 #include "icon.h"
 #include "button.h"
 
@@ -291,15 +293,15 @@ sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPActi
 {
        if (action) {
                unsigned int shortcut = sp_shortcut_get_primary (action->verb);
-               if (shortcut) {
+               if (shortcut!=GDK_VoidSymbol) {
                        // there's both action and shortcut
 
-                       gchar        key[256];
-                       sp_ui_shortcut_string (shortcut, key);
+                       gchar* key = sp_shortcut_get_label(shortcut);
 
                        gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
                        gtk_tooltips_set_tip (tooltips, widget, tip, NULL);
                        g_free (tip);
+            g_free (key);
 
                } else {
                        // action has no shortcut
index bdf1e6ff2a11b094847bd934745a46795c608ab8..f6a6735e9eab250fecf4f58ad7f25fe83e2575b8 100644 (file)
@@ -827,14 +827,14 @@ GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inksc
 
 
     unsigned int shortcut = sp_shortcut_get_primary(verb);
-    if (shortcut) {
-        gchar key[256];
-        sp_ui_shortcut_string(shortcut, key);
+    if (shortcut!=GDK_VoidSymbol) {
+        gchar* key = sp_shortcut_get_label(shortcut);
         gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
         if ( t ) {
             gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
         }
         g_free(tip);
+        g_free(key);
     } else {
         if ( t ) {
             gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );