diff --git a/app/widgets/gimpcontainerview.c b/app/widgets/gimpcontainerview.c
index f7dde5d2e0..b51a9d64f6 100644
--- a/app/widgets/gimpcontainerview.c
+++ b/app/widgets/gimpcontainerview.c
@@ -1191,9 +1191,7 @@ gimp_container_view_remove (GimpContainerView *view,
if (insert_data)
{
- GIMP_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view,
- viewable,
- insert_data);
+ GIMP_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view, viewable, insert_data);
g_hash_table_remove (private->item_hash, viewable);
}
diff --git a/app/widgets/gimppickablebutton.c b/app/widgets/gimppickablebutton.c
index 364e3cc158..b9cd60abbf 100644
--- a/app/widgets/gimppickablebutton.c
+++ b/app/widgets/gimppickablebutton.c
@@ -57,6 +57,10 @@ struct _GimpPickableButtonPrivate
GimpPickable *pickable;
GtkWidget *view;
+
+ GBinding *popup_binding;
+ GtkWidget *popup;
+ GimpPickable *initial_pickable;
};
@@ -74,8 +78,8 @@ static void gimp_pickable_button_get_property (GObject *object,
static void gimp_pickable_button_clicked (GtkButton *button);
-static void gimp_pickable_button_popup_confirm (GimpPickablePopup *popup,
- GimpPickableButton *button);
+static void gimp_pickable_button_popup_confirm (GimpPickableButton *button);
+static void gimp_pickable_button_popup_cancel (GimpPickableButton *button);
static void gimp_pickable_button_drop_pickable (GtkWidget *widget,
gint x,
gint y,
@@ -127,6 +131,7 @@ gimp_pickable_button_init (GimpPickableButton *button)
button->private->view_size = GIMP_VIEW_SIZE_LARGE;
button->private->view_border_width = 1;
+ button->private->popup_binding = NULL;
gimp_dnd_viewable_dest_add (GTK_WIDGET (button), GIMP_TYPE_LAYER,
gimp_pickable_button_drop_pickable,
@@ -178,6 +183,9 @@ gimp_pickable_button_finalize (GObject *object)
GimpPickableButton *button = GIMP_PICKABLE_BUTTON (object);
g_clear_object (&button->private->context);
+ g_clear_object (&button->private->initial_pickable);
+ if (button->private->popup)
+ gtk_widget_destroy (button->private->popup);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -240,23 +248,39 @@ gimp_pickable_button_clicked (GtkButton *button)
pickable_button->private->view_size,
pickable_button->private->view_border_width);
- g_signal_connect (popup, "confirm",
- G_CALLBACK (gimp_pickable_button_popup_confirm),
- button);
+ g_signal_connect_swapped (popup, "confirm",
+ G_CALLBACK (gimp_pickable_button_popup_confirm),
+ button);
+ g_signal_connect_swapped (popup, "cancel",
+ G_CALLBACK (gimp_pickable_button_popup_cancel),
+ button);
+ pickable_button->private->popup_binding = g_object_bind_property (G_OBJECT (button), "pickable",
+ G_OBJECT (popup), "pickable",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+ pickable_button->private->initial_pickable = pickable_button->private->pickable;
+ if (pickable_button->private->initial_pickable)
+ g_object_ref (pickable_button->private->initial_pickable);
+ pickable_button->private->popup = popup;
+ g_signal_connect (popup, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &pickable_button->private->popup);
gimp_popup_show (GIMP_POPUP (popup), GTK_WIDGET (button));
}
static void
-gimp_pickable_button_popup_confirm (GimpPickablePopup *popup,
- GimpPickableButton *button)
+gimp_pickable_button_popup_confirm (GimpPickableButton *button)
{
- GimpPickable *pickable = gimp_pickable_popup_get_pickable (popup);
-
- if (pickable)
- gimp_pickable_button_set_pickable (button, pickable);
+ g_clear_pointer (&button->private->popup_binding, g_binding_unbind);
+ g_clear_object (&button->private->initial_pickable);
}
+static void
+gimp_pickable_button_popup_cancel (GimpPickableButton *button)
+{
+ gimp_pickable_button_set_pickable (button, button->private->initial_pickable);
+ gimp_pickable_button_popup_confirm (button);
+}
static void
gimp_pickable_button_drop_pickable (GtkWidget *widget,
gint x,
diff --git a/app/widgets/gimppickablechooser.c b/app/widgets/gimppickablechooser.c
new file mode 100644
index 0000000000..7e12016a99
--- /dev/null
+++ b/app/widgets/gimppickablechooser.c
@@ -0,0 +1,533 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimppickablechooser.c
+ * Copyright (C) 2023 Jehan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpchannel.h"
+#include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimplayer.h"
+#include "core/gimppickable.h"
+#include "core/gimpviewable.h"
+
+#include "gimpcontainertreeview.h"
+#include "gimpcontainerview.h"
+#include "gimppickablechooser.h"
+#include "gimpviewrenderer.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ ACTIVATE,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_CONTEXT,
+ PROP_PICKABLE,
+ PROP_VIEW_SIZE,
+ PROP_VIEW_BORDER_WIDTH
+};
+
+struct _GimpPickableChooserPrivate
+{
+ GimpPickable *pickable;
+ GimpContext *context;
+
+ gint view_size;
+ gint view_border_width;
+
+ GtkWidget *image_view;
+ GtkWidget *layer_view;
+ GtkWidget *channel_view;
+ GtkWidget *layer_label;
+};
+
+
+static void gimp_pickable_chooser_constructed (GObject *object);
+static void gimp_pickable_chooser_finalize (GObject *object);
+static void gimp_pickable_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_pickable_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_pickable_chooser_image_changed (GimpContext *context,
+ GimpImage *image,
+ GimpPickableChooser *chooser);
+static void gimp_pickable_chooser_item_activate (GimpContainerView *view,
+ GimpPickable *pickable,
+ gpointer unused,
+ GimpPickableChooser *chooser);
+static void gimp_pickable_chooser_items_selected (GimpContainerView *view,
+ GList *items,
+ GList *paths,
+ GimpPickableChooser *chooser);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpPickableChooser, gimp_pickable_chooser, GTK_TYPE_FRAME)
+
+#define parent_class gimp_pickable_chooser_parent_class
+
+static guint signals[LAST_SIGNAL];
+
+static void
+gimp_pickable_chooser_class_init (GimpPickableChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gimp_pickable_chooser_constructed;
+ object_class->finalize = gimp_pickable_chooser_finalize;
+ object_class->get_property = gimp_pickable_chooser_get_property;
+ object_class->set_property = gimp_pickable_chooser_set_property;
+
+ /**
+ * GimpPickableChooser::activate:
+ * @chooser:
+ *
+ * Emitted when a pickable is activated, which is mostly forwarding when
+ * "activate-item" signal is emitted from any of either the image, layer or
+ * channel view. E.g. this happens when one double-click on one of the
+ * pickables.
+ */
+ signals[ACTIVATE] =
+ g_signal_new ("activate",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpPickableChooserClass, activate),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ GIMP_TYPE_OBJECT);
+
+ g_object_class_install_property (object_class, PROP_CONTEXT,
+ g_param_spec_object ("context",
+ NULL, NULL,
+ GIMP_TYPE_CONTEXT,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_PICKABLE,
+ g_param_spec_object ("pickable",
+ NULL, NULL,
+ GIMP_TYPE_PICKABLE,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_EXPLICIT_NOTIFY));
+
+ g_object_class_install_property (object_class, PROP_VIEW_SIZE,
+ g_param_spec_int ("view-size",
+ NULL, NULL,
+ 1, GIMP_VIEWABLE_MAX_PREVIEW_SIZE,
+ GIMP_VIEW_SIZE_MEDIUM,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_VIEW_BORDER_WIDTH,
+ g_param_spec_int ("view-border-width",
+ NULL, NULL,
+ 0,
+ GIMP_VIEW_MAX_BORDER_WIDTH,
+ 1,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_pickable_chooser_init (GimpPickableChooser *chooser)
+{
+ chooser->priv = gimp_pickable_chooser_get_instance_private (chooser);
+
+ chooser->priv->view_size = GIMP_VIEW_SIZE_SMALL;
+ chooser->priv->view_border_width = 1;
+}
+
+static void
+gimp_pickable_chooser_constructed (GObject *object)
+{
+ GimpPickableChooser *chooser = GIMP_PICKABLE_CHOOSER (object);
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *label;
+ GtkWidget *notebook;
+ GimpImage *image;
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ gimp_assert (GIMP_IS_CONTEXT (chooser->priv->context));
+
+ gtk_frame_set_shadow_type (GTK_FRAME (chooser), GTK_SHADOW_OUT);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
+ gtk_container_add (GTK_CONTAINER (chooser), hbox);
+ gtk_widget_show (hbox);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ label = gtk_label_new (_("Images"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ chooser->priv->image_view =
+ gimp_container_tree_view_new (chooser->priv->context->gimp->images,
+ chooser->priv->context,
+ chooser->priv->view_size,
+ chooser->priv->view_border_width);
+ gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (chooser->priv->image_view),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width));
+ gtk_box_pack_start (GTK_BOX (vbox), chooser->priv->image_view, TRUE, TRUE, 0);
+ gtk_widget_show (chooser->priv->image_view);
+
+ g_signal_connect_object (chooser->priv->image_view, "activate-item",
+ G_CALLBACK (gimp_pickable_chooser_item_activate),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->image_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ chooser->priv->layer_label = label =
+ gtk_label_new (_("Select an image in the left pane"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ notebook = gtk_notebook_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
+ gtk_widget_show (notebook);
+
+ chooser->priv->layer_view =
+ gimp_container_tree_view_new (NULL,
+ chooser->priv->context,
+ chooser->priv->view_size,
+ chooser->priv->view_border_width);
+ gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (GIMP_CONTAINER_TREE_VIEW (chooser->priv->layer_view)->view),
+ TRUE);
+ gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (chooser->priv->layer_view),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width));
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+ chooser->priv->layer_view,
+ gtk_label_new (_("Layers")));
+ gtk_widget_show (chooser->priv->layer_view);
+
+ g_signal_connect_object (chooser->priv->layer_view, "activate-item",
+ G_CALLBACK (gimp_pickable_chooser_item_activate),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->layer_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+
+ chooser->priv->channel_view =
+ gimp_container_tree_view_new (NULL,
+ chooser->priv->context,
+ chooser->priv->view_size,
+ chooser->priv->view_border_width);
+ gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (chooser->priv->channel_view),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width),
+ 4 * (chooser->priv->view_size +
+ 2 * chooser->priv->view_border_width));
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+ chooser->priv->channel_view,
+ gtk_label_new (_("Channels")));
+ gtk_widget_show (chooser->priv->channel_view);
+
+ g_signal_connect_object (chooser->priv->channel_view, "activate-item",
+ G_CALLBACK (gimp_pickable_chooser_item_activate),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->channel_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+
+ g_signal_connect_object (chooser->priv->context, "image-changed",
+ G_CALLBACK (gimp_pickable_chooser_image_changed),
+ G_OBJECT (chooser), 0);
+
+ image = gimp_context_get_image (chooser->priv->context);
+ gimp_pickable_chooser_image_changed (chooser->priv->context, image, chooser);
+}
+
+static void
+gimp_pickable_chooser_finalize (GObject *object)
+{
+ GimpPickableChooser *chooser = GIMP_PICKABLE_CHOOSER (object);
+
+ g_clear_object (&chooser->priv->pickable);
+ g_clear_object (&chooser->priv->context);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_pickable_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpPickableChooser *chooser = GIMP_PICKABLE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONTEXT:
+ if (chooser->priv->context)
+ g_object_unref (chooser->priv->context);
+ chooser->priv->context = g_value_dup_object (value);
+ break;
+
+ case PROP_VIEW_SIZE:
+ chooser->priv->view_size = g_value_get_int (value);
+ break;
+
+ case PROP_VIEW_BORDER_WIDTH:
+ chooser->priv->view_border_width = g_value_get_int (value);
+ break;
+
+ case PROP_PICKABLE:
+ gimp_pickable_chooser_set_pickable (chooser, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_pickable_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpPickableChooser *chooser = GIMP_PICKABLE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONTEXT:
+ g_value_set_object (value, chooser->priv->context);
+ break;
+
+ case PROP_PICKABLE:
+ g_value_set_object (value, chooser->priv->pickable);
+ break;
+
+ case PROP_VIEW_SIZE:
+ g_value_set_int (value, chooser->priv->view_size);
+ break;
+
+ case PROP_VIEW_BORDER_WIDTH:
+ g_value_set_int (value, chooser->priv->view_border_width);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+GtkWidget *
+gimp_pickable_chooser_new (GimpContext *context,
+ gint view_size,
+ gint view_border_width)
+{
+ g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (view_size > 0 &&
+ view_size <= GIMP_VIEWABLE_MAX_POPUP_SIZE, NULL);
+ g_return_val_if_fail (view_border_width >= 0 &&
+ view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH,
+ NULL);
+
+ return g_object_new (GIMP_TYPE_PICKABLE_CHOOSER,
+ "context", context,
+ "view-size", view_size,
+ "view-border-width", view_border_width,
+ NULL);
+}
+
+GimpPickable *
+gimp_pickable_chooser_get_pickable (GimpPickableChooser *chooser)
+{
+ g_return_val_if_fail (GIMP_IS_PICKABLE_CHOOSER (chooser), NULL);
+
+ return chooser->priv->pickable;
+}
+
+void
+gimp_pickable_chooser_set_pickable (GimpPickableChooser *chooser,
+ GimpPickable *pickable)
+{
+ if (! gtk_widget_in_destruction (GTK_WIDGET (chooser)))
+ {
+ g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ if (GIMP_IS_IMAGE (pickable))
+ {
+ gimp_container_view_select_item (GIMP_CONTAINER_VIEW (chooser->priv->image_view),
+ GIMP_VIEWABLE (pickable));
+ gimp_context_set_image (chooser->priv->context, GIMP_IMAGE (pickable));
+ }
+ else if (GIMP_IS_LAYER (pickable))
+ {
+ gimp_context_set_image (chooser->priv->context, gimp_item_get_image (GIMP_ITEM (pickable)));
+ gimp_container_view_select_item (GIMP_CONTAINER_VIEW (chooser->priv->layer_view),
+ GIMP_VIEWABLE (pickable));
+ }
+ else if (GIMP_IS_CHANNEL (pickable))
+ {
+ gimp_context_set_image (chooser->priv->context, gimp_item_get_image (GIMP_ITEM (pickable)));
+ gimp_container_view_select_item (GIMP_CONTAINER_VIEW (chooser->priv->channel_view),
+ GIMP_VIEWABLE (pickable));
+ }
+ else
+ {
+ g_return_if_fail (pickable == NULL);
+ gimp_container_view_select_item (GIMP_CONTAINER_VIEW (chooser->priv->image_view), NULL);
+ gimp_context_set_image (chooser->priv->context, NULL);
+ }
+ g_signal_connect_object (chooser->priv->image_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->layer_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->channel_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ }
+
+ if (pickable != chooser->priv->pickable)
+ {
+ g_clear_object (&chooser->priv->pickable);
+ chooser->priv->pickable = (pickable != NULL ? g_object_ref (pickable) : NULL);
+ g_object_notify (G_OBJECT (chooser), "pickable");
+ }
+}
+
+
+/* private functions */
+
+static void
+gimp_pickable_chooser_image_changed (GimpContext *context,
+ GimpImage *image,
+ GimpPickableChooser *chooser)
+{
+ GimpContainer *layers = NULL;
+ GimpContainer *channels = NULL;
+
+ if (image)
+ {
+ gchar *desc;
+
+ layers = gimp_image_get_layers (image);
+ channels = gimp_image_get_channels (image);
+
+ desc = gimp_viewable_get_description (GIMP_VIEWABLE (image), NULL);
+ gtk_label_set_text (GTK_LABEL (chooser->priv->layer_label), desc);
+ g_free (desc);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (chooser->priv->layer_label),
+ _("Select an image in the left pane"));
+ }
+
+ g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ chooser);
+ gimp_container_view_set_container (GIMP_CONTAINER_VIEW (chooser->priv->layer_view),
+ layers);
+ gimp_container_view_set_container (GIMP_CONTAINER_VIEW (chooser->priv->channel_view),
+ channels);
+ g_signal_connect_object (chooser->priv->image_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->layer_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->channel_view, "select-items",
+ G_CALLBACK (gimp_pickable_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+}
+
+static void
+gimp_pickable_chooser_item_activate (GimpContainerView *view,
+ GimpPickable *pickable,
+ gpointer unused,
+ GimpPickableChooser *chooser)
+{
+ g_signal_emit (chooser, signals[ACTIVATE], 0, pickable);
+}
+
+static void
+gimp_pickable_chooser_items_selected (GimpContainerView *view,
+ GList *items,
+ GList *paths,
+ GimpPickableChooser *chooser)
+{
+ GimpPickable *pickable = NULL;
+
+ g_return_if_fail (g_list_length (items) <= 1);
+
+ if (items != NULL)
+ pickable = items->data;
+
+ gimp_pickable_chooser_set_pickable (chooser, pickable);
+}
diff --git a/app/widgets/gimppickablechooser.h b/app/widgets/gimppickablechooser.h
new file mode 100644
index 0000000000..9e1e19856f
--- /dev/null
+++ b/app/widgets/gimppickablechooser.h
@@ -0,0 +1,65 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimppickablechooser.h
+ * Copyright (C) 2023 Jehan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __GIMP_PICKABLE_CHOOSER_H__
+#define __GIMP_PICKABLE_CHOOSER_H__
+
+
+#define GIMP_TYPE_PICKABLE_CHOOSER (gimp_pickable_chooser_get_type ())
+#define GIMP_PICKABLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PICKABLE_CHOOSER, GimpPickableChooser))
+#define GIMP_PICKABLE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PICKABLE_CHOOSER, GimpPickableChooserClass))
+#define GIMP_IS_PICKABLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PICKABLE_CHOOSER))
+#define GIMP_IS_PICKABLE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PICKABLE_CHOOSER))
+#define GIMP_PICKABLE_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PICKABLE_CHOOSER, GimpPickableChooserClass))
+
+
+typedef struct _GimpPickableChooserPrivate GimpPickableChooserPrivate;
+typedef struct _GimpPickableChooserClass GimpPickableChooserClass;
+
+struct _GimpPickableChooser
+{
+ GtkFrame parent_instance;
+
+ GimpPickableChooserPrivate *priv;
+};
+
+struct _GimpPickableChooserClass
+{
+ GtkFrameClass parent_instance;
+
+ /* Signals. */
+
+ void (* activate) (GimpPickableChooser *view,
+ GimpPickable *pickable);
+};
+
+
+GType gimp_pickable_chooser_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_pickable_chooser_new (GimpContext *context,
+ gint view_size,
+ gint view_border_width);
+
+GimpPickable * gimp_pickable_chooser_get_pickable (GimpPickableChooser *chooser);
+void gimp_pickable_chooser_set_pickable (GimpPickableChooser *chooser,
+ GimpPickable *pickable);
+
+
+#endif /* __GIMP_PICKABLE_CHOOSER_H__ */
diff --git a/app/widgets/gimppickablepopup.c b/app/widgets/gimppickablepopup.c
index 93c2cdc21c..27c3c5a0b3 100644
--- a/app/widgets/gimppickablepopup.c
+++ b/app/widgets/gimppickablepopup.c
@@ -37,6 +37,7 @@
#include "gimpcontainertreeview.h"
#include "gimpcontainerview.h"
+#include "gimppickablechooser.h"
#include "gimppickablepopup.h"
#include "gimpviewrenderer.h"
@@ -54,12 +55,13 @@ enum
struct _GimpPickablePopupPrivate
{
- GimpPickable *pickable;
GimpContext *context;
gint view_size;
gint view_border_width;
+ GtkWidget *chooser;
+
GtkWidget *image_view;
GtkWidget *layer_view;
GtkWidget *channel_view;
@@ -67,24 +69,19 @@ struct _GimpPickablePopupPrivate
};
-static void gimp_pickable_popup_constructed (GObject *object);
-static void gimp_pickable_popup_finalize (GObject *object);
-static void gimp_pickable_popup_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec);
-static void gimp_pickable_popup_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec);
+static void gimp_pickable_popup_constructed (GObject *object);
+static void gimp_pickable_popup_finalize (GObject *object);
+static void gimp_pickable_popup_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_pickable_popup_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
-static void gimp_pickable_popup_image_changed (GimpContext *context,
- GimpImage *image,
- GimpPickablePopup *popup);
-static void gimp_pickable_popup_item_activate (GimpContainerView *view,
- GimpPickable *pickable,
- gpointer unused,
- GimpPickablePopup *popup);
+static void gimp_pickable_popup_activate (GimpPickablePopup *popup);
+static void gimp_pickable_popup_notify_pickable (GimpPickablePopup *popup);
G_DEFINE_TYPE_WITH_PRIVATE (GimpPickablePopup, gimp_pickable_popup,
@@ -114,7 +111,7 @@ gimp_pickable_popup_class_init (GimpPickablePopupClass *klass)
g_param_spec_object ("pickable",
NULL, NULL,
GIMP_TYPE_PICKABLE,
- GIMP_PARAM_READABLE));
+ GIMP_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_VIEW_SIZE,
g_param_spec_int ("view-size",
@@ -149,114 +146,21 @@ static void
gimp_pickable_popup_constructed (GObject *object)
{
GimpPickablePopup *popup = GIMP_PICKABLE_POPUP (object);
- GtkWidget *frame;
- GtkWidget *hbox;
- GtkWidget *vbox;
- GtkWidget *label;
- GtkWidget *notebook;
- GimpImage *image;
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_CONTEXT (popup->priv->context));
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
- gtk_container_add (GTK_CONTAINER (popup), frame);
- gtk_widget_show (frame);
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
- gtk_container_add (GTK_CONTAINER (frame), hbox);
- gtk_widget_show (hbox);
-
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
- gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
- gtk_widget_show (vbox);
-
- label = gtk_label_new (_("Images"));
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- popup->priv->image_view =
- gimp_container_tree_view_new (popup->priv->context->gimp->images,
- popup->priv->context,
- popup->priv->view_size,
- popup->priv->view_border_width);
- gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (popup->priv->image_view),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width));
- gtk_box_pack_start (GTK_BOX (vbox), popup->priv->image_view, TRUE, TRUE, 0);
- gtk_widget_show (popup->priv->image_view);
-
- g_signal_connect_object (popup->priv->image_view, "activate-item",
- G_CALLBACK (gimp_pickable_popup_item_activate),
- G_OBJECT (popup), 0);
-
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
- gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
- gtk_widget_show (vbox);
-
- popup->priv->layer_label = label =
- gtk_label_new (_("Select an image in the left pane"));
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- notebook = gtk_notebook_new ();
- gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
- gtk_widget_show (notebook);
-
- popup->priv->layer_view =
- gimp_container_tree_view_new (NULL,
- popup->priv->context,
- popup->priv->view_size,
- popup->priv->view_border_width);
- gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (GIMP_CONTAINER_TREE_VIEW (popup->priv->layer_view)->view),
- TRUE);
- gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (popup->priv->layer_view),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width));
- gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
- popup->priv->layer_view,
- gtk_label_new (_("Layers")));
- gtk_widget_show (popup->priv->layer_view);
-
- g_signal_connect_object (popup->priv->layer_view, "activate-item",
- G_CALLBACK (gimp_pickable_popup_item_activate),
- G_OBJECT (popup), 0);
-
- popup->priv->channel_view =
- gimp_container_tree_view_new (NULL,
- popup->priv->context,
- popup->priv->view_size,
- popup->priv->view_border_width);
- gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (popup->priv->channel_view),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width),
- 4 * (popup->priv->view_size +
- 2 * popup->priv->view_border_width));
- gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
- popup->priv->channel_view,
- gtk_label_new (_("Channels")));
- gtk_widget_show (popup->priv->channel_view);
-
- g_signal_connect_object (popup->priv->channel_view, "activate-item",
- G_CALLBACK (gimp_pickable_popup_item_activate),
- G_OBJECT (popup), 0);
-
- g_signal_connect_object (popup->priv->context, "image-changed",
- G_CALLBACK (gimp_pickable_popup_image_changed),
- G_OBJECT (popup), 0);
-
- image = gimp_context_get_image (popup->priv->context);
- gimp_pickable_popup_image_changed (popup->priv->context, image, popup);
+ popup->priv->chooser = gimp_pickable_chooser_new (popup->priv->context, popup->priv->view_size,
+ popup->priv->view_border_width);
+ gtk_container_add (GTK_CONTAINER (popup), popup->priv->chooser);
+ g_signal_connect_swapped (popup->priv->chooser, "notify::pickable",
+ G_CALLBACK (gimp_pickable_popup_notify_pickable),
+ popup);
+ g_signal_connect_swapped (popup->priv->chooser, "activate",
+ G_CALLBACK (gimp_pickable_popup_activate),
+ popup);
+ gtk_widget_show (popup->priv->chooser);
}
static void
@@ -264,7 +168,6 @@ gimp_pickable_popup_finalize (GObject *object)
{
GimpPickablePopup *popup = GIMP_PICKABLE_POPUP (object);
- g_clear_object (&popup->priv->pickable);
g_clear_object (&popup->priv->context);
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -286,6 +189,11 @@ gimp_pickable_popup_set_property (GObject *object,
popup->priv->context = g_value_dup_object (value);
break;
+ case PROP_PICKABLE:
+ gimp_pickable_chooser_set_pickable (GIMP_PICKABLE_CHOOSER (popup->priv->chooser),
+ g_value_get_object (value));
+ break;
+
case PROP_VIEW_SIZE:
popup->priv->view_size = g_value_get_int (value);
break;
@@ -294,7 +202,6 @@ gimp_pickable_popup_set_property (GObject *object,
popup->priv->view_border_width = g_value_get_int (value);
break;
- case PROP_PICKABLE:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -316,7 +223,7 @@ gimp_pickable_popup_get_property (GObject *object,
break;
case PROP_PICKABLE:
- g_value_set_object (value, popup->priv->pickable);
+ g_value_set_object (value, gimp_pickable_popup_get_pickable (popup));
break;
case PROP_VIEW_SIZE:
@@ -333,6 +240,9 @@ gimp_pickable_popup_get_property (GObject *object,
}
}
+
+/* Public functions */
+
GtkWidget *
gimp_pickable_popup_new (GimpContext *context,
gint view_size,
@@ -356,82 +266,22 @@ gimp_pickable_popup_new (GimpContext *context,
GimpPickable *
gimp_pickable_popup_get_pickable (GimpPickablePopup *popup)
{
- GtkWidget *focus;
- GimpPickable *pickable = NULL;
-
g_return_val_if_fail (GIMP_IS_PICKABLE_POPUP (popup), NULL);
- focus = gtk_window_get_focus (GTK_WINDOW (popup));
-
- if (focus && gtk_widget_is_ancestor (focus, popup->priv->image_view))
- {
- pickable = GIMP_PICKABLE (gimp_context_get_image (popup->priv->context));
- }
- else if (focus && gtk_widget_is_ancestor (focus, popup->priv->layer_view))
- {
- GList *selected;
-
- if (gimp_container_view_get_selected (GIMP_CONTAINER_VIEW (popup->priv->layer_view),
- &selected, NULL))
- {
- pickable = selected->data;
- g_list_free (selected);
- }
- }
- else if (focus && gtk_widget_is_ancestor (focus, popup->priv->channel_view))
- {
- GList *selected;
-
- if (gimp_container_view_get_selected (GIMP_CONTAINER_VIEW (popup->priv->channel_view),
- &selected, NULL))
- {
- pickable = selected->data;
- g_list_free (selected);
- }
- }
-
- return pickable;
+ return gimp_pickable_chooser_get_pickable (GIMP_PICKABLE_CHOOSER (popup->priv->chooser));
}
-/* private functions */
+/* Private functions */
static void
-gimp_pickable_popup_image_changed (GimpContext *context,
- GimpImage *image,
- GimpPickablePopup *popup)
-{
- GimpContainer *layers = NULL;
- GimpContainer *channels = NULL;
-
- if (image)
- {
- gchar *desc;
-
- layers = gimp_image_get_layers (image);
- channels = gimp_image_get_channels (image);
-
- desc = gimp_viewable_get_description (GIMP_VIEWABLE (image), NULL);
- gtk_label_set_text (GTK_LABEL (popup->priv->layer_label), desc);
- g_free (desc);
- }
- else
- {
- gtk_label_set_text (GTK_LABEL (popup->priv->layer_label),
- _("Select an image in the left pane"));
- }
-
- gimp_container_view_set_container (GIMP_CONTAINER_VIEW (popup->priv->layer_view),
- layers);
- gimp_container_view_set_container (GIMP_CONTAINER_VIEW (popup->priv->channel_view),
- channels);
-}
-
-static void
-gimp_pickable_popup_item_activate (GimpContainerView *view,
- GimpPickable *pickable,
- gpointer unused,
- GimpPickablePopup *popup)
+gimp_pickable_popup_activate (GimpPickablePopup *popup)
{
g_signal_emit_by_name (popup, "confirm");
}
+
+static void
+gimp_pickable_popup_notify_pickable (GimpPickablePopup *popup)
+{
+ g_object_notify (G_OBJECT (popup), "pickable");
+}
diff --git a/app/widgets/meson.build b/app/widgets/meson.build
index baeecd4c91..8baaff7515 100644
--- a/app/widgets/meson.build
+++ b/app/widgets/meson.build
@@ -161,6 +161,7 @@ libappwidgets_sources = [
'gimppatternselect.c',
'gimppdbdialog.c',
'gimppickablebutton.c',
+ 'gimppickablechooser.c',
'gimppickablepopup.c',
'gimppivotselector.c',
'gimppixbuf.c',
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index 598b3ca6c0..0f2ad439d1 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -221,6 +221,7 @@ typedef struct _GimpMeter GimpMeter;
typedef struct _GimpModifiersEditor GimpModifiersEditor;
typedef struct _GimpOverlayBox GimpOverlayBox;
typedef struct _GimpPickableButton GimpPickableButton;
+typedef struct _GimpPickableChooser GimpPickableChooser;
typedef struct _GimpPickablePopup GimpPickablePopup;
typedef struct _GimpPivotSelector GimpPivotSelector;
typedef struct _GimpPlugInView GimpPlugInView;