widgets, pdb, libgimp: GimpProcedureDialog Image Widget

This patch adds a GimpImageChooser widget
for use in GimpProcedureDialog Image parameter
GUI creation.
This commit is contained in:
Alx Sa 2025-11-12 03:12:24 +00:00
parent 5cfcc9608b
commit a9dc4ddb2c
23 changed files with 1761 additions and 5 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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);
}

View file

@ -30,7 +30,7 @@
#include "internal-procs.h"
/* 779 procedures registered total */
/* 782 procedures registered total */
void
internal_procs_init (GimpPDB *pdb)

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#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);
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#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);

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#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);
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#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;

View file

@ -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',

View file

@ -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;

View file

@ -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

573
libgimp/gimpimagechooser.c Normal file
View file

@ -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
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#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);
}
}

View file

@ -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
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION)
#error "Only <libgimp/gimpui.h> 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__ */

View file

@ -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;
}

View file

@ -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

View file

@ -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));

View file

@ -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.

View file

@ -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);

View file

@ -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

View file

@ -35,6 +35,7 @@
#include <libgimp/gimpdrawablepreview.h>
#include <libgimp/gimpfontchooser.h>
#include <libgimp/gimpgradientchooser.h>
#include <libgimp/gimpimagechooser.h>
#include <libgimp/gimpimagecombobox.h>
#include <libgimp/gimpitemcombobox.h>
#include <libgimp/gimppalettechooser.h>

View file

@ -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;

View file

@ -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',

View file

@ -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]);