[gimp/wip/Jehan/issue-498-quick-brush-edit: 47/48] app: now support custom actions as input device button + modifiers.




commit 02933eea21f8451b3c1e0eaeb92b9907a5012fc6
Author: Jehan <jehan girinstud io>
Date:   Tue Aug 16 15:20:58 2022 +0200

    app: now support custom actions as input device button + modifiers.
    
    Custom actions are basically any action (currently GtkAction) which can
    be assigned a shortcut. Now they can also be assigned to an input device
    button (with modifier or not).

 app/display/display-enums.c                |   2 +
 app/display/display-enums.h                |  18 +-
 app/display/gimpdisplayshell-tool-events.c |  39 +++-
 app/display/gimpmodifiersmanager.c         |  48 ++++-
 app/display/gimpmodifiersmanager.h         |   6 +-
 app/widgets/gimpmodifierseditor.c          | 288 ++++++++++++++++++++++++++---
 6 files changed, 348 insertions(+), 53 deletions(-)
---
diff --git a/app/display/display-enums.c b/app/display/display-enums.c
index c9be1369dc..9ba4003a47 100644
--- a/app/display/display-enums.c
+++ b/app/display/display-enums.c
@@ -604,6 +604,7 @@ gimp_modifier_action_get_type (void)
     { GIMP_MODIFIER_ACTION_STEP_ROTATING, "GIMP_MODIFIER_ACTION_STEP_ROTATING", "step-rotating" },
     { GIMP_MODIFIER_ACTION_LAYER_PICKING, "GIMP_MODIFIER_ACTION_LAYER_PICKING", "layer-picking" },
     { GIMP_MODIFIER_ACTION_MENU, "GIMP_MODIFIER_ACTION_MENU", "menu" },
+    { GIMP_MODIFIER_ACTION_ACTION, "GIMP_MODIFIER_ACTION_ACTION", "action" },
     { GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE, "GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE", "brush-pixel-size" },
     { GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, "GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE", 
"brush-radius-pixel-size" },
     { 0, NULL, NULL }
@@ -618,6 +619,7 @@ gimp_modifier_action_get_type (void)
     { GIMP_MODIFIER_ACTION_STEP_ROTATING, NC_("modifier-action", "Rotate View by 15 degree steps"), NULL },
     { GIMP_MODIFIER_ACTION_LAYER_PICKING, NC_("modifier-action", "Pick a layer"), NULL },
     { GIMP_MODIFIER_ACTION_MENU, NC_("modifier-action", "Display the menu"), NULL },
+    { GIMP_MODIFIER_ACTION_ACTION, NC_("modifier-action", "Custom action"), NULL },
     { GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE, NC_("modifier-action", "Change brush size in canvas pixels"), 
NULL },
     { GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, NC_("modifier-action", "Change brush radius' size in 
canvas pixels"), NULL },
     { 0, NULL, NULL }
diff --git a/app/display/display-enums.h b/app/display/display-enums.h
index bcb81028e5..fb969bca0d 100644
--- a/app/display/display-enums.h
+++ b/app/display/display-enums.h
@@ -267,16 +267,18 @@ GType gimp_modifier_action_get_type (void) G_GNUC_CONST;
 
 typedef enum
 {
-  GIMP_MODIFIER_ACTION_NONE,                    /*< desc="No action"                          >*/
-  GIMP_MODIFIER_ACTION_PANNING,                 /*< desc="Pan"                                >*/
-  GIMP_MODIFIER_ACTION_ZOOMING,                 /*< desc="Zoom"                               >*/
-  GIMP_MODIFIER_ACTION_ROTATING,                /*< desc="Rotate View"                        >*/
-  GIMP_MODIFIER_ACTION_STEP_ROTATING,           /*< desc="Rotate View by 15 degree steps"     >*/
-  GIMP_MODIFIER_ACTION_LAYER_PICKING,           /*< desc="Pick a layer"                       >*/
+  GIMP_MODIFIER_ACTION_NONE,                    /*< desc="No action"                                  >*/
+  GIMP_MODIFIER_ACTION_PANNING,                 /*< desc="Pan"                                        >*/
+  GIMP_MODIFIER_ACTION_ZOOMING,                 /*< desc="Zoom"                                       >*/
+  GIMP_MODIFIER_ACTION_ROTATING,                /*< desc="Rotate View"                                >*/
+  GIMP_MODIFIER_ACTION_STEP_ROTATING,           /*< desc="Rotate View by 15 degree steps"             >*/
+  GIMP_MODIFIER_ACTION_LAYER_PICKING,           /*< desc="Pick a layer"                               >*/
 
-  GIMP_MODIFIER_ACTION_MENU,                    /*< desc="Display the menu"                   >*/
+  GIMP_MODIFIER_ACTION_MENU,                    /*< desc="Display the menu"                           >*/
 
-  GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE,        /*< desc="Change brush size in canvas pixels" >*/
+  GIMP_MODIFIER_ACTION_ACTION,                  /*< desc="Custom action"                              >*/
+
+  GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE,        /*< desc="Change brush size in canvas pixels"         >*/
   GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, /*< desc="Change brush radius' size in canvas pixels" >*/
 } GimpModifierAction;
 
diff --git a/app/display/gimpdisplayshell-tool-events.c b/app/display/gimpdisplayshell-tool-events.c
index 8fd0c85e3c..e38259d7a4 100644
--- a/app/display/gimpdisplayshell-tool-events.c
+++ b/app/display/gimpdisplayshell-tool-events.c
@@ -575,10 +575,12 @@ gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
           {
             GdkDevice            *device;
             GimpModifierAction    action;
+            const gchar          *action_desc = NULL;
 
             device = gdk_event_get_source_device (event);
             action = gimp_modifiers_manager_get_action (mod_manager, device,
-                                                        bevent->button, bevent->state);
+                                                        bevent->button, bevent->state,
+                                                        &action_desc);
             shell->mod_action = action;
             switch (action)
               {
@@ -594,6 +596,9 @@ gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
               case GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE:
                 gimp_display_shell_start_scrolling (shell, event, state,
                                                     bevent->x, bevent->y);
+                break;
+              case GIMP_MODIFIER_ACTION_ACTION:
+                break;
               case GIMP_MODIFIER_ACTION_NONE:
                 gimp_display_triggers_context_menu (event, shell, gimp, &image_coords, FALSE);
                 break;
@@ -719,12 +724,18 @@ gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
           }
         else
           {
-            GdkDevice            *device;
-            GimpModifierAction    action;
-
-            device = gdk_event_get_source_device (event);
-            action = gimp_modifiers_manager_get_action (mod_manager, device,
-                                                        bevent->button, bevent->state);
+            const gchar        *action_desc = NULL;
+            GimpImageWindow    *window;
+            GimpUIManager      *manager;
+            GdkDevice          *device;
+            GimpModifierAction  action;
+
+            window  = gimp_display_shell_get_window (shell);
+            manager = gimp_image_window_get_ui_manager (window);
+            device  = gdk_event_get_source_device (event);
+            action  = gimp_modifiers_manager_get_action (mod_manager, device,
+                                                         bevent->button, bevent->state,
+                                                         &action_desc);
 
             switch (action)
               {
@@ -744,6 +755,10 @@ gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
               case GIMP_MODIFIER_ACTION_BRUSH_PIXEL_SIZE:
               case GIMP_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE:
                 gimp_display_shell_stop_scrolling (shell, event);
+                break;
+              case GIMP_MODIFIER_ACTION_ACTION:
+                gimp_display_shell_activate_action (manager, action_desc, NULL);
+                break;
               case GIMP_MODIFIER_ACTION_NONE:
                 break;
               }
@@ -1751,6 +1766,7 @@ gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
         }
     case GIMP_MODIFIER_ACTION_MENU:
     case GIMP_MODIFIER_ACTION_PANNING:
+    case GIMP_MODIFIER_ACTION_ACTION:
     case GIMP_MODIFIER_ACTION_NONE:
       gimp_display_shell_set_override_cursor (shell,
                                               (GimpCursorType) GDK_FLEUR);
@@ -1922,6 +1938,7 @@ gimp_display_shell_handle_scrolling (GimpDisplayShell *shell,
       /* Do nothing. We only pick the layer on click. */
     case GIMP_MODIFIER_ACTION_MENU:
     case GIMP_MODIFIER_ACTION_NONE:
+    case GIMP_MODIFIER_ACTION_ACTION:
       break;
     }
 
@@ -2157,7 +2174,7 @@ gimp_display_shell_update_cursor (GimpDisplayShell *shell,
 
   active_tool = tool_manager_get_active (gimp);
 
-  if (active_tool)
+  if (active_tool && image)
     {
       if ((! gimp_image_is_empty (image) ||
            gimp_tool_control_get_handle_empty_image (active_tool->control)) &&
@@ -2363,6 +2380,8 @@ gimp_display_shell_activate_action (GimpUIManager *manager,
   gchar *group_name;
   gchar *action_name;
 
+  g_return_if_fail (action_desc != NULL);
+
   group_name  = g_strdup (action_desc);
   action_name = strchr (group_name, '/');
 
@@ -2383,6 +2402,10 @@ gimp_display_shell_activate_action (GimpUIManager *manager,
         {
           gimp_action_emit_activate (action, value);
         }
+      else
+        {
+          gimp_action_activate (action);
+        }
     }
 
   g_free (group_name);
diff --git a/app/display/gimpmodifiersmanager.c b/app/display/gimpmodifiersmanager.c
index 087496ae92..8f52098f25 100644
--- a/app/display/gimpmodifiersmanager.c
+++ b/app/display/gimpmodifiersmanager.c
@@ -42,8 +42,9 @@ enum
 
 typedef struct
 {
-  GdkModifierType    modifiers;
-  GimpModifierAction mod_action;
+  GdkModifierType     modifiers;
+  GimpModifierAction  mod_action;
+  gchar              *action_desc;
 } GimpModifierMapping;
 
 struct _GimpModifiersManagerPrivate
@@ -148,6 +149,8 @@ gimp_modifiers_manager_serialize (GimpConfig       *config,
       enum_value = g_enum_get_value (enum_class, GPOINTER_TO_INT (mapping->mod_action));
       gimp_config_writer_open (writer, "mod-action");
       gimp_config_writer_identifier (writer, enum_value->value_nick);
+      if (mapping->mod_action == GIMP_MODIFIER_ACTION_ACTION)
+        gimp_config_writer_string (writer, mapping->action_desc);
       gimp_config_writer_close (writer);
 
       gimp_config_writer_close (writer);
@@ -245,6 +248,18 @@ gimp_modifiers_manager_deserialize (GimpConfig *config,
                   else
                     {
                       gchar *suffix;
+                      gchar *action_desc = NULL;
+
+                      if (enum_value->value == GIMP_MODIFIER_ACTION_ACTION)
+                        {
+                          if (! gimp_scanner_parse_string (scanner, &action_desc))
+                            {
+                              g_printerr ("%s: missing action description for mapping %s\n",
+                                          G_STRFUNC, actions_key);
+                              goto error;
+                            }
+                        }
+
                       suffix = g_strdup_printf ("-%d", modifiers);
 
                       if (g_str_has_suffix (actions_key, suffix))
@@ -253,8 +268,9 @@ gimp_modifiers_manager_deserialize (GimpConfig *config,
                                                           strlen (actions_key) - strlen (suffix));
 
                           mapping = g_slice_new (GimpModifierMapping);
-                          mapping->modifiers  = modifiers;
-                          mapping->mod_action = enum_value->value;
+                          mapping->modifiers   = modifiers;
+                          mapping->mod_action  = enum_value->value;
+                          mapping->action_desc = action_desc;
                           g_hash_table_insert (manager->p->actions, actions_key, mapping);
 
                           if (g_list_find_custom (manager->p->buttons, buttons_key, (GCompareFunc) 
g_strcmp0))
@@ -326,13 +342,18 @@ GimpModifierAction
 gimp_modifiers_manager_get_action (GimpModifiersManager *manager,
                                    GdkDevice            *device,
                                    guint                 button,
-                                   GdkModifierType       state)
+                                   GdkModifierType       state,
+                                   const gchar         **action_desc)
 {
   gchar              *actions_key = NULL;
   gchar              *buttons_key = NULL;
   GdkModifierType     mod_state;
   GimpModifierAction  retval      = GIMP_MODIFIER_ACTION_NONE;
 
+  g_return_val_if_fail (GIMP_IS_MODIFIERS_MANAGER (manager), GIMP_MODIFIER_ACTION_NONE);
+  g_return_val_if_fail (GDK_IS_DEVICE (device), GIMP_MODIFIER_ACTION_NONE);
+  g_return_val_if_fail (action_desc != NULL && *action_desc == NULL, GIMP_MODIFIER_ACTION_NONE);
+
   mod_state = state & gimp_get_all_modifiers_mask ();
 
   gimp_modifiers_manager_get_keys (device, button, mod_state,
@@ -348,6 +369,9 @@ gimp_modifiers_manager_get_action (GimpModifiersManager *manager,
         retval = GIMP_MODIFIER_ACTION_NONE;
       else
         retval = mapping->mod_action;
+
+      if (retval == GIMP_MODIFIER_ACTION_ACTION)
+        *action_desc = mapping->action_desc;
     }
   else if (button == 2)
     {
@@ -421,7 +445,8 @@ gimp_modifiers_manager_set (GimpModifiersManager *manager,
                             GdkDevice            *device,
                             guint                 button,
                             GdkModifierType       modifiers,
-                            GimpModifierAction    action)
+                            GimpModifierAction    action,
+                            const gchar          *action_desc)
 {
   gchar *actions_key = NULL;
   gchar *buttons_key = NULL;
@@ -434,7 +459,8 @@ gimp_modifiers_manager_set (GimpModifiersManager *manager,
 
   gimp_modifiers_manager_initialize (manager, device, button);
 
-  if (action == GIMP_MODIFIER_ACTION_NONE)
+  if (action == GIMP_MODIFIER_ACTION_NONE ||
+      (action == GIMP_MODIFIER_ACTION_ACTION && action_desc == NULL))
     {
       g_hash_table_remove (manager->p->actions, actions_key);
       g_free (actions_key);
@@ -444,8 +470,9 @@ gimp_modifiers_manager_set (GimpModifiersManager *manager,
       GimpModifierMapping *mapping;
 
       mapping = g_slice_new (GimpModifierMapping);
-      mapping->modifiers  = modifiers;
-      mapping->mod_action = action;
+      mapping->modifiers   = modifiers;
+      mapping->mod_action  = action;
+      mapping->action_desc = action_desc ? g_strdup (action_desc) : NULL;
       g_hash_table_insert (manager->p->actions, actions_key,
                            mapping);
     }
@@ -458,7 +485,7 @@ gimp_modifiers_manager_remove (GimpModifiersManager *manager,
                                GdkModifierType       modifiers)
 {
   gimp_modifiers_manager_set (manager, device, button, modifiers,
-                              GIMP_MODIFIER_ACTION_NONE);
+                              GIMP_MODIFIER_ACTION_NONE, NULL);
 }
 
 void
@@ -474,6 +501,7 @@ gimp_modifiers_manager_clear (GimpModifiersManager *manager)
 static void
 gimp_modifiers_manager_free_mapping (GimpModifierMapping *mapping)
 {
+  g_free (mapping->action_desc);
   g_slice_free (GimpModifierMapping, mapping);
 }
 
diff --git a/app/display/gimpmodifiersmanager.h b/app/display/gimpmodifiersmanager.h
index 8cffdc2e4d..23d779c17b 100644
--- a/app/display/gimpmodifiersmanager.h
+++ b/app/display/gimpmodifiersmanager.h
@@ -58,7 +58,8 @@ GimpModifiersManager * gimp_modifiers_manager_new           (void);
 GimpModifierAction     gimp_modifiers_manager_get_action    (GimpModifiersManager *manager,
                                                              GdkDevice            *device,
                                                              guint                 button,
-                                                             GdkModifierType       modifiers);
+                                                             GdkModifierType       modifiers,
+                                                             const gchar         **action_desc);
 
 /* Protected functions: only use them from GimpModifiersEditor */
 
@@ -70,7 +71,8 @@ void                   gimp_modifiers_manager_set           (GimpModifiersManage
                                                              GdkDevice            *device,
                                                              guint                 button,
                                                              GdkModifierType       modifiers,
-                                                             GimpModifierAction    action);
+                                                             GimpModifierAction    action,
+                                                             const gchar          *action_desc);
 void                   gimp_modifiers_manager_remove        (GimpModifiersManager *manager,
                                                              GdkDevice            *device,
                                                              guint                 button,
diff --git a/app/widgets/gimpmodifierseditor.c b/app/widgets/gimpmodifierseditor.c
index 68e4c87c05..4e1414cdaf 100644
--- a/app/widgets/gimpmodifierseditor.c
+++ b/app/widgets/gimpmodifierseditor.c
@@ -31,8 +31,13 @@
 #include "display/display-types.h"
 #include "display/gimpmodifiersmanager.h"
 
+#include "gimpaction.h"
+#include "gimpactionview.h"
+#include "gimpactioneditor.h"
+#include "gimphelp-ids.h"
 #include "gimpmodifierseditor.h"
 #include "gimpshortcutbutton.h"
+#include "gimpuimanager.h"
 #include "gimpwidgets-utils.h"
 
 #include "gimp-intl.h"
@@ -59,9 +64,12 @@ struct _GimpModifiersEditorPrivate
 
   GtkSizeGroup         *mod_size_group;
   GtkSizeGroup         *action_size_group;
+  GtkSizeGroup         *action_action_size_group;
   GtkSizeGroup         *minus_size_group;
 
   GimpModifiersManager *manager;
+
+  GtkTreeSelection     *action_selection;
 };
 
 
@@ -86,13 +94,24 @@ static void     gimp_modifiers_editor_minus_button_clicked (GtkButton
 static void     gimp_modifiers_editor_notify_accelerator   (GtkWidget           *widget,
                                                             const GParamSpec    *pspec,
                                                             GimpModifiersEditor *editor);
+static void     gimp_modifiers_editor_search_clicked       (GtkWidget           *button,
+                                                            GimpModifiersEditor *editor);
 
 static void     gimp_modifiers_editor_show_settings         (GimpModifiersEditor *editor,
                                                              GdkDevice           *device,
                                                              guint                button);
 static void     gimp_modifiers_editor_add_mapping           (GimpModifiersEditor *editor,
                                                              GdkModifierType      modifiers,
-                                                             GimpModifierAction   mod_action);
+                                                             GimpModifierAction   mod_action,
+                                                             const gchar         *action_desc);
+
+static void     gimp_controller_modifiers_action_activated  (GtkTreeView         *tv,
+                                                             GtkTreePath         *path,
+                                                             GtkTreeViewColumn   *column,
+                                                             GtkWidget           *edit_dialog);
+static void     gimp_modifiers_editor_search_response       (GtkWidget           *dialog,
+                                                             gint                 response_id,
+                                                             GimpModifiersEditor *editor);
 
 G_DEFINE_TYPE_WITH_PRIVATE (GimpModifiersEditor, gimp_modifiers_editor,
                             GIMP_TYPE_FRAME)
@@ -127,12 +146,13 @@ gimp_modifiers_editor_init (GimpModifiersEditor *editor)
   gchar     *text;
 
   editor->priv = gimp_modifiers_editor_get_instance_private (editor);
-  editor->priv->device            = NULL;
-  editor->priv->plus_button       = NULL;
-  editor->priv->current_settings  = NULL;
-  editor->priv->mod_size_group    = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
-  editor->priv->action_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
-  editor->priv->minus_size_group  = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  editor->priv->device                   = NULL;
+  editor->priv->plus_button              = NULL;
+  editor->priv->current_settings         = NULL;
+  editor->priv->mod_size_group           = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  editor->priv->action_size_group        = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  editor->priv->action_action_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  editor->priv->minus_size_group         = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
   /* Setup the title. */
   gtk_frame_set_label_align (GTK_FRAME (editor), 0.5, 0.5);
@@ -203,14 +223,15 @@ gimp_modifiers_editor_finalize (GObject *object)
   g_clear_object (&editor->priv->device);
   g_object_unref (editor->priv->mod_size_group);
   g_object_unref (editor->priv->action_size_group);
+  g_object_unref (editor->priv->action_action_size_group);
   g_object_unref (editor->priv->minus_size_group);
 }
 
 static void
 gimp_modifiers_editor_set_property (GObject      *object,
-                                   guint         property_id,
-                                   const GValue *value,
-                                   GParamSpec   *pspec)
+                                    guint         property_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
 {
   GimpModifiersEditor *editor = GIMP_MODIFIERS_EDITOR (object);
 
@@ -229,9 +250,9 @@ gimp_modifiers_editor_set_property (GObject      *object,
 
 static void
 gimp_modifiers_editor_get_property (GObject    *object,
-                                   guint       property_id,
-                                   GValue     *value,
-                                   GParamSpec *pspec)
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
 {
   GimpModifiersEditor *editor = GIMP_MODIFIERS_EDITOR (object);
 
@@ -330,12 +351,14 @@ gimp_modifiers_editor_show_settings (GimpModifiersEditor *editor,
                                                         device, editor->priv->button);
       for (iter = modifiers; iter; iter = iter->next)
         {
-          GdkModifierType    mods = GPOINTER_TO_INT (iter->data);
-          GimpModifierAction action;
+          GdkModifierType     mods = GPOINTER_TO_INT (iter->data);
+          GimpModifierAction  action;
+          const gchar        *action_desc = NULL;
 
           action = gimp_modifiers_manager_get_action (editor->priv->manager, device,
-                                                      editor->priv->button, mods);
-          gimp_modifiers_editor_add_mapping (editor, mods, action);
+                                                      editor->priv->button, mods,
+                                                      &action_desc);
+          gimp_modifiers_editor_add_mapping (editor, mods, action, action_desc);
         }
 
       plus_button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR);
@@ -395,13 +418,16 @@ gimp_modifiers_editor_button_press_event (GtkWidget      *widget,
 static void
 gimp_modifiers_editor_add_mapping (GimpModifiersEditor *editor,
                                    GdkModifierType      modifiers,
-                                   GimpModifierAction   mod_action)
+                                   GimpModifierAction   mod_action,
+                                   const gchar         *action_desc)
 {
   GtkWidget   *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
   GtkWidget   *box_row;
+  GtkWidget   *combo_action_box;
   GtkWidget   *combo;
   GtkWidget   *shortcut;
   GtkWidget   *minus_button;
+  GtkWidget   *action_button = NULL;
   GtkWidget   *plus_button;
 
   plus_button = g_object_get_data (G_OBJECT (editor->priv->current_settings), "plus-button");
@@ -414,12 +440,33 @@ gimp_modifiers_editor_add_mapping (GimpModifiersEditor *editor,
   gtk_size_group_add_widget (editor->priv->mod_size_group, shortcut);
   gtk_widget_show (shortcut);
 
+  combo_action_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+  gtk_box_pack_start (GTK_BOX (box), combo_action_box, FALSE, FALSE, 0);
+  gtk_size_group_add_widget (editor->priv->action_action_size_group, combo_action_box);
+  gtk_widget_show (combo_action_box);
+
   combo = gimp_enum_combo_box_new (GIMP_TYPE_MODIFIER_ACTION);
-  gtk_box_pack_start (GTK_BOX (box), combo, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (combo_action_box), combo, FALSE, FALSE, 0);
   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), mod_action);
   gtk_size_group_add_widget (editor->priv->action_size_group, combo);
   gtk_widget_show (combo);
 
+  if (action_desc)
+    {
+      gchar *action_name = strchr (action_desc, '/');
+
+      if (action_name)
+        action_name++;
+
+      if (strlen (action_name) > 0)
+        action_button = gtk_button_new_with_label (action_name);
+    }
+
+  if (action_button == NULL)
+    action_button = gtk_button_new_from_icon_name ("system-search", GTK_ICON_SIZE_SMALL_TOOLBAR);
+  gtk_box_pack_start (GTK_BOX (combo_action_box), action_button, FALSE, FALSE, 0);
+  gtk_widget_set_visible (action_button, mod_action == GIMP_MODIFIER_ACTION_ACTION);
+
   minus_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_SMALL_TOOLBAR);
   gtk_size_group_add_widget (editor->priv->minus_size_group, minus_button);
   gtk_box_pack_start (GTK_BOX (box), minus_button, FALSE, FALSE, 0);
@@ -432,8 +479,10 @@ gimp_modifiers_editor_add_mapping (GimpModifiersEditor *editor,
 
   g_object_set_data (G_OBJECT (shortcut), "shortcut-button", shortcut);
   g_object_set_data (G_OBJECT (shortcut), "shortcut-action", combo);
+  g_object_set_data (G_OBJECT (shortcut), "shortcut-action-action", action_button);
   g_object_set_data (G_OBJECT (combo),    "shortcut-button", shortcut);
   g_object_set_data (G_OBJECT (combo),    "shortcut-action", combo);
+  g_object_set_data (G_OBJECT (combo),    "shortcut-action-action", action_button);
   g_signal_connect (shortcut, "notify::accelerator",
                     G_CALLBACK (gimp_modifiers_editor_notify_accelerator),
                     editor);
@@ -441,6 +490,11 @@ gimp_modifiers_editor_add_mapping (GimpModifiersEditor *editor,
                     G_CALLBACK (gimp_modifiers_editor_notify_accelerator),
                     editor);
 
+  g_object_set_data (G_OBJECT (action_button), "shortcut-button", shortcut);
+  g_signal_connect (action_button, "clicked",
+                    G_CALLBACK (gimp_modifiers_editor_search_clicked),
+                    editor);
+
   gtk_list_box_insert (GTK_LIST_BOX (editor->priv->current_settings), box, -1);
 
   if (plus_button)
@@ -459,7 +513,7 @@ static void
 gimp_modifiers_editor_plus_button_clicked (GtkButton           *plus_button,
                                            GimpModifiersEditor *editor)
 {
-  gimp_modifiers_editor_add_mapping (editor, 0, GIMP_MODIFIER_ACTION_NONE);
+  gimp_modifiers_editor_add_mapping (editor, 0, GIMP_MODIFIER_ACTION_NONE, NULL);
 }
 
 static void
@@ -501,17 +555,201 @@ gimp_modifiers_editor_notify_accelerator (GtkWidget           *widget,
 {
   GtkWidget          *shortcut;
   GtkWidget          *combo;
+  GtkWidget          *action_button;
   GimpModifierAction  action = GIMP_MODIFIER_ACTION_NONE;
 
   GdkModifierType  modifiers;
 
-  shortcut = g_object_get_data (G_OBJECT (widget), "shortcut-button");
-  combo    = g_object_get_data (G_OBJECT (widget), "shortcut-action");
+  shortcut      = g_object_get_data (G_OBJECT (widget), "shortcut-button");
+  combo         = g_object_get_data (G_OBJECT (widget), "shortcut-action");
+  action_button = g_object_get_data (G_OBJECT (widget), "shortcut-action-action");
 
   gimp_shortcut_button_get_keys (GIMP_SHORTCUT_BUTTON (shortcut), NULL, &modifiers);
 
   if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo), (gint *) &action))
-    gimp_modifiers_manager_set (editor->priv->manager, editor->priv->device,
-                                editor->priv->button, modifiers,
-                                action);
+    {
+      const gchar *action_desc;
+
+      action_desc = g_object_get_data (G_OBJECT (action_button), "shortcut-action-desc");
+      gimp_modifiers_manager_set (editor->priv->manager, editor->priv->device,
+                                  editor->priv->button, modifiers,
+                                  action, action_desc);
+      gtk_widget_set_visible (action_button, action == GIMP_MODIFIER_ACTION_ACTION);
+    }
+}
+
+static void
+gimp_modifiers_editor_search_clicked (GtkWidget           *button,
+                                      GimpModifiersEditor *editor)
+{
+  gchar           *accel_name  = NULL;
+  gchar           *action_name = "action name";
+
+  GtkWidget       *shortcut;
+  GdkModifierType  modifiers;
+
+  shortcut = g_object_get_data (G_OBJECT (button), "shortcut-button");
+  gimp_shortcut_button_get_keys (GIMP_SHORTCUT_BUTTON (shortcut), NULL, &modifiers);
+  accel_name = gtk_accelerator_name (0, modifiers);
+
+  if (accel_name)
+    {
+      GtkWidget *view;
+      GtkWidget *edit_dialog;
+      gchar     *title;
+
+      if (strlen (accel_name) > 0)
+        {
+          if (gdk_device_get_name (editor->priv->device) != NULL)
+            /* TRANSLATORS: first %s is modifier keys, %d is button
+             * number, last %s is an input device (e.g. a mouse) name.
+             */
+            title = g_strdup_printf (_("Select Action for %s button %d of %s"),
+                                     accel_name, editor->priv->button,
+                                     gdk_device_get_name (editor->priv->device));
+          else
+            /* TRANSLATORS: %s is modifiers key, %d is a button number. */
+            title = g_strdup_printf (_("Editing modifiers for %s button %d"),
+                                     accel_name, editor->priv->button);
+        }
+      else
+        {
+            /* TRANSLATORS: %d is a button number, %s is the device (e.g. a mouse) name. */
+          if (gdk_device_get_name (editor->priv->device) != NULL)
+            title = g_strdup_printf (_("Select Action for button %d of %s"),
+                                     editor->priv->button,
+                                     gdk_device_get_name (editor->priv->device));
+          else
+            /* TRANSLATORS: %d is an input device button number. */
+            title = g_strdup_printf (_("Editing modifiers for button %d"),
+                                     editor->priv->button);
+        }
+
+      edit_dialog =
+        gimp_dialog_new (title,
+                         "gimp-modifiers-action-dialog",
+                         gtk_widget_get_toplevel (GTK_WIDGET (editor)),
+                         GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+                         gimp_standard_help_func,
+                         GIMP_HELP_PREFS_CANVAS_MODIFIERS,
+
+                         _("_Cancel"), GTK_RESPONSE_CANCEL,
+                         _("_OK"),     GTK_RESPONSE_OK,
+
+                         NULL);
+      g_free (title);
+
+      /* Default height is very crappy because of the scrollbar so we
+       * end up to resize manually each time. Let's have a minimum
+       * height.
+       */
+      gtk_window_set_default_size (GTK_WINDOW (edit_dialog), -1, 400);
+      gimp_dialog_set_alternative_button_order (GTK_DIALOG (edit_dialog),
+                                                GTK_RESPONSE_OK,
+                                                GTK_RESPONSE_CANCEL,
+                                                -1);
+
+      g_object_set_data (G_OBJECT (edit_dialog), "shortcut-button", shortcut);
+      g_object_set_data (G_OBJECT (edit_dialog), "shortcut-action-action", button);
+      g_signal_connect (edit_dialog, "response",
+                        G_CALLBACK (gimp_modifiers_editor_search_response),
+                        editor);
+
+      view = gimp_action_editor_new (gimp_ui_managers_from_name ("<Image>")->data,
+                                     action_name, FALSE);
+      gtk_container_set_border_width (GTK_CONTAINER (view), 12);
+      gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (edit_dialog))),
+                          view, TRUE, TRUE, 0);
+      gtk_widget_show (view);
+
+      g_signal_connect_object (GIMP_ACTION_EDITOR (view)->view, "row-activated",
+                               G_CALLBACK (gimp_controller_modifiers_action_activated),
+                               edit_dialog, 0);
+
+      editor->priv->action_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GIMP_ACTION_EDITOR 
(view)->view));
+
+      g_object_add_weak_pointer (G_OBJECT (editor->priv->action_selection),
+                                 (gpointer) &editor->priv->action_selection);
+
+      gtk_widget_show (edit_dialog);
+
+      g_free (accel_name);
+    }
+}
+
+static void
+gimp_controller_modifiers_action_activated (GtkTreeView       *view,
+                                            GtkTreePath       *path,
+                                            GtkTreeViewColumn *column,
+                                            GtkWidget         *edit_dialog)
+{
+  gtk_dialog_response (GTK_DIALOG (edit_dialog), GTK_RESPONSE_OK);
+}
+
+static void
+gimp_modifiers_editor_search_response (GtkWidget           *dialog,
+                                       gint                 response_id,
+                                       GimpModifiersEditor *editor)
+{
+  if (response_id == GTK_RESPONSE_OK)
+    {
+      GtkTreeModel *model;
+      GtkTreeIter   iter;
+      gchar        *icon_name   = NULL;
+      GimpAction   *action      = NULL;
+
+      if (gtk_tree_selection_get_selected (editor->priv->action_selection, &model, &iter))
+        gtk_tree_model_get (model, &iter,
+                            GIMP_ACTION_VIEW_COLUMN_ACTION,    &action,
+                            GIMP_ACTION_VIEW_COLUMN_ICON_NAME, &icon_name,
+                            -1);
+
+      if (action)
+        {
+          GtkActionGroup *group;
+
+          g_object_get (action,
+                        "action-group", &group,
+                        NULL);
+
+          if (group)
+            {
+              GtkWidget       *action_button;
+              GtkWidget       *shortcut;
+              GtkWidget       *label;
+              gchar           *action_desc;
+              GdkModifierType  modifiers;
+
+              shortcut      = g_object_get_data (G_OBJECT (dialog), "shortcut-button");
+              gimp_shortcut_button_get_keys (GIMP_SHORTCUT_BUTTON (shortcut), NULL, &modifiers);
+
+              action_button = g_object_get_data (G_OBJECT (dialog), "shortcut-action-action");
+              action_desc = g_strdup_printf ("%s/%s",
+                                             gtk_action_group_get_name (group),
+                                             gimp_action_get_name (action));
+
+              g_object_set_data_full (G_OBJECT (action_button), "shortcut-action-desc",
+                                      action_desc, g_free);
+
+              gimp_modifiers_manager_set (editor->priv->manager, editor->priv->device,
+                                          editor->priv->button, modifiers,
+                                          GIMP_MODIFIER_ACTION_ACTION, action_desc);
+
+              /* Change the button label. */
+              gtk_container_foreach (GTK_CONTAINER (action_button),
+                                     (GtkCallback) gtk_widget_destroy,
+                                     NULL);
+              label = gtk_label_new (gimp_action_get_name (action));
+              gtk_container_add (GTK_CONTAINER (action_button), label);
+              gtk_widget_show (label);
+
+              g_object_unref (group);
+            }
+        }
+
+      g_free (icon_name);
+      g_clear_object (&action);
+    }
+
+  gtk_widget_destroy (dialog);
 }


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