[gimp/wip/Jehan/layers-dockable-refresh: 16/87] app: add logical operations on layer sets.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/Jehan/layers-dockable-refresh: 16/87] app: add logical operations on layer sets.
- Date: Mon, 15 Nov 2021 01:38:08 +0000 (UTC)
commit d7e26365011ad7b5ddaacaaac2976c13ca698c33
Author: Jehan <jehan girinstud io>
Date: Thu Feb 4 21:26:34 2021 +0100
app: add logical operations on layer sets.
app/core/gimpimage.c | 96 +++++++++++++++++++++++++++++++++++++++++
app/core/gimpimage.h | 4 ++
app/widgets/gimplayertreeview.c | 67 +++++++++++++++++++---------
3 files changed, 147 insertions(+), 20 deletions(-)
---
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index b5f147ec40..07cca851a1 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -5507,6 +5507,102 @@ gimp_image_add_linked_layers (GimpImage *image,
g_list_free (layers);
}
+/*
+ * @gimp_image_remove_linked_layers:
+ * @image:
+ * @link_name:
+ *
+ * Remove the layers belonging to the set named @link_name (which must
+ * exist) from the layers currently selected in @image.
+ *
+ * Returns: %TRUE if the selection change is done (even if it turned out
+ * selected layers stay the same), %FALSE if no sets with this
+ * name existed.
+ */
+void
+gimp_image_remove_linked_layers (GimpImage *image,
+ const gchar *link_name)
+{
+ GimpImagePrivate *private;
+ GList *linked;
+ GList *layers;
+ GList *iter;
+
+ g_return_if_fail (GIMP_IS_IMAGE (image));
+ g_return_if_fail (link_name != NULL);
+
+ private = GIMP_IMAGE_GET_PRIVATE (image);
+
+ linked = g_hash_table_lookup (private->linked_layers,
+ link_name);
+
+ g_return_if_fail (linked);
+
+ layers = gimp_image_get_selected_layers (image);
+ layers = g_list_copy (layers);
+ for (iter = linked; iter; iter = iter->next)
+ {
+ GList *remove;
+
+ if ((remove = g_list_find (layers, iter->data)))
+ layers = g_list_delete_link (layers, remove);
+ }
+
+ gimp_image_set_selected_layers (image, layers);
+ g_list_free (layers);
+}
+
+/*
+ * @gimp_image_intersect_linked_layers:
+ * @image:
+ * @link_name:
+ *
+ * Remove any layers from the layers currently selected in @image if
+ * they don't also belong to the set named @link_name (which must
+ * exist).
+ *
+ * Returns: %TRUE if the selection change is done (even if it turned out
+ * selected layers stay the same), %FALSE if no sets with this
+ * name existed.
+ */
+void
+gimp_image_intersect_linked_layers (GimpImage *image,
+ const gchar *link_name)
+{
+ GimpImagePrivate *private;
+ GList *linked;
+ GList *layers;
+ GList *remove = NULL;
+ GList *iter;
+
+ g_return_if_fail (GIMP_IS_IMAGE (image));
+ g_return_if_fail (link_name != NULL);
+
+ private = GIMP_IMAGE_GET_PRIVATE (image);
+
+ linked = g_hash_table_lookup (private->linked_layers,
+ link_name);
+
+ g_return_if_fail (linked);
+
+ layers = gimp_image_get_selected_layers (image);
+ layers = g_list_copy (layers);
+
+ /* Remove items in layers but not in linked. */
+ for (iter = layers; iter; iter = iter->next)
+ {
+ if (! g_list_find (linked, iter->data))
+ remove = g_list_prepend (remove, iter);
+ }
+ for (iter = remove; iter; iter = iter->next)
+ layers = g_list_delete_link (layers, iter->data);
+ g_list_free (remove);
+
+ /* Finally select the intersection. */
+ gimp_image_set_selected_layers (image, layers);
+ g_list_free (layers);
+}
+
/*
* @gimp_image_get_linked_layer_names:
* @image:
diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h
index 42406f9191..07eabcdcd3 100644
--- a/app/core/gimpimage.h
+++ b/app/core/gimpimage.h
@@ -461,6 +461,10 @@ void gimp_image_select_linked_layers (GimpImage *image,
const gchar *link_name);
void gimp_image_add_linked_layers (GimpImage *image,
const gchar *link_name);
+void gimp_image_remove_linked_layers (GimpImage *image,
+ const gchar *link_name);
+void gimp_image_intersect_linked_layers (GimpImage *image,
+ const gchar *link_name);
GList * gimp_image_get_linked_layer_names (GimpImage *image);
gboolean gimp_image_add_channel (GimpImage *image,
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index 91b550f1b7..5ccbb65b59 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -148,8 +148,8 @@ static void gimp_layer_tree_view_floating_selection_changed (GimpImage
static void gimp_layer_tree_view_layer_links_changed (GimpImage *image,
GimpLayerTreeView *view);
-static void gimp_layer_tree_view_link_activated (GtkListBox *list,
- GtkListBoxRow *row,
+static gboolean gimp_layer_tree_view_link_clicked (GtkWidget *box,
+ GdkEvent *event,
GimpLayerTreeView *view);
static void gimp_layer_tree_view_new_link_clicked (GtkButton *button,
GimpLayerTreeView *view);
@@ -483,10 +483,6 @@ gimp_layer_tree_view_constructed (GObject *object)
gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (layer_view->priv->link_list),
TRUE);
- g_signal_connect (layer_view->priv->link_list,
- "row-activated",
- G_CALLBACK (gimp_layer_tree_view_link_activated),
- layer_view);
/* Link popover: new links. */
@@ -1138,8 +1134,6 @@ gimp_layer_tree_view_layer_links_changed (GimpImage *image,
grid = gtk_grid_new ();
label = gtk_label_new (iter->data);
- g_object_set_data (G_OBJECT (grid), "link-name",
- (gpointer) gtk_label_get_text (GTK_LABEL (label)));
gtk_widget_set_hexpand (GTK_WIDGET (label), TRUE);
gtk_widget_set_halign (GTK_WIDGET (label), GTK_ALIGN_START);
gtk_size_group_add_widget (label_size, label);
@@ -1167,7 +1161,27 @@ gimp_layer_tree_view_layer_links_changed (GimpImage *image,
gtk_container_add (GTK_CONTAINER (event_box), icon);
gtk_widget_show (icon);
- gtk_list_box_prepend (GTK_LIST_BOX (view->priv->link_list), grid);
+ /* Now using again an event box on the whole grid, but behind its
+ * child (so that the delete button is processed first. I do it
+ * this way instead of using the "row-activated" of GtkListBox
+ * because this signal does not give us event info, and in
+ * particular modifier state. Yet I want to be able to process
+ * Shift/Ctrl state for logical operations on layer sets.
+ */
+ event_box = gtk_event_box_new ();
+ gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), FALSE);
+ gtk_widget_add_events (event_box, GDK_BUTTON_RELEASE_MASK);
+ g_object_set_data (G_OBJECT (event_box), "link-name",
+ (gpointer) gtk_label_get_text (GTK_LABEL (label)));
+ gtk_container_add (GTK_CONTAINER (event_box), grid);
+ gtk_list_box_prepend (GTK_LIST_BOX (view->priv->link_list), event_box);
+ gtk_widget_show (event_box);
+
+ g_signal_connect (event_box,
+ "button-release-event",
+ G_CALLBACK (gimp_layer_tree_view_link_clicked),
+ view);
+
gtk_widget_show (grid);
}
g_object_unref (label_size);
@@ -1176,22 +1190,35 @@ gimp_layer_tree_view_layer_links_changed (GimpImage *image,
g_list_free (links);
}
-static void
-gimp_layer_tree_view_link_activated (GtkListBox *list,
- GtkListBoxRow *row,
- GimpLayerTreeView *view)
+static gboolean
+gimp_layer_tree_view_link_clicked (GtkWidget *box,
+ GdkEvent *event,
+ GimpLayerTreeView *view)
{
- GimpImage *image;
- GtkWidget *grid;
+ GimpImage *image;
+ GdkEventButton *bevent = (GdkEventButton *) event;
+ GdkModifierType modifiers;
image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
- grid = gtk_bin_get_child (GTK_BIN (row));
- g_return_if_fail (GIMP_IS_IMAGE (image));
- g_return_if_fail (GTK_IS_GRID (grid));
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+ g_return_val_if_fail (GTK_IS_EVENT_BOX (box), FALSE);
+
+ modifiers = bevent->state & gimp_get_all_modifiers_mask ();
+ if (modifiers == GDK_SHIFT_MASK)
+ gimp_image_add_linked_layers (image,
+ g_object_get_data (G_OBJECT (box), "link-name"));
+ else if (modifiers == GDK_CONTROL_MASK)
+ gimp_image_remove_linked_layers (image,
+ g_object_get_data (G_OBJECT (box), "link-name"));
+ else if (modifiers == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
+ gimp_image_intersect_linked_layers (image,
+ g_object_get_data (G_OBJECT (box), "link-name"));
+ else
+ gimp_image_select_linked_layers (image,
+ g_object_get_data (G_OBJECT (box), "link-name"));
- gimp_image_select_linked_layers (image,
- g_object_get_data (G_OBJECT (grid), "link-name"));
+ return FALSE;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]