[gimp/wip/Jehan/layers-dockable-refresh: 18/80] app: improve item lock management with gimp_item_tree_view_add_lock().




commit f94328ae7485b014457a869a80b2f7832e46303b
Author: Jehan <jehan girinstud io>
Date:   Tue Feb 9 02:39:37 2021 +0100

    app: improve item lock management with gimp_item_tree_view_add_lock().
    
    Use this for the alpha lock brought by GimpLayerTreeView.
    Also use the new gimp_widget_blink_rect() to only blink the appropriate
    cell when a lock is preventing you from doing something.

 app/tools/gimptools-utils.c     |  23 ++-
 app/widgets/gimpitemtreeview.c  | 321 +++++++++++++++++++++++++++++++++-------
 app/widgets/gimpitemtreeview.h  |  20 ++-
 app/widgets/gimplayertreeview.c | 142 ++----------------
 4 files changed, 320 insertions(+), 186 deletions(-)
---
diff --git a/app/tools/gimptools-utils.c b/app/tools/gimptools-utils.c
index 8aa9188b1a..db078c48bf 100644
--- a/app/tools/gimptools-utils.c
+++ b/app/tools/gimptools-utils.c
@@ -30,6 +30,7 @@
 
 #include "vectors/gimpvectors.h"
 
+#include "widgets/gimpcontainerview.h"
 #include "widgets/gimpdialogfactory.h"
 #include "widgets/gimpitemtreeview.h"
 #include "widgets/gimpwidgets-utils.h"
@@ -49,6 +50,10 @@ gimp_tools_blink_lock_box (Gimp     *gimp,
   GdkMonitor       *monitor;
   const gchar      *identifier;
 
+  GtkTreeIter      *iter;
+  GtkTreePath      *path;
+  GdkRectangle      rect;
+
   g_return_if_fail (GIMP_IS_GIMP (gimp));
   g_return_if_fail (GIMP_IS_ITEM (item));
 
@@ -75,5 +80,21 @@ gimp_tools_blink_lock_box (Gimp     *gimp,
 
   view = GIMP_ITEM_TREE_VIEW (gtk_bin_get_child (GTK_BIN (dockable)));
 
-  gimp_widget_blink (gimp_item_tree_view_get_lock_box (view));
+  /* Find the item in the tree view. */
+  iter = gimp_container_view_lookup (GIMP_CONTAINER_VIEW (view),
+                                     (GimpViewable *) item);
+  path = gtk_tree_model_get_path (GIMP_CONTAINER_TREE_VIEW (view)->model, iter);
+
+  /* Scroll dockable to make sure the cell is showing. */
+  gtk_tree_view_scroll_to_cell (GIMP_CONTAINER_TREE_VIEW (view)->view, path,
+                                gtk_tree_view_get_column (GIMP_CONTAINER_TREE_VIEW (view)->view, 1),
+                                FALSE, 0.0, 0.0);
+
+  /* Now blink the lock cell of the specified item. */
+  gtk_tree_view_get_cell_area (GIMP_CONTAINER_TREE_VIEW (view)->view, path,
+                               gtk_tree_view_get_column (GIMP_CONTAINER_TREE_VIEW (view)->view, 1),
+                               &rect);
+  gimp_widget_blink_rect (GTK_WIDGET (GIMP_CONTAINER_TREE_VIEW (view)->view), &rect);
+
+  gtk_tree_path_free (path);
 }
diff --git a/app/widgets/gimpitemtreeview.c b/app/widgets/gimpitemtreeview.c
index a791812276..47afa19340 100644
--- a/app/widgets/gimpitemtreeview.c
+++ b/app/widgets/gimpitemtreeview.c
@@ -80,6 +80,8 @@ struct _GimpItemTreeViewPrivate
   GtkWidget       *lock_position_toggle;
   GtkWidget       *lock_visibility_toggle;
 
+  GList           *additional_locks;
+
   GtkWidget       *new_button;
   GtkWidget       *raise_button;
   GtkWidget       *lower_button;
@@ -103,6 +105,29 @@ struct _GimpItemTreeViewPrivate
   gboolean         inserting_item; /* EEK */
 };
 
+typedef struct
+{
+  GtkWidget        *toggle;
+  const gchar      *icon_name;
+
+  GimpIsLockedFunc  is_locked;
+  GimpCanLockFunc   can_lock;
+  GimpSetLockFunc   lock;
+
+  const gchar      *tooltip;
+  const gchar      *help_id;
+
+  /* Signal handling when lock is changed from core. */
+  const gchar      *signal_name;
+  GimpTreeHandler  *changed_handler;
+
+  /* Undo types and labels. */
+  GimpUndoType      undo_type;
+  GimpUndoType      group_undo_type;
+  const gchar      *undo_lock_label;
+  const gchar      *undo_unlock_label;
+} LockToggle;
+
 
 static void   gimp_item_tree_view_view_iface_init   (GimpContainerViewInterface *view_iface);
 static void   gimp_item_tree_view_docked_iface_init (GimpDockedInterface *docked_iface);
@@ -191,6 +216,8 @@ static void   gimp_item_tree_view_lock_clicked      (GtkCellRendererToggle *togg
                                                      gchar             *path,
                                                      GdkModifierType    state,
                                                      GimpItemTreeView  *view);
+static void   gimp_item_tree_view_lock_toggled      (GtkWidget         *widget,
+                                                     GimpItemTreeView  *view);
 static void   gimp_item_tree_view_lock_content_toggled
                                                     (GtkWidget         *widget,
                                                      GimpItemTreeView  *view);
@@ -217,6 +244,11 @@ static void   gimp_item_tree_view_row_expanded      (GtkTreeView       *tree_vie
                                                      GtkTreePath       *path,
                                                      GimpItemTreeView  *item_view);
 
+static gint   gimp_item_tree_view_get_n_locks       (GimpItemTreeView *view,
+                                                     GimpItem         *item,
+                                                     const gchar     **icon_name);
+
+
 G_DEFINE_TYPE_WITH_CODE (GimpItemTreeView, gimp_item_tree_view,
                          GIMP_TYPE_CONTAINER_TREE_VIEW,
                          G_ADD_PRIVATE (GimpItemTreeView)
@@ -361,9 +393,9 @@ gimp_item_tree_view_constructed (GObject *object)
   GimpContainerTreeView *tree_view       = GIMP_CONTAINER_TREE_VIEW (object);
   GimpItemTreeView      *item_view       = GIMP_ITEM_TREE_VIEW (object);
   GtkTreeViewColumn     *column;
-  GtkWidget             *hbox;
   GtkWidget             *image;
   GtkIconSize            icon_size;
+  gint                   button_spacing;
 
   G_OBJECT_CLASS (parent_class)->constructed (object);
 
@@ -492,13 +524,18 @@ gimp_item_tree_view_constructed (GObject *object)
                              gtk_widget_get_parent (item_view->priv->multi_selection_label),
                              FALSE, FALSE, 0, GTK_PACK_END);
 
-  hbox = gimp_item_tree_view_get_lock_box (item_view);
+  /* Lock box. */
+  gtk_widget_style_get (GTK_WIDGET (item_view),
+                        "button-spacing", &button_spacing,
+                        NULL);
+
+  item_view->priv->lock_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing);
 
-  /*  Lock content toggle  */
+  /*  Lock box: content toggle  */
   item_view->priv->lock_content_toggle = gtk_toggle_button_new ();
-  gtk_box_pack_start (GTK_BOX (hbox), item_view->priv->lock_content_toggle,
+  gtk_box_pack_start (GTK_BOX (item_view->priv->lock_box), item_view->priv->lock_content_toggle,
                       FALSE, FALSE, 0);
-  gtk_box_reorder_child (GTK_BOX (hbox),
+  gtk_box_reorder_child (GTK_BOX (item_view->priv->lock_box),
                          item_view->priv->lock_content_toggle, 0);
   gtk_widget_show (item_view->priv->lock_content_toggle);
 
@@ -520,11 +557,11 @@ gimp_item_tree_view_constructed (GObject *object)
                      image);
   gtk_widget_show (image);
 
-  /*  Lock position toggle  */
+  /*  Lock box: position toggle  */
   item_view->priv->lock_position_toggle = gtk_toggle_button_new ();
-  gtk_box_pack_start (GTK_BOX (hbox), item_view->priv->lock_position_toggle,
+  gtk_box_pack_start (GTK_BOX (item_view->priv->lock_box), item_view->priv->lock_position_toggle,
                       FALSE, FALSE, 0);
-  gtk_box_reorder_child (GTK_BOX (hbox),
+  gtk_box_reorder_child (GTK_BOX (item_view->priv->lock_box),
                          item_view->priv->lock_position_toggle, 1);
   gtk_widget_show (item_view->priv->lock_position_toggle);
 
@@ -542,11 +579,11 @@ gimp_item_tree_view_constructed (GObject *object)
                      image);
   gtk_widget_show (image);
 
-  /*  Lock visibility toggle  */
+  /*  Lock box: visibility toggle  */
   item_view->priv->lock_visibility_toggle = gtk_toggle_button_new ();
-  gtk_box_pack_start (GTK_BOX (hbox), item_view->priv->lock_visibility_toggle,
+  gtk_box_pack_start (GTK_BOX (item_view->priv->lock_box), item_view->priv->lock_visibility_toggle,
                       FALSE, FALSE, 0);
-  gtk_box_reorder_child (GTK_BOX (hbox),
+  gtk_box_reorder_child (GTK_BOX (item_view->priv->lock_box),
                          item_view->priv->lock_visibility_toggle, 2);
   gtk_widget_show (item_view->priv->lock_visibility_toggle);
 
@@ -567,8 +604,8 @@ gimp_item_tree_view_constructed (GObject *object)
   /* Lock popover. */
   item_view->priv->lock_popover = gtk_popover_new (GTK_WIDGET (tree_view->view));
   gtk_popover_set_modal (GTK_POPOVER (item_view->priv->lock_popover), TRUE);
-  gtk_container_add (GTK_CONTAINER (item_view->priv->lock_popover), hbox);
-  gtk_widget_show (hbox);
+  gtk_container_add (GTK_CONTAINER (item_view->priv->lock_popover), item_view->priv->lock_box);
+  gtk_widget_show (item_view->priv->lock_box);
 }
 
 static void
@@ -585,6 +622,13 @@ gimp_item_tree_view_dispose (GObject *object)
       view->priv->lock_popover = NULL;
     }
 
+  if (view->priv->additional_locks)
+    {
+      g_list_free_full (view->priv->additional_locks,
+                        (GDestroyNotify) g_free);
+      view->priv->additional_locks = NULL;
+    }
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
@@ -803,23 +847,61 @@ gimp_item_tree_view_add_options (GimpItemTreeView *view,
     }
 }
 
-GtkWidget *
-gimp_item_tree_view_get_lock_box (GimpItemTreeView *view)
+void
+gimp_item_tree_view_add_lock (GimpItemTreeView *view,
+                              const gchar      *icon_name,
+                              GimpIsLockedFunc  is_locked,
+                              GimpCanLockFunc   can_lock,
+                              GimpSetLockFunc   lock,
+                              const gchar      *signal_name,
+                              GimpUndoType      undo_type,
+                              GimpUndoType      group_undo_type,
+                              const gchar      *undo_lock_label,
+                              const gchar      *undo_unlock_label,
+                              const gchar      *tooltip,
+                              const gchar      *help_id)
 {
-  g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), NULL);
+  LockToggle  *data;
+  GtkWidget   *toggle = gtk_toggle_button_new ();
+  GtkWidget   *image;
+  GtkIconSize  icon_size;
+
+  data = g_new0 (LockToggle, 1);
+  data->toggle       = toggle;
+  data->icon_name    = icon_name;
+  data->is_locked    = is_locked;
+  data->can_lock     = can_lock;
+  data->lock         = lock;
+  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;
+
+  view->priv->additional_locks = g_list_prepend (view->priv->additional_locks,
+                                                 data);
+
+  gtk_box_pack_end (GTK_BOX (view->priv->lock_box), toggle, FALSE, FALSE, 0);
+  gtk_box_reorder_child (GTK_BOX (view->priv->lock_box), toggle, 0);
+  gtk_widget_show (toggle);
+
+  g_object_set_data (G_OBJECT (toggle), "lock-data", data);
+  g_signal_connect (toggle, "toggled",
+                    G_CALLBACK (gimp_item_tree_view_lock_toggled),
+                    view);
+
+  gimp_help_set_help_data (toggle, tooltip, help_id);
 
-  if (! view->priv->lock_box)
-    {
-      gint button_spacing;
-
-      gtk_widget_style_get (GTK_WIDGET (view),
-                            "button-spacing", &button_spacing,
-                            NULL);
-
-      view->priv->lock_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing);
-    }
+  gtk_widget_style_get (GTK_WIDGET (view),
+                        "button-icon-size", &icon_size,
+                        NULL);
 
-  return view->priv->lock_box;
+  image = gtk_image_new_from_icon_name (icon_name, icon_size);
+  gtk_container_add (GTK_CONTAINER (toggle), image);
+  gtk_widget_show (image);
 }
 
 GtkWidget *
@@ -948,6 +1030,7 @@ gimp_item_tree_view_set_container (GimpContainerView *view,
 {
   GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (view);
   GimpContainer    *old_container;
+  GList            *list;
 
   old_container = gimp_container_view_get_container (view);
 
@@ -967,6 +1050,14 @@ gimp_item_tree_view_set_container (GimpContainerView *view,
 
       gimp_tree_handler_disconnect (item_view->priv->lock_visibility_changed_handler);
       item_view->priv->lock_visibility_changed_handler = NULL;
+
+      for (list = item_view->priv->additional_locks; list; list = list->next)
+        {
+          LockToggle *data = list->data;
+
+          gimp_tree_handler_disconnect (data->changed_handler);
+          data->changed_handler = NULL;
+        }
     }
 
   parent_view_iface->set_container (view, container);
@@ -997,6 +1088,16 @@ gimp_item_tree_view_set_container (GimpContainerView *view,
         gimp_tree_handler_connect (container, "lock-visibility-changed",
                                    G_CALLBACK (gimp_item_tree_view_lock_changed),
                                    view);
+
+      for (list = item_view->priv->additional_locks; list; list = list->next)
+        {
+          LockToggle *data = list->data;
+
+          data->changed_handler = gimp_tree_handler_connect (container,
+                                                             data->signal_name,
+                                                             G_CALLBACK (gimp_item_tree_view_lock_changed),
+                                                             view);
+        }
     }
 }
 
@@ -1041,7 +1142,6 @@ gimp_item_tree_view_insert_item (GimpContainerView *view,
                                  gpointer           parent_insert_data,
                                  gint               index)
 {
-  GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (view);
   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
   GimpItemTreeView      *item_view = GIMP_ITEM_TREE_VIEW (view);
   GimpItem              *item      = GIMP_ITEM (viewable);
@@ -1049,6 +1149,7 @@ gimp_item_tree_view_insert_item (GimpContainerView *view,
   GimpRGB                color;
   gboolean               has_color;
   const gchar           *icon_name = "system-lock-screen";
+  gint                   n_locks;
 
   item_view->priv->inserting_item = TRUE;
 
@@ -1062,14 +1163,7 @@ gimp_item_tree_view_insert_item (GimpContainerView *view,
                                         gimp_item_get_color_tag (item) ==
                                         GIMP_COLOR_TAG_NONE);
 
-  if ((gint) gimp_item_is_content_locked (item)  +
-      (gint) gimp_item_is_position_locked (item) +
-      (gint) gimp_item_is_visibility_locked (item) == 1)
-    icon_name = gimp_item_is_content_locked (item) ?
-      item_view_class->lock_content_icon_name :
-      (gimp_item_is_position_locked (item) ?
-       item_view_class->lock_position_icon_name :
-       item_view_class->lock_visibility_icon_name);
+  n_locks = gimp_item_tree_view_get_n_locks (item_view, item, &icon_name);
 
   gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
 
@@ -1081,9 +1175,7 @@ gimp_item_tree_view_insert_item (GimpContainerView *view,
                       ! gimp_item_is_visible (item),
 
                       item_view->priv->model_column_locked,
-                      gimp_item_is_content_locked (item)  ||
-                      gimp_item_is_position_locked (item) ||
-                      gimp_item_is_visibility_locked (item),
+                      n_locks > 0,
 
                       item_view->priv->model_column_lock_icon,
                       icon_name,
@@ -1748,31 +1840,22 @@ static void
 gimp_item_tree_view_lock_changed (GimpItem         *item,
                                   GimpItemTreeView *view)
 {
-  GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (view);
   GimpContainerView     *container_view  = GIMP_CONTAINER_VIEW (view);
   GimpContainerTreeView *tree_view       = GIMP_CONTAINER_TREE_VIEW (view);
   GtkTreeIter           *iter;
   const gchar           *icon_name       = "system-lock-screen";
+  gint                   n_locks;
 
   iter = gimp_container_view_lookup (container_view,
                                      (GimpViewable *) item);
 
-  if ((gint) gimp_item_is_content_locked (item)  +
-      (gint) gimp_item_is_position_locked (item) +
-      (gint) gimp_item_is_visibility_locked (item) == 1)
-    icon_name = gimp_item_is_content_locked (item) ?
-      item_view_class->lock_content_icon_name :
-      (gimp_item_is_position_locked (item) ?
-       item_view_class->lock_position_icon_name :
-       item_view_class->lock_visibility_icon_name);
+  n_locks = gimp_item_tree_view_get_n_locks (view, item, &icon_name);
 
   if (iter)
     gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
 
                         view->priv->model_column_locked,
-                        gimp_item_is_content_locked (item)  ||
-                        gimp_item_is_position_locked (item) ||
-                        gimp_item_is_visibility_locked (item),
+                        n_locks > 0,
 
                         view->priv->model_column_lock_icon,
                         icon_name,
@@ -1783,6 +1866,52 @@ gimp_item_tree_view_lock_changed (GimpItem         *item,
     gimp_item_tree_view_update_lock_box (view, item);
 }
 
+static void
+gimp_item_tree_view_lock_toggled (GtkWidget         *widget,
+                                  GimpItemTreeView  *view)
+{
+  GimpImage   *image = view->priv->image;
+  LockToggle  *data;
+  GimpUndo    *undo;
+  const gchar *undo_label;
+  gboolean     push_undo = TRUE;
+  gboolean     locked;
+
+  locked = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+  data = g_object_get_data (G_OBJECT (widget), "lock-data");
+
+  if (! data->can_lock (view->priv->lock_box_item) ||
+      locked == data->is_locked (view->priv->lock_box_item))
+    return;
+
+  undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
+                                       data->undo_type);
+
+  if (undo && GIMP_ITEM_UNDO (undo)->item == view->priv->lock_box_item)
+    push_undo = FALSE;
+
+  if (push_undo)
+    {
+      if (locked)
+        undo_label = data->undo_lock_label;
+      else
+        undo_label = data->undo_unlock_label;
+
+      gimp_image_undo_group_start (image, data->group_undo_type,
+                                   undo_label);
+    }
+
+  /* TODO: maybe we should also have a modifier-interaction where we can
+   * lock all same-level items (Shift-click for instance like eye click)
+   * and maybe another modifier for all selected items at once.
+   */
+  data->lock (view->priv->lock_box_item, locked, push_undo);
+
+  gimp_image_flush (image);
+  if (push_undo)
+    gimp_image_undo_group_end (image);
+}
+
 static void
 gimp_item_tree_view_lock_content_toggled (GtkWidget         *widget,
                                           GimpItemTreeView  *view)
@@ -1977,12 +2106,13 @@ static void
 gimp_item_tree_view_update_lock_box (GimpItemTreeView *view,
                                      GimpItem         *item)
 {
-  gboolean have_lock_content;
-  gboolean can_lock_content;
-  gboolean have_lock_position;
-  gboolean can_lock_position;
-  gboolean have_lock_visibility;
-  gboolean can_lock_visibility;
+  GList    *list;
+  gboolean  have_lock_content;
+  gboolean  can_lock_content;
+  gboolean  have_lock_position;
+  gboolean  can_lock_position;
+  gboolean  have_lock_visibility;
+  gboolean  can_lock_visibility;
 
   have_lock_content    = gimp_item_get_lock_content (item);
   can_lock_content     = gimp_item_can_lock_content (item);
@@ -2040,6 +2170,26 @@ gimp_item_tree_view_update_lock_box (GimpItemTreeView *view,
   gtk_widget_set_sensitive (view->priv->lock_position_toggle, can_lock_position);
   gtk_widget_set_sensitive (view->priv->lock_position_toggle, can_lock_visibility);
 
+  for (list = view->priv->additional_locks; list; list = list->next)
+    {
+      LockToggle *data = list->data;
+
+      if (data->is_locked (item) !=
+          gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->toggle)))
+        {
+          g_signal_handlers_block_by_func (data->toggle,
+                                           gimp_item_tree_view_lock_toggled,
+                                           view);
+
+          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->toggle),
+                                        data->is_locked (item));
+
+          g_signal_handlers_unblock_by_func (data->toggle,
+                                             gimp_item_tree_view_lock_toggled,
+                                             view);
+        }
+      gtk_widget_set_sensitive (data->toggle, data->can_lock (item));
+    }
   view->priv->lock_box_item = item;
 }
 
@@ -2081,3 +2231,60 @@ gimp_item_tree_view_row_expanded (GtkTreeView      *tree_view,
         }
     }
 }
+
+
+/*  Helper functions.  */
+
+static gint
+gimp_item_tree_view_get_n_locks (GimpItemTreeView *view,
+                                 GimpItem         *item,
+                                 const gchar     **icon_name)
+{
+  GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (view);
+  GList                 *list;
+  gint                   n_locks;
+
+  *icon_name = "system-lock-screen";
+
+  n_locks = (gint) gimp_item_is_content_locked (item)  +
+    (gint) gimp_item_is_position_locked (item) +
+    (gint) gimp_item_is_visibility_locked (item);
+
+  for (list = view->priv->additional_locks; list; list = list->next)
+    {
+      LockToggle *data = list->data;
+
+      n_locks += (gint) data->is_locked (item);
+    }
+
+  if (n_locks == 1)
+    {
+      if (gimp_item_is_content_locked (item))
+        {
+          *icon_name = item_view_class->lock_content_icon_name;
+        }
+      else if (gimp_item_is_position_locked (item))
+        {
+          *icon_name = item_view_class->lock_position_icon_name;
+        }
+      else if (gimp_item_is_visibility_locked (item))
+        {
+          *icon_name = item_view_class->lock_visibility_icon_name;
+        }
+      else
+        {
+          for (list = view->priv->additional_locks; list; list = list->next)
+            {
+              LockToggle *data = list->data;
+
+              if (data->is_locked (item))
+                {
+                  *icon_name = data->icon_name;
+                  break;
+                }
+            }
+        }
+    }
+
+  return n_locks;
+}
diff --git a/app/widgets/gimpitemtreeview.h b/app/widgets/gimpitemtreeview.h
index 951d6b4b8f..680ac056a3 100644
--- a/app/widgets/gimpitemtreeview.h
+++ b/app/widgets/gimpitemtreeview.h
@@ -44,6 +44,13 @@ typedef void            (* GimpRemoveItemFunc)   (GimpImage *image,
 typedef GimpItem      * (* GimpNewItemFunc)      (GimpImage *image);
 
 
+typedef gboolean        (* GimpIsLockedFunc)     (GimpItem  *item);
+typedef gboolean        (* GimpCanLockFunc)      (GimpItem  *item);
+typedef void            (* GimpSetLockFunc)      (GimpItem  *item,
+                                                  gboolean   lock,
+                                                  gboolean   push_undo);
+
+
 #define GIMP_TYPE_ITEM_TREE_VIEW            (gimp_item_tree_view_get_type ())
 #define GIMP_ITEM_TREE_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ITEM_TREE_VIEW, 
GimpItemTreeView))
 #define GIMP_ITEM_TREE_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ITEM_TREE_VIEW, 
GimpItemTreeViewClass))
@@ -130,7 +137,18 @@ GimpImage * gimp_item_tree_view_get_image         (GimpItemTreeView *view);
 void        gimp_item_tree_view_add_options       (GimpItemTreeView *view,
                                                    const gchar      *label,
                                                    GtkWidget        *options);
-GtkWidget * gimp_item_tree_view_get_lock_box      (GimpItemTreeView *view);
+void        gimp_item_tree_view_add_lock          (GimpItemTreeView *view,
+                                                   const gchar      *icon_name,
+                                                   GimpIsLockedFunc  is_locked,
+                                                   GimpCanLockFunc   can_lock,
+                                                   GimpSetLockFunc   lock,
+                                                   const gchar      *signal_name,
+                                                   GimpUndoType      undo_type,
+                                                   GimpUndoType      group_undo_type,
+                                                   const gchar      *undo_lock_label,
+                                                   const gchar      *undo_unlock_label,
+                                                   const gchar      *tooltip,
+                                                   const gchar      *help_id);
 
 GtkWidget * gimp_item_tree_view_get_new_button    (GimpItemTreeView *view);
 GtkWidget * gimp_item_tree_view_get_delete_button (GimpItemTreeView *view);
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index f53fe33366..ba7fbbf852 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -73,7 +73,6 @@ struct _GimpLayerTreeViewPrivate
 {
   GtkWidget       *layer_mode_box;
   GtkAdjustment   *opacity_adjustment;
-  GtkWidget       *lock_alpha_toggle;
   GtkWidget       *anchor_button;
 
   GtkWidget       *link_button;
@@ -93,7 +92,6 @@ struct _GimpLayerTreeViewPrivate
 
   GimpTreeHandler *mode_changed_handler;
   GimpTreeHandler *opacity_changed_handler;
-  GimpTreeHandler *lock_alpha_changed_handler;
   GimpTreeHandler *mask_changed_handler;
   GimpTreeHandler *alpha_changed_handler;
 };
@@ -169,8 +167,6 @@ static void       gimp_layer_tree_view_layer_mode_box_callback    (GtkWidget
                                                                    GimpLayerTreeView          *view);
 static void       gimp_layer_tree_view_opacity_scale_changed      (GtkAdjustment              *adj,
                                                                    GimpLayerTreeView          *view);
-static void       gimp_layer_tree_view_lock_alpha_button_toggled  (GtkWidget                  *widget,
-                                                                   GimpLayerTreeView          *view);
 static void       gimp_layer_tree_view_layer_signal_handler       (GimpLayer                  *layer,
                                                                    GimpLayerTreeView          *view);
 static void       gimp_layer_tree_view_update_options             (GimpLayerTreeView          *view,
@@ -281,9 +277,6 @@ gimp_layer_tree_view_init (GimpLayerTreeView *view)
 {
   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
   GtkWidget             *scale;
-  GtkWidget             *hbox;
-  GtkWidget             *image;
-  GtkIconSize            icon_size;
   PangoAttribute        *attr;
 
   view->priv = gimp_layer_tree_view_get_instance_private (view);
@@ -330,31 +323,6 @@ gimp_layer_tree_view_init (GimpLayerTreeView *view)
                     G_CALLBACK (gimp_layer_tree_view_opacity_scale_changed),
                     view);
 
-  /*  Lock alpha toggle  */
-
-  hbox = gimp_item_tree_view_get_lock_box (GIMP_ITEM_TREE_VIEW (view));
-
-  view->priv->lock_alpha_toggle = gtk_toggle_button_new ();
-  gtk_box_pack_start (GTK_BOX (hbox), view->priv->lock_alpha_toggle,
-                      FALSE, FALSE, 0);
-  gtk_widget_show (view->priv->lock_alpha_toggle);
-
-  g_signal_connect (view->priv->lock_alpha_toggle, "toggled",
-                    G_CALLBACK (gimp_layer_tree_view_lock_alpha_button_toggled),
-                    view);
-
-  gimp_help_set_help_data (view->priv->lock_alpha_toggle,
-                           _("Lock alpha channel"),
-                           GIMP_HELP_LAYER_LOCK_ALPHA);
-
-  gtk_widget_style_get (GTK_WIDGET (view),
-                        "button-icon-size", &icon_size,
-                        NULL);
-
-  image = gtk_image_new_from_icon_name (GIMP_ICON_TRANSPARENCY, icon_size);
-  gtk_container_add (GTK_CONTAINER (view->priv->lock_alpha_toggle), image);
-  gtk_widget_show (image);
-
   view->priv->italic_attrs = pango_attr_list_new ();
   attr = pango_attr_style_new (PANGO_STYLE_ITALIC);
   attr->start_index = 0;
@@ -555,6 +523,21 @@ gimp_layer_tree_view_constructed (GObject *object)
 
   gtk_container_add (GTK_CONTAINER (layer_view->priv->link_popover), grid);
   gtk_widget_show (grid);
+
+  /*  Lock alpha toggle  */
+
+  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,
+                                "lock-alpha-changed",
+                                GIMP_UNDO_LAYER_LOCK_ALPHA,
+                                GIMP_UNDO_GROUP_LAYER_LOCK_ALPHA,
+                                _("Lock alpha channel"),
+                                _("Unlock alpha channel"),
+                                _("Lock alpha channel"),
+                                GIMP_HELP_LAYER_LOCK_ALPHA);
 }
 
 static void
@@ -597,9 +580,6 @@ gimp_layer_tree_view_set_container (GimpContainerView *view,
       gimp_tree_handler_disconnect (layer_view->priv->opacity_changed_handler);
       layer_view->priv->opacity_changed_handler = NULL;
 
-      gimp_tree_handler_disconnect (layer_view->priv->lock_alpha_changed_handler);
-      layer_view->priv->lock_alpha_changed_handler = NULL;
-
       gimp_tree_handler_disconnect (layer_view->priv->mask_changed_handler);
       layer_view->priv->mask_changed_handler = NULL;
 
@@ -621,11 +601,6 @@ gimp_layer_tree_view_set_container (GimpContainerView *view,
                                    G_CALLBACK (gimp_layer_tree_view_layer_signal_handler),
                                    view);
 
-      layer_view->priv->lock_alpha_changed_handler =
-        gimp_tree_handler_connect (container, "lock-alpha-changed",
-                                   G_CALLBACK (gimp_layer_tree_view_layer_signal_handler),
-                                   view);
-
       layer_view->priv->mask_changed_handler =
         gimp_tree_handler_connect (container, "mask-changed",
                                    G_CALLBACK (gimp_layer_tree_view_mask_changed),
@@ -1478,63 +1453,6 @@ gimp_layer_tree_view_layer_mode_box_callback (GtkWidget         *widget,
     gimp_image_undo_group_end (image);
 }
 
-static void
-gimp_layer_tree_view_lock_alpha_button_toggled (GtkWidget         *widget,
-                                                GimpLayerTreeView *view)
-{
-  GimpImage *image;
-  GList     *layers;
-  GList     *iter;
-  GimpUndo  *undo;
-  gboolean   push_undo = TRUE;
-  gboolean   lock_alpha;
-  gint       n_layers  = 0;
-
-  lock_alpha = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-  image      = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
-  layers     = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_selected_items (image);
-  undo       = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
-                                             GIMP_UNDO_LAYER_LOCK_ALPHA);
-
-  for (iter = layers; iter; iter = iter->next)
-    {
-      if (gimp_layer_can_lock_alpha (iter->data) &&
-          gimp_layer_get_lock_alpha (iter->data) != lock_alpha)
-        {
-          n_layers++;
-
-          if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (iter->data))
-            push_undo = FALSE;
-        }
-    }
-
-  if (n_layers > 1)
-    {
-      /*  Don't compress mode undos with more than 1 layer changed. */
-      push_undo = TRUE;
-
-      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_LOCK_ALPHA,
-                                   lock_alpha ? _("Lock alpha channels") : _("Unlock alpha channels"));
-    }
-
-  for (iter = layers; iter; iter = iter->next)
-    {
-      GimpLayer *layer = iter->data;
-
-      if (gimp_layer_can_lock_alpha (layer) &&
-          gimp_layer_get_lock_alpha (layer) != lock_alpha)
-        {
-          BLOCK();
-          gimp_layer_set_lock_alpha (layer, lock_alpha, push_undo);
-          UNBLOCK();
-        }
-    }
-  gimp_image_flush (image);
-
-  if (n_layers > 1)
-    gimp_image_undo_group_end (image);
-}
-
 static void
 gimp_layer_tree_view_opacity_scale_changed (GtkAdjustment     *adjustment,
                                             GimpLayerTreeView *view)
@@ -1624,23 +1542,12 @@ gimp_layer_tree_view_update_options (GimpLayerTreeView *view,
   GList                *iter;
   GimpLayerMode         mode = GIMP_LAYER_MODE_SEPARATOR;
   GimpLayerModeContext  context = 0;
-  gboolean              all_have_lock_alpha = TRUE;
-  gboolean              some_can_lock_alpha = FALSE;
-  gboolean              inconsistent_lock_alpha = FALSE;
   /*gboolean              inconsistent_opacity    = FALSE;*/
   gboolean              inconsistent_mode       = FALSE;
   gdouble               opacity = -1.0;
 
   for (iter = layers; iter; iter = iter->next)
     {
-      if (! gimp_layer_get_lock_alpha (iter->data))
-        all_have_lock_alpha = FALSE;
-      else
-        inconsistent_lock_alpha = TRUE;
-
-      if (gimp_layer_can_lock_alpha (iter->data))
-        some_can_lock_alpha = TRUE;
-
 #if 0
       if (opacity != -1.0 &&
           opacity != gimp_layer_get_opacity (iter->data))
@@ -1672,8 +1579,6 @@ gimp_layer_tree_view_update_options (GimpLayerTreeView *view,
   if (! context)
     context = GIMP_LAYER_MODE_CONTEXT_LAYER;
 
-  inconsistent_lock_alpha = (! all_have_lock_alpha && inconsistent_lock_alpha);
-
   BLOCK (view->priv->layer_mode_box,
          gimp_layer_tree_view_layer_mode_box_callback);
 
@@ -1685,23 +1590,6 @@ gimp_layer_tree_view_update_options (GimpLayerTreeView *view,
   UNBLOCK (view->priv->layer_mode_box,
            gimp_layer_tree_view_layer_mode_box_callback);
 
-  if (all_have_lock_alpha !=
-      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->priv->lock_alpha_toggle)))
-    {
-      BLOCK (view->priv->lock_alpha_toggle,
-             gimp_layer_tree_view_lock_alpha_button_toggled);
-
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->lock_alpha_toggle),
-                                    all_have_lock_alpha);
-
-      UNBLOCK (view->priv->lock_alpha_toggle,
-               gimp_layer_tree_view_lock_alpha_button_toggled);
-    }
-  gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (view->priv->lock_alpha_toggle),
-                                      inconsistent_lock_alpha);
-
-  gtk_widget_set_sensitive (view->priv->lock_alpha_toggle, some_can_lock_alpha);
-
   if (opacity * 100.0 !=
       gtk_adjustment_get_value (view->priv->opacity_adjustment))
     {


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