[gimp/wip/Jehan/layers-dockable-refresh: 26/105] app: add layer selection by regular expression.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/Jehan/layers-dockable-refresh: 26/105] app: add layer selection by regular expression.
- Date: Thu, 23 Dec 2021 00:44:30 +0000 (UTC)
commit 3702a7bb87176957ffd0932f9380e9a3ba1c49f6
Author: Jehan <jehan girinstud io>
Date: Sat Feb 6 16:10:22 2021 +0100
app: add layer selection by regular expression.
I am unsure if regular expression is the right choice as it may
obviously be a bit too technical. I hesitated with glob-type match for a
while. We'll see!
app/core/gimpimage.c | 54 ++++++++++++++++++++++++
app/core/gimpimage.h | 3 ++
app/widgets/gimplayertreeview.c | 91 +++++++++++++++++++++++++++++++++++++++--
3 files changed, 145 insertions(+), 3 deletions(-)
---
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 07cca851a1..d2795c21f6 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -5464,6 +5464,60 @@ gimp_image_select_linked_layers (GimpImage *image,
gimp_image_set_selected_layers (image, linked);
}
+/*
+ * @gimp_image_select_layers_by_regexp:
+ * @image:
+ * @pattern:
+ * @error:
+ *
+ * Replace currently selected layers in @image with the layers whose
+ * names match with the @pattern regular expression.
+ *
+ * Returns: %TRUE if some layers matched @pattern (even if it turned out
+ * selected layers stay the same), %FALSE otherwise or if
+ * @pattern is an invalid regular expression (in which case,
+ * @error will be filled with the appropriate error).
+ */
+gboolean
+gimp_image_select_layers_by_regexp (GimpImage *image,
+ const gchar *pattern,
+ GError **error)
+{
+ GList *layers;
+ GList *match = NULL;
+ GList *iter;
+ GRegex *regex;
+ gboolean matched;
+
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+ g_return_val_if_fail (pattern != NULL, FALSE);
+
+ regex = g_regex_new (pattern, 0, 0, error);
+
+ if (regex == NULL)
+ {
+ return FALSE;
+ }
+
+ layers = gimp_image_get_layer_list (image);
+
+ for (iter = layers; iter; iter = iter->next)
+ {
+ if (g_regex_match (regex,
+ gimp_object_get_name (iter->data),
+ 0, NULL))
+ match = g_list_prepend (match, iter->data);
+ }
+
+ gimp_image_set_selected_layers (image, match);
+ matched = (match != NULL);
+
+ g_list_free (match);
+ g_regex_unref (regex);
+
+ return matched;
+}
+
/*
* @gimp_image_add_linked_layers:
* @image:
diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h
index 07eabcdcd3..d45e9bfeb5 100644
--- a/app/core/gimpimage.h
+++ b/app/core/gimpimage.h
@@ -459,6 +459,9 @@ gboolean gimp_image_unlink_layers (GimpImage *image,
const gchar *link_name);
void gimp_image_select_linked_layers (GimpImage *image,
const gchar *link_name);
+gboolean gimp_image_select_layers_by_regexp (GimpImage *image,
+ const gchar *pattern,
+ GError **error);
void gimp_image_add_linked_layers (GimpImage *image,
const gchar *link_name);
void gimp_image_remove_linked_layers (GimpImage *image,
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
index 5ccbb65b59..650ad50bfd 100644
--- a/app/widgets/gimplayertreeview.c
+++ b/app/widgets/gimplayertreeview.c
@@ -78,6 +78,7 @@ struct _GimpLayerTreeViewPrivate
GtkWidget *link_button;
GtkWidget *link_list;
GtkWidget *link_entry;
+ GtkWidget *link_regexp_entry;
gint model_column_mask;
gint model_column_mask_visible;
@@ -151,6 +152,9 @@ static void gimp_layer_tree_view_layer_links_changed (GimpImage
static gboolean gimp_layer_tree_view_link_clicked (GtkWidget *box,
GdkEvent *event,
GimpLayerTreeView *view);
+static void gimp_layer_tree_view_regexp_modified (GtkEntry *entry,
+ const GParamSpec *pspec,
+ GimpLayerTreeView *view);
static void gimp_layer_tree_view_new_link_clicked (GtkButton *button,
GimpLayerTreeView *view);
static gboolean gimp_layer_tree_view_unlink_clicked (GtkWidget *widget,
@@ -474,11 +478,36 @@ gimp_layer_tree_view_constructed (GObject *object)
grid = gtk_grid_new ();
+ /* Link popover: regexp search. */
+ layer_view->priv->link_regexp_entry = gtk_entry_new ();
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (layer_view->priv->link_regexp_entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ "system-search");
+ gtk_entry_set_placeholder_text (GTK_ENTRY (layer_view->priv->link_regexp_entry),
+ _("Regular Expression search"));
+ gtk_grid_attach (GTK_GRID (grid),
+ layer_view->priv->link_regexp_entry,
+ 0, 0, 2, 1);
+ gtk_widget_show (layer_view->priv->link_regexp_entry);
+ g_signal_connect (layer_view->priv->link_regexp_entry,
+ "notify::text",
+ G_CALLBACK (gimp_layer_tree_view_regexp_modified),
+ layer_view);
+
+ /* Enter on regexp entry closes the popover dialog. This allows to use
+ * the feature for quick name-based layer selection, not for actually
+ * storing the selected items.
+ */
+ g_signal_connect_swapped (layer_view->priv->link_regexp_entry,
+ "activate",
+ G_CALLBACK (gtk_popover_popdown),
+ popover);
+
/* Link popover: existing links. */
layer_view->priv->link_list = gtk_list_box_new ();
gtk_grid_attach (GTK_GRID (grid),
layer_view->priv->link_list,
- 0, 0, 2, 1);
+ 0, 1, 2, 1);
gtk_widget_show (layer_view->priv->link_list);
gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (layer_view->priv->link_list),
@@ -491,13 +520,13 @@ gimp_layer_tree_view_constructed (GObject *object)
_("Named Selection"));
gtk_grid_attach (GTK_GRID (grid),
layer_view->priv->link_entry,
- 0, 1, 1, 1);
+ 0, 2, 1, 1);
gtk_widget_show (layer_view->priv->link_entry);
button = gtk_button_new_from_icon_name (GIMP_ICON_DOCUMENT_SAVE, button_size);
gtk_grid_attach (GTK_GRID (grid),
button,
- 1, 1, 1, 1);
+ 1, 2, 1, 1);
g_signal_connect (button,
"clicked",
G_CALLBACK (gimp_layer_tree_view_new_link_clicked),
@@ -1221,6 +1250,62 @@ gimp_layer_tree_view_link_clicked (GtkWidget *box,
return FALSE;
}
+static void
+gimp_layer_tree_view_regexp_modified (GtkEntry *entry,
+ const GParamSpec *pspec,
+ GimpLayerTreeView *view)
+{
+ GimpImage *image;
+ const gchar *pattern;
+
+ gtk_entry_set_attributes (GTK_ENTRY (view->priv->link_regexp_entry),
+ NULL);
+ gtk_widget_set_tooltip_text (view->priv->link_regexp_entry,
+ _("Select layers by regular expressions"));
+ image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
+
+ if (! image)
+ return;
+
+ pattern = gtk_entry_get_text (GTK_ENTRY (view->priv->link_regexp_entry));
+ if (pattern && strlen (pattern) > 0)
+ {
+ GError *error = NULL;
+
+ gtk_entry_set_text (GTK_ENTRY (view->priv->link_entry), "");
+ gtk_widget_set_sensitive (view->priv->link_entry, FALSE);
+ if (! gimp_image_select_layers_by_regexp (image, pattern, &error))
+ {
+ if (error)
+ {
+ /* Invalid regular expression. */
+ PangoAttrList *attrs = pango_attr_list_new ();
+ gchar *tooltip;
+
+ pango_attr_list_insert (attrs, pango_attr_strikethrough_new (TRUE));
+ tooltip = g_strdup_printf (_("Invalid regular expression: %s\n"),
+ error->message);
+ gtk_widget_set_tooltip_text (view->priv->link_regexp_entry,
+ tooltip);
+ gtk_entry_set_attributes (GTK_ENTRY (view->priv->link_regexp_entry),
+ attrs);
+ g_free (tooltip);
+ g_error_free (error);
+ pango_attr_list_unref (attrs);
+ }
+ else
+ {
+ /* Pattern does not match any results. */
+ gimp_widget_blink (view->priv->link_regexp_entry);
+ }
+ }
+ }
+ else
+ {
+ gtk_widget_set_sensitive (view->priv->link_entry, TRUE);
+ }
+}
+
static void
gimp_layer_tree_view_new_link_clicked (GtkButton *button,
GimpLayerTreeView *view)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]