ScriptFu: fix defaults for script args of type Resource

Script authors declare defaults by name strings.
Which can be valid name, or empty string, or "from context".

ScriptFu declares formal arguments to the PDB,
either with a default GimpResource, or defaulting dynamically from context.

Works with both new-style dialogs (ProcedureDialog and ProcedureConfig)
or with old-style dialog (script-fu-interface.c)
This commit is contained in:
lloyd konneker 2024-09-16 16:25:12 -04:00 committed by Lloyd Konneker
parent 1513f41614
commit 15ae108150
6 changed files with 350 additions and 148 deletions

View file

@ -116,7 +116,7 @@ script_fu_arg_free (SFArg *arg)
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
/* FUTURE: call method to free resource */
sf_resource_arg_free (arg);
break;
case SF_VALUE:
@ -188,7 +188,8 @@ script_fu_arg_reset (SFArg *arg, gboolean should_reset_ids)
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
/* FUTURE call method to reset arg from default. */
if (should_reset_ids)
sf_resource_arg_reset (arg);
break;
case SF_COLOR:
@ -227,6 +228,102 @@ script_fu_arg_reset (SFArg *arg, gboolean should_reset_ids)
}
}
/* The type of a function that declares a formal, resource argument to a PDB procedure. */
typedef void (*ResourceArgDeclareFunc) (
GimpProcedure*, const gchar*, const gchar*, const gchar*,
gboolean, GimpResource*, gboolean, GParamFlags);
static void
script_fu_add_resource_arg_default_from_context (
GimpProcedure *procedure,
const gchar *name,
const gchar *nick,
SFArg *arg,
ResourceArgDeclareFunc func)
{
/* Default from context, dynamically: default:NULL, default_from_context:TRUE */
(*func) (procedure, name, nick,
arg->label,
FALSE, /* none OK */
NULL, /* default */
TRUE, /* default_from_context */
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
}
static void
script_fu_add_resource_arg_with_default (
GimpProcedure *procedure,
const gchar *name,
const gchar *nick,
SFArg *arg,
ResourceArgDeclareFunc func,
GimpResource *default_resource)
{
(*func) (procedure, name, nick,
arg->label,
FALSE, /* none OK */
default_resource,
FALSE, /* default_from_context */
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
}
/* Formally declare a resource arg of a PDB procedure.
* From the given SFArg.
*/
static void
script_fu_add_resource_arg (
GimpProcedure *procedure,
const gchar *name,
const gchar *nick,
SFArg *arg,
ResourceArgDeclareFunc func)
{
/* Switch on script author's declared resource name. */
gchar *declared_name_of_default = sf_resource_arg_get_name_default (arg);
if (g_strcmp0 (declared_name_of_default, "from context") == 0 ||
g_utf8_strlen (declared_name_of_default, 256) == 0
)
{
/* Author declared default name is empty or the special "from context". */
script_fu_add_resource_arg_default_from_context (procedure, name, nick, arg, func);
}
else
{
/* Author declared default name should name a resource.
* Declare the formal arg to default to the named resource.
*
* The declared name should be untranslated.
* Note that names might not be unique e.g. for fonts.
* Note that some resources have translated names e.g. generated gradients.
*
* The default resource could still be NULL if the declared name does not match.
* Warn in that case, to the console, at procedure creation time.
* Note we still pass none_OK:FALSE meaning the procedure expects
* a non-NULL resource at call time (after GUI.)
* In interactive mode, the GUI may default from context when passed a NULL default.
*/
GimpResource *default_resource = sf_resource_arg_get_default (arg);
if (default_resource == NULL)
{
g_warning ("%s declared resource name is invalid %s", G_STRFUNC, declared_name_of_default);
script_fu_add_resource_arg_default_from_context (procedure, name, nick, arg, func);
}
else
{
/* Declared name is valid name of resource. */
script_fu_add_resource_arg_with_default (procedure, name, nick, arg, func,
default_resource);
}
}
}
/* Return param spec that describes the arg.
* Convert instance of SFArg to instance of GParamSpec.
*
@ -324,49 +421,30 @@ script_fu_arg_add_argument (SFArg *arg,
break;
/* Subclasses of GimpResource. Special widgets. */
/* The name_of_default was declared by the plugin author.
*
* FIXME: after the param_spec takes a default
* each should pass arg sf_resource_get_name_of_default (arg).
* For now, a default defined here e.g. "Default"
*/
case SF_FONT:
gimp_procedure_add_font_argument (procedure, name,
nick, arg->label,
FALSE, /* none OK */
NULL, TRUE,
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
/* Avoid compiler warning: cast a type specific function to a generic function. */
script_fu_add_resource_arg (procedure, name, nick, arg,
(ResourceArgDeclareFunc) gimp_procedure_add_font_argument);
break;
case SF_PALETTE:
gimp_procedure_add_palette_argument (procedure, name,
nick, arg->label,
FALSE, /* none OK */
NULL, TRUE,
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
script_fu_add_resource_arg (procedure, name, nick, arg,
(ResourceArgDeclareFunc) gimp_procedure_add_palette_argument);
break;
case SF_PATTERN:
gimp_procedure_add_pattern_argument (procedure, name,
nick, arg->label,
FALSE, /* none OK */
NULL, TRUE,
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
script_fu_add_resource_arg (procedure, name, nick, arg,
(ResourceArgDeclareFunc) gimp_procedure_add_pattern_argument);
break;
case SF_GRADIENT:
gimp_procedure_add_gradient_argument (procedure, name,
nick, arg->label,
FALSE, /* none OK */
NULL, TRUE,
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
script_fu_add_resource_arg (procedure, name, nick, arg,
(ResourceArgDeclareFunc) gimp_procedure_add_gradient_argument);
break;
case SF_BRUSH:
gimp_procedure_add_brush_argument (procedure, name,
nick, arg->label,
FALSE, /* none OK */
NULL, TRUE,
G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE);
script_fu_add_resource_arg (procedure, name, nick, arg,
(ResourceArgDeclareFunc) gimp_procedure_add_brush_argument);
break;
case SF_ADJUSTMENT:
@ -623,14 +701,11 @@ script_fu_arg_append_repr_from_self (SFArg *arg,
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
g_string_append_printf (result_string, "%d", arg_value->sfa_image);
/* FUTURE
{
gchar *repr = sf_resource_get_repr (&arg_value->sfa_resource);
gchar *repr = sf_resource_arg_get_repr (arg);
g_string_append (result_string, repr);
g_free (repr);
}
*/
break;
case SF_COLOR:
@ -838,39 +913,6 @@ script_fu_arg_generate_name_and_nick (SFArg *arg,
*returned_nick = arg->label;
}
/* FUTURE this goes away or moves to script_fu_resource.c */
/* Init the value of an SFArg that is a resource.
* In case user does not touch a widget.
* Cannot be called at registration time.
* Init to value from context, the same as a widget
* will do when passed a NULL initial resource.
*/
void
script_fu_arg_init_resource (SFArg *arg, GType resource_type)
{
GimpResource *resource;
if (resource_type == GIMP_TYPE_BRUSH)
resource = GIMP_RESOURCE (gimp_context_get_brush ());
else if (resource_type == GIMP_TYPE_FONT)
resource = GIMP_RESOURCE (gimp_context_get_font ());
else if (resource_type == GIMP_TYPE_GRADIENT)
resource = GIMP_RESOURCE (gimp_context_get_gradient ());
else if (resource_type == GIMP_TYPE_PALETTE)
resource = GIMP_RESOURCE (gimp_context_get_palette ());
else if (resource_type == GIMP_TYPE_PATTERN)
resource = GIMP_RESOURCE (gimp_context_get_pattern ());
else
{
g_warning ("%s: Failed get resource from context", G_STRFUNC);
arg->value.sfa_resource = -1;
return;
}
arg->value.sfa_resource = gimp_resource_get_id (resource);
}
/* Set the default of a GParamSpec to a GFile for a path string.
* The GFile is allocated and ownership is transferred to the GParamSpec.
* The GFile is only a name and a so-named file might not exist.

View file

@ -85,7 +85,7 @@ static void script_fu_resource_set_handler (gpointer data,
gboolean closing);
static GtkWidget * script_fu_resource_widget (const gchar *title,
SFResourceType *model,
SFArg *arg,
GType resource_type);
static void script_fu_flush_events (void);
@ -412,44 +412,35 @@ script_fu_interface_dialog (SFScript *script,
break;
case SF_FONT:
/* FIXME this should be a method of the arg.
in script-fu-resource and it should return the default.
*/
script_fu_arg_init_resource (arg, GIMP_TYPE_FONT);
widget = script_fu_resource_widget (label_text,
/* FIXME and the call can go here*/
&arg->value.sfa_resource,
arg,
GIMP_TYPE_FONT);
break;
case SF_PALETTE:
script_fu_arg_init_resource (arg, GIMP_TYPE_PALETTE);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
arg,
GIMP_TYPE_PALETTE);
break;
case SF_PATTERN:
left_align = TRUE;
script_fu_arg_init_resource (arg, GIMP_TYPE_PATTERN);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
arg,
GIMP_TYPE_PATTERN);
break;
case SF_GRADIENT:
left_align = TRUE;
script_fu_arg_init_resource (arg, GIMP_TYPE_GRADIENT);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
arg,
GIMP_TYPE_GRADIENT);
break;
case SF_BRUSH:
left_align = TRUE;
script_fu_arg_init_resource (arg, GIMP_TYPE_BRUSH);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
arg,
GIMP_TYPE_BRUSH);
break;
@ -531,45 +522,53 @@ script_fu_interface_dialog (SFScript *script,
/* Return a widget for choosing a resource.
* Dispatch on resource type.
* Widget will show initial choice from context.
*
* On first show, widget will show initial choice : declared by script.
* Thereafter, the choice from prior use of filter.
*
* Widget will update model if user touches widget.
*/
static GtkWidget *
script_fu_resource_widget (const gchar *title,
SFResourceType *model,
SFArg *arg,
GType resource_type)
{
GtkWidget *result_widget = NULL;
GtkWidget *result_widget = NULL;
GResource *initial_value;
g_debug ("%s type: %" G_GSIZE_FORMAT, G_STRFUNC, resource_type);
/* Init the arg's value (ID).
* On first run, initialize to default.
* On second run, init to prior choice.
* Can't do it at registration time, resources are not loaded.
*/
sf_resource_arg_init_current_value (arg);
/* Passing empty string for outer widget label,
* since this old-style interface makes the label.
*/
/* Create a widget with initial value of the arg. */
initial_value = sf_resource_arg_get_value (arg);
if (g_type_is_a (resource_type, GIMP_TYPE_FONT))
{
result_widget = gimp_font_chooser_new (title, "",
sf_resource_get_default (model));
result_widget = gimp_font_chooser_new (title, "", initial_value);
}
else if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH))
{
result_widget = gimp_brush_chooser_new (title, "",
sf_resource_get_default (model));
result_widget = gimp_brush_chooser_new (title, "", initial_value);
}
else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT))
{
result_widget = gimp_gradient_chooser_new (title, "",
sf_resource_get_default (model));
result_widget = gimp_gradient_chooser_new (title, "", initial_value);
}
else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE))
{
result_widget = gimp_palette_chooser_new (title, "",
sf_resource_get_default (model));
result_widget = gimp_palette_chooser_new (title, "", initial_value);
}
else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN))
{
result_widget = gimp_pattern_chooser_new (title, "",
sf_resource_get_default (model));
result_widget = gimp_pattern_chooser_new (title, "", initial_value);
}
else
{
@ -579,12 +578,13 @@ script_fu_resource_widget (const gchar *title,
if (result_widget != NULL)
{
/* All resource widgets emit signal resource-set
* Connect to our handler which will be passed the id_handle,
* Connect to our handler which will be passed
* a Resource* and int* to the arg's value,
* the model of the new choice of resource.
*/
g_signal_connect_swapped (result_widget, "resource-set",
G_CALLBACK (script_fu_resource_set_handler),
model); /* data */
&arg->value.sfa_resource.history); /* data */
}
return result_widget;
@ -829,7 +829,8 @@ script_fu_reset (SFScript *script)
/* Reset the view to the model values. */
for (i = 0; i < script->n_args; i++)
{
SFArgValue *value = &script->args[i].value;
SFArg *arg = &script->args[i];
SFArgValue *value = &arg->value;
GtkWidget *widget = sf_interface->widgets[i];
switch (script->args[i].type)
@ -915,8 +916,7 @@ script_fu_reset (SFScript *script)
case SF_GRADIENT:
case SF_BRUSH:
gimp_resource_chooser_set_resource (GIMP_RESOURCE_CHOOSER (widget),
sf_resource_get_default (
&value->sfa_resource));
sf_resource_arg_get_default (arg));
break;
case SF_OPTION:

View file

@ -120,6 +120,28 @@ script_fu_script_new_from_metadata_args (scheme *sc,
}
/* GimpResource
*
* Store the subclass type and the declared default name.
*
* Default_spec given by author is a name of resource.
* It must be an untranslated name.
* FIXME some generated Gradients have translated names.
*/
static pointer
script_fu_parse_default_spec_resource (scheme *sc,
pointer default_spec,
SFArg *arg,
GType resource_type)
{
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "resource defaults must be strings");
sf_resource_arg_set_name_default (arg, resource_type, sc->vptr->string_value (default_spec));
/* success */
return sc->NIL;
}
/* Parse a default spec from registration data.
*
* Side effects on arg.
@ -302,17 +324,21 @@ script_fu_parse_default_spec (scheme *sc,
#endif
break;
/* For GimpResource subclasses. */
case SF_FONT:
return script_fu_parse_default_spec_resource (sc, default_spec, arg, GIMP_TYPE_FONT);
break;
case SF_PALETTE:
return script_fu_parse_default_spec_resource (sc, default_spec, arg, GIMP_TYPE_PALETTE);
break;
case SF_PATTERN:
return script_fu_parse_default_spec_resource (sc, default_spec, arg, GIMP_TYPE_PATTERN);
break;
case SF_BRUSH:
return script_fu_parse_default_spec_resource (sc, default_spec, arg, GIMP_TYPE_BRUSH);
break;
case SF_GRADIENT:
/* Default_spec given by author is a name. */
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "resource defaults must be strings");
sf_resource_set_default (&arg->default_value.sfa_resource,
sc->vptr->string_value (default_spec));
return script_fu_parse_default_spec_resource (sc, default_spec, arg, GIMP_TYPE_GRADIENT);
break;
case SF_OPTION:

View file

@ -25,51 +25,168 @@
/* This encapsulates the implementation of the SFResourceType.
* It knows how to manipulate a SFArg of that type.
*
* Separate because it is likely to change.
*
* Likely to change:
* - default and resettable
* Separate because it is likely to change:
* when the old-style GUI of script-fu-interface is obsoleted.
*/
/* Set is at registration time.
* The name may be invalid.
* We can't then check for validity because Gimp is not done initializing resources.
* Checking for validity must be done later.
*/
static gint32 sf_resource_arg_get_ID_from_context (SFArg *arg);
/* Called at registration time.
* The name may be empty i.e. NULL, the special value "from context",
* a name that matches a resource, or an invalid name of a resource.
* We can't check for validity now because Gimp is not done initializing resources.
*/
void
sf_resource_set_default (SFResourceType *arg_value, gchar * name_of_default)
sf_resource_arg_set_name_default (SFArg *arg, GType resource_type, gchar *name_of_default)
{
/* Store the name and later put to ParamSpecResource.name_of_default.*/
/* FIXME */
/* like .default_value.name_of_default = g_strdup (sc->vptr->string_value (default_spec));*/
arg->default_value.sfa_resource.declared_name_of_default = g_strdup (name_of_default);
arg->default_value.sfa_resource.resource_type = resource_type;
/* Not store the resource value.
* We can't look up resource by name now, at registration time,
* because Gimp is not done initializing Resources.
*
* Instead, set the default to the "invalid ID" value, -1
*/
/* FIXME arg->default_value.sfa_resource.history = -1; */
/* Init current value to unknown. */
sf_resource_arg_set (arg, -1);
}
/* Return a default value.
/* Return the name stored at registration time. */
gchar *
sf_resource_arg_get_name_default (SFArg *arg)
{
return arg->default_value.sfa_resource.declared_name_of_default;
}
/* Return a default value from the declared name of default.
* Ensure the value is acceptable by a ResourceChooser widget.
* The value can be NULL, when the name_of_default is invalid.
* A NULL will make a ResourceChooser get from context.
* Returns NULL when the name_of_default is not the name of a resource.
* A NULL will make a ResourceChooser widget get from context.
*
* This does not increase the reference count.
* ScriptFu does not keep a reference,
* only passes the reference when declaring args to PDB procedure.
*/
GimpResource*
sf_resource_get_default (SFResourceType *arg_value)
sf_resource_arg_get_default (SFArg *arg)
{
/* FIXME, NULL since default not implemented. */
return NULL;
GimpResource *result;
result = gimp_resource_get_by_name (
arg->default_value.sfa_resource.resource_type,
sf_resource_arg_get_name_default (arg));
g_debug ("%s name %s result %p", G_STRFUNC, sf_resource_arg_get_name_default (arg), result);
return result;
}
gchar *
sf_arg_get_name_of_default (SFArg *arg)
/* Return the current value. */
GimpResource *sf_resource_arg_get_value (SFArg *arg)
{
/* Return the name stored at registration time. */
/* FIXME */
return "Default";
return gimp_resource_get_by_id (arg->value.sfa_resource.history);
}
/* Sets the arg's internal value.
*
* FUTURE: Deprecated when script-fu-interface is deleted.
*/
void
sf_resource_arg_set (SFArg *arg, gint32 ID)
{
g_debug ("%s ID: %d", G_STRFUNC, ID);
arg->value.sfa_resource.history = ID;
}
/* Free allocated memory of an SFArg. */
void
sf_resource_arg_free (SFArg *arg)
{
g_free (arg->default_value.sfa_resource.declared_name_of_default);
}
/* Reset the current value to the default value.
* FUTURE: obsolete with script-fu-interface.
*/
void
sf_resource_arg_reset (SFArg *arg)
{
/* Copy the whole struct.
* This copies a gchar * but we don't need to free it.
*/
arg->value.sfa_resource = arg->default_value.sfa_resource;
}
/* Return representation of the current value.
* Representation in Scheme language: a literal numeric for the ID.
* Transfer full, caller must free.
*/
gchar*
sf_resource_arg_get_repr (SFArg *arg)
{
return g_strdup_printf ("%d", arg->value.sfa_resource.history);
}
/* Init the current value of an SFArg that is a resource
* when it is not already set, i.e. -1.
* Init to default value, either the declared named resource, or from context.
*
* !!! The current value is traditionally called "history"
* because it persists across runs of the plugin.
*
* For old-style interface, where the data flow is different,
* from the arg to the widget then back,
* but not automatic via a bound property.
* Must initialize inc case user does not touch a widget.
*
* Cannot be called at registration time.
*
* FUTURE: obsolete with script-fu-interface.
*/
void
sf_resource_arg_init_current_value (SFArg *arg)
{
if (arg->value.sfa_resource.history < 1)
{
/* The ID has not flowed from a widget in a prior run of plugin. */
GimpResource *default_resource = sf_resource_arg_get_default (arg);
if (default_resource != NULL)
sf_resource_arg_set (arg, gimp_resource_get_id (default_resource));
else
/* The author declared default is not valid. */
sf_resource_arg_set (arg, sf_resource_arg_get_ID_from_context (arg));
}
/* Else the current value is positive int, a resource ID from prior run. */
g_debug ("%s %i", G_STRFUNC, arg->value.sfa_resource.history);
}
/* FUTURE: obsolete with script-fu-interface. */
static gint32
sf_resource_arg_get_ID_from_context (SFArg *arg)
{
GimpResource *resource = NULL;
gint32 result_ID;
GType resource_type = arg->default_value.sfa_resource.resource_type;
if (resource_type == GIMP_TYPE_BRUSH)
resource = GIMP_RESOURCE (gimp_context_get_brush ());
else if (resource_type == GIMP_TYPE_FONT)
resource = GIMP_RESOURCE (gimp_context_get_font ());
else if (resource_type == GIMP_TYPE_GRADIENT)
resource = GIMP_RESOURCE (gimp_context_get_gradient ());
else if (resource_type == GIMP_TYPE_PALETTE)
resource = GIMP_RESOURCE (gimp_context_get_palette ());
else if (resource_type == GIMP_TYPE_PATTERN)
resource = GIMP_RESOURCE (gimp_context_get_pattern ());
if (resource == NULL)
{
g_warning ("%s: Failed get resource from context", G_STRFUNC);
result_ID = -1;
}
else
{
result_ID = gimp_resource_get_id (resource);
}
return result_ID;
}

View file

@ -19,15 +19,15 @@
#define __SCRIPT_FU_RESOURCE_H__
/* ScriptFu stores Resources as int IDs. */
typedef guint32 SFResourceType;
/* ScriptFu internally stores Resources as int IDs.
* In binding to and from the PDB, converted to GimpResource *
* (which is a proxy object.)
*/
typedef struct {
gint32 history; /* The current value. Can be -1 meaning invalid. */
gchar *declared_name_of_default;
GType resource_type;
} SFResourceType;
/* Methods on SFResourceType. */
void sf_resource_set_default (SFResourceType *arg_value,
gchar *name_of_default);
GimpResource* sf_resource_get_default (SFResourceType *arg_value);
gchar* sf_resource_get_name_of_default (SFResourceType *arg);
#endif /* __SCRIPT_FU_RESOURCE__ */

View file

@ -116,4 +116,21 @@ void sf_color_arg_set_default_by_color (SFArg *arg,
GeglColor *color);
GeglColor* sf_color_arg_get_default_color (SFArg *arg);
/* defined in script-fu-resource. c */
void sf_resource_arg_set_name_default (SFArg *arg,
GType resource_type,
gchar *name_of_default);
gchar *sf_resource_arg_get_name_default (SFArg *arg);
GimpResource *sf_resource_arg_get_default (SFArg *arg);
GimpResource *sf_resource_arg_get_value (SFArg *arg);
void sf_resource_arg_set (SFArg *arg,
gint32 ID);
void sf_resource_arg_free (SFArg *arg);
void sf_resource_arg_reset (SFArg *arg);
gchar *sf_resource_arg_get_repr (SFArg *arg);
void sf_resource_arg_init_current_value (SFArg *arg);
#endif /* __SCRIPT_FU_TYPES__ */