[gthumb] scripts: allow to specify a generic accelerator



commit 1f8c167e612498c81902396eaeb8d67ed9f6c6f1
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Tue Jul 4 15:26:55 2017 +0200

    scripts: allow to specify a generic accelerator

 extensions/list_tools/callbacks.c                  |   18 +-
 .../list_tools/data/ui/personalize-scripts.ui      |    3 +-
 extensions/list_tools/data/ui/script-editor.ui     |   29 +--
 extensions/list_tools/dlg-personalize-scripts.c    |   13 +-
 extensions/list_tools/gth-script-editor-dialog.c   |   91 ++-----
 extensions/list_tools/gth-script.c                 |   80 +++---
 extensions/list_tools/gth-script.h                 |   30 +-
 gthumb/Makefile.am                                 |    2 +
 gthumb/gth-accel-button.c                          |  329 ++++++++++++++++++++
 gthumb/gth-accel-button.h                          |   65 ++++
 po/POTFILES.in                                     |    2 +
 11 files changed, 498 insertions(+), 164 deletions(-)
---
diff --git a/extensions/list_tools/callbacks.c b/extensions/list_tools/callbacks.c
index 87fc26b..5da5ad0 100644
--- a/extensions/list_tools/callbacks.c
+++ b/extensions/list_tools/callbacks.c
@@ -193,15 +193,23 @@ gpointer
 list_tools__gth_browser_file_list_key_press_cb (GthBrowser  *browser,
                                                GdkEventKey *event)
 {
-       gpointer  result = NULL;
-       GList    *script_list;
-       GList    *scan;
+       gpointer         result = NULL;
+       guint            event_key;
+       GdkModifierType  event_modifiers;
+       GList           *script_list;
+       GList           *scan;
+
+       event_key = gdk_keyval_to_lower (event->keyval);
+       event_modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
        script_list = gth_script_file_get_scripts (gth_script_file_get ());
        for (scan = script_list; scan; scan = scan->next) {
-               GthScript *script = scan->data;
+               GthScript       *script = scan->data;
+               guint            keyval;
+               GdkModifierType  modifiers;
 
-               if (gth_script_get_shortcut (script) == event->keyval) {
+               gth_script_get_accelerator (script, &keyval, &modifiers);
+               if ((keyval == event_key) && (modifiers == event_modifiers)) {
                        gth_browser_exec_script (browser, script);
                        result = GINT_TO_POINTER (1);
                        break;
diff --git a/extensions/list_tools/data/ui/personalize-scripts.ui 
b/extensions/list_tools/data/ui/personalize-scripts.ui
index 6d8be8e..d04d634 100644
--- a/extensions/list_tools/data/ui/personalize-scripts.ui
+++ b/extensions/list_tools/data/ui/personalize-scripts.ui
@@ -30,7 +30,7 @@
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="fill">True</property>
+                <property name="fill">False</property>
                 <property name="position">0</property>
               </packing>
             </child>
@@ -45,6 +45,7 @@
                     <property name="height_request">300</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="vexpand">True</property>
                     <property name="shadow_type">etched-in</property>
                     <child>
                       <placeholder/>
diff --git a/extensions/list_tools/data/ui/script-editor.ui b/extensions/list_tools/data/ui/script-editor.ui
index cec4767..0f4b262 100644
--- a/extensions/list_tools/data/ui/script-editor.ui
+++ b/extensions/list_tools/data/ui/script-editor.ui
@@ -2,14 +2,6 @@
 <!-- Generated with glade 3.20.0 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
-  <object class="GtkListStore" id="shortcut_liststore">
-    <columns>
-      <!-- column-name name -->
-      <column type="gchararray"/>
-      <!-- column-name sensitive -->
-      <column type="gboolean"/>
-    </columns>
-  </object>
   <object class="GtkBox" id="script_editor">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
@@ -108,7 +100,6 @@
             <property name="can_focus">False</property>
             <property name="label" translatable="yes">Sh_ortcut:</property>
             <property name="use_underline">True</property>
-            <property name="mnemonic_widget">shortcut_combobox</property>
             <property name="xalign">1</property>
           </object>
           <packing>
@@ -119,28 +110,12 @@
           </packing>
         </child>
         <child>
-          <object class="GtkBox" id="hbox1">
+          <object class="GtkBox" id="accel_box">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="spacing">6</property>
             <child>
-              <object class="GtkComboBox" id="shortcut_combobox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="model">shortcut_liststore</property>
-                <child>
-                  <object class="GtkCellRendererText" id="cellrenderertext1"/>
-                  <attributes>
-                    <attribute name="sensitive">1</attribute>
-                    <attribute name="text">0</attribute>
-                  </attributes>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
+              <placeholder/>
             </child>
             <child>
               <placeholder/>
diff --git a/extensions/list_tools/dlg-personalize-scripts.c b/extensions/list_tools/dlg-personalize-scripts.c
index 07eb516..0a765a3 100644
--- a/extensions/list_tools/dlg-personalize-scripts.c
+++ b/extensions/list_tools/dlg-personalize-scripts.c
@@ -133,16 +133,11 @@ row_inserted_cb (GtkTreeModel *tree_model,
 static char *
 get_script_shortcut (GthScript *script)
 {
-       guint        keyval;
-       char        *shortcut;
+       guint           keyval;
+       GdkModifierType modifiers;
 
-       keyval = gth_script_get_shortcut (script);
-       if ((keyval >= GDK_KEY_KP_0) && (keyval <= GDK_KEY_KP_9))
-               shortcut = g_strdup_printf ("%c", '0' + (keyval - GDK_KEY_KP_0));
-       else
-               shortcut = g_strdup ("");
-
-       return shortcut;
+       gth_script_get_accelerator (script, &keyval, &modifiers);
+       return gtk_accelerator_get_label (keyval, modifiers);
 }
 
 
diff --git a/extensions/list_tools/gth-script-editor-dialog.c 
b/extensions/list_tools/gth-script-editor-dialog.c
index 33d0b98..dab45d6 100644
--- a/extensions/list_tools/gth-script-editor-dialog.c
+++ b/extensions/list_tools/gth-script-editor-dialog.c
@@ -41,6 +41,7 @@ enum {
 
 struct _GthScriptEditorDialogPrivate {
        GtkBuilder *builder;
+       GtkWidget  *accel_button;
        char       *script_id;
        gboolean    script_visible;
        gboolean    wait_command;
@@ -115,9 +116,6 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
                                    const char            *title,
                                    GtkWindow             *parent)
 {
-       GtkTreeIter  iter;
-       int          i;
-
        if (title != NULL)
                gtk_window_set_title (GTK_WINDOW (self), title);
        if (parent != NULL)
@@ -133,28 +131,15 @@ gth_script_editor_dialog_construct (GthScriptEditorDialog *self,
        self->priv->builder = gtk_builder_new_from_resource 
("/org/gnome/gThumb/list_tools/data/ui/script-editor.ui");
        gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 
_gtk_builder_get_widget (self->priv->builder, "script_editor"), TRUE, TRUE, 0);
 
+       self->priv->accel_button = gth_accel_button_new ();
+       gtk_widget_show (self->priv->accel_button);
+       gtk_box_pack_start (GTK_BOX (GET_WIDGET ("accel_box")), self->priv->accel_button, FALSE, FALSE, 0);
+
        g_signal_connect (GET_WIDGET ("command_entry"),
                          "icon-press",
                          G_CALLBACK (command_entry_icon_press_cb),
                          self);
 
-       gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter);
-       gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter,
-                           SHORTCUT_NAME_COLUMN, _("none"),
-                           -1);
-
-       for (i = 0; i <= 9; i++) {
-               char *value;
-
-               value = g_strdup_printf (_("key %d on the numeric keypad"), i);
-               gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter);
-               gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter,
-                                   SHORTCUT_NAME_COLUMN, value,
-                                   -1);
-
-               g_free (value);
-       }
-
        /**/
 
        gth_script_editor_dialog_set_script (self, NULL);
@@ -184,7 +169,7 @@ _gth_script_editor_dialog_set_new_script (GthScriptEditorDialog *self)
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("shell_script_checkbutton")), TRUE);
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton")), FALSE);
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton")), FALSE);
-       gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("shortcut_combobox")), NO_SHORTCUT);
+       gth_accel_button_set_accelerator (GTH_ACCEL_BUTTON (self->priv->accel_button), 0, 0);
 }
 
 
@@ -192,11 +177,6 @@ void
 gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
                                     GthScript             *script)
 {
-       GtkTreeIter  iter;
-       GtkTreePath *path;
-       GList       *script_list;
-       GList       *scan;
-
        g_free (self->priv->script_id);
        self->priv->script_id = NULL;
        self->priv->script_visible = TRUE;
@@ -204,7 +184,9 @@ gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
        _gth_script_editor_dialog_set_new_script (self);
 
        if (script != NULL) {
-               guint keyval;
+               guint            keyval;
+               GdkModifierType  modifiers;
+
 
                self->priv->script_id = g_strdup (gth_script_get_id (script));
                self->priv->script_visible = gth_script_is_visible (script);
@@ -215,43 +197,10 @@ gth_script_editor_dialog_set_script (GthScriptEditorDialog *self,
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("for_each_file_checkbutton")), 
gth_script_for_each_file (script));
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("wait_command_checkbutton")), 
gth_script_wait_command (script));
 
-               keyval = gth_script_get_shortcut (script);
-               if ((keyval >= GDK_KEY_KP_0) && (keyval <= GDK_KEY_KP_9))
-                       gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("shortcut_combobox")), (keyval - 
GDK_KEY_KP_0) + 1);
-               else
-                       gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("shortcut_combobox")), 
NO_SHORTCUT);
+               gth_script_get_accelerator (script, &keyval, &modifiers);
+               gth_accel_button_set_accelerator (GTH_ACCEL_BUTTON (self->priv->accel_button), keyval, 
modifiers);
        }
 
-       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (GET_WIDGET ("shortcut_liststore")), &iter)) {
-               do {
-                       gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter,
-                                           SHORTCUT_SENSITIVE_COLUMN, TRUE,
-                                           -1);
-               }
-               while (gtk_tree_model_iter_next (GTK_TREE_MODEL (GET_WIDGET ("shortcut_liststore")), &iter));
-       }
-
-       script_list = gth_script_file_get_scripts (gth_script_file_get ());
-       for (scan = script_list; scan; scan = scan->next) {
-               GthScript *other_script = scan->data;
-               guint      keyval;
-
-               keyval = gth_script_get_shortcut (other_script);
-               if ((keyval >= GDK_KEY_KP_0) && (keyval <= GDK_KEY_KP_9)) {
-                       if (g_strcmp0 (gth_script_get_id (other_script), self->priv->script_id) == 0)
-                               continue;
-
-                       path = gtk_tree_path_new_from_indices (keyval - GDK_KEY_KP_0 + 1, -1);
-                       gtk_tree_model_get_iter (GTK_TREE_MODEL (GET_WIDGET ("shortcut_liststore")), &iter, 
path);
-                       gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("shortcut_liststore")), &iter,
-                                           SHORTCUT_SENSITIVE_COLUMN, FALSE,
-                                           -1);
-
-                       gtk_tree_path_free (path);
-               }
-       }
-       _g_object_list_unref (script_list);
-
        update_sensitivity (self);
 }
 
@@ -260,19 +209,17 @@ GthScript *
 gth_script_editor_dialog_get_script (GthScriptEditorDialog  *self,
                                     GError                **error)
 {
-       GthScript *script;
-       int        keyval_index;
-       guint      keyval;
+       GthScript       *script;
+       guint            keyval;
+       GdkModifierType  modifiers;
+       char            *accelerator;
 
        script = gth_script_new ();
        if (self->priv->script_id != NULL)
                g_object_set (script, "id", self->priv->script_id, NULL);
 
-       keyval_index = gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("shortcut_combobox")));
-       if ((keyval_index >= 1) && (keyval_index <= 10))
-               keyval = GDK_KEY_KP_0 + (keyval_index - 1);
-       else
-               keyval = GDK_KEY_VoidSymbol;
+       gth_accel_button_get_accelerator (GTH_ACCEL_BUTTON (self->priv->accel_button), &keyval, &modifiers);
+       accelerator = gtk_accelerator_name (keyval, modifiers);
 
        g_object_set (script,
                      "display-name", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("name_entry"))),
@@ -281,7 +228,7 @@ gth_script_editor_dialog_get_script (GthScriptEditorDialog  *self,
                      "shell-script", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET 
("shell_script_checkbutton"))),
                      "for-each-file", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET 
("for_each_file_checkbutton"))),
                      "wait-command", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET 
("wait_command_checkbutton"))),
-                     "shortcut", keyval,
+                     "accelerator", accelerator,
                      NULL);
 
        if (g_strcmp0 (gth_script_get_display_name (script), "") == 0) {
@@ -296,5 +243,7 @@ gth_script_editor_dialog_get_script (GthScriptEditorDialog  *self,
                return NULL;
        }
 
+       g_free (accelerator);
+
        return script;
 }
diff --git a/extensions/list_tools/gth-script.c b/extensions/list_tools/gth-script.c
index 6904171..0296376 100644
--- a/extensions/list_tools/gth-script.c
+++ b/extensions/list_tools/gth-script.c
@@ -47,19 +47,25 @@ enum {
         PROP_SHELL_SCRIPT,
         PROP_FOR_EACH_FILE,
         PROP_WAIT_COMMAND,
-        PROP_SHORTCUT
+        PROP_ACCELERATOR
 };
 
 
+typedef struct {
+       guint            keyval;
+       GdkModifierType  modifiers;
+       char            *name;
+} _Accel;
+
 struct _GthScriptPrivate {
-       char     *id;
-       char     *display_name;
-       char     *command;
-       gboolean  visible;
-       gboolean  shell_script;
-       gboolean  for_each_file;
-       gboolean  wait_command;
-       guint     shortcut;
+       char            *id;
+       char            *display_name;
+       char            *command;
+       gboolean         visible;
+       gboolean         shell_script;
+       gboolean         for_each_file;
+       gboolean         wait_command;
+       _Accel           accelerator;
 };
 
 
@@ -73,6 +79,7 @@ gth_script_real_create_element (DomDomizable *base,
        g_return_val_if_fail (DOM_IS_DOCUMENT (doc), NULL);
 
        self = GTH_SCRIPT (base);
+
        element = dom_document_create_element (doc, "script",
                                               "id", self->priv->id,
                                               "display-name", self->priv->display_name,
@@ -80,7 +87,7 @@ gth_script_real_create_element (DomDomizable *base,
                                               "shell-script", (self->priv->shell_script ? "true" : "false"),
                                               "for-each-file", (self->priv->for_each_file ? "true" : 
"false"),
                                               "wait-command", (self->priv->wait_command ? "true" : "false"),
-                                              "shortcut", gdk_keyval_name (self->priv->shortcut),
+                                              "accelerator", self->priv->accelerator.name,
                                               NULL);
        if (! self->priv->visible)
                dom_element_set_attribute (element, "display", "none");
@@ -89,16 +96,6 @@ gth_script_real_create_element (DomDomizable *base,
 }
 
 
-static guint
-_gdk_keyval_from_name (const gchar *keyval_name)
-{
-       if (keyval_name != NULL)
-               return gdk_keyval_from_name (keyval_name);
-       else
-               return GDK_KEY_VoidSymbol;
-}
-
-
 static void
 gth_script_real_load_from_element (DomDomizable *base,
                                   DomElement   *element)
@@ -116,7 +113,7 @@ gth_script_real_load_from_element (DomDomizable *base,
                      "shell-script", (g_strcmp0 (dom_element_get_attribute (element, "shell-script"), 
"true") == 0),
                      "for-each-file", (g_strcmp0 (dom_element_get_attribute (element, "for-each-file"), 
"true") == 0),
                      "wait-command", (g_strcmp0 (dom_element_get_attribute (element, "wait-command"), 
"true") == 0),
-                     "shortcut", _gdk_keyval_from_name (dom_element_get_attribute (element, "shortcut")),
+                     "accelerator", dom_element_get_attribute (element, "accelerator"),
                      NULL);
 }
 
@@ -136,7 +133,7 @@ gth_script_real_duplicate (GthDuplicable *duplicable)
                      "shell-script", script->priv->shell_script,
                      "for-each-file", script->priv->for_each_file,
                      "wait-command", script->priv->wait_command,
-                     "shortcut", script->priv->shortcut,
+                     "accelerator", script->priv->accelerator.name,
                      NULL);
 
        return (GObject *) new_script;
@@ -152,6 +149,7 @@ gth_script_finalize (GObject *base)
        g_free (self->priv->id);
        g_free (self->priv->display_name);
        g_free (self->priv->command);
+       g_free (self->priv->accelerator.name);
 
        G_OBJECT_CLASS (gth_script_parent_class)->finalize (base);
 }
@@ -198,8 +196,11 @@ gth_script_set_property (GObject      *object,
        case PROP_WAIT_COMMAND:
                self->priv->wait_command = g_value_get_boolean (value);
                break;
-       case PROP_SHORTCUT:
-               self->priv->shortcut = g_value_get_uint (value);
+       case PROP_ACCELERATOR:
+               self->priv->accelerator.name = g_value_dup_string (value);
+               gtk_accelerator_parse (self->priv->accelerator.name,
+                                      &self->priv->accelerator.keyval,
+                                      &self->priv->accelerator.modifiers);
                break;
        default:
                break;
@@ -239,8 +240,8 @@ gth_script_get_property (GObject    *object,
        case PROP_WAIT_COMMAND:
                g_value_set_boolean (value, self->priv->wait_command);
                break;
-       case PROP_SHORTCUT:
-               g_value_set_uint (value, self->priv->wait_command);
+       case PROP_ACCELERATOR:
+               g_value_set_string (value, self->priv->accelerator.name);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -313,14 +314,12 @@ gth_script_class_init (GthScriptClass *klass)
                                                               FALSE,
                                                               G_PARAM_READWRITE));
        g_object_class_install_property (object_class,
-                                        PROP_SHORTCUT,
-                                        g_param_spec_uint ("shortcut",
-                                                           "Shortcut",
-                                                           "The keyboard shortcut to activate the script",
-                                                           0,
-                                                           G_MAXUINT,
-                                                           GDK_KEY_VoidSymbol,
-                                                           G_PARAM_READWRITE));
+                                        PROP_ACCELERATOR,
+                                        g_param_spec_string ("accelerator",
+                                                             "Accelerator",
+                                                             "The keyboard shortcut to activate the script",
+                                                             "",
+                                                             G_PARAM_READWRITE));
 }
 
 
@@ -346,6 +345,9 @@ gth_script_init (GthScript *self)
        self->priv->id = NULL;
        self->priv->display_name = NULL;
        self->priv->command = NULL;
+       self->priv->accelerator.name = NULL;
+       self->priv->accelerator.keyval = 0;
+       self->priv->accelerator.modifiers = 0;
 }
 
 
@@ -1024,8 +1026,12 @@ gth_script_get_command_line (GthScript  *script,
 }
 
 
-guint
-gth_script_get_shortcut (GthScript *script)
+void
+gth_script_get_accelerator (GthScript       *self,
+                           guint           *keyval,
+                           GdkModifierType *modifiers)
 {
-       return script->priv->shortcut;
+       g_return_if_fail (GTH_IS_SCRIPT (self));
+       if (keyval) *keyval = self->priv->accelerator.keyval;
+       if (modifiers) *modifiers = self->priv->accelerator.modifiers;
 }
diff --git a/extensions/list_tools/gth-script.h b/extensions/list_tools/gth-script.h
index ab3e1a6..2c1891e 100644
--- a/extensions/list_tools/gth-script.h
+++ b/extensions/list_tools/gth-script.h
@@ -52,20 +52,22 @@ struct _GthScriptClass
 
 GType             gth_script_get_type                  (void) G_GNUC_CONST;
 GthScript *       gth_script_new                       (void);
-const char *      gth_script_get_id                    (GthScript  *script);
-const char *      gth_script_get_display_name          (GthScript  *script);
-const char *      gth_script_get_command               (GthScript  *script);
-gboolean          gth_script_is_visible                (GthScript  *script);
-gboolean          gth_script_is_shell_script           (GthScript  *script);
-gboolean          gth_script_for_each_file             (GthScript  *script);
-gboolean          gth_script_wait_command              (GthScript  *script);
-char *            gth_script_get_requested_attributes  (GthScript  *script);
-char *            gth_script_get_command_line          (GthScript  *script,
-                                                       GtkWindow  *parent,
-                                                       GList      *file_list /* GthFileData */,
-                                                       gboolean    can_skip,
-                                                       GError    **error);
-guint             gth_script_get_shortcut              (GthScript  *script);
+const char *      gth_script_get_id                    (GthScript       *script);
+const char *      gth_script_get_display_name          (GthScript       *script);
+const char *      gth_script_get_command               (GthScript       *script);
+gboolean          gth_script_is_visible                (GthScript       *script);
+gboolean          gth_script_is_shell_script           (GthScript       *script);
+gboolean          gth_script_for_each_file             (GthScript       *script);
+gboolean          gth_script_wait_command              (GthScript       *script);
+char *            gth_script_get_requested_attributes  (GthScript       *script);
+char *            gth_script_get_command_line          (GthScript       *script,
+                                                       GtkWindow       *parent,
+                                                       GList           *file_list /* GthFileData */,
+                                                       gboolean         can_skip,
+                                                       GError         **error);
+void              gth_script_get_accelerator           (GthScript       *script,
+                                                       guint           *keyval,
+                                                       GdkModifierType *modifiers);
 
 G_END_DECLS
 
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 4e1ca2a..acb743c 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -31,6 +31,7 @@ PUBLIC_HEADER_FILES =                                         \
        glib-utils.h                                    \
        gnome-desktop-thumbnail.h                       \
        gsignature.h                                    \
+       gth-accel-button.h                              \
        gth-auto-paned.h                                \
        gth-async-task.h                                \
        gth-buffer-data.h                               \
@@ -175,6 +176,7 @@ gthumb_SOURCES =                                    \
        gio-utils.c                                     \
        glib-utils.c                                    \
        gsignature.c                                    \
+       gth-accel-button.c                              \
        gth-application.c                               \
        gth-auto-paned.c                                \
        gth-async-task.c                                \
diff --git a/gthumb/gth-accel-button.c b/gthumb/gth-accel-button.c
new file mode 100644
index 0000000..d75a3b1
--- /dev/null
+++ b/gthumb/gth-accel-button.c
@@ -0,0 +1,329 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include "gth-accel-button.h"
+#include "gtk-utils.h"
+
+
+/* Properties */
+enum {
+        PROP_0,
+        PROP_KEY,
+        PROP_MODS
+};
+
+/* Signals */
+enum {
+        CHANGED,
+        LAST_SIGNAL
+};
+
+struct _GthAccelButtonPrivate {
+       guint            keyval;
+       GdkModifierType  modifiers;
+       gboolean         valid;
+       GtkWidget       *label;
+};
+
+
+static guint gth_accel_button_signals[LAST_SIGNAL] = { 0 };
+
+
+G_DEFINE_TYPE (GthAccelButton, gth_accel_button, GTK_TYPE_BUTTON)
+
+
+static void
+gth_accel_button_finalize (GObject *object)
+{
+       /*GthAccelButton *self;
+
+       self = GTH_ACCEL_BUTTON (object);*/
+
+
+       G_OBJECT_CLASS (gth_accel_button_parent_class)->finalize (object);
+}
+
+
+static void
+gth_accel_button_set_property (GObject      *object,
+                              guint         property_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+       GthAccelButton *self;
+
+        self = GTH_ACCEL_BUTTON (object);
+
+       switch (property_id) {
+       case PROP_KEY:
+               self->priv->keyval = g_value_get_uint (value);
+               break;
+       case PROP_MODS:
+               self->priv->modifiers = g_value_get_flags (value);
+               break;
+       default:
+               break;
+       }
+}
+
+
+static void
+gth_accel_button_get_property (GObject    *object,
+                              guint       property_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+       GthAccelButton *self;
+
+        self = GTH_ACCEL_BUTTON (object);
+
+       switch (property_id) {
+       case PROP_KEY:
+               g_value_set_uint (value, self->priv->keyval);
+               break;
+       case PROP_MODS:
+               g_value_set_flags (value, self->priv->modifiers);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+               break;
+       }
+}
+
+
+static void
+gth_accel_button_class_init (GthAccelButtonClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (GthAccelButtonPrivate));
+
+       object_class = (GObjectClass*) klass;
+       object_class->set_property = gth_accel_button_set_property;
+       object_class->get_property = gth_accel_button_get_property;
+       object_class->finalize = gth_accel_button_finalize;
+
+       /* properties */
+
+       g_object_class_install_property (object_class,
+                                        PROP_KEY,
+                                        g_param_spec_uint ("key",
+                                                           "Key",
+                                                           "The key value",
+                                                           0,
+                                                           G_MAXUINT,
+                                                           0,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_MODS,
+                                        g_param_spec_flags ("mods",
+                                                            "Mods",
+                                                            "The active modifiers",
+                                                            GDK_TYPE_MODIFIER_TYPE,
+                                                            0,
+                                                            G_PARAM_READWRITE));
+
+       /* signals */
+
+       gth_accel_button_signals[CHANGED] =
+                g_signal_new ("changed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GthAccelButtonClass, changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+}
+
+
+static void
+_update_label (GthAccelButton *self)
+{
+       self->priv->valid = gtk_accelerator_valid (self->priv->keyval, self->priv->modifiers);
+       if (self->priv->valid) {
+               char *label = gtk_accelerator_get_label (self->priv->keyval, self->priv->modifiers);
+               gtk_label_set_text (GTK_LABEL (self->priv->label), label);
+               g_free (label);
+       }
+       else
+               gtk_label_set_text (GTK_LABEL (self->priv->label), _("None"));
+}
+
+
+#define _RESPONSE_RESET 10
+
+
+static void
+accel_dialog_response_cb (GtkDialog *dialog,
+                         gint       response_id,
+                         gpointer   user_data)
+{
+       GthAccelButton *accel_button = user_data;
+
+       switch (response_id) {
+       case GTK_RESPONSE_CANCEL:
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+               break;
+       case _RESPONSE_RESET:
+               gth_accel_button_set_accelerator (accel_button, 0, 0);
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+               break;
+       }
+}
+
+
+static gboolean
+accel_dialog_keypress_cb (GtkWidget    *widget,
+                         GdkEventKey  *event,
+                         gpointer      user_data)
+{
+       GthAccelButton  *accel_button = user_data;
+       GdkModifierType  modifiers;
+
+       if (event->keyval == GDK_KEY_Escape)
+               return FALSE;
+
+       modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+       if (gth_accel_button_set_accelerator (accel_button, event->keyval, modifiers))
+               gtk_widget_destroy (widget);
+
+       return TRUE;
+}
+
+
+static void
+button_clicked_cb (GtkButton *button,
+                  gpointer   user_data)
+{
+       GtkWidget *dialog, *box, *label, *secondary_label, *content_area;
+
+       dialog = g_object_new (GTK_TYPE_DIALOG,
+                              "use-header-bar", _gtk_settings_get_dialogs_use_header (),
+                              "modal", TRUE,
+                              "transient-for", gtk_widget_get_toplevel (GTK_WIDGET (button)),
+                              "resizable", FALSE,
+                              "title", _("Shortcut"),
+                              NULL);
+       gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                               _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
+                               ! gth_accel_button_get_valid (GTH_ACCEL_BUTTON (button)) ? NULL : 
_GTK_LABEL_DELETE,
+                               _RESPONSE_RESET,
+                               NULL);
+
+       content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+       label = gtk_label_new (_("Press a combination of keys to use as shortcut."));
+       secondary_label = gtk_label_new (_("Press Esc to cancel"));
+       gtk_style_context_add_class (gtk_widget_get_style_context (secondary_label), "dim-label");
+       box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 50);
+       gtk_widget_set_margin_top (box, 50);
+       gtk_widget_set_margin_bottom (box, 50);
+       gtk_widget_set_margin_start (box, 50);
+       gtk_widget_set_margin_end (box, 50);
+       gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX (box), secondary_label, TRUE, TRUE, 0);
+
+       g_signal_connect (dialog,
+                         "response",
+                         G_CALLBACK (accel_dialog_response_cb),
+                         button);
+       g_signal_connect (dialog,
+                         "key-press-event",
+                         G_CALLBACK (accel_dialog_keypress_cb),
+                         button);
+
+       gtk_container_add (GTK_CONTAINER (content_area), box);
+       gtk_widget_show_all (dialog);
+}
+
+
+static void
+gth_accel_button_init (GthAccelButton *self)
+{
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_ACCEL_BUTTON, GthAccelButtonPrivate);
+       self->priv->keyval = 0;
+       self->priv->modifiers = 0;
+       self->priv->valid = FALSE;
+
+       self->priv->label = gtk_label_new ("");
+       gtk_widget_show (self->priv->label);
+       gtk_container_add (GTK_CONTAINER (self), self->priv->label);
+
+       _update_label (self);
+
+       g_signal_connect (self, "clicked", G_CALLBACK (button_clicked_cb), self);
+}
+
+
+GtkWidget *
+gth_accel_button_new (void)
+{
+       return (GtkWidget*) g_object_new (GTH_TYPE_ACCEL_BUTTON, NULL);
+}
+
+
+gboolean
+gth_accel_button_set_accelerator (GthAccelButton  *self,
+                                 guint            keyval,
+                                 GdkModifierType  modifiers)
+{
+       g_return_val_if_fail (GTH_IS_ACCEL_BUTTON (self), FALSE);
+
+       self->priv->keyval = keyval;
+       self->priv->modifiers = modifiers;
+
+       _update_label (self);
+
+       return self->priv->valid;
+}
+
+
+gboolean
+gth_accel_button_get_accelerator (GthAccelButton  *self,
+                                 guint           *keyval,
+                                 GdkModifierType *modifiers)
+{
+       g_return_val_if_fail (GTH_IS_ACCEL_BUTTON (self), FALSE);
+
+       if (! self->priv->valid) {
+               if (keyval) *keyval = 0;
+               if (modifiers) *modifiers = 0;
+               return FALSE;
+       }
+
+       if (keyval) *keyval = self->priv->keyval;
+       if (modifiers) *modifiers = self->priv->modifiers;
+
+       return TRUE;
+}
+
+
+gboolean
+gth_accel_button_get_valid (GthAccelButton *self)
+{
+       g_return_val_if_fail (GTH_IS_ACCEL_BUTTON (self), FALSE);
+       return self->priv->valid;
+}
diff --git a/gthumb/gth-accel-button.h b/gthumb/gth-accel-button.h
new file mode 100644
index 0000000..8d1fc63
--- /dev/null
+++ b/gthumb/gth-accel-button.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_ACCEL_BUTTON_H
+#define GTH_ACCEL_BUTTON_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_ACCEL_BUTTON         (gth_accel_button_get_type ())
+#define GTH_ACCEL_BUTTON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_ACCEL_BUTTON, 
GthAccelButton))
+#define GTH_ACCEL_BUTTON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_ACCEL_BUTTON, 
GthAccelButtonClass))
+#define GTH_IS_ACCEL_BUTTON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_ACCEL_BUTTON))
+#define GTH_IS_ACCEL_BUTTON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_ACCEL_BUTTON))
+#define GTH_ACCEL_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_ACCEL_BUTTON, 
GthAccelButtonClass))
+
+typedef struct _GthAccelButton         GthAccelButton;
+typedef struct _GthAccelButtonPrivate  GthAccelButtonPrivate;
+typedef struct _GthAccelButtonClass    GthAccelButtonClass;
+
+struct _GthAccelButton {
+       GtkButton __parent;
+       GthAccelButtonPrivate *priv;
+};
+
+struct _GthAccelButtonClass {
+       GtkButtonClass __parent_class;
+
+       /*< signals >*/
+
+       void (*changed) (GthAccelButton *accel_button);
+};
+
+GType         gth_accel_button_get_type            (void) G_GNUC_CONST;
+GtkWidget *   gth_accel_button_new                 (void);
+gboolean      gth_accel_button_set_accelerator     (GthAccelButton  *accel_button,
+                                                   guint            accelerator_key,
+                                                   GdkModifierType  accelerator_mods);
+gboolean      gth_accel_button_get_accelerator     (GthAccelButton  *accel_button,
+                                                   guint           *accelerator_key,
+                                                   GdkModifierType *accelerator_mods);
+gboolean      gth_accel_button_get_valid           (GthAccelButton  *accel_button);
+
+G_END_DECLS
+
+#endif /* GTH_ACCEL_BUTTON_H */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3a894fd..e48a5fb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -706,6 +706,8 @@ gthumb/gnome-desktop-thumbnail.h
 gthumb/gnome-thumbnail-pixbuf-utils.c
 gthumb/gsignature.c
 gthumb/gsignature.h
+gthumb/gth-accel-button.c
+gthumb/gth-accel-button.h
 gthumb/gth-application.c
 gthumb/gth-application.h
 gthumb/gth-async-task.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]