2.99 ScriptFu: add custom widgets to GimpProcedureDialog

For version 3 scripts, using script-fu-register-filter

Widgets for SF-OPTION and SF-DIRNAME

Fixes #9992

Test case is Sphere v3.

Note that SF-VECTORS is still not supported,
until there is a VectorsChooser widget in libgimp.

A step towards deprecating old-style scripts using script-fu-register,
and deleting script-fu-interface, the duplicate dialog for SF.
But we still need to change or replace script-fu-register (for non-filter plugins)
to use GimpProcedureDialog.
This commit is contained in:
bootchk 2024-02-01 11:29:50 -05:00 committed by Lloyd Konneker
parent 978a795eb7
commit ab626e79ec
7 changed files with 247 additions and 7 deletions

View file

@ -21,6 +21,7 @@ libscriptfu_sources = [
'script-fu-dialog.c',
'script-fu-run-func.c',
'script-fu-command.c',
'script-fu-widgets-custom.c',
]
# !! just "library(...)" which means shared versus static depends on configuration of project.

View file

@ -91,6 +91,7 @@ void
script_fu_arg_free (SFArg *arg)
{
g_free (arg->label);
g_free (arg->property_name);
switch (arg->type)
{
@ -386,6 +387,10 @@ script_fu_arg_get_param_spec (SFArg *arg,
/* FUTURE: Default not now appear in PDB browser, but appears in widgets? */
break;
/* Not necessary to have a more specific pspec:
* pspec = gimp_param_spec_config_path (...GIMP_TYPE_CONFIG_PATH...)
*/
case SF_ENUM:
/* history is the last used value AND the default. */
pspec = g_param_spec_enum (name,
@ -695,6 +700,8 @@ script_fu_arg_reset_name_generator (void)
* The returned string is owned by the generator, a constant.
* The caller need not copy it,
* but usually does by creating a GParamSpec.
*
* As a side effect, a copy of the string is kept in arg->property_name.
*/
void
script_fu_arg_generate_name_and_nick (SFArg *arg,
@ -803,6 +810,9 @@ script_fu_arg_generate_name_and_nick (SFArg *arg,
arg_count[arg->type]++;
/* Side effect: remember the generated name. */
arg->property_name = g_strdup (numbered_name);
*returned_name = numbered_name;
/* nick is what the script author said describes the arg */

View file

@ -27,6 +27,7 @@
#include "script-fu-command.h"
#include "script-fu-dialog.h"
#include "script-fu-widgets-custom.h"
/* An informal class that shows a dialog for a script then runs the script.
@ -159,13 +160,11 @@ script_fu_dialog_run (GimpProcedure *procedure,
script_fu_script_get_title (script));
/* dialog has no widgets except standard buttons. */
/* It is possible to create custom widget where the provided widget is not adequate.
* Then gimp_procedure_dialog_fill_list will create the rest.
* For now, the provided widgets should be adequate.
*/
/* Create custom widget where the stock widget is not adequate. */
script_fu_widgets_custom_add (dialog, script);
/* NULL means create widgets for all properties of the procedure
* that we have not already created widgets for.
* that we have not already created custom widgets for.
*/
gimp_procedure_dialog_fill_list (dialog, NULL);

View file

@ -73,7 +73,8 @@ typedef union
typedef struct
{
SFArgType type;
gchar *label;
gchar *label; /* label on widget in dialog. Not unique. */
gchar *property_name; /* name of property of Procedure. Unique. */
SFArgValue default_value;
SFArgValue value;
} SFArg;

View file

@ -0,0 +1,200 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2024 Lloyd Konneker
*
* 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 <libgimp/gimpui.h>
#include "script-fu-types.h"
#include "script-fu-widgets-custom.h"
/* Widgets in GimpProcedureDialog *custom* to ScriptFu.
*
* GimpProcedureDialog provides stock widgets
* based on the type of a procedure argument.
* A custom widget is the same kind of widget as stock, but specialized.
*
* Both stock and custom widgets are keyed to a property name
* of the GimpProcedure for the script.
* You add custom widgets, then call gimp_procedure_dialog_fill_list()
* which adds a stock widget for any property name not having a custom widget.
*
* FUTURE: implement these in GimpProcedureDialog.
* That can't be done now because GParamSpecs are limited
* in the types they can describe.
* E.G. SF-OPTION describes an enumerated type
* that can't be described completely in a GParamSpec.
* E.G. property type GFile is a general type
* whose subtypes: existing-file, existing-dir, or file-to-save
* can't be described in a GParamSpec.
*
* Most SFArg types are supported by stock widgets.
*
* SF-FILENAME is stock.
* For property of type G_TYPE_FILE.
* A GtkFileChooser in the mode for user to open a existing file.
*
* SF-DIRNAME is custom.
* Also a GtkFileChooser but in mode for user to choose a directory.
*
* FUTURE:
* SF-SAVE-FILENAME is custom.
* Also a GtkFileChooser but in mode for user to save a file
* (choose a file to replace, or enter filename and choose a directory.)
*
* SF-OPTION is custom.
* Is an int combo box widget, for an enumeration defined by the script
* (versus SF-ENUM for enums defined by GIMP.)
* Note SF-OPTION does not create symbols in the interpreter.
* The script itself, and all other plugins, must use integer literals
* to denote values.
*/
/* Does SFArg type need custom widget? */
static gboolean
sf_arg_type_is_custom (SFScript *script,
guint arg_index)
{
switch (script->args[arg_index].type)
{
case SF_DIRNAME:
case SF_OPTION:
return TRUE;
default:
return FALSE;
}
}
/* Returns new GtkListStore from SFArg declaration.
* Transfers ownership of the allocated, returned store.
* Ownership transfers to a dialog, which frees it on dialog destroy.
*
* Returned value is never NULL.
* Returned store can be empty if the declaration of the arg is non-sensical.
*/
static GtkListStore *
sf_widget_custom_new_int_store (SFArg *arg)
{
GtkListStore *result;
GSList *list;
guint counter = 0; /* SF enumerations start at 0. */
/* Create empty store. */
result = g_object_new (GIMP_TYPE_INT_STORE, NULL);
/* Iterate over list of names of enumerated values,
* appending each to store having value equal to the iteration index.
*
* ScriptFu does NOT define constant Scheme symbols in the interpreter;
* the names of enumerated values are not available to the script,
* which must use integer literals or (define other symbols for the values.)
*/
for (list = arg->default_value.sfa_option.list;
list;
list = g_slist_next (list))
{
GtkTreeIter iter;
gtk_list_store_append (result, &iter);
gtk_list_store_set (result, &iter,
GIMP_INT_STORE_VALUE, counter,
GIMP_INT_STORE_LABEL, list->data,
-1);
counter++;
}
return result;
}
/* Adds widget for arg of type SF-OPTION to the dialog.
* Widget is a combobox widget.
* Specializes the widget by a custom store i.e. model
* derived from the arg's declaration.
*/
static void
sf_widget_custom_option (GimpProcedureDialog *dialog,
SFArg *arg)
{
GtkListStore *store;
store = sf_widget_custom_new_int_store (arg);
gimp_procedure_dialog_get_int_combo (dialog,
arg->property_name,
GIMP_INT_STORE (store));
}
/* Adds widget for arg of type SF-DIRNAME to the dialog.
* Widget is a GtkFileChooserButton.
* Specializes the widget to be in mode for user to choose a directory.
*
* Note that this is implemented by gtk_file_chooser_button,
* which does not support ACTION_SAVE, and which becomes obsolete in Gtk4.
* Thus, we don't have SF-SAVE-FILENAME.
* To offer save, a script must use two widgets:
* SF-STRING for user to name a file to save,
* and SF-DIRNAME for user to choose directory to save to.
*/
static void
sf_widget_custom_dirname (GimpProcedureDialog *dialog,
SFArg *arg)
{
gimp_procedure_dialog_get_file_chooser (dialog,
arg->property_name,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
}
/* Add a custom widget for a script's arg to the script's dialog.
* Does nothing when the type of the arg does not need a custom widget.
*
* Widget is associated with the arg's property, by name of the property.
* The arg's property is a property of the Procedure.
* The widget will be positioned in the dialog by order of property.
*/
static void
sf_widget_custom_add_to_dialog (GimpProcedureDialog *dialog,
SFArg *arg)
{
/* Handles same cases as sf_arg_type_is_custom() */
switch (arg->type)
{
case SF_OPTION:
sf_widget_custom_option (dialog, arg);
break;
case SF_DIRNAME:
sf_widget_custom_dirname (dialog, arg);
break;
default:
break;
}
}
/* Add custom widgets to dialog, for certain type of args of script. */
void
script_fu_widgets_custom_add (GimpProcedureDialog *dialog,
SFScript *script)
{
for (int arg_index=0; arg_index < script->n_args; arg_index++)
{
if (sf_arg_type_is_custom (script, arg_index))
{
sf_widget_custom_add_to_dialog (dialog, &script->args[arg_index]);
}
}
}

View file

@ -0,0 +1,26 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2024 Lloyd Konneker
*
* 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/>.
*/
#ifndef __SCRIPT_FU_WIDGETS_CUSTOM_H__
#define __SCRIPT_FU_WIDGETS_CUSTOM_H__
void script_fu_widgets_custom_add (GimpProcedureDialog *dialog,
SFScript *script);
#endif /* __SCRIPT_FU_WIDGETS_CUSTOM_H__ */

View file

@ -30,7 +30,7 @@
size
unused-palette
unused-filename
unused-orientation
orientation
unused-interpolation
unused-dirname
unused-image
@ -123,6 +123,9 @@
size
font)))
(if (= orientation 1)
(gimp-image-rotate img ROTATE-DEGREES90))
(gimp-image-undo-enable img)
(gimp-display-new img)