app, libgimp, pdb: generate widgets for GIMP_PROC_ARG_LAYER|CHANNEL arguments.

I am using the same GimpDrawableChooser with an additional drawable_type
argument to only show the appropriate tab if we want to limit what can be
chosen.

None of our plug-ins actually use a GimpLayer or GimpChannel only arg so far,
but if we have some day, or if some third-party plug-ins want to have such arg,
now they quite easily can!
This commit is contained in:
Jehan 2023-09-05 22:39:04 +02:00
parent 4be1166982
commit 2f4d625059
14 changed files with 219 additions and 90 deletions

View file

@ -418,7 +418,9 @@ 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) ||
contents_type == GIMP_TYPE_DRAWABLE, FALSE);
g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE), 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);
g_return_val_if_fail (callback_name != NULL, FALSE);

View file

@ -655,18 +655,22 @@ gui_pdb_dialog_new (Gimp *gimp,
dialog_role = "gimp-pattern-selection";
help_id = GIMP_HELP_PATTERN_DIALOG;
}
else if (contents_type == GIMP_TYPE_DRAWABLE)
else if (g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE))
{
dialog_type = GIMP_TYPE_PICKABLE_SELECT;
dialog_role = "gimp-pickable-selection";
}
else
{
g_return_val_if_reached (FALSE);
}
if (dialog_type != G_TYPE_NONE)
{
if (! object && contents_type != GIMP_TYPE_DRAWABLE)
if (! object && ! g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE))
object = gimp_context_get_by_type (context, contents_type);
if (object || contents_type == GIMP_TYPE_DRAWABLE)
if (object || g_type_is_a (contents_type, GIMP_TYPE_DRAWABLE))
{
gint n_properties = 0;
gchar **names = NULL;

View file

@ -50,21 +50,24 @@ drawables_popup_invoker (GimpProcedure *procedure,
gboolean success = TRUE;
const gchar *callback;
const gchar *popup_title;
const gchar *drawable_type;
GimpDrawable *initial_drawable;
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_drawable = g_value_get_object (gimp_value_array_index (args, 2));
parent_window = g_value_get_boxed (gimp_value_array_index (args, 3));
drawable_type = g_value_get_string (gimp_value_array_index (args, 2));
initial_drawable = g_value_get_object (gimp_value_array_index (args, 3));
parent_window = g_value_get_boxed (gimp_value_array_index (args, 4));
if (success)
{
if (gimp->no_interface ||
! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
! gimp_pdb_dialog_new (gimp, context, progress,
GIMP_TYPE_DRAWABLE, parent_window,
popup_title, callback, GIMP_OBJECT (initial_drawable),
g_type_from_name (drawable_type),
parent_window, popup_title, callback,
GIMP_OBJECT (initial_drawable),
NULL))
success = FALSE;
}
@ -158,6 +161,13 @@ register_drawable_select_procs (GimpPDB *pdb)
FALSE, FALSE, FALSE,
NULL,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("drawable-type",
"drawable type",
"The name of the GIMP_TYPE_DRAWABLE subtype",
FALSE, FALSE, TRUE,
NULL,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_drawable ("initial-drawable",
"initial drawable",

View file

@ -55,6 +55,7 @@ enum
{
PROP_0,
PROP_CONTEXT,
PROP_PICKABLE_TYPE,
PROP_PICKABLE,
PROP_VIEW_SIZE,
PROP_VIEW_BORDER_WIDTH
@ -62,6 +63,7 @@ enum
struct _GimpPickableChooserPrivate
{
GType pickable_type;
GimpPickable *pickable;
GimpContext *context;
@ -140,6 +142,13 @@ gimp_pickable_chooser_class_init (GimpPickableChooserClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_PICKABLE_TYPE,
g_param_spec_gtype ("pickable-type",
NULL, NULL,
GIMP_TYPE_PICKABLE,
GIMP_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_PICKABLE,
g_param_spec_object ("pickable",
NULL, NULL,
@ -172,6 +181,9 @@ gimp_pickable_chooser_init (GimpPickableChooser *chooser)
chooser->priv->view_size = GIMP_VIEW_SIZE_SMALL;
chooser->priv->view_border_width = 1;
chooser->priv->layer_view = NULL;
chooser->priv->channel_view = NULL;
}
static void
@ -239,6 +251,8 @@ gimp_pickable_chooser_constructed (GObject *object)
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
gtk_widget_show (notebook);
if (g_type_is_a (GIMP_TYPE_LAYER, chooser->priv->pickable_type))
{
chooser->priv->layer_view =
gimp_container_tree_view_new (NULL,
chooser->priv->context,
@ -262,7 +276,10 @@ gimp_pickable_chooser_constructed (GObject *object)
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
if (g_type_is_a (GIMP_TYPE_CHANNEL, chooser->priv->pickable_type))
{
chooser->priv->channel_view =
gimp_container_tree_view_new (NULL,
chooser->priv->context,
@ -284,6 +301,7 @@ gimp_pickable_chooser_constructed (GObject *object)
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
g_signal_connect_object (chooser->priv->context, "image-changed",
G_CALLBACK (gimp_pickable_chooser_image_changed),
@ -328,7 +346,19 @@ gimp_pickable_chooser_set_property (GObject *object,
chooser->priv->view_border_width = g_value_get_int (value);
break;
case PROP_PICKABLE_TYPE:
g_return_if_fail (g_value_get_gtype (value) == GIMP_TYPE_LAYER ||
g_value_get_gtype (value) == GIMP_TYPE_CHANNEL ||
g_value_get_gtype (value) == GIMP_TYPE_DRAWABLE ||
g_value_get_gtype (value) == GIMP_TYPE_IMAGE ||
g_value_get_gtype (value) == GIMP_TYPE_PICKABLE);
chooser->priv->pickable_type = g_value_get_gtype (value);
break;
case PROP_PICKABLE:
g_return_if_fail (g_value_get_object (value) == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (g_value_get_object (value)),
chooser->priv->pickable_type));
gimp_pickable_chooser_set_pickable (chooser, g_value_get_object (value));
break;
@ -352,6 +382,10 @@ gimp_pickable_chooser_get_property (GObject *object,
g_value_set_object (value, chooser->priv->context);
break;
case PROP_PICKABLE_TYPE:
g_value_set_gtype (value, chooser->priv->pickable_type);
break;
case PROP_PICKABLE:
g_value_set_object (value, chooser->priv->pickable);
break;
@ -372,6 +406,7 @@ gimp_pickable_chooser_get_property (GObject *object,
GtkWidget *
gimp_pickable_chooser_new (GimpContext *context,
GType pickable_type,
gint view_size,
gint view_border_width)
{
@ -384,6 +419,7 @@ gimp_pickable_chooser_new (GimpContext *context,
return g_object_new (GIMP_TYPE_PICKABLE_CHOOSER,
"context", context,
"pickable-type", pickable_type,
"view-size", view_size,
"view-border-width", view_border_width,
NULL);
@ -406,12 +442,20 @@ gimp_pickable_chooser_set_pickable (GimpPickableChooser *chooser,
g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
if (chooser->priv->layer_view != NULL)
g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
else
g_return_if_fail (! GIMP_IS_LAYER (pickable));
if (chooser->priv->channel_view != NULL)
g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
else
g_return_if_fail (! GIMP_IS_CHANNEL (pickable));
if (GIMP_IS_IMAGE (pickable))
{
gimp_container_view_select_item (GIMP_CONTAINER_VIEW (chooser->priv->image_view),
@ -439,9 +483,11 @@ gimp_pickable_chooser_set_pickable (GimpPickableChooser *chooser,
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
if (chooser->priv->layer_view != NULL)
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
if (chooser->priv->channel_view != NULL)
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
@ -486,26 +532,32 @@ gimp_pickable_chooser_image_changed (GimpContext *context,
g_signal_handlers_disconnect_by_func (chooser->priv->image_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
if (chooser->priv->layer_view != NULL)
{
g_signal_handlers_disconnect_by_func (chooser->priv->layer_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
gimp_container_view_set_container (GIMP_CONTAINER_VIEW (chooser->priv->layer_view),
layers);
gimp_container_view_set_container (GIMP_CONTAINER_VIEW (chooser->priv->channel_view),
channels);
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
g_signal_connect_object (chooser->priv->layer_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
if (chooser->priv->channel_view != NULL)
{
g_signal_handlers_disconnect_by_func (chooser->priv->channel_view,
G_CALLBACK (gimp_pickable_chooser_items_selected),
chooser);
gimp_container_view_set_container (GIMP_CONTAINER_VIEW (chooser->priv->channel_view),
channels);
g_signal_connect_object (chooser->priv->channel_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
g_signal_connect_object (chooser->priv->image_view, "select-items",
G_CALLBACK (gimp_pickable_chooser_items_selected),
G_OBJECT (chooser), 0);
}
static void
gimp_pickable_chooser_item_activate (GimpContainerView *view,

View file

@ -54,6 +54,7 @@ struct _GimpPickableChooserClass
GType gimp_pickable_chooser_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_pickable_chooser_new (GimpContext *context,
GType pickable_type,
gint view_size,
gint view_border_width);

View file

@ -151,7 +151,8 @@ gimp_pickable_popup_constructed (GObject *object)
gimp_assert (GIMP_IS_CONTEXT (popup->priv->context));
popup->priv->chooser = gimp_pickable_chooser_new (popup->priv->context, popup->priv->view_size,
popup->priv->chooser = gimp_pickable_chooser_new (popup->priv->context, GIMP_TYPE_PICKABLE,
popup->priv->view_size,
popup->priv->view_border_width);
gtk_container_add (GTK_CONTAINER (popup), popup->priv->chooser);
g_signal_connect_swapped (popup->priv->chooser, "notify::pickable",

View file

@ -94,7 +94,8 @@ gimp_pickable_select_constructed (GObject *object)
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
select->chooser = gimp_pickable_chooser_new (dialog->context, GIMP_VIEW_SIZE_LARGE, 1);
select->chooser = gimp_pickable_chooser_new (dialog->context, dialog->select_type,
GIMP_VIEW_SIZE_LARGE, 1);
gimp_pickable_chooser_set_pickable (GIMP_PICKABLE_CHOOSER (select->chooser),
GIMP_PICKABLE (dialog->initial_object));
g_signal_connect_swapped (select->chooser, "notify::pickable",

View file

@ -54,6 +54,7 @@ enum
PROP_TITLE,
PROP_LABEL,
PROP_DRAWABLE,
PROP_DRAWABLE_TYPE,
N_PROPS
};
@ -61,6 +62,7 @@ struct _GimpDrawableChooser
{
GtkBox parent_instance;
GType drawable_type;
GimpDrawable *drawable;
gchar *title;
gchar *label;
@ -168,6 +170,22 @@ gimp_drawable_chooser_class_init (GimpDrawableChooserClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GimpDrawableChooser:drawable-type:
*
* Allowed drawable types, which must be either GIMP_TYPE_DRAWABLE or a
* subtype.
*
* Since: 3.0
*/
drawable_button_props[PROP_DRAWABLE_TYPE] =
g_param_spec_gtype ("drawable-type",
"Allowed drawable Type",
"The GType of the drawable property",
GIMP_TYPE_DRAWABLE,
G_PARAM_CONSTRUCT_ONLY |
GIMP_PARAM_READWRITE);
g_object_class_install_properties (object_class,
N_PROPS, drawable_button_props);
}
@ -275,9 +293,16 @@ gimp_drawable_chooser_set_property (GObject *object,
break;
case PROP_DRAWABLE:
g_return_if_fail (g_value_get_object (gvalue) == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (g_value_get_object (gvalue)),
chooser->drawable_type));
gimp_drawable_chooser_set_drawable (chooser, g_value_get_object (gvalue));
break;
case PROP_DRAWABLE_TYPE:
chooser->drawable_type = g_value_get_gtype (gvalue);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -306,6 +331,10 @@ gimp_drawable_chooser_get_property (GObject *object,
g_value_set_object (value, chooser->drawable);
break;
case PROP_DRAWABLE_TYPE:
g_value_set_gtype (value, chooser->drawable_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -316,9 +345,13 @@ gimp_drawable_chooser_get_property (GObject *object,
* gimp_drawable_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.
* @drawable_type: the acceptable subtype of choosable drawables.
* @drawable: (nullable): Initial drawable.
*
* Creates a new #GtkWidget that lets a user choose a drawable.
* Creates a new #GtkWidget that lets a user choose a drawable which must be of
* type @drawable_type. @drawable_type of values %G_TYPE_NONE and
* %GIMP_TYPE_DRAWABLE are equivalent. Otherwise it must be a subtype of
* %GIMP_TYPE_DRAWABLE.
*
* When @drawable is %NULL, initial choice is from context.
*
@ -329,14 +362,24 @@ gimp_drawable_chooser_get_property (GObject *object,
GtkWidget *
gimp_drawable_chooser_new (const gchar *title,
const gchar *label,
GType drawable_type,
GimpDrawable *drawable)
{
GtkWidget *chooser;
if (drawable_type == G_TYPE_NONE)
drawable_type = GIMP_TYPE_DRAWABLE;
g_return_val_if_fail (g_type_is_a (drawable_type, GIMP_TYPE_DRAWABLE), NULL);
g_return_val_if_fail (drawable == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (drawable), drawable_type),
NULL);
chooser = g_object_new (GIMP_TYPE_DRAWABLE_CHOOSER,
"title", title,
"label", label,
"drawable", drawable,
"drawable-type", drawable_type,
NULL);
return chooser;
@ -482,7 +525,7 @@ gimp_drawable_chooser_clicked (GimpDrawableChooser *chooser)
g_free (callback_name);
if (gimp_drawables_popup (gimp_procedure_get_name (callback_procedure), chooser->title,
chooser->drawable, handle))
g_type_name (chooser->drawable_type), chooser->drawable, handle))
{
/* Allow callbacks to be watched */
gimp_plug_in_extension_enable (plug_in);

View file

@ -34,6 +34,7 @@ G_DECLARE_FINAL_TYPE (GimpDrawableChooser, gimp_drawable_chooser, GIMP, DRAWABLE
GtkWidget * gimp_drawable_chooser_new (const gchar *title,
const gchar *label,
GType drawable_type,
GimpDrawable *drawable);
GimpDrawable * gimp_drawable_chooser_get_drawable (GimpDrawableChooser *chooser);

View file

@ -40,6 +40,7 @@
* gimp_drawables_popup:
* @callback: The callback PDB proc to call when user chooses an drawable.
* @popup_title: Title of the drawable selection dialog.
* @drawable_type: The name of the GIMP_TYPE_DRAWABLE subtype.
* @initial_drawable: The drawable to set as the initial choice.
* @parent_window: An optional parent window handle for the popup to be set transient to.
*
@ -52,6 +53,7 @@
gboolean
gimp_drawables_popup (const gchar *callback,
const gchar *popup_title,
const gchar *drawable_type,
GimpDrawable *initial_drawable,
GBytes *parent_window)
{
@ -62,6 +64,7 @@ gimp_drawables_popup (const gchar *callback,
args = gimp_value_array_new_from_types (NULL,
G_TYPE_STRING, callback,
G_TYPE_STRING, popup_title,
G_TYPE_STRING, drawable_type,
GIMP_TYPE_DRAWABLE, initial_drawable,
G_TYPE_BYTES, parent_window,
G_TYPE_NONE);

View file

@ -34,6 +34,7 @@ G_BEGIN_DECLS
gboolean gimp_drawables_popup (const gchar *callback,
const gchar *popup_title,
const gchar *drawable_type,
GimpDrawable *initial_drawable,
GBytes *parent_window);
gboolean gimp_drawables_close_popup (const gchar *callback);

View file

@ -799,7 +799,9 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
{
widget = gimp_prop_pattern_chooser_new (G_OBJECT (dialog->priv->config), property, _("Pattern Chooser"));
}
else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_DRAWABLE)
else if (G_IS_PARAM_SPEC_OBJECT (pspec) && (pspec->value_type == GIMP_TYPE_DRAWABLE ||
pspec->value_type == GIMP_TYPE_LAYER ||
pspec->value_type == GIMP_TYPE_CHANNEL))
{
widget = gimp_prop_drawable_chooser_new (G_OBJECT (dialog->priv->config), property, NULL);
}

View file

@ -190,6 +190,11 @@ gimp_prop_drawable_chooser_new (GObject *config,
gchar *canonical;
canonical = gimp_utils_make_canonical_menu_label (label);
if (g_type_is_a (param_spec->value_type, GIMP_TYPE_LAYER))
title = g_strdup_printf (_("Choose layer: %s"), canonical);
if (g_type_is_a (param_spec->value_type, GIMP_TYPE_CHANNEL))
title = g_strdup_printf (_("Choose channel: %s"), canonical);
else
title = g_strdup_printf (_("Choose drawable: %s"), canonical);
g_free (canonical);
}
@ -198,7 +203,7 @@ gimp_prop_drawable_chooser_new (GObject *config,
title = g_strdup (chooser_title);
}
prop_chooser = gimp_drawable_chooser_new (title, label, initial_drawable);
prop_chooser = gimp_drawable_chooser_new (title, label, param_spec->value_type, initial_drawable);
g_clear_object (&initial_drawable);
g_free (title);

View file

@ -25,6 +25,8 @@ sub drawables_popup {
desc => 'The callback PDB proc to call when user chooses an drawable' },
{ name => 'popup_title', type => 'string',
desc => 'Title of the drawable selection dialog' },
{ name => 'drawable_type', type => 'string', non_empty => 1,
desc => 'The name of the GIMP_TYPE_DRAWABLE subtype' },
{ name => 'initial_drawable', type => 'drawable', null_ok => 1, no_validate => 1,
desc => 'The drawable to set as the initial choice' },
{ name => 'parent_window', type => 'bytes', null_ok => 1,
@ -37,8 +39,9 @@ sub drawables_popup {
if (gimp->no_interface ||
! gimp_pdb_lookup_procedure (gimp->pdb, callback) ||
! gimp_pdb_dialog_new (gimp, context, progress,
GIMP_TYPE_DRAWABLE, parent_window,
popup_title, callback, GIMP_OBJECT (initial_drawable),
g_type_from_name (drawable_type),
parent_window, popup_title, callback,
GIMP_OBJECT (initial_drawable),
NULL))
success = FALSE;
}