[gimp] Bug 589010 - Don't make Alt-Clicked layers active



commit 706900c4f6e9d669b7c8be2065decf49a9898620
Author: Martin Nordholts <martinn src gnome org>
Date:   Sun Jun 27 21:44:29 2010 +0200

    Bug 589010 - Don't make Alt-Clicked layers active
    
    Add a "pre-clicked" signal to GimpCellRendererViewable that can
    prevent a selection from happening. Move the Alt-Click code in
    GimpLayerTreeView to this signal and if a layer is Alt-Clicked, don't
    go ahead and make the layer active. Also add a test for this use case.

 app/core/gimpmarshal.list              |    1 +
 app/tests/test-ui.c                    |   61 ++++++++++----
 app/widgets/gimpcellrendererviewable.c |   53 ++++++++++++
 app/widgets/gimpcellrendererviewable.h |   22 +++--
 app/widgets/gimpcontainertreeview.c    |   13 +++-
 app/widgets/gimplayertreeview.c        |  138 +++++++++++++++++++-------------
 6 files changed, 206 insertions(+), 82 deletions(-)
---
diff --git a/app/core/gimpmarshal.list b/app/core/gimpmarshal.list
index 7f97ddb..104cfa1 100644
--- a/app/core/gimpmarshal.list
+++ b/app/core/gimpmarshal.list
@@ -27,6 +27,7 @@ BOOLEAN: ENUM, INT
 BOOLEAN: OBJECT, POINTER
 BOOLEAN: OBJECT, POINTER, STRING
 BOOLEAN: STRING
+BOOLEAN: STRING, FLAGS
 
 VOID: BOOLEAN
 VOID: BOOLEAN, INT, INT, INT, INT
diff --git a/app/tests/test-ui.c b/app/tests/test-ui.c
index 9a4259b..bdd2bc2 100644
--- a/app/tests/test-ui.c
+++ b/app/tests/test-ui.c
@@ -358,7 +358,8 @@ keyboard_zoom_focus (GimpTestFixture *fixture,
  * @data:
  *
  * Makes sure that we can alt-click on a layer to do
- * layer-to-selection.
+ * layer-to-selection. Also makes sure that the layer clicked on is
+ * not set as the active layer.
  **/
 static void
 alt_click_is_layer_to_selection (GimpTestFixture *fixture,
@@ -367,46 +368,74 @@ alt_click_is_layer_to_selection (GimpTestFixture *fixture,
   Gimp        *gimp      = GIMP (data);
   GimpImage   *image     = GIMP_IMAGE (gimp_get_image_iter (gimp)->data);
   GimpChannel *selection = gimp_image_get_mask (image);
+  GimpLayer   *active_layer;
   GtkWidget   *dockable;
   GtkWidget   *gtk_tree_view;
   gint         assumed_layer_x;
-  gint         assumed_layer_y;
+  gint         assumed_empty_layer_y;
+  gint         assumed_background_layer_y;
 
-  /* Hardcode an assumption of where the layer is in the
+  /* Hardcode assumptions of where the layers are in the
    * GtkTreeView. Doesn't feel worth adding proper API for this. One
    * can just use GIMP_PAUSE and re-measure new coordinates if we
    * start to layout layers in the GtkTreeView differently
    */
-  assumed_layer_x = 96;
-  assumed_layer_y = 42;
+  assumed_layer_x            = 96;
+  assumed_empty_layer_y      = 16;
+  assumed_background_layer_y = 42;
 
-  /* First make sure there is no selection */
-  g_assert (! gimp_channel_bounds (selection,
-                                   NULL, NULL, /*x1, y1*/
-                                   NULL, NULL  /*x2, y2*/));
+  /* Store the active layer, it shall not change during the execution
+   * of this test
+   */
+  active_layer = gimp_image_get_active_layer (image);
 
-  /* Now simulate alt-click on a layer after finding the GtkTreeView
-   * that shows layers. Note that there is a potential problem with
-   * gtk_test_find_widget and GtkNotebook: it will return e.g. a
-   * GtkTreeView from another page if that page is "on top" of the
-   * reference label.
+  /* Find the layer tree view to click in. Note that there is a
+   * potential problem with gtk_test_find_widget and GtkNotebook: it
+   * will return e.g. a GtkTreeView from another page if that page is
+   * "on top" of the reference label.
    */
   dockable = gimp_ui_find_window (gimp_dialog_factory_get_singleton (),
                                   gimp_ui_is_gimp_layer_list);
   gtk_tree_view = gtk_test_find_widget (dockable,
                                         "Lock:",
                                         GTK_TYPE_TREE_VIEW);
+  
+  /* First make sure there is no selection */
+  g_assert (! gimp_channel_bounds (selection,
+                                   NULL, NULL, /*x1, y1*/
+                                   NULL, NULL  /*x2, y2*/));
+
+  /* Now simulate alt-click on the background layer */
   g_assert (gimp_ui_synthesize_click (gtk_tree_view,
                                       assumed_layer_x,
-                                      assumed_layer_y,
+                                      assumed_background_layer_y,
                                       1 /*button*/,
                                       GDK_MOD1_MASK));
   gimp_test_run_mainloop_until_idle ();
 
-  /* Make sure we got a selection */
+  /* Make sure we got a selection and that the active layer didn't
+   * change
+   */
   g_assert (gimp_channel_bounds (selection,
                                  NULL, NULL, /*x1, y1*/
                                  NULL, NULL  /*x2, y2*/));
+  g_assert (gimp_image_get_active_layer (image) == active_layer);
+
+  /* Now simulate alt-click on the empty layer */
+  g_assert (gimp_ui_synthesize_click (gtk_tree_view,
+                                      assumed_layer_x,
+                                      assumed_empty_layer_y,
+                                      1 /*button*/,
+                                      GDK_MOD1_MASK));
+  gimp_test_run_mainloop_until_idle ();
+
+  /* Make sure that emptied the selection and that the active layer
+   * still didn't change
+   */
+  g_assert (! gimp_channel_bounds (selection,
+                                   NULL, NULL, /*x1, y1*/
+                                   NULL, NULL  /*x2, y2*/));
+  g_assert (gimp_image_get_active_layer (image) == active_layer);
 }
 
 static void
diff --git a/app/widgets/gimpcellrendererviewable.c b/app/widgets/gimpcellrendererviewable.c
index 1f74a62..67e8e24 100644
--- a/app/widgets/gimpcellrendererviewable.c
+++ b/app/widgets/gimpcellrendererviewable.c
@@ -34,6 +34,7 @@
 
 enum
 {
+  PRE_CLICKED,
   CLICKED,
   LAST_SIGNAL
 };
@@ -91,6 +92,39 @@ gimp_cell_renderer_viewable_class_init (GimpCellRendererViewableClass *klass)
   GObjectClass         *object_class = G_OBJECT_CLASS (klass);
   GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS (klass);
 
+  /**
+   * GimpCellRendererViewable::pre-clicked:
+   * @cell:
+   * @path:
+   * @state:
+   *
+   * Called early on a viewable cell when it is clicked, typically
+   * before selection code is invoked for example.
+   *
+   * Returns: %TRUE if the signal handled the event and event
+   *          propagation should stop, for example preventing a
+   *          selection from happening, %FALSE to continue as normal
+   **/
+  viewable_cell_signals[PRE_CLICKED] =
+    g_signal_new ("pre-clicked",
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GimpCellRendererViewableClass, pre_clicked),
+                  g_signal_accumulator_true_handled, NULL,
+                  gimp_marshal_BOOLEAN__STRING_FLAGS,
+                  G_TYPE_BOOLEAN, 2,
+                  G_TYPE_STRING,
+                  GDK_TYPE_MODIFIER_TYPE);
+
+  /**
+   * GimpCellRendererViewable::clicked:
+   * @cell:
+   * @path:
+   * @state:
+   *
+   * Called late on a viewable cell when it is clicked, typically
+   * after selection code has been invoked for example.
+   **/
   viewable_cell_signals[CLICKED] =
     g_signal_new ("clicked",
                   G_OBJECT_CLASS_TYPE (object_class),
@@ -315,6 +349,25 @@ gimp_cell_renderer_viewable_new (void)
   return g_object_new (GIMP_TYPE_CELL_RENDERER_VIEWABLE, NULL);
 }
 
+gboolean
+gimp_cell_renderer_viewable_pre_clicked (GimpCellRendererViewable *cell,
+                                         const gchar              *path,
+                                         GdkModifierType           state)
+{
+  gboolean handled = FALSE;
+
+  g_return_val_if_fail (GIMP_IS_CELL_RENDERER_VIEWABLE (cell), FALSE);
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  g_signal_emit (cell,
+                 viewable_cell_signals[PRE_CLICKED],
+                 0 /*detail*/,
+                 path, state,
+                 &handled);
+
+  return handled;
+}
+
 void
 gimp_cell_renderer_viewable_clicked (GimpCellRendererViewable *cell,
                                      const gchar              *path,
diff --git a/app/widgets/gimpcellrendererviewable.h b/app/widgets/gimpcellrendererviewable.h
index 0d9b37d..5f43579 100644
--- a/app/widgets/gimpcellrendererviewable.h
+++ b/app/widgets/gimpcellrendererviewable.h
@@ -43,17 +43,23 @@ struct _GimpCellRendererViewableClass
 {
   GtkCellRendererClass  parent_class;
 
-  void (* clicked) (GimpCellRendererViewable *cell,
-                    const gchar              *path,
-                    GdkModifierType           state);
+  gboolean (* pre_clicked) (GimpCellRendererViewable *cell,
+                            const gchar              *path,
+                            GdkModifierType           state);
+  void     (* clicked)     (GimpCellRendererViewable *cell,
+                            const gchar              *path,
+                            GdkModifierType           state);
 };
 
 
-GType             gimp_cell_renderer_viewable_get_type   (void) G_GNUC_CONST;
-GtkCellRenderer * gimp_cell_renderer_viewable_new        (void);
-void              gimp_cell_renderer_viewable_clicked    (GimpCellRendererViewable *cell,
-                                                          const gchar              *path,
-                                                          GdkModifierType           state);
+GType             gimp_cell_renderer_viewable_get_type    (void) G_GNUC_CONST;
+GtkCellRenderer * gimp_cell_renderer_viewable_new         (void);
+gboolean          gimp_cell_renderer_viewable_pre_clicked (GimpCellRendererViewable *cell,
+                                                           const gchar              *path,
+                                                           GdkModifierType           state);
+void              gimp_cell_renderer_viewable_clicked     (GimpCellRendererViewable *cell,
+                                                           const gchar              *path,
+                                                           GdkModifierType           state);
 
 
 #endif /* __GIMP_CELL_RENDERER_VIEWABLE_H__ */
diff --git a/app/widgets/gimpcontainertreeview.c b/app/widgets/gimpcontainertreeview.c
index 30c50b3..1920b11 100644
--- a/app/widgets/gimpcontainertreeview.c
+++ b/app/widgets/gimpcontainertreeview.c
@@ -950,16 +950,25 @@ gimp_container_tree_view_button_press (GtkWidget             *widget,
               /*  don't select item if a toggle was clicked */
               if (! toggled_cell)
                 {
-                  if (multisel_mode)
+                  gchar *path_str = gtk_tree_path_to_string (path);
+
+                  handled =
+                    gimp_cell_renderer_viewable_pre_clicked (clicked_cell,
+                                                             path_str,
+                                                             bevent->state);
+
+                  if (! handled && multisel_mode)
                     {
                       /* let parent do the work */
                       handled = FALSE;
                     }
-                  else
+                  else if (! handled)
                     {
                       handled = gimp_container_view_item_selected (container_view,
                                                                    renderer->viewable);
                     }
+
+                  g_free (path_str);
                 }
 
               /*  a callback invoked by selecting the item may have
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index 9591c7b..2e2a26e 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -152,6 +152,10 @@ static void       gimp_layer_tree_view_update_borders             (GimpLayerTree
                                                                    GtkTreeIter                *iter);
 static void       gimp_layer_tree_view_mask_callback              (GimpLayerMask              *mask,
                                                                    GimpLayerTreeView          *view);
+static gboolean   gimp_layer_tree_view_layer_pre_clicked          (GimpCellRendererViewable   *cell,
+                                                                   const gchar                *path_str,
+                                                                   GdkModifierType             state,
+                                                                   GimpLayerTreeView          *layer_view);
 static void       gimp_layer_tree_view_layer_clicked              (GimpCellRendererViewable   *cell,
                                                                    const gchar                *path,
                                                                    GdkModifierType             state,
@@ -363,6 +367,9 @@ gimp_layer_tree_view_constructor (GType                  type,
   gimp_container_tree_view_add_renderer_cell (tree_view,
                                               layer_view->priv->mask_cell);
 
+  g_signal_connect (tree_view->renderer_cell, "pre-clicked",
+                    G_CALLBACK (gimp_layer_tree_view_layer_pre_clicked),
+                    layer_view);
   g_signal_connect (tree_view->renderer_cell, "clicked",
                     G_CALLBACK (gimp_layer_tree_view_layer_clicked),
                     layer_view);
@@ -1300,6 +1307,69 @@ gimp_layer_tree_view_mask_callback (GimpLayerMask     *mask,
   gimp_layer_tree_view_update_borders (layer_view, iter);
 }
 
+static gboolean
+gimp_layer_tree_view_layer_pre_clicked (GimpCellRendererViewable   *cell,
+                                        const gchar                *path_str,
+                                        GdkModifierType             state,
+                                        GimpLayerTreeView          *layer_view)
+{
+  GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+  GtkTreePath           *path;
+  GtkTreeIter            iter;
+  gboolean               handled = FALSE;
+
+  path = gtk_tree_path_new_from_string (path_str);
+
+  if (gtk_tree_model_get_iter (tree_view->model, &iter, path) &&
+      state & GDK_MOD1_MASK)
+    {
+      GimpItemTreeView *item_view      = GIMP_ITEM_TREE_VIEW (tree_view);
+      GimpImage        *image          = gimp_item_tree_view_get_image (item_view);
+      GimpViewRenderer *layer_renderer = NULL;
+      GimpDrawable     *layer          = NULL;
+      GimpChannelOps    op;
+
+      gtk_tree_model_get (tree_view->model, &iter,
+                          GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &layer_renderer,
+                          -1);
+
+      if (layer_renderer)
+        layer = GIMP_DRAWABLE (layer_renderer->viewable);
+
+      op = GIMP_CHANNEL_OP_REPLACE;
+
+      if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
+        {
+          op = GIMP_CHANNEL_OP_INTERSECT;
+        }
+      else if (state & GDK_SHIFT_MASK)
+        {
+          op = GIMP_CHANNEL_OP_ADD;
+        }
+      else if (state & GDK_CONTROL_MASK)
+        {
+          op = GIMP_CHANNEL_OP_SUBTRACT;
+        }
+
+      gimp_channel_select_alpha (gimp_image_get_mask (image),
+                                 layer,
+                                 op,
+                                 FALSE /*feather*/,
+                                 0.0, 0.0 /*feather_radius_x,y*/);
+      gimp_image_flush (image);
+
+      if (layer_renderer)
+        g_object_unref (layer_renderer);
+
+      /* Don't select the clicked layer */
+      handled = TRUE;
+    }
+
+  gtk_tree_path_free (path);
+
+  return handled;
+}
+
 static void
 gimp_layer_tree_view_layer_clicked (GimpCellRendererViewable *cell,
                                     const gchar              *path_str,
@@ -1314,69 +1384,25 @@ gimp_layer_tree_view_layer_clicked (GimpCellRendererViewable *cell,
 
   if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
     {
-      GimpUIManager   *ui_manager = GIMP_EDITOR (tree_view)->ui_manager;
-      GimpActionGroup *group;
+      GimpUIManager    *ui_manager = GIMP_EDITOR (tree_view)->ui_manager;
+      GimpActionGroup  *group;
+      GimpViewRenderer *renderer;
 
       group = gimp_ui_manager_get_action_group (ui_manager, "layers");
 
-      if (state & GDK_MOD1_MASK)
-        {
-          GimpItemTreeView *item_view      = GIMP_ITEM_TREE_VIEW (tree_view);
-          GimpImage        *image          = gimp_item_tree_view_get_image (item_view);
-          GimpViewRenderer *layer_renderer = NULL;
-          GimpDrawable     *layer          = NULL;
-          GimpChannelOps    op;
-
-          gtk_tree_model_get (tree_view->model, &iter,
-                              GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &layer_renderer,
-                              -1);
-
-          if (layer_renderer)
-            layer = GIMP_DRAWABLE (layer_renderer->viewable);
-
-          op = GIMP_CHANNEL_OP_REPLACE;
-
-          if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
-            {
-              op = GIMP_CHANNEL_OP_INTERSECT;
-            }
-          else if (state & GDK_SHIFT_MASK)
-            {
-              op = GIMP_CHANNEL_OP_ADD;
-            }
-          else if (state & GDK_CONTROL_MASK)
-            {
-              op = GIMP_CHANNEL_OP_SUBTRACT;
-            }
-
-          gimp_channel_select_alpha (gimp_image_get_mask (image),
-                                     layer,
-                                     op,
-                                     FALSE /*feather*/,
-                                     0.0, 0.0 /*feather_radius_x,y*/);
-          gimp_image_flush (image);
+      gtk_tree_model_get (tree_view->model, &iter,
+                          layer_view->priv->model_column_mask, &renderer,
+                          -1);
 
-          if (layer_renderer)
-            g_object_unref (layer_renderer);
-        }
-      else
+      if (renderer)
         {
-          GimpViewRenderer *renderer;
-
-          gtk_tree_model_get (tree_view->model, &iter,
-                              layer_view->priv->model_column_mask, &renderer,
-                              -1);
-
-          if (renderer)
-            {
-              GimpLayerMask *mask = GIMP_LAYER_MASK (renderer->viewable);
+          GimpLayerMask *mask = GIMP_LAYER_MASK (renderer->viewable);
 
-              if (gimp_layer_mask_get_edit (mask))
-                gimp_action_group_set_action_active (group,
-                                                     "layers-mask-edit", FALSE);
+          if (gimp_layer_mask_get_edit (mask))
+            gimp_action_group_set_action_active (group,
+                                                 "layers-mask-edit", FALSE);
 
-              g_object_unref (renderer);
-            }
+          g_object_unref (renderer);
         }
     }
 



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