diff --git a/app/core/gimp-gui.c b/app/core/gimp-gui.c
index 140813b982..3e6c4e5248 100644
--- a/app/core/gimp-gui.c
+++ b/app/core/gimp-gui.c
@@ -418,7 +418,8 @@ gimp_pdb_dialog_new (Gimp *gimp,
g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, GIMP_TYPE_RESOURCE) ||
- g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE), FALSE);
+ g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE) ||
+ g_type_is_a (contents_type, GIMP_TYPE_IMAGE), FALSE);
g_return_val_if_fail (object == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
g_return_val_if_fail (title != NULL, FALSE);
@@ -451,7 +452,8 @@ gimp_pdb_dialog_set (Gimp *gimp,
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, GIMP_TYPE_RESOURCE) ||
- contents_type == GIMP_TYPE_DRAWABLE, FALSE);
+ contents_type == GIMP_TYPE_DRAWABLE ||
+ contents_type == GIMP_TYPE_IMAGE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE);
g_return_val_if_fail (object == NULL || g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
@@ -477,7 +479,8 @@ gimp_pdb_dialog_close (Gimp *gimp,
{
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, GIMP_TYPE_RESOURCE) ||
- contents_type == GIMP_TYPE_DRAWABLE, FALSE);
+ contents_type == GIMP_TYPE_DRAWABLE ||
+ contents_type == GIMP_TYPE_IMAGE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE);
if (gimp->gui.pdb_dialog_close)
diff --git a/app/gui/gui-vtable.c b/app/gui/gui-vtable.c
index 6d5b6ebae5..090d1d48d4 100644
--- a/app/gui/gui-vtable.c
+++ b/app/gui/gui-vtable.c
@@ -84,6 +84,8 @@
#include "widgets/gimpgradientselect.h"
#include "widgets/gimphelp.h"
#include "widgets/gimphelp-ids.h"
+#include "widgets/gimpimageselect.h"
+#include "widgets/gimpimageview.h"
#include "widgets/gimpmenufactory.h"
#include "widgets/gimppaletteselect.h"
#include "widgets/gimppatternselect.h"
@@ -643,6 +645,12 @@ gui_pdb_dialog_new (Gimp *gimp,
dialog_role = "gimp-gradient-selection";
help_id = GIMP_HELP_GRADIENT_DIALOG;
}
+ else if (contents_type == GIMP_TYPE_IMAGE)
+ {
+ dialog_type = GIMP_TYPE_IMAGE_SELECT;
+ dialog_role = "gimp-image-selection";
+ help_id = GIMP_HELP_IMAGE_DIALOG;
+ }
else if (contents_type == GIMP_TYPE_PALETTE)
{
dialog_type = GIMP_TYPE_PALETTE_SELECT;
@@ -768,6 +776,10 @@ gui_pdb_dialog_set (Gimp *gimp,
klass = g_type_class_peek (GIMP_TYPE_GRADIENT_SELECT);
container = gimp_data_factory_get_container (gimp->gradient_factory);
}
+ else if (contents_type == GIMP_TYPE_IMAGE)
+ {
+ klass = g_type_class_peek (GIMP_TYPE_IMAGE_SELECT);
+ }
else if (contents_type == GIMP_TYPE_PALETTE)
{
klass = g_type_class_peek (GIMP_TYPE_PALETTE_SELECT);
@@ -828,6 +840,8 @@ gui_pdb_dialog_close (Gimp *gimp,
klass = g_type_class_peek (GIMP_TYPE_FONT_SELECT);
else if (contents_type == GIMP_TYPE_GRADIENT)
klass = g_type_class_peek (GIMP_TYPE_GRADIENT_SELECT);
+ else if (contents_type == GIMP_TYPE_IMAGE)
+ klass = g_type_class_peek (GIMP_TYPE_IMAGE_SELECT);
else if (contents_type == GIMP_TYPE_PALETTE)
klass = g_type_class_peek (GIMP_TYPE_PALETTE_SELECT);
else if (contents_type == GIMP_TYPE_PATTERN)
diff --git a/app/pdb/image-select-cmds.c b/app/pdb/image-select-cmds.c
index b03cea35da..0c7e9942d3 100644
--- a/app/pdb/image-select-cmds.c
+++ b/app/pdb/image-select-cmds.c
@@ -34,7 +34,9 @@
#include "pdb-types.h"
+#include "core/gimp.h"
#include "core/gimpchannel-select.h"
+#include "core/gimpdatafactory.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpitem.h"
@@ -354,6 +356,93 @@ image_select_item_invoker (GimpProcedure *procedure,
error ? *error : NULL);
}
+static GimpValueArray *
+images_popup_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ const gchar *callback;
+ const gchar *popup_title;
+ GimpImage *initial_image;
+ GBytes *parent_window;
+
+ callback = g_value_get_string (gimp_value_array_index (args, 0));
+ popup_title = g_value_get_string (gimp_value_array_index (args, 1));
+ initial_image = g_value_get_object (gimp_value_array_index (args, 2));
+ parent_window = g_value_get_boxed (gimp_value_array_index (args, 3));
+
+ if (success)
+ {
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_new (gimp, context, progress,
+ GIMP_TYPE_IMAGE,
+ parent_window, popup_title, callback,
+ GIMP_OBJECT (initial_image),
+ NULL))
+ success = FALSE;
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+images_close_popup_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ const gchar *callback;
+
+ callback = g_value_get_string (gimp_value_array_index (args, 0));
+
+ if (success)
+ {
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_close (gimp, GIMP_TYPE_IMAGE, callback))
+ success = FALSE;
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+images_set_popup_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ const gchar *callback;
+ GimpImage *image;
+
+ callback = g_value_get_string (gimp_value_array_index (args, 0));
+ image = g_value_get_object (gimp_value_array_index (args, 1));
+
+ if (success)
+ {
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_set (gimp, GIMP_TYPE_IMAGE, callback, GIMP_OBJECT (image), NULL))
+ success = FALSE;
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
void
register_image_select_procs (GimpPDB *pdb)
{
@@ -712,4 +801,101 @@ register_image_select_procs (GimpPDB *pdb)
GIMP_PARAM_READWRITE));
gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
+
+ /*
+ * gimp-images-popup
+ */
+ procedure = gimp_procedure_new (images_popup_invoker, FALSE);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "gimp-images-popup");
+ gimp_procedure_set_static_help (procedure,
+ "Invokes the image selection dialog.",
+ "Opens a dialog letting a user choose an image.",
+ NULL);
+ gimp_procedure_set_static_attribution (procedure,
+ "Alex S.",
+ "Alex S.",
+ "2025");
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_string ("callback",
+ "callback",
+ "The callback PDB proc to call when user chooses an image",
+ FALSE, FALSE, TRUE,
+ NULL,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_string ("popup-title",
+ "popup title",
+ "Title of the image selection dialog",
+ FALSE, FALSE, FALSE,
+ NULL,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_image ("initial-image",
+ "initial image",
+ "The image to set as the initial choice",
+ TRUE,
+ GIMP_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_boxed ("parent-window",
+ "parent window",
+ "An optional parent window handle for the popup to be set transient to",
+ G_TYPE_BYTES,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-images-close-popup
+ */
+ procedure = gimp_procedure_new (images_close_popup_invoker, FALSE);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "gimp-images-close-popup");
+ gimp_procedure_set_static_help (procedure,
+ "Close the image selection dialog.",
+ "Closes an open image selection dialog.",
+ NULL);
+ gimp_procedure_set_static_attribution (procedure,
+ "Alex S.",
+ "Alex S.",
+ "2025");
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_string ("callback",
+ "callback",
+ "The name of the callback registered for this pop-up",
+ FALSE, FALSE, TRUE,
+ NULL,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-images-set-popup
+ */
+ procedure = gimp_procedure_new (images_set_popup_invoker, FALSE);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "gimp-images-set-popup");
+ gimp_procedure_set_static_help (procedure,
+ "Sets the selected image in a image selection dialog.",
+ "Sets the selected image in a image selection dialog.",
+ NULL);
+ gimp_procedure_set_static_attribution (procedure,
+ "Alex S.",
+ "Alex S.",
+ "2025");
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_string ("callback",
+ "callback",
+ "The name of the callback registered for this pop-up",
+ FALSE, FALSE, TRUE,
+ NULL,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_image ("image",
+ "image",
+ "The image to set as selected",
+ FALSE,
+ GIMP_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
}
diff --git a/app/pdb/internal-procs.c b/app/pdb/internal-procs.c
index 7745233b04..a6aa965fc4 100644
--- a/app/pdb/internal-procs.c
+++ b/app/pdb/internal-procs.c
@@ -30,7 +30,7 @@
#include "internal-procs.h"
-/* 779 procedures registered total */
+/* 782 procedures registered total */
void
internal_procs_init (GimpPDB *pdb)
diff --git a/app/widgets/gimpimagechooser.c b/app/widgets/gimpimagechooser.c
new file mode 100644
index 0000000000..f10b28097e
--- /dev/null
+++ b/app/widgets/gimpimagechooser.c
@@ -0,0 +1,370 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimagechooser.c
+ *
+ * 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/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimpviewable.h"
+
+#include "gimpcontainertreeview.h"
+#include "gimpcontainerview.h"
+#include "gimpimagechooser.h"
+#include "gimpviewrenderer.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ ACTIVATE,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_CONTEXT,
+ PROP_IMAGE,
+ PROP_VIEW_SIZE,
+ PROP_VIEW_BORDER_WIDTH
+};
+
+struct _GimpImageChooserPrivate
+{
+ GimpImage *image;
+ GimpContext *context;
+
+ gint view_size;
+ gint view_border_width;
+
+ GtkWidget *image_view;
+};
+
+
+static void gimp_image_chooser_constructed (GObject *object);
+static void gimp_image_chooser_finalize (GObject *object);
+static void gimp_image_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_image_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_image_chooser_item_activated (GimpContainerView *view,
+ GimpImage *image,
+ GimpImageChooser *chooser);
+static void gimp_image_chooser_items_selected (GimpContainerView *view,
+ GimpImageChooser *chooser);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpImageChooser, gimp_image_chooser, GTK_TYPE_FRAME)
+
+#define parent_class gimp_image_chooser_parent_class
+
+static guint signals[LAST_SIGNAL];
+
+static void
+gimp_image_chooser_class_init (GimpImageChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gimp_image_chooser_constructed;
+ object_class->finalize = gimp_image_chooser_finalize;
+ object_class->get_property = gimp_image_chooser_get_property;
+ object_class->set_property = gimp_image_chooser_set_property;
+
+ /**
+ * GimpImageChooser::activate:
+ * @chooser:
+ *
+ * Emitted when an image is activated, which is mostly forwarding when
+ * "item-activated" signal is emitted from the image view.
+ */
+ signals[ACTIVATE] =
+ g_signal_new ("activate",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpImageChooserClass, 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_IMAGE,
+ g_param_spec_object ("image",
+ NULL, NULL,
+ GIMP_TYPE_IMAGE,
+ 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_image_chooser_init (GimpImageChooser *chooser)
+{
+ chooser->priv = gimp_image_chooser_get_instance_private (chooser);
+
+ chooser->priv->view_size = GIMP_VIEW_SIZE_SMALL;
+ chooser->priv->view_border_width = 1;
+}
+
+static void
+gimp_image_chooser_constructed (GObject *object)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *label;
+
+ 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_set_visible (chooser->priv->image_view, TRUE);
+
+ g_signal_connect_object (chooser->priv->image_view, "item-activated",
+ G_CALLBACK (gimp_image_chooser_item_activated),
+ G_OBJECT (chooser), 0);
+ g_signal_connect_object (chooser->priv->image_view, "selection-changed",
+ G_CALLBACK (gimp_image_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+}
+
+static void
+gimp_image_chooser_finalize (GObject *object)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ g_clear_object (&chooser->priv->image);
+ g_clear_object (&chooser->priv->context);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_image_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_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_IMAGE:
+ gimp_image_chooser_set_image (chooser, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_image_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONTEXT:
+ g_value_set_object (value, chooser->priv->context);
+ break;
+
+ case PROP_IMAGE:
+ g_value_set_object (value, chooser->priv->image);
+ 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_image_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_IMAGE_CHOOSER,
+ "context", context,
+ "view-size", view_size,
+ "view-border-width", view_border_width,
+ NULL);
+}
+
+GimpImage *
+gimp_image_chooser_get_image (GimpImageChooser *chooser)
+{
+ g_return_val_if_fail (GIMP_IS_IMAGE_CHOOSER (chooser), NULL);
+
+ return chooser->priv->image;
+}
+
+void
+gimp_image_chooser_set_image (GimpImageChooser *chooser,
+ GimpImage *image)
+{
+ if (! gtk_widget_in_destruction (GTK_WIDGET (chooser)))
+ {
+ g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
+ G_CALLBACK (gimp_image_chooser_items_selected),
+ chooser);
+
+ if (GIMP_IS_IMAGE (image))
+ {
+ gimp_context_set_image (chooser->priv->context, image);
+ gimp_container_view_set_1_selected (GIMP_CONTAINER_VIEW (chooser->priv->image_view),
+ GIMP_VIEWABLE (image));
+ }
+
+ g_signal_connect_object (chooser->priv->image_view, "selection-changed",
+ G_CALLBACK (gimp_image_chooser_items_selected),
+ G_OBJECT (chooser), 0);
+ }
+
+ if (image != chooser->priv->image)
+ {
+ g_clear_object (&chooser->priv->image);
+ chooser->priv->image = (image != NULL ? g_object_ref (image) : NULL);
+ g_object_notify (G_OBJECT (chooser), "image");
+ }
+}
+
+
+/* private functions */
+
+static void
+gimp_image_chooser_item_activated (GimpContainerView *view,
+ GimpImage *image,
+ GimpImageChooser *chooser)
+{
+ g_signal_emit (chooser, signals[ACTIVATE], 0, image);
+}
+
+static void
+gimp_image_chooser_items_selected (GimpContainerView *view,
+ GimpImageChooser *chooser)
+{
+ GimpImage *image = NULL;
+ gint n_items;
+ GList *items;
+
+ n_items = gimp_container_view_get_selected (view, &items);
+
+ g_return_if_fail (n_items <= 1);
+
+ if (items)
+ image = items->data;
+
+ gimp_image_chooser_set_image (chooser, image);
+}
diff --git a/app/widgets/gimpimagechooser.h b/app/widgets/gimpimagechooser.h
new file mode 100644
index 0000000000..ff1729fe30
--- /dev/null
+++ b/app/widgets/gimpimagechooser.h
@@ -0,0 +1,60 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimagechooser.h
+ *
+ * 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 .
+ */
+
+#pragma once
+
+
+#define GIMP_TYPE_IMAGE_CHOOSER (gimp_image_chooser_get_type ())
+#define GIMP_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE_CHOOSER, GimpImageChooser))
+#define GIMP_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE_CHOOSER, GimpImageChooserClass))
+#define GIMP_IS_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE_CHOOSER))
+#define GIMP_IS_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE_CHOOSER))
+#define GIMP_IMAGE_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE_CHOOSER, GimpImageChooserClass))
+
+
+typedef struct _GimpImageChooserPrivate GimpImageChooserPrivate;
+typedef struct _GimpImageChooserClass GimpImageChooserClass;
+
+struct _GimpImageChooser
+{
+ GtkFrame parent_instance;
+
+ GimpImageChooserPrivate *priv;
+};
+
+struct _GimpImageChooserClass
+{
+ GtkFrameClass parent_instance;
+
+ /* Signals. */
+
+ void (* activate) (GimpImageChooser *view,
+ GimpImage *image);
+};
+
+
+GType gimp_image_chooser_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_image_chooser_new (GimpContext *context,
+ gint view_size,
+ gint view_border_width);
+
+GimpImage * gimp_image_chooser_get_image (GimpImageChooser *chooser);
+void gimp_image_chooser_set_image (GimpImageChooser *chooser,
+ GimpImage *image);
diff --git a/app/widgets/gimpimageselect.c b/app/widgets/gimpimageselect.c
new file mode 100644
index 0000000000..8533ab23d5
--- /dev/null
+++ b/app/widgets/gimpimageselect.c
@@ -0,0 +1,163 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimageselect.c
+ *
+ * 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 "libgimpbase/gimpbase.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "gegl/gimp-babl-compat.h"
+
+#include "core/gimp.h"
+#include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimpparamspecs.h"
+#include "core/gimptempbuf.h"
+
+#include "pdb/gimppdb.h"
+
+#include "gimpcontainerbox.h"
+#include "gimpcontainerview.h"
+#include "gimpimagechooser.h"
+#include "gimpimageselect.h"
+#include "gimplayermodebox.h"
+
+#include "gimp-intl.h"
+
+
+static void gimp_image_select_constructed (GObject *object);
+
+static GimpValueArray * gimp_image_select_run_callback (GimpPdbDialog *dialog,
+ GimpObject *object,
+ gboolean closing,
+ GError **error);
+static GimpObject * gimp_image_select_get_object (GimpPdbDialog *dialog);
+static void gimp_image_select_set_object (GimpPdbDialog *dialog,
+ GimpObject *object);
+
+
+static void gimp_image_select_activate (GimpImageSelect *select);
+static void gimp_image_select_notify_image (GimpImageSelect *select);
+
+G_DEFINE_TYPE (GimpImageSelect, gimp_image_select, GIMP_TYPE_PDB_DIALOG)
+
+#define parent_class gimp_image_select_parent_class
+
+
+static void
+gimp_image_select_class_init (GimpImageSelectClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpPdbDialogClass *pdb_class = GIMP_PDB_DIALOG_CLASS (klass);
+
+ object_class->constructed = gimp_image_select_constructed;
+
+ pdb_class->run_callback = gimp_image_select_run_callback;
+ pdb_class->set_object = gimp_image_select_set_object;
+ pdb_class->get_object = gimp_image_select_get_object;
+}
+
+static void
+gimp_image_select_init (GimpImageSelect *select)
+{
+}
+
+static void
+gimp_image_select_constructed (GObject *object)
+{
+ GimpPdbDialog *dialog = GIMP_PDB_DIALOG (object);
+ GimpImageSelect *select = GIMP_IMAGE_SELECT (object);
+ GtkWidget *content_area;
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ select->chooser = gimp_image_chooser_new (dialog->context,
+ GIMP_VIEW_SIZE_LARGE, 1);
+ gimp_image_chooser_set_image (GIMP_IMAGE_CHOOSER (select->chooser),
+ GIMP_IMAGE (dialog->initial_object));
+ g_signal_connect_swapped (select->chooser, "notify::image",
+ G_CALLBACK (gimp_image_select_notify_image),
+ select);
+ g_signal_connect_swapped (select->chooser, "activate",
+ G_CALLBACK (gimp_image_select_activate),
+ select);
+
+ gtk_box_pack_start (GTK_BOX (content_area), select->chooser, TRUE, TRUE, 0);
+ gtk_widget_set_visible (select->chooser, TRUE);
+}
+
+static GimpValueArray *
+gimp_image_select_run_callback (GimpPdbDialog *dialog,
+ GimpObject *object,
+ gboolean closing,
+ GError **error)
+{
+ GimpImage *image = GIMP_IMAGE (object);
+ GimpValueArray *return_vals;
+
+ return_vals =
+ gimp_pdb_execute_procedure_by_name (dialog->pdb,
+ dialog->caller_context,
+ NULL, error,
+ dialog->callback_name,
+ GIMP_TYPE_IMAGE, image,
+ G_TYPE_BOOLEAN, closing,
+ G_TYPE_NONE);
+
+ return return_vals;
+}
+
+static GimpObject *
+gimp_image_select_get_object (GimpPdbDialog *dialog)
+{
+ GimpImageSelect *select = GIMP_IMAGE_SELECT (dialog);
+
+ return (GimpObject *) gimp_image_chooser_get_image (GIMP_IMAGE_CHOOSER (select->chooser));
+
+}
+
+static void
+gimp_image_select_set_object (GimpPdbDialog *dialog,
+ GimpObject *object)
+{
+ GimpImageSelect *select = GIMP_IMAGE_SELECT (dialog);
+
+ gimp_image_chooser_set_image (GIMP_IMAGE_CHOOSER (select->chooser), GIMP_IMAGE (object));
+}
+
+
+static void
+gimp_image_select_activate (GimpImageSelect *select)
+{
+ gimp_pdb_dialog_run_callback ((GimpPdbDialog **) &select, TRUE);
+ gtk_widget_destroy (GTK_WIDGET (select));
+}
+
+static void
+gimp_image_select_notify_image (GimpImageSelect *select)
+{
+ gimp_pdb_dialog_run_callback ((GimpPdbDialog **) &select, FALSE);
+}
diff --git a/app/widgets/gimpimageselect.h b/app/widgets/gimpimageselect.h
new file mode 100644
index 0000000000..596299b3f4
--- /dev/null
+++ b/app/widgets/gimpimageselect.h
@@ -0,0 +1,48 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimageselect.h
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "gimppdbdialog.h"
+
+
+#define GIMP_TYPE_IMAGE_SELECT (gimp_image_select_get_type ())
+#define GIMP_IMAGE_SELECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE_SELECT, GimpImageSelect))
+#define GIMP_IMAGE_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE_SELECT, GimpImageSelectClass))
+#define GIMP_IS_IMAGE_SELECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE_SELECT))
+#define GIMP_IS_IMAGE_SELECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE_SELECT))
+#define GIMP_IMAGE_SELECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE_SELECT, GimpImageSelectClass))
+
+
+typedef struct _GimpImageSelectClass GimpImageSelectClass;
+
+struct _GimpImageSelect
+{
+ GimpPdbDialog parent_instance;
+
+ GtkWidget *chooser;
+};
+
+struct _GimpImageSelectClass
+{
+ GimpPdbDialogClass parent_class;
+};
+
+
+GType gimp_image_select_get_type (void) G_GNUC_CONST;
diff --git a/app/widgets/meson.build b/app/widgets/meson.build
index d4f10287f5..8b63b0fe63 100644
--- a/app/widgets/meson.build
+++ b/app/widgets/meson.build
@@ -137,11 +137,13 @@ libappwidgets_sources = [
'gimphistogrameditor.c',
'gimphistogramview.c',
'gimpiconpicker.c',
+ 'gimpimagechooser.c',
'gimpimagecommenteditor.c',
'gimpimageeditor.c',
'gimpimageparasiteview.c',
'gimpimageprofileview.c',
'gimpimagepropview.c',
+ 'gimpimageselect.c',
'gimpimageview.c',
'gimpitemtreeview.c',
'gimpitemtreeview-search.c',
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index 8806d82975..7dc5fb43b3 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -162,6 +162,7 @@ typedef struct _GimpViewableDialog GimpViewableDialog;
typedef struct _GimpBrushSelect GimpBrushSelect;
typedef struct _GimpFontSelect GimpFontSelect;
typedef struct _GimpGradientSelect GimpGradientSelect;
+typedef struct _GimpImageSelect GimpImageSelect;
typedef struct _GimpPaletteSelect GimpPaletteSelect;
typedef struct _GimpPatternSelect GimpPatternSelect;
typedef struct _GimpPickableSelect GimpPickableSelect;
@@ -204,6 +205,7 @@ typedef struct _GimpHighlightableButton GimpHighlightableButton;
typedef struct _GimpHistogramBox GimpHistogramBox;
typedef struct _GimpHistogramView GimpHistogramView;
typedef struct _GimpIconPicker GimpIconPicker;
+typedef struct _GimpImageChooser GimpImageChooser;
typedef struct _GimpImageCommentEditor GimpImageCommentEditor;
typedef struct _GimpImageParasiteView GimpImageParasiteView;
typedef struct _GimpImageProfileView GimpImageProfileView;
diff --git a/libgimp/gimp.def b/libgimp/gimp.def
index 733854efa5..e0eb48909a 100644
--- a/libgimp/gimp.def
+++ b/libgimp/gimp.def
@@ -579,6 +579,9 @@ EXPORTS
gimp_image_undo_is_enabled
gimp_image_undo_thaw
gimp_image_unset_active_channel
+ gimp_images_close_popup
+ gimp_images_popup
+ gimp_images_set_popup
gimp_item_attach_parasite
gimp_item_delete
gimp_item_detach_parasite
diff --git a/libgimp/gimpimagechooser.c b/libgimp/gimpimagechooser.c
new file mode 100644
index 0000000000..7fda6af419
--- /dev/null
+++ b/libgimp/gimpimagechooser.c
@@ -0,0 +1,573 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpimagechooser.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include "config.h"
+
+#include
+#include
+
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "gimp.h"
+
+#include "gimpuitypes.h"
+#include "gimpimagechooser.h"
+#include "gimpuimarshal.h"
+
+#include "libgimp-intl.h"
+
+
+/**
+ * SECTION: gimpimagechooser
+ * @title: GimpImageChooser
+ * @short_description: A widget allowing to select a image.
+ *
+ * The chooser contains an optional label and a button which queries the core
+ * process to pop up an image selection dialog.
+ *
+ * Since: 3.0
+ **/
+
+#define CELL_SIZE 40
+#define BUTTON_SIZE 96
+
+enum
+{
+ PROP_0,
+ PROP_TITLE,
+ PROP_LABEL,
+ PROP_IMAGE,
+ N_PROPS
+};
+
+struct _GimpImageChooser
+{
+ GtkBox parent_instance;
+
+ GimpImage *image;
+ gchar *title;
+ gchar *label;
+ gchar *callback;
+
+ GBytes *thumbnail;
+ gint width;
+ gint height;
+ gint bpp;
+
+ GtkWidget *label_widget;
+ GtkWidget *preview_frame;
+ GtkWidget *preview;
+ GtkWidget *preview_title;
+};
+
+
+/* local function prototypes */
+
+static void gimp_image_chooser_constructed (GObject *object);
+static void gimp_image_chooser_dispose (GObject *object);
+static void gimp_image_chooser_finalize (GObject *object);
+
+static void gimp_image_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_image_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_image_chooser_clicked (GimpImageChooser *chooser);
+
+static GimpValueArray * gimp_temp_callback_run (GimpProcedure *procedure,
+ GimpProcedureConfig *config,
+ GimpImageChooser *chooser);
+static gboolean gimp_image_select_remove_after_run (const gchar *procedure_name);
+
+static void gimp_image_chooser_draw (GimpImageChooser *chooser);
+static void gimp_image_chooser_get_thumbnail (GimpImageChooser *chooser,
+ gint width,
+ gint height);
+
+
+static GParamSpec *image_button_props[N_PROPS] = { NULL, };
+
+G_DEFINE_FINAL_TYPE (GimpImageChooser, gimp_image_chooser, GTK_TYPE_BOX)
+
+
+static void
+gimp_image_chooser_class_init (GimpImageChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gimp_image_chooser_constructed;
+ object_class->dispose = gimp_image_chooser_dispose;
+ object_class->finalize = gimp_image_chooser_finalize;
+ object_class->set_property = gimp_image_chooser_set_property;
+ object_class->get_property = gimp_image_chooser_get_property;
+
+ /**
+ * GimpImageChooser:title:
+ *
+ * The title to be used for the image selection popup dialog.
+ *
+ * Since: 3.0
+ */
+ image_button_props[PROP_TITLE] =
+ g_param_spec_string ("title",
+ "Title",
+ "The title to be used for the image selection popup dialog",
+ "Image Selection",
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ /**
+ * GimpImageChooser:label:
+ *
+ * Label text with mnemonic.
+ *
+ * Since: 3.0
+ */
+ image_button_props[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "The label to be used next to the button",
+ NULL,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ /**
+ * GimpImageChooser:image:
+ *
+ * The currently selected image.
+ *
+ * Since: 3.0
+ */
+ image_button_props[PROP_IMAGE] =
+ gimp_param_spec_image ("image",
+ "Image",
+ "The currently selected image",
+ TRUE,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class,
+ N_PROPS, image_button_props);
+}
+
+static void
+gimp_image_chooser_init (GimpImageChooser *chooser)
+{
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (chooser),
+ GTK_ORIENTATION_HORIZONTAL);
+ gtk_box_set_spacing (GTK_BOX (chooser), 6);
+
+ chooser->thumbnail = NULL;
+}
+
+static void
+gimp_image_chooser_constructed (GObject *object)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+ GtkWidget *button;
+ GtkWidget *box;
+ gint scale_factor;
+
+ scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (chooser));
+
+ chooser->label_widget = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX (chooser), chooser->label_widget, FALSE, FALSE, 0);
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (chooser->label_widget), chooser->label);
+ gtk_widget_set_visible (GTK_WIDGET (chooser->label_widget), TRUE);
+
+ button = gtk_button_new ();
+ gtk_box_pack_start (GTK_BOX (chooser), button, FALSE, FALSE, 0);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (chooser->label_widget), button);
+ gtk_widget_set_visible (button, TRUE);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+ gtk_container_add (GTK_CONTAINER (button), box);
+ gtk_widget_set_visible (box, TRUE);
+
+ chooser->preview_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
+ gtk_frame_set_shadow_type (GTK_FRAME (chooser->preview_frame), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (box), chooser->preview_frame, FALSE, FALSE, 0);
+ gtk_widget_set_visible (chooser->preview_frame, TRUE);
+
+ chooser->preview = gimp_preview_area_new ();
+ gtk_widget_set_size_request (chooser->preview, scale_factor * CELL_SIZE, scale_factor * CELL_SIZE);
+ gtk_container_add (GTK_CONTAINER (chooser->preview_frame), chooser->preview);
+ gtk_widget_set_visible (chooser->preview, TRUE);
+
+ chooser->preview_title = gtk_label_new (_("Browse..."));
+ gtk_box_pack_start (GTK_BOX (box), chooser->preview_title, FALSE, FALSE, 0);
+ gtk_widget_set_visible (chooser->preview_title, TRUE);
+
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (gimp_image_chooser_clicked),
+ chooser);
+
+ G_OBJECT_CLASS (gimp_image_chooser_parent_class)->constructed (object);
+}
+
+static void
+gimp_image_chooser_dispose (GObject *object)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ if (chooser->callback)
+ {
+ gimp_images_close_popup (chooser->callback);
+
+ gimp_plug_in_remove_temp_procedure (gimp_get_plug_in (), chooser->callback);
+ g_clear_pointer (&chooser->callback, g_free);
+ }
+
+ G_OBJECT_CLASS (gimp_image_chooser_parent_class)->dispose (object);
+}
+
+static void
+gimp_image_chooser_finalize (GObject *object)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ g_clear_pointer (&chooser->title, g_free);
+ g_clear_pointer (&chooser->label, g_free);
+ g_clear_pointer (&chooser->thumbnail, g_bytes_unref);
+
+ G_OBJECT_CLASS (gimp_image_chooser_parent_class)->finalize (object);
+}
+
+static void
+gimp_image_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *gvalue,
+ GParamSpec *pspec)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_TITLE:
+ chooser->title = g_value_dup_string (gvalue);
+ break;
+
+ case PROP_LABEL:
+ chooser->label = g_value_dup_string (gvalue);
+ break;
+
+ case PROP_IMAGE:
+ gimp_image_chooser_set_image (chooser, g_value_get_object (gvalue));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_image_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpImageChooser *chooser = GIMP_IMAGE_CHOOSER (object);
+
+ switch (property_id)
+ {
+ case PROP_TITLE:
+ g_value_set_string (value, chooser->title);
+ break;
+
+ case PROP_LABEL:
+ g_value_set_string (value, chooser->label);
+ break;
+
+ case PROP_IMAGE:
+ g_value_set_object (value, chooser->image);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gimp_image_chooser_new:
+ * @title: (nullable): Title of the dialog to use or %NULL to use the default title.
+ * @label: (nullable): Button label or %NULL for no label.
+ * @image: (nullable): Initial image.
+ *
+ * Creates a new #GtkWidget that lets a user choose an image.
+ *
+ * When @image is %NULL, initial choice is from context.
+ *
+ * Returns: A [class@GimpUi.ImageChooser.
+ *
+ * Since: 3.0
+ */
+GtkWidget *
+gimp_image_chooser_new (const gchar *title,
+ const gchar *label,
+ GimpImage *image)
+{
+ GtkWidget *chooser;
+
+ g_return_val_if_fail (image == NULL, NULL);
+
+ chooser = g_object_new (GIMP_TYPE_IMAGE_CHOOSER,
+ "title", title,
+ "label", label,
+ "image", image,
+ NULL);
+
+ return chooser;
+}
+
+/**
+ * gimp_image_chooser_get_image:
+ * @chooser: A #GimpImageChooser
+ *
+ * Gets the currently selected image.
+ *
+ * Returns: (transfer none): an internal copy of the image which must not be freed.
+ *
+ * Since: 3.0
+ */
+GimpImage *
+gimp_image_chooser_get_image (GimpImageChooser *chooser)
+{
+ g_return_val_if_fail (GIMP_IS_IMAGE_CHOOSER (chooser), NULL);
+
+ return chooser->image;
+}
+
+/**
+ * gimp_image_chooser_set_image:
+ * @chooser: A #GimpImageChooser
+ * @image: Image to set.
+ *
+ * Sets the currently selected image.
+ * This will select the image in both the button and any chooser popup.
+ *
+ * Since: 3.0
+ */
+void
+gimp_image_chooser_set_image (GimpImageChooser *chooser,
+ GimpImage *image)
+{
+ g_return_if_fail (GIMP_IS_IMAGE_CHOOSER (chooser));
+ g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
+
+ chooser->image = image;
+
+ if (chooser->callback)
+ gimp_images_set_popup (chooser->callback, chooser->image);
+
+ g_object_notify_by_pspec (G_OBJECT (chooser), image_button_props[PROP_IMAGE]);
+
+ gimp_image_chooser_draw (chooser);
+}
+
+/**
+ * gimp_image_chooser_get_label:
+ * @widget: A [class@ImageChooser].
+ *
+ * Returns the label widget.
+ *
+ * Returns: (transfer none): the [class@Gtk.Widget] showing the label text.
+ * Since: 3.0
+ */
+GtkWidget *
+gimp_image_chooser_get_label (GimpImageChooser *chooser)
+{
+ g_return_val_if_fail (GIMP_IS_IMAGE_CHOOSER (chooser), NULL);
+
+ return chooser->label_widget;
+}
+
+
+/* private functions */
+
+static GimpValueArray *
+gimp_temp_callback_run (GimpProcedure *procedure,
+ GimpProcedureConfig *config,
+ GimpImageChooser *chooser)
+{
+ GimpImage *image;
+ gboolean closing;
+
+ g_object_get (config,
+ "image", &image,
+ "closing", &closing,
+ NULL);
+
+ g_object_set (chooser, "image", image, NULL);
+
+ if (closing)
+ {
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) gimp_image_select_remove_after_run,
+ g_strdup (gimp_procedure_get_name (procedure)),
+ g_free);
+ g_clear_pointer (&chooser->callback, g_free);
+ }
+
+ g_clear_object (&image);
+
+ return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
+}
+
+static gboolean
+gimp_image_select_remove_after_run (const gchar *procedure_name)
+{
+ gimp_plug_in_remove_temp_procedure (gimp_get_plug_in (), procedure_name);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+gimp_image_chooser_clicked (GimpImageChooser *chooser)
+{
+ if (chooser->callback)
+ {
+ /* Popup already created. Calling setter raises the popup. */
+ gimp_images_set_popup (chooser->callback, chooser->image);
+ }
+ else
+ {
+ GimpPlugIn *plug_in = gimp_get_plug_in ();
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (chooser));
+ GBytes *handle = NULL;
+ gchar *callback_name;
+ GimpProcedure *callback_procedure;
+
+ if (GIMP_IS_DIALOG (toplevel))
+ handle = gimp_dialog_get_native_handle (GIMP_DIALOG (toplevel));
+
+ callback_name = gimp_pdb_temp_procedure_name (gimp_get_pdb ());
+ callback_procedure = gimp_procedure_new (plug_in,
+ callback_name,
+ GIMP_PDB_PROC_TYPE_TEMPORARY,
+ (GimpRunFunc) gimp_temp_callback_run,
+ g_object_ref (chooser),
+ (GDestroyNotify) g_object_unref);
+ gimp_procedure_add_image_argument (callback_procedure, "image",
+ "Image", "The selected image",
+ TRUE, G_PARAM_READWRITE);
+ gimp_procedure_add_boolean_argument (callback_procedure, "closing",
+ "Closing", "If the dialog was closing",
+ FALSE, G_PARAM_READWRITE);
+
+ gimp_plug_in_add_temp_procedure (plug_in, callback_procedure);
+ g_object_unref (callback_procedure);
+ g_free (callback_name);
+
+ if (gimp_images_popup (gimp_procedure_get_name (callback_procedure), chooser->title,
+ chooser->image, handle))
+ {
+ /* Allow callbacks to be watched */
+ gimp_plug_in_persistent_enable (plug_in);
+
+ chooser->callback = g_strdup (gimp_procedure_get_name (callback_procedure));
+ }
+ else
+ {
+ g_warning ("%s: failed to open remote image select dialog.", G_STRFUNC);
+ gimp_plug_in_remove_temp_procedure (plug_in, gimp_procedure_get_name (callback_procedure));
+ return;
+ }
+ gimp_images_set_popup (chooser->callback, chooser->image);
+ }
+}
+
+static void
+gimp_image_chooser_draw (GimpImageChooser *chooser)
+{
+ GimpPreviewArea *area = GIMP_PREVIEW_AREA (chooser->preview);
+ GtkAllocation allocation;
+ gint x = 0;
+ gint y = 0;
+
+ gtk_widget_get_allocation (chooser->preview, &allocation);
+
+ gimp_image_chooser_get_thumbnail (chooser, allocation.width, allocation.height);
+
+ if (chooser->width < allocation.width ||
+ chooser->height < allocation.height)
+ {
+ x = ((allocation.width - chooser->width) / 2);
+ y = ((allocation.height - chooser->height) / 2);
+ }
+ gimp_preview_area_reset (area);
+
+ if (chooser->thumbnail)
+ {
+ GimpImageType type;
+ gint rowstride;
+
+ rowstride = chooser->width * chooser->bpp;
+ switch (chooser->bpp)
+ {
+ case 1:
+ type = GIMP_GRAY_IMAGE;
+ break;
+ case 2:
+ type = GIMP_GRAYA_IMAGE;
+ break;
+ case 3:
+ type = GIMP_RGB_IMAGE;
+ break;
+ case 4:
+ type = GIMP_RGBA_IMAGE;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ gimp_preview_area_draw (area, x, y, chooser->width, chooser->height, type,
+ g_bytes_get_data (chooser->thumbnail, NULL), rowstride);
+ }
+}
+
+static void
+gimp_image_chooser_get_thumbnail (GimpImageChooser *chooser,
+ gint width,
+ gint height)
+{
+ if (chooser->width == width &&
+ chooser->height == height)
+ /* Let's assume image contents is not changing in a single run. */
+ return;
+
+ g_clear_pointer (&chooser->thumbnail, g_bytes_unref);
+
+ if (chooser->image)
+ {
+ chooser->width = BUTTON_SIZE;
+ chooser->height = BUTTON_SIZE;
+
+ chooser->thumbnail = gimp_image_get_thumbnail_data (chooser->image,
+ &chooser->width,
+ &chooser->height,
+ &chooser->bpp);
+ }
+}
diff --git a/libgimp/gimpimagechooser.h b/libgimp/gimpimagechooser.h
new file mode 100644
index 0000000000..4bc3d4b960
--- /dev/null
+++ b/libgimp/gimpimagechooser.h
@@ -0,0 +1,46 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpimagechooser.h
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __GIMP_IMAGE_CHOOSER_H__
+#define __GIMP_IMAGE_CHOOSER_H__
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_IMAGE_CHOOSER (gimp_image_chooser_get_type ())
+G_DECLARE_FINAL_TYPE (GimpImageChooser, gimp_image_chooser, GIMP, IMAGE_CHOOSER, GtkBox)
+
+
+GtkWidget * gimp_image_chooser_new (const gchar *title,
+ const gchar *label,
+ GimpImage *image);
+
+GimpImage * gimp_image_chooser_get_image (GimpImageChooser *chooser);
+void gimp_image_chooser_set_image (GimpImageChooser *chooser,
+ GimpImage *image);
+
+GtkWidget * gimp_image_chooser_get_label (GimpImageChooser *widget);
+
+G_END_DECLS
+
+#endif /* __GIMP_IMAGE_CHOOSER_H__ */
diff --git a/libgimp/gimpimageselect_pdb.c b/libgimp/gimpimageselect_pdb.c
index 3d0ac5aa31..b16b54801b 100644
--- a/libgimp/gimpimageselect_pdb.c
+++ b/libgimp/gimpimageselect_pdb.c
@@ -447,3 +447,114 @@ gimp_image_select_item (GimpImage *image,
return success;
}
+
+/**
+ * gimp_images_popup:
+ * @callback: The callback PDB proc to call when user chooses an image.
+ * @popup_title: Title of the image selection dialog.
+ * @initial_image: (nullable): The image to set as the initial choice.
+ * @parent_window: (nullable): An optional parent window handle for the popup to be set transient to.
+ *
+ * Invokes the image selection dialog.
+ *
+ * Opens a dialog letting a user choose an image.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_images_popup (const gchar *callback,
+ const gchar *popup_title,
+ GimpImage *initial_image,
+ GBytes *parent_window)
+{
+ GimpValueArray *args;
+ GimpValueArray *return_vals;
+ gboolean success = TRUE;
+
+ args = gimp_value_array_new_from_types (NULL,
+ G_TYPE_STRING, callback,
+ G_TYPE_STRING, popup_title,
+ GIMP_TYPE_IMAGE, initial_image,
+ G_TYPE_BYTES, parent_window,
+ G_TYPE_NONE);
+
+ return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
+ "gimp-images-popup",
+ args);
+ gimp_value_array_unref (args);
+
+ success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
+
+ gimp_value_array_unref (return_vals);
+
+ return success;
+}
+
+/**
+ * gimp_images_close_popup:
+ * @callback: The name of the callback registered for this pop-up.
+ *
+ * Close the image selection dialog.
+ *
+ * Closes an open image selection dialog.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_images_close_popup (const gchar *callback)
+{
+ GimpValueArray *args;
+ GimpValueArray *return_vals;
+ gboolean success = TRUE;
+
+ args = gimp_value_array_new_from_types (NULL,
+ G_TYPE_STRING, callback,
+ G_TYPE_NONE);
+
+ return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
+ "gimp-images-close-popup",
+ args);
+ gimp_value_array_unref (args);
+
+ success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
+
+ gimp_value_array_unref (return_vals);
+
+ return success;
+}
+
+/**
+ * gimp_images_set_popup:
+ * @callback: The name of the callback registered for this pop-up.
+ * @image: The image to set as selected.
+ *
+ * Sets the selected image in a image selection dialog.
+ *
+ * Sets the selected image in a image selection dialog.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_images_set_popup (const gchar *callback,
+ GimpImage *image)
+{
+ GimpValueArray *args;
+ GimpValueArray *return_vals;
+ gboolean success = TRUE;
+
+ args = gimp_value_array_new_from_types (NULL,
+ G_TYPE_STRING, callback,
+ GIMP_TYPE_IMAGE, image,
+ G_TYPE_NONE);
+
+ return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
+ "gimp-images-set-popup",
+ args);
+ gimp_value_array_unref (args);
+
+ success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
+
+ gimp_value_array_unref (return_vals);
+
+ return success;
+}
diff --git a/libgimp/gimpimageselect_pdb.h b/libgimp/gimpimageselect_pdb.h
index dc8b887a9f..32160e9afb 100644
--- a/libgimp/gimpimageselect_pdb.h
+++ b/libgimp/gimpimageselect_pdb.h
@@ -68,6 +68,13 @@ gboolean gimp_image_select_polygon (GimpImage *image,
gboolean gimp_image_select_item (GimpImage *image,
GimpChannelOps operation,
GimpItem *item);
+gboolean gimp_images_popup (const gchar *callback,
+ const gchar *popup_title,
+ GimpImage *initial_image,
+ GBytes *parent_window);
+gboolean gimp_images_close_popup (const gchar *callback);
+gboolean gimp_images_set_popup (const gchar *callback,
+ GimpImage *image);
G_END_DECLS
diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c
index 7deb08718b..ff215d4451 100644
--- a/libgimp/gimpproceduredialog.c
+++ b/libgimp/gimpproceduredialog.c
@@ -913,6 +913,10 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
{
widget = gimp_prop_drawable_chooser_new (G_OBJECT (priv->config), property, NULL);
}
+ else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_IMAGE)
+ {
+ widget = gimp_prop_image_chooser_new (G_OBJECT (priv->config), property, NULL);
+ }
else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_ENUM)
{
GimpIntStore *store;
@@ -962,6 +966,8 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
label = gimp_resource_chooser_get_label (GIMP_RESOURCE_CHOOSER (widget));
else if (GIMP_IS_DRAWABLE_CHOOSER (widget))
label = gimp_drawable_chooser_get_label (GIMP_DRAWABLE_CHOOSER (widget));
+ else if (GIMP_IS_IMAGE_CHOOSER (widget))
+ label = gimp_image_chooser_get_label (GIMP_IMAGE_CHOOSER (widget));
}
if (label != NULL)
@@ -2916,6 +2922,10 @@ gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog *dialog,
{
label = gimp_drawable_chooser_get_label (GIMP_DRAWABLE_CHOOSER (widget));
}
+ else if (GIMP_IS_IMAGE_CHOOSER (widget))
+ {
+ label = gimp_image_chooser_get_label (GIMP_IMAGE_CHOOSER (widget));
+ }
else if (GIMP_IS_FILE_CHOOSER (widget))
{
label = gimp_file_chooser_get_label_widget (GIMP_FILE_CHOOSER (widget));
diff --git a/libgimp/gimppropwidgets.c b/libgimp/gimppropwidgets.c
index ec13aee8f6..76c42c57c1 100644
--- a/libgimp/gimppropwidgets.c
+++ b/libgimp/gimppropwidgets.c
@@ -146,6 +146,66 @@ gimp_prop_pattern_chooser_new (GObject *config,
config, property_name, chooser_title);
}
+/**
+ * gimp_prop_image_chooser_new:
+ * @config: Object to which property is attached.
+ * @property_name: Name of a [class@Gimp.Image] property.
+ * @chooser_title: (nullable): title for the poppable dialog.
+ *
+ * Creates a [class@GimpUi.ImageChooser] controlled by the specified property.
+ *
+ * Returns: (transfer full): A new [class@GimpUi.ImageChooser].
+ *
+ * Since: 3.0
+ */
+GtkWidget *
+gimp_prop_image_chooser_new (GObject *config,
+ const gchar *property_name,
+ const gchar *chooser_title)
+{
+ GParamSpec *param_spec;
+ GtkWidget *prop_chooser;
+ GimpImage *initial_image = NULL;
+ gchar *title = NULL;
+ const gchar *label;
+
+ param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
+ property_name);
+
+ g_return_val_if_fail (param_spec != NULL, NULL);
+ g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec), G_TYPE_PARAM_OBJECT) &&
+ g_type_is_a (param_spec->value_type, GIMP_TYPE_IMAGE), NULL);
+
+ g_object_get (config,
+ property_name, &initial_image,
+ NULL);
+
+ label = g_param_spec_get_nick (param_spec);
+
+ if (chooser_title == NULL)
+ {
+ gchar *canonical;
+
+ canonical = gimp_utils_make_canonical_menu_label (label);
+ title = g_strdup_printf (_("Choose image: %s"), canonical);
+ g_free (canonical);
+ }
+ else
+ {
+ title = g_strdup (chooser_title);
+ }
+
+ prop_chooser = gimp_image_chooser_new (title, label, initial_image);
+ g_clear_object (&initial_image);
+ g_free (title);
+
+ g_object_bind_property (prop_chooser, "image",
+ config, property_name,
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ return prop_chooser;
+}
+
/**
* gimp_prop_drawable_chooser_new:
* @config: Object to which property is attached.
diff --git a/libgimp/gimppropwidgets.h b/libgimp/gimppropwidgets.h
index 0db7063158..dddc006a8a 100644
--- a/libgimp/gimppropwidgets.h
+++ b/libgimp/gimppropwidgets.h
@@ -48,6 +48,9 @@ GtkWidget * gimp_prop_pattern_chooser_new (GObject *config,
const gchar *property_name,
const gchar *chooser_title);
+GtkWidget * gimp_prop_image_chooser_new (GObject *config,
+ const gchar *property_name,
+ const gchar *chooser_title);
GtkWidget * gimp_prop_drawable_chooser_new (GObject *config,
const gchar *property_name,
const gchar *chooser_title);
diff --git a/libgimp/gimpui.def b/libgimp/gimpui.def
index 3d8a9309d1..e7453c96b8 100644
--- a/libgimp/gimpui.def
+++ b/libgimp/gimpui.def
@@ -22,6 +22,11 @@ EXPORTS
gimp_font_chooser_new
gimp_gradient_chooser_get_type
gimp_gradient_chooser_new
+ gimp_image_chooser_get_image
+ gimp_image_chooser_get_label
+ gimp_image_chooser_get_type
+ gimp_image_chooser_new
+ gimp_image_chooser_set_image
gimp_image_combo_box_get_type
gimp_image_combo_box_new
gimp_layer_combo_box_get_type
@@ -70,6 +75,7 @@ EXPORTS
gimp_prop_drawable_chooser_new
gimp_prop_font_chooser_new
gimp_prop_gradient_chooser_new
+ gimp_prop_image_chooser_new
gimp_prop_palette_chooser_new
gimp_prop_pattern_chooser_new
gimp_prop_resolution_entry_new
diff --git a/libgimp/gimpui.h b/libgimp/gimpui.h
index 25a01bf41f..81570cc854 100644
--- a/libgimp/gimpui.h
+++ b/libgimp/gimpui.h
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libgimp/gimpuitypes.h b/libgimp/gimpuitypes.h
index 1ddfdef2cb..eb9ad8810a 100644
--- a/libgimp/gimpuitypes.h
+++ b/libgimp/gimpuitypes.h
@@ -50,6 +50,7 @@ typedef struct _GimpResourceChooser GimpResourceChooser;
typedef struct _GimpBrushChooser GimpBrushChooser;
typedef struct _GimpFontChooser GimpFontChooser;
typedef struct _GimpGradientChooser GimpGradientChooser;
+typedef struct _GimpImageChooser GimpImageChooser;
typedef struct _GimpPaletteChooser GimpPaletteChooser;
typedef struct _GimpPatternChooser GimpPatternChooser;
diff --git a/libgimp/meson.build b/libgimp/meson.build
index c290593d50..acb0580d61 100644
--- a/libgimp/meson.build
+++ b/libgimp/meson.build
@@ -303,6 +303,7 @@ libgimpui_sources_introspectable = [
'gimpdrawablepreview.c',
'gimpfontchooser.c',
'gimpgradientchooser.c',
+ 'gimpimagechooser.c',
'gimpimagecombobox.c',
'gimpitemcombobox.c',
'gimppalettechooser.c',
@@ -339,6 +340,7 @@ libgimpui_headers_introspectable = [
'gimpdrawablepreview.h',
'gimpfontchooser.h',
'gimpgradientchooser.h',
+ 'gimpimagechooser.h',
'gimpimagecombobox.h',
'gimpitemcombobox.h',
'gimppalettechooser.h',
diff --git a/pdb/groups/image_select.pdb b/pdb/groups/image_select.pdb
index 8ae8647653..f8d0d8e47c 100644
--- a/pdb/groups/image_select.pdb
+++ b/pdb/groups/image_select.pdb
@@ -424,9 +424,91 @@ CODE
}
+sub images_popup {
+ $blurb = 'Invokes the image selection dialog.';
+ $help = 'Opens a dialog letting a user choose an image.';
+
+ &alxsa_pdb_misc('2025');
+
+ @inargs = (
+ { name => 'callback', type => 'string', non_empty => 1,
+ desc => 'The callback PDB proc to call when user chooses an image' },
+ { name => 'popup_title', type => 'string',
+ desc => 'Title of the image selection dialog' },
+ { name => 'initial_image', type => 'image', none_ok => 1, no_validate => 1,
+ desc => 'The image to set as the initial choice' },
+ { name => 'parent_window', type => 'bytes', none_ok => 1,
+ desc => 'An optional parent window handle for the popup to be set transient to' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_new (gimp, context, progress,
+ GIMP_TYPE_IMAGE,
+ parent_window, popup_title, callback,
+ GIMP_OBJECT (initial_image),
+ NULL))
+ success = FALSE;
+}
+CODE
+ );
+}
+
+sub images_close_popup {
+ $blurb = 'Close the image selection dialog.';
+ $help = 'Closes an open image selection dialog.';
+
+ &alxsa_pdb_misc('2025');
+
+ @inargs = (
+ { name => 'callback', type => 'string', non_empty => 1,
+ desc => 'The name of the callback registered for this pop-up' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_close (gimp, GIMP_TYPE_IMAGE, callback))
+ success = FALSE;
+}
+CODE
+ );
+}
+
+sub images_set_popup {
+ $blurb = 'Sets the selected image in a image selection dialog.';
+ $help = $blurb;
+
+ &alxsa_pdb_misc('2025');
+
+ @inargs = (
+ { name => 'callback', type => 'string', non_empty => 1,
+ desc => 'The name of the callback registered for this pop-up' },
+ { name => 'image', type => 'image', no_validate => 1,
+ desc => 'The image to set as selected' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ if (gimp->no_interface ||
+ ! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
+ ! gimp_pdb_dialog_set (gimp, GIMP_TYPE_IMAGE, callback, GIMP_OBJECT (image), NULL))
+ success = FALSE;
+}
+CODE
+ );
+}
@headers = qw("libgimpbase/gimpbase.h"
+ "core/gimp.h"
"core/gimpchannel-select.h"
+ "core/gimpdatafactory.h"
"gimppdb-utils.h"
"gimppdbcontext.h"
"gimp-intl.h");
@@ -437,7 +519,10 @@ CODE
image_select_round_rectangle
image_select_ellipse
image_select_polygon
- image_select_item);
+ image_select_item
+ images_popup
+ images_close_popup
+ images_set_popup);
%exports = (app => [@procs], lib => [@procs]);