[gimp] app: implement exclusive lock switching (Shift-click).



commit cd7f399006a08a277d849cf2593e879a7ef27c7b
Author: Jehan <jehan girinstud io>
Date:   Thu Feb 11 16:17:36 2021 +0100

    app: implement exclusive lock switching (Shift-click).
    
    Similar to exclusive visibility switch on layers, now for locks too, if
    one wants to lock all layers within a same level for instance by
    Shift-clicking the lock icon.
    
    Also once again I factorized the exclusive switching code to ensure it
    will always works the same for all similar features (visibility and all
    locks).

 app/core/gimpitem-exclusive.c   | 102 +++++++++++++++++++++++++---------------
 app/core/gimpitem-exclusive.h   |  26 ++++++++--
 app/widgets/gimpitemtreeview.c  |  84 ++++++++++++++++++++++++++-------
 app/widgets/gimpitemtreeview.h  |   5 ++
 app/widgets/gimplayertreeview.c |   7 ++-
 5 files changed, 165 insertions(+), 59 deletions(-)
---
diff --git a/app/core/gimpitem-exclusive.c b/app/core/gimpitem-exclusive.c
index 6b07c268f3..7f62bfac81 100644
--- a/app/core/gimpitem-exclusive.c
+++ b/app/core/gimpitem-exclusive.c
@@ -37,11 +37,13 @@
 #include "gimp-intl.h"
 
 
-static GList * gimp_item_exclusive_get_ancestry (GimpItem     *item);
-static void    gimp_item_exclusive_get_lists    (GimpItem     *item,
-                                                 const gchar  *property,
-                                                 GList       **on,
-                                                 GList       **off);
+static GList * gimp_item_exclusive_get_ancestry (GimpItem              *item);
+static void    gimp_item_exclusive_get_lists    (GimpItem              *item,
+                                                 GimpItemIsEnabledFunc  is_enabled,
+                                                 GimpItemCanSetFunc     can_set,
+                                                 GimpItemIsPropLocked   is_prop_locked,
+                                                 GList                **on,
+                                                 GList                **off);
 
 
 /*  public functions  */
@@ -50,73 +52,99 @@ void
 gimp_item_toggle_exclusive_visible (GimpItem    *item,
                                     GimpContext *context)
 {
-  GList *ancestry;
-  GList *on;
-  GList *off;
-  GList *list;
+  gimp_item_toggle_exclusive (item,
+                              (GimpItemIsEnabledFunc) gimp_item_is_visible,
+                              (GimpItemSetFunc)       gimp_item_set_visible,
+                              NULL,
+                              (GimpItemIsPropLocked)  gimp_item_is_visibility_locked,
+                              (GimpItemUndoPush)      gimp_image_undo_push_item_visibility,
+                              _("Set Item Exclusive Visibility"),
+                              GIMP_UNDO_GROUP_ITEM_VISIBILITY,
+                              context);
+}
+
+void
+gimp_item_toggle_exclusive (GimpItem               *item,
+                            GimpItemIsEnabledFunc   is_enabled,
+                            GimpItemSetFunc         set_prop,
+                            GimpItemCanSetFunc      can_set,
+                            GimpItemIsPropLocked    is_prop_locked,
+                            GimpItemUndoPush        undo_push,
+                            const gchar            *undo_desc,
+                            GimpUndoType            group_undo_type,
+                            GimpContext            *context)
+{
+  GList       *ancestry;
+  GList       *on;
+  GList       *off;
+  GList       *list;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (gimp_item_is_attached (item));
-  g_return_if_fail (GIMP_IS_CONTEXT (context));
+  g_return_if_fail (undo_desc != NULL);
+  g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
 
   ancestry = gimp_item_exclusive_get_ancestry (item);
-  gimp_item_exclusive_get_lists (item, "visible", &on, &off);
+  gimp_item_exclusive_get_lists (item, is_enabled, can_set, is_prop_locked, &on, &off);
 
-  if (on || off || ! gimp_item_is_visible (item))
+  if (on || off || (! is_enabled (item) && (can_set == NULL || can_set (item))))
     {
       GimpImage *image = gimp_item_get_image (item);
       GimpUndo  *undo;
       gboolean   push_undo = TRUE;
 
       undo = gimp_image_undo_can_compress (image, GIMP_TYPE_UNDO_STACK,
-                                           GIMP_UNDO_GROUP_ITEM_VISIBILITY);
+                                           group_undo_type);
 
-      if (undo && (g_object_get_data (G_OBJECT (undo), "exclusive-visible-item") ==
+      /* Use the undo description as the undo object key, as we should
+       * assume that a same undo description means the same exclusive
+       * action.
+       */
+      if (undo && (g_object_get_data (G_OBJECT (undo), undo_desc) ==
                    (gpointer) item))
         push_undo = FALSE;
 
       if (push_undo)
         {
           if (gimp_image_undo_group_start (image,
-                                           GIMP_UNDO_GROUP_ITEM_VISIBILITY,
-                                           _("Set Item Exclusive Visible")))
+                                           group_undo_type,
+                                           undo_desc))
             {
               undo = gimp_image_undo_can_compress (image, GIMP_TYPE_UNDO_STACK,
-                                                   GIMP_UNDO_GROUP_ITEM_VISIBILITY);
+                                                   group_undo_type);
 
               if (undo)
-                g_object_set_data (G_OBJECT (undo), "exclusive-visible-item",
-                                   (gpointer) item);
+                g_object_set_data (G_OBJECT (undo), undo_desc, (gpointer) item);
             }
 
           for (list = ancestry; list; list = g_list_next (list))
-            gimp_image_undo_push_item_visibility (image, NULL, list->data);
+            undo_push (image, NULL, list->data);
 
           for (list = on; list; list = g_list_next (list))
-            gimp_image_undo_push_item_visibility (image, NULL, list->data);
+            undo_push (image, NULL, list->data);
 
           for (list = off; list; list = g_list_next (list))
-            gimp_image_undo_push_item_visibility (image, NULL, list->data);
+            undo_push (image, NULL, list->data);
 
           gimp_image_undo_group_end (image);
         }
-      else
+      else if (context)
         {
           gimp_undo_refresh_preview (undo, context);
         }
 
       for (list = ancestry; list; list = g_list_next (list))
-        gimp_item_set_visible (list->data, TRUE, FALSE);
+        set_prop (list->data, TRUE, FALSE);
 
       if (on)
         {
           for (list = on; list; list = g_list_next (list))
-            gimp_item_set_visible (list->data, FALSE, FALSE);
+            set_prop (list->data, FALSE, FALSE);
         }
       else if (off)
         {
           for (list = off; list; list = g_list_next (list))
-            gimp_item_set_visible (list->data, TRUE, FALSE);
+            set_prop (list->data, TRUE, FALSE);
         }
 
       g_list_free (on);
@@ -233,10 +261,12 @@ gimp_item_exclusive_get_ancestry (GimpItem *item)
 }
 
 static void
-gimp_item_exclusive_get_lists (GimpItem     *item,
-                               const gchar  *property,
-                               GList       **on,
-                               GList       **off)
+gimp_item_exclusive_get_lists (GimpItem              *item,
+                               GimpItemIsEnabledFunc  is_enabled,
+                               GimpItemCanSetFunc     can_set,
+                               GimpItemIsPropLocked   is_prop_locked,
+                               GList                 **on,
+                               GList                 **off)
 {
   GimpItemTree *tree;
   GList        *items;
@@ -253,18 +283,16 @@ gimp_item_exclusive_get_lists (GimpItem     *item,
     {
       GimpItem *other = list->data;
 
-      if (other != item                            &&
+      if (other != item                                        &&
           /* Don't include item with visibility locks. */
-          ! gimp_item_is_visibility_locked (other) &&
+          (is_prop_locked == NULL || ! is_prop_locked (other)) &&
+          /* Don't include item which can be changed. */
+          (can_set == NULL || can_set (other))                 &&
           /* We are only interested in same level items. */
           gimp_viewable_get_parent (GIMP_VIEWABLE (other)) ==
           gimp_viewable_get_parent (GIMP_VIEWABLE (item)))
         {
-          gboolean value;
-
-          g_object_get (other, property, &value, NULL);
-
-          if (value)
+          if (is_enabled (other))
             *on = g_list_prepend (*on, other);
           else
             *off = g_list_prepend (*off, other);
diff --git a/app/core/gimpitem-exclusive.h b/app/core/gimpitem-exclusive.h
index 98838c58cb..5381721bdd 100644
--- a/app/core/gimpitem-exclusive.h
+++ b/app/core/gimpitem-exclusive.h
@@ -21,11 +21,29 @@
 #ifndef __GIMP_ITEM_EXCLUSIVE_H__
 #define __GIMP_ITEM_EXCLUSIVE_H__
 
+typedef gboolean        (* GimpItemIsEnabledFunc)    (GimpItem  *item);
+typedef gboolean        (* GimpItemCanSetFunc)       (GimpItem  *item);
+typedef void            (* GimpItemSetFunc)          (GimpItem  *item,
+                                                      gboolean   enabled,
+                                                      gboolean   push_undo);
+typedef gboolean        (* GimpItemIsPropLocked)     (GimpItem  *item);
+typedef GimpUndo      * (*GimpItemUndoPush)          (GimpImage     *image,
+                                                      const gchar   *undo_desc,
+                                                      GimpItem      *item);
 
-void   gimp_item_toggle_exclusive_visible (GimpItem    *item,
-                                           GimpContext *context);
-void   gimp_item_toggle_exclusive_linked  (GimpItem    *item,
-                                           GimpContext *context);
+void   gimp_item_toggle_exclusive_visible (GimpItem             *item,
+                                           GimpContext          *context);
+void   gimp_item_toggle_exclusive         (GimpItem             *item,
+                                           GimpItemIsEnabledFunc is_enabled,
+                                           GimpItemSetFunc       set_prop,
+                                           GimpItemCanSetFunc    can_set,
+                                           GimpItemIsPropLocked  is_prop_locked,
+                                           GimpItemUndoPush      undo_push,
+                                           const gchar          *undo_desc,
+                                           GimpUndoType          group_undo_type,
+                                           GimpContext          *context);
+void   gimp_item_toggle_exclusive_linked  (GimpItem             *item,
+                                           GimpContext          *context);
 
 
 #endif /* __GIMP_ITEM_EXCLUSIVE_H__ */
diff --git a/app/widgets/gimpitemtreeview.c b/app/widgets/gimpitemtreeview.c
index 1800440dea..096d66dd9d 100644
--- a/app/widgets/gimpitemtreeview.c
+++ b/app/widgets/gimpitemtreeview.c
@@ -108,6 +108,7 @@ typedef struct
   GimpIsLockedFunc  is_locked;
   GimpCanLockFunc   can_lock;
   GimpSetLockFunc   lock;
+  GimpUndoLockPush  undo_push;
 
   const gchar      *tooltip;
   const gchar      *help_id;
@@ -119,8 +120,9 @@ typedef struct
   /* Undo types and labels. */
   GimpUndoType      undo_type;
   GimpUndoType      group_undo_type;
-  const gchar      *undo_lock_label;
-  const gchar      *undo_unlock_label;
+  const gchar      *undo_lock_desc;
+  const gchar      *undo_unlock_desc;
+  const gchar      *undo_exclusive_desc;
 } LockToggle;
 
 
@@ -208,6 +210,9 @@ static void   gimp_item_tree_view_lock_clicked      (GtkCellRendererToggle *togg
                                                      gchar             *path,
                                                      GdkModifierType    state,
                                                      GimpItemTreeView  *view);
+static gboolean gimp_item_tree_view_lock_button_release (GtkWidget        *widget,
+                                         GdkEvent         *event,
+                                         GimpItemTreeView *view);
 static void   gimp_item_tree_view_lock_toggled      (GtkWidget         *widget,
                                                      GimpItemTreeView  *view);
 static void   gimp_item_tree_view_update_lock_box   (GimpItemTreeView  *view,
@@ -519,13 +524,15 @@ gimp_item_tree_view_constructed (GObject *object)
   gimp_item_tree_view_add_lock (item_view,
                                 item_view_class->lock_content_icon_name,
                                 (GimpIsLockedFunc) gimp_item_get_lock_content,
-                                (GimpCanLockFunc) gimp_item_can_lock_content,
-                                (GimpSetLockFunc) gimp_item_set_lock_content,
+                                (GimpCanLockFunc)  gimp_item_can_lock_content,
+                                (GimpSetLockFunc)  gimp_item_set_lock_content,
+                                (GimpUndoLockPush) gimp_image_undo_push_item_lock_content,
                                 "lock-content-changed",
                                 GIMP_UNDO_ITEM_LOCK_CONTENT,
                                 GIMP_UNDO_GROUP_ITEM_LOCK_CONTENTS,
                                 _("Lock content"),
                                 _("Unlock content"),
+                                _("Set Item Exclusive Content Lock"),
                                 item_view_class->lock_content_tooltip,
                                 item_view_class->lock_content_help_id);
 
@@ -533,13 +540,15 @@ gimp_item_tree_view_constructed (GObject *object)
   gimp_item_tree_view_add_lock (item_view,
                                 item_view_class->lock_position_icon_name,
                                 (GimpIsLockedFunc) gimp_item_get_lock_position,
-                                (GimpCanLockFunc) gimp_item_can_lock_position,
-                                (GimpSetLockFunc) gimp_item_set_lock_position,
+                                (GimpCanLockFunc)  gimp_item_can_lock_position,
+                                (GimpSetLockFunc)  gimp_item_set_lock_position,
+                                (GimpUndoLockPush) gimp_image_undo_push_item_lock_position,
                                 "lock-position-changed",
                                 GIMP_UNDO_ITEM_LOCK_POSITION,
                                 GIMP_UNDO_GROUP_ITEM_LOCK_POSITION,
                                 _("Lock position"),
                                 _("Unlock position"),
+                                _("Set Item Exclusive Position Lock"),
                                 item_view_class->lock_position_tooltip,
                                 item_view_class->lock_position_help_id);
 
@@ -547,13 +556,15 @@ gimp_item_tree_view_constructed (GObject *object)
   gimp_item_tree_view_add_lock (item_view,
                                 item_view_class->lock_visibility_icon_name,
                                 (GimpIsLockedFunc) gimp_item_get_lock_visibility,
-                                (GimpCanLockFunc) gimp_item_can_lock_visibility,
-                                (GimpSetLockFunc) gimp_item_set_lock_visibility,
+                                (GimpCanLockFunc)  gimp_item_can_lock_visibility,
+                                (GimpSetLockFunc)  gimp_item_set_lock_visibility,
+                                (GimpUndoLockPush) gimp_image_undo_push_item_lock_visibility,
                                 "lock-visibility-changed",
                                 GIMP_UNDO_ITEM_LOCK_VISIBILITY,
                                 GIMP_UNDO_GROUP_ITEM_LOCK_VISIBILITY,
                                 _("Lock visibility"),
                                 _("Unlock visibility"),
+                                _("Set Item Exclusive Visibility Lock"),
                                 item_view_class->lock_visibility_tooltip,
                                 item_view_class->lock_visibility_help_id);
 
@@ -819,11 +830,13 @@ gimp_item_tree_view_add_lock (GimpItemTreeView *view,
                               GimpIsLockedFunc  is_locked,
                               GimpCanLockFunc   can_lock,
                               GimpSetLockFunc   lock,
+                              GimpUndoLockPush  undo_push,
                               const gchar      *signal_name,
                               GimpUndoType      undo_type,
                               GimpUndoType      group_undo_type,
-                              const gchar      *undo_lock_label,
-                              const gchar      *undo_unlock_label,
+                              const gchar      *undo_lock_desc,
+                              const gchar      *undo_unlock_desc,
+                              const gchar      *undo_exclusive_desc,
                               const gchar      *tooltip,
                               const gchar      *help_id)
 {
@@ -838,14 +851,16 @@ gimp_item_tree_view_add_lock (GimpItemTreeView *view,
   data->is_locked    = is_locked;
   data->can_lock     = can_lock;
   data->lock         = lock;
+  data->undo_push    = undo_push;
   data->signal_name  = signal_name;
   data->tooltip      = tooltip;
   data->help_id      = help_id;
 
-  data->undo_type         = undo_type;
-  data->group_undo_type   = group_undo_type;
-  data->undo_lock_label   = undo_lock_label;
-  data->undo_unlock_label = undo_unlock_label;
+  data->undo_type           = undo_type;
+  data->group_undo_type     = group_undo_type;
+  data->undo_lock_desc      = undo_lock_desc;
+  data->undo_unlock_desc    = undo_unlock_desc;
+  data->undo_exclusive_desc = undo_exclusive_desc;
 
   view->priv->locks = g_list_prepend (view->priv->locks, data);
 
@@ -857,6 +872,9 @@ gimp_item_tree_view_add_lock (GimpItemTreeView *view,
   g_signal_connect (toggle, "toggled",
                     G_CALLBACK (gimp_item_tree_view_lock_toggled),
                     view);
+  g_signal_connect (toggle, "button-release-event",
+                    G_CALLBACK (gimp_item_tree_view_lock_button_release),
+                    view);
 
   gimp_help_set_help_data (toggle, tooltip, help_id);
 
@@ -1826,6 +1844,34 @@ gimp_item_tree_view_lock_changed (GimpItem         *item,
     gimp_item_tree_view_update_lock_box (view, item, NULL);
 }
 
+static gboolean
+gimp_item_tree_view_lock_button_release (GtkWidget        *widget,
+                                         GdkEvent         *event,
+                                         GimpItemTreeView *view)
+{
+  GdkEventButton  *bevent = (GdkEventButton *) event;
+  LockToggle      *data;
+  GdkModifierType  modifiers;
+
+  data      = g_object_get_data (G_OBJECT (widget), "lock-data");
+  modifiers = bevent->state & gimp_get_all_modifiers_mask ();
+
+  if (modifiers == GDK_SHIFT_MASK)
+    gimp_item_toggle_exclusive (view->priv->lock_box_item,
+                                data->is_locked,
+                                data->lock,
+                                data->can_lock,
+                                NULL,
+                                data->undo_push,
+                                data->undo_exclusive_desc,
+                                data->group_undo_type,
+                                NULL);
+  else
+    return GDK_EVENT_PROPAGATE;
+
+  return GDK_EVENT_STOP;
+}
+
 static void
 gimp_item_tree_view_lock_toggled (GtkWidget         *widget,
                                   GimpItemTreeView  *view)
@@ -1853,9 +1899,9 @@ gimp_item_tree_view_lock_toggled (GtkWidget         *widget,
   if (push_undo)
     {
       if (locked)
-        undo_label = data->undo_lock_label;
+        undo_label = data->undo_lock_desc;
       else
-        undo_label = data->undo_unlock_label;
+        undo_label = data->undo_unlock_desc;
 
       gimp_image_undo_group_start (image, data->group_undo_type,
                                    undo_label);
@@ -1950,6 +1996,9 @@ gimp_item_tree_view_update_lock_box (GimpItemTreeView *view,
           g_signal_handlers_block_by_func (data->toggle,
                                            gimp_item_tree_view_lock_toggled,
                                            view);
+          g_signal_handlers_block_by_func (data->toggle,
+                                           gimp_item_tree_view_lock_button_release,
+                                           view);
 
           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->toggle),
                                         data->is_locked (item));
@@ -1957,6 +2006,9 @@ gimp_item_tree_view_update_lock_box (GimpItemTreeView *view,
           g_signal_handlers_unblock_by_func (data->toggle,
                                              gimp_item_tree_view_lock_toggled,
                                              view);
+          g_signal_handlers_unblock_by_func (data->toggle,
+                                           gimp_item_tree_view_lock_button_release,
+                                           view);
         }
       gtk_widget_set_sensitive (data->toggle, data->can_lock (item));
     }
diff --git a/app/widgets/gimpitemtreeview.h b/app/widgets/gimpitemtreeview.h
index 05319a7763..cee2bd552d 100644
--- a/app/widgets/gimpitemtreeview.h
+++ b/app/widgets/gimpitemtreeview.h
@@ -49,6 +49,9 @@ typedef gboolean        (* GimpCanLockFunc)      (GimpItem  *item);
 typedef void            (* GimpSetLockFunc)      (GimpItem  *item,
                                                   gboolean   lock,
                                                   gboolean   push_undo);
+typedef GimpUndo      * (*GimpUndoLockPush)      (GimpImage     *image,
+                                                  const gchar   *undo_desc,
+                                                  GimpItem      *item);
 
 
 #define GIMP_TYPE_ITEM_TREE_VIEW            (gimp_item_tree_view_get_type ())
@@ -142,11 +145,13 @@ void        gimp_item_tree_view_add_lock          (GimpItemTreeView *view,
                                                    GimpIsLockedFunc  is_locked,
                                                    GimpCanLockFunc   can_lock,
                                                    GimpSetLockFunc   lock,
+                                                   GimpUndoLockPush  undo_push,
                                                    const gchar      *signal_name,
                                                    GimpUndoType      undo_type,
                                                    GimpUndoType      group_undo_type,
                                                    const gchar      *undo_lock_label,
                                                    const gchar      *undo_unlock_label,
+                                                   const gchar      *undo_exclusive_desc,
                                                    const gchar      *tooltip,
                                                    const gchar      *help_id);
 void        gimp_item_tree_view_blink_lock        (GimpItemTreeView *view,
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index 5af94fb09e..796b1b90bf 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -40,6 +40,7 @@
 #include "core/gimpchannel.h"
 #include "core/gimpcontainer.h"
 #include "core/gimpimage-undo.h"
+#include "core/gimpimage-undo-push.h"
 #include "core/gimpimage.h"
 #include "core/gimpitemlist.h"
 #include "core/gimpitemundo.h"
@@ -529,13 +530,15 @@ gimp_layer_tree_view_constructed (GObject *object)
   gimp_item_tree_view_add_lock (GIMP_ITEM_TREE_VIEW (tree_view),
                                 GIMP_ICON_TRANSPARENCY,
                                 (GimpIsLockedFunc) gimp_layer_get_lock_alpha,
-                                (GimpCanLockFunc) gimp_layer_can_lock_alpha,
-                                (GimpSetLockFunc) gimp_layer_set_lock_alpha,
+                                (GimpCanLockFunc)  gimp_layer_can_lock_alpha,
+                                (GimpSetLockFunc)  gimp_layer_set_lock_alpha,
+                                (GimpUndoLockPush) gimp_image_undo_push_layer_lock_alpha,
                                 "lock-alpha-changed",
                                 GIMP_UNDO_LAYER_LOCK_ALPHA,
                                 GIMP_UNDO_GROUP_LAYER_LOCK_ALPHA,
                                 _("Lock alpha channel"),
                                 _("Unlock alpha channel"),
+                                _("Set Item Exclusive Alpha Channel lock"),
                                 _("Lock alpha channel"),
                                 GIMP_HELP_LAYER_LOCK_ALPHA);
 }


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