Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View File

@ -0,0 +1,272 @@
# API changes in libpika and the PDB for resources
This explains changes to the PIKA API from v2 to v3,
concerning resources.
The audience is plugin authors, and PIKA developers.
### Resources
A resource is a chunk of data that can be installed with PIKA
and is used by painting tools or for other rendering tasks.
Usually known as brush, font, palette, pattern, gradient and so forth.
### Resources are now first class objects
PikaResource is now a class in libpika.
It has subclasses:
- Brush
- Font
- Gradient
- Palette
- Pattern
Formerly, the PIKA API had functions operating on resources by name.
Now, there are methods on resource objects.
Methods take an instance of the object as the first argument,
often called "self."
This means that where you formerly used a string name to refer to a resource object,
now you usually should pass an instance of an object.
### Changes to reference documents
#### libpika API reference
Shows classes Brush, Font, and so forth.
The classes have instance methods taking the instance as the first argument.
Example:
```
gboolean gboolean pika_brush_delete(gcharray) => gboolean pika_brush_delete ( PikaBrush*)
```
The classes may also have class methods still taking string names.
Example:
```
gboolean pika_brush_id_is_valid (const gchar* id)
```
Is a class method (in the "Functions" section of the class) taking the ID
(same as the name) to test whether such a brush is installed in Pika core.
#### PDB Browser
Remember the PDB Browser shows the C API. You must mentally convert
to the API in bound languages.
Shows some procedures that now take type e.g. PikaBrush
where formerly they took type gcharray i.e. strings.
Shows some procedures that take a string name of a brush.
These are usually class methods.
#### Other changes to the API
Many of the Pika functions dealing with the context
now take or return an instance of a resource.
Example:
```
gcharray* pika_context_get_brush (void) => PikaBrush* pika_context_get_brush (void)
```
A few functions have even more changed signature:
```
gint pika_palette_get_info (gcharray) =>
gint pika_palette_get_color_count (PikaPalette*)
```
The name and description of this function are changed
to accurately describe that the function only returns an integer
(formerly, the description said it also returned the name of the palette.)
### New resource objects
FUTURE
Formerly there were no methods in the libpika API or the PDB for objects:
- Dynamics
- ColorProfile
- ToolPreset
These classes exist primarily so that plugins can let a user choose an instance,
and pass the instance on to other procedures.
### Traits
Informally, resources can have these traits:
- Nameable
- Creatable/Deleable
- Cloneable (Duplicatable)
- Editable
Some resource subclasses don't have all traits.
### ID's and names
The ID and name of a resource are currently the same.
(Some documents and method names may use either word, inconsistently.)
You usually use resource instances instead of their IDs.
This will insulate your code from changes to PIKA re ID versus name.
A plugin should not use a resource's ID.
A plugin should not show the ID/name to a user.
The PIKA app shows the names of resources as a convenience to users,
but usually shows resources visually, that is, iconically.
An ID is opaque, that is, used internally by PIKA.
FUTURE: the ID and name of a resource are distinct.
Different resource instances may have the same name.
Methods returning lists of resources or resource names may return
lists having duplicate names.
### Resource instances are references to underlying data
A resource instance is a proxy, or reference, to the underlying data.
Methods on the instance act on the underlying data.
The underlying data is in PIKA's store of resources.
It is possible for a resource instance to be "invalid"
that is, referring to underlying data that does not exist,
usually when a user uninstalls the thing.
### Creating Resources
Installing a resource is distinct from creating a resource.
PIKA lets you create some resources.
You can't create fonts in PIKA, you can only install them.
For those resources that PIKA lets you create,
the act of creating it also installs it.
For resources that you can create in PIKA:
- some you create using menu items
- some you can create using the API
The API does not let you create a raster brush.
The API does let you create a parametric brush.
For example, in Python:
```
brush = Pika.Brush.new("Foo")
```
creates a new parametric brush.
Note that the passed name is a proposed name.
If the name is already in use,
the new brush will have a different name.
The brush instance will always be valid.
### Getting Resources by ID
Currently, you usually ask the user to interactively choose a resource.
If you must get a reference to a resource for which you know the ID,
you can new() the resource class and set it's ID property.
See below.
FUTURE Resource classes have get_by_id() methods.
If such a named resource is currently installed,
get_by_id() returns a valid instance of the resource class.
If such a named resource is not currently installed,
the method returns an error.
### Uninitialized or invalid resource instances
You can create an instance of a resource class that is invalid.
For example, in Python:
```
brush = Pika.Brush()
brush.set_property("id", "Foo")
```
creates an instance that is invalid because there is no underlying data in the PIKA store
(assuming a brush named "Foo" is not installed.)
Ordinarily, you would not use such a construct.
Instead, you should use the new() method
(for resource classes where it is defined)
which creates, installs, and returns a valid instance except in dire circumstances (out of memory.)
### Invalid resource instances due to uninstalls
A plugin may have a resource as a parameter.
An interactive plugin may show a chooser widget to let a user choose a resource.
The user's choices may be saved in settings.
In the same sesssion of PIKA, or in a subsequent session,
a user may invoke the plugin again.
Then the saved settings are displayed in the plugin's dialog
(when the second invocation is also interactive).
When, in the meantime (between invocations of the plugin)
a user has uninstalled the reference resource,
the resource, as a reference, is invalid.
A well-written plugin should handle this case.
Resource classes have:
- is_valid() instance method
- id_is_valid(char * name) class method
Well-written plugins should use these methods to ensure
that saved (deserialized) resource instances
are valid before subsequently using them.
### Naming and renaming
As mentioned above, currently names must be unique.
For some resources, the method rename(char * name) changes the name.
The method fails if the new name is already used.
When the instance is invalid to start with
(it has an ID that does not refer to any installed data)
renaming it can succeed and then it creates a valid instance.
### Duplicating
Duplicating a resource creates and installs the underlying data,
under a new, generated name.
The duplicate() method on an instance returns a new instance.
### Deleting
You can delete some resources. This uninstalls them.
You can delete some brushes, palettes, and gradients,
when they are writeable i.e. editable,
which usually means that a user previously created them.
You can't delete fonts and patterns.
You can delete using the delete() instance method
When you delete a resource, the instance (the proxy in a variable) continues to exist, but is invalid.
### Resource lists
Some functions in PIKA return lists of resource names,
representing the set of resources installed.
For example: pika_brushes_get_list.
This returns a list of strings, the ID's of the resources.
The list will have no duplicates.
FUTURE: this will return a list of resource instances, and their names may have duplicates.

View File

@ -0,0 +1,15 @@
Here you'll find documentation useful for porting older PIKA
plug-ins, especially Python ones, to the PIKA 3.0 APIs.
Files:
- [classes.md:](classes.md)
A list of some of the important classes and modules in PIKA 3.0.
- [pdb-calls.md:](pdb-calls.md)
An incomplete list of old PDB functions and their equivalents,
using Python classes.
- [removed_functions.md:](removed_functions.md)
Functions that have been removed from PIKA, and their replacements.

View File

@ -0,0 +1,100 @@
# Useful Modules/Classes in PIKA 3.0+
Here's a guide to the modules you're likely to need.
It's a work in progress: feel free to add to it.
Eventually we'll have online documentation for these classes.
In the meantime, you can generate your own:
```
HTMLDOCDIR=/path/to/doc/dir
g-ir-doc-tool -I /path/to/share/gir-1.0/ --language=Python -o $HTMLDOCDIR Gimp-3.0.gir
```
Then browse $HTMLDOCDIR with yelp, or generate HTML from it:
```
cd $HTMLDOCDIR
yelp-build cache *.page
yelp-build html .
```
You can also get some information in PIKA's Python console with
*help(module)* or *help(object)*, and you can get a list of functions
with *dir(object)*.
## Gimp
The base module: almost everything is under Pika.
## Pika.Image
The image object.
Some operations that used to be PDB calls, like
```
pdb.pika_selection_layer_alpha(layer)
```
are now in the Image object, e.g.
```
img.select_item(Pika.ChannelOps.REPLACE, layer)
```
## Pika.Layer
The layer object.
```
fog = Pika.Layer.new(image, name,
drawable.width(), drawable.height(), type, opacity,
Pika.LayerMode.NORMAL)
```
## Pika.Selection
Selection operations that used to be in the PDB, e.g.
```
pdb.pika_selection_none(img)
```
are now in the Pika.Selection module, e.g.
```
Pika.Selection.none(img)
```
## Pika.ImageType
A home for image types like RGBA, GRAY, etc:
```
Pika.ImageType.RGBA_IMAGE
```
## Pika.FillType
e.g. Pika.FillType.TRANSPARENT, Pika.FillType.BACKGROUND
## Pika.ChannelOps
The old channel op definitions in the pikafu module, like
```
CHANNEL_OP_REPLACE
```
are now in their own module:
```
Pika.ChannelOps.REPLACE
```
## Pika.RGB
In legacy plug-ins you could pass a simple list of integers, like (0, 0, 0).
In 3.0+, create a Pika.RGB object:
```
c = Pika.RGB()
c.set(240.0, 180.0, 70.0)
```
or
```
c.r = 0
c.g = 0
c.b = 0
c.a = 1
```

View File

@ -0,0 +1,76 @@
# PDB equivalence
A table of old PDB calls, and their equivalents in the PIKA 3.0+ world.
This document is a work in progress. Feel free to add to it.
## Undo/Context
| Removed function | Replacement |
| -------------------------------- | ----------------------------
| pika_undo_push_group_start | image.undo_group_start() |
| pika_undo_push_group_end | image.undo_group_end() |
| pika.context_push() | Pika.context_push() |
| pika.context_push() | Pika.context_push() |
| pika_context_get_background | Pika.context_get_background
| pika_context_set_background | Pika.context_set_background
## File load/save
| Removed function | Replacement |
| -------------------------------- | ----------------------------
| pika_file_load | Pika.file_load |
| pika_file_save | Pika.file_save |
## Selection operations
Selection operations are now in the Pika.Selection class (except
a few in the Image class). E.g.
| Removed function | Replacement |
| -------------------------------- | ----------------------------
| pdb.pika_selection_invert(img) | Pika.Selection.invert(img) |
| pdb.pika_selection_none(img) | Pika.Selection.none(img) |
| pdb.pika_selection_layer_alpha(layer) | img.select_item(Pika.ChannelOps.REPLACE, layer) |
| pika_image_select_item | img.select_item(channel_op, layer) |
## Filling and Masks
| Removed function | Replacement |
| -------------------------------- | ----------------------------
| Pika.drawable_fill() | layer.fill() |
| pdb.pika_edit_fill(FILL_BACKGROUND) | layer.edit_fill(Pika.FillType.BACKGROUND) |
| pika_layer_add_mask | layer.add_mask
| pika_layer_remove_mask | layer.remove_mask
## Miscellaneous and Non-PDB Calls
| Removed function | Replacement |
| -------------------------------- | ----------------------------
| pika_displays_flush | Pika.displays_flush
| pika_image_insert_layer | image.insert_layer
## Plug-ins
Calling other plug-ins is trickier than before. The old
```
pdb.script_fu_drop_shadow(img, layer, -3, -3, blur,
(0, 0, 0), 80.0, False)
```
becomes
```
c = Pika.RGB()
c.set(240.0, 180.0, 70.0)
Pika.get_pdb().run_procedure('script-fu-drop-shadow',
[ Pika.RunMode.NONINTERACTIVE,
GObject.Value(Pika.Image, img),
GObject.Value(Pika.Drawable, layer),
GObject.Value(GObject.TYPE_DOUBLE, -3),
GObject.Value(GObject.TYPE_DOUBLE, -3),
GObject.Value(GObject.TYPE_DOUBLE,blur),
c,
GObject.Value(GObject.TYPE_DOUBLE, 80.0),
GObject.Value(GObject.TYPE_BOOLEAN, False)
])
```

View File

@ -0,0 +1,175 @@
## About this document
This describes *some* changes needed to port a Scriptfu script to PIKA 3:
- changes in types
- changes in PDB signatures for multi-layer support
- changes in error messages
- changes in logging
It does *not* document:
- PDB procedures whose names have changed (see pdb-calls.md)
- PDB procedures that have been removed (see removed_functions.md)
- PDB procedures that have been added
- other changes in signature where arguments are reordered or changed in number
## Changes in types of PDB signatures
Calls from a script to PIKA are calls to PDB procedures.
PDB procedures are documented in terms of C and GLib types.
This table summarizes the changes:
| Purpose | Old C type | New C type | Old Scheme type | New Scheme type |
| ---------------|-----------------------|-----------------------| ----------------|-----------------------|
| Pass file name | gchar*, gchar* | GFile | string string | string |
| Recv file name | gchar* | GFile | string | string |
| pass drawable | PikaDrawable | gint, PikaObjectArray | int (an ID) | int (a length) vector |
| Pass obj array | gint, PikaInt32Array | gint, PikaObjectArray | int vector | int vector |
| Recv obj array | gint, PikaInt32Array | gint, PikaObjectArray | int vector | int vector |
| Pass set of str | gint, PikaStringArray | GStrv | int list | list |
| Recv set of str | gint, PikaStringArray | GStrv | int list | list |
(Where "obj" means an object of a PIKA type such as PikaDrawable or similar.)
### Use one string for a filename instead of two.
Formerly a PDB procedure taking a filename (usually a full path) required two strings (two gchar* .)
Now such PDB procedures require a GFile.
In Scheme, where formerly you passed two strings, now pass one string.
Formerly a script passed the second string for a URI, to specify a remote file.
Formerly, in most cases you passed an empty second string.
Now, the single string in a script can be either a local file path or a remote URI.
Example:
(pika-file-load RUN-NONINTERACTIVE "/tmp/foo" "")
=> (pika-file-load RUN-NONINTERACTIVE "/tmp/foo")
### PDB procedures still return a string for a filename
All PDB procedures returning a filename return a single string to Scheme scripts.
That is unchanged.
Formerly a PDB signature for a procedure returning a filename
specifies a returned type gchar*, but now specifies a returned type GFile.
But a Scheme script continues to receive a string.
The returned string is either a local file path or a URI.
### Use a vector of drawables for PDB procedures that now take an array of drawables
Formerly, some PDB procedures took a single PikaDrawable,
but now they take an array of PikaDrawable ( type PikaObjectArray.)
(Formerly, no PDB procedure took an array of drawables.
Some that formerly took a single drawable still take a single drawable.
See the list below. )
For such PDB procedures, in Scheme pass a numeric length and a vector of numeric drawable ID's.
These changes support a user selecting multiple layers for an operation.
Example:
(pika-edit-copy drawable) => (pika-edit-copy 1 (vector drawable))
(pika-edit-copy 2) => (pika-edit-copy 1 '#(2))
### The PDB procedures which formerly took single Drawable and now take PikaObjectArray
- Many of the file load/save procedures.
- pika-color-picker
- pika-edit-copy
- pika-edit-cut
- pika-edit-named-copy
- pika-edit-named-cut
- pika-file-save
- pika-image-pick-color
- pika-selection-float
- pika-xcf-save
### Receiving an array of drawables
Formerly a PDB procedure returning an array of drawables (or other PIKA objects)
had a signature specifying a returned gint and PikaInt32Array.
Now the signature specifies a returned gint and PikaObjectArray.
A script receives an int and a vector.
The elements of the vector are numeric ID's,
but are opaque to scripts
(a script can pass them around, but should not for example use arithmetic on them.)
No changes are needed to a script.
Example:
(pika-image-get-layers image)
Will return a list whose first element is a length,
and whose second element is a vector of drawables (Scheme numerics for drawable ID's)
In the ScriptFu console,
(pika-image-get-layers (car (pika-image-new 10 30 1)))
would print:
(0 #())
Meaning a list length of zero, and an empty vector.
(Since a new image has no layers.)
### Passing or receiving a set of strings
Formerly, you passed an integer count of strings, and a list of strings.
Now you only pass the list.
ScriptFu converts to/from the C type GStrv
(which is an object knowing its own length.)
An example is the PDB procedure file-gih-save.
Formerly, you received an integer count of strings, and a list of strings.
Now you only receive the list
(and subsequently get its length using "(length list)").
Examples are the many PDB procedures whose name ends in "-list".
Remember that the result of a call to the PDB is a list of values,
in this case the result is a list containing a list,
and for example you get the list of strings like "(car (pika-fonts-get-list ".*"))"
## Changes in error messages
ScriptFu is now more forgiving.
Formerly, ScriptFu would not accept a call construct where the argument count was wrong,
except for the case when you provided one argument to a PDB procedure
that took zero arguments (sometimes called a nullary function.)
Now, when a script has the wrong count of arguments to a PDB procedure:
- too many actual arguments: ScriptFu will give a warning to the console
and call the PDB procedure with a prefix of the actual arguments.
This is now true no matter how many arguments the PDB procedure takes.
Extra arguments in the script are ignored by Scriptfu,
not evaluated and not passed to the PDB.
- too few actual arguments: ScriptFu will give a warning to the console
and call the PDB procedure with the given actual arguments.
The warning will say the expected Scheme formal type of the first missing actual argument.
Usually the PDB procedure will fail and return its own error message.
When you suspect errors in a script,
it is now important to run PIKA from a console to see warnings.
## ScriptFu logging
ScriptFu now does some logging using GLib logging.
When you define in the environment "G_MESSAGES_DEBUG=scriptfu"
ScriptFu will print many messages to the console.
This is mostly useful for PIKA developers.

View File

@ -0,0 +1,222 @@
## Removed Functions
These functions have been removed from PIKA 3. Most of them were deprecated
since PIKA 2.10.x or older versions. As we bump the major version, it is time
to start with a clean slate.
Below is a correspondence table with replacement function. The replacement is
not necessarily a direct search-and-replace equivalent. Some may have different
parameters, and in some case, it may require to think a bit about how things
work to reproduce the same functionality. Nevertheless everything which was
possible in the previous API is obviously still possible.
| Removed function | Replacement |
| ----------------------------------------------- | ------------------------------------------------- |
| `pika_attach_new_parasite()` | `pika_attach_parasite()` |
| `pika_brightness_contrast()` | `pika_drawable_brightness_contrast()` |
| `pika_brushes_get_brush()` | `pika_context_get_brush()` |
| `pika_brushes_get_brush_data()` | `pika_brush_get_pixels()` |
| `pika_brushes_get_spacing()` | `pika_brush_get_spacing()` |
| `pika_brushes_set_spacing()` | `pika_brush_set_spacing()` |
| `pika_by_color_select()` | `pika_image_select_color()` |
| `pika_by_color_select_full()` | `pika_image_select_color()` |
| `pika_channel_menu_new()` | `pika_channel_combo_box_new()` |
| `pika_checks_get_shades()` | `pika_checks_get_colors()` |
| `pika_color_balance()` | `pika_drawable_color_color_balance()` |
| `pika_color_display_convert()` | `pika_color_display_convert_buffer()` |
| `pika_color_display_convert_surface()` | `pika_color_display_convert_buffer()` |
| `pika_color_display_stack_convert()` | `pika_color_display_stack_convert_buffer()` |
| `pika_color_display_stack_convert_surface()` | `pika_color_display_stack_convert_buffer()` |
| `pika_color_profile_combo_box_add()` | `pika_color_profile_combo_box_add_file()` |
| `pika_color_profile_combo_box_get_active()` | `pika_color_profile_combo_box_get_active_file()` |
| `pika_color_profile_combo_box_set_active()` | `pika_color_profile_combo_box_set_active_file()` |
| `pika_color_profile_store_add()` | `pika_color_profile_store_add_file()` |
| `pika_colorize()` | `pika_drawable_colorize_hsl()` |
| `pika_context_get_transform_recursion()` | *N/A* |
| `pika_context_set_transform_recursion()` | *N/A* |
| `pika_curves_explicit()` | `pika_drawable_curves_explicit()` |
| `pika_curves_spline()` | `pika_drawable_curves_spline()` |
| `pika_desaturate()` | `pika_drawable_desaturate()` |
| `pika_desaturate_full()` | `pika_drawable_desaturate()` |
| `pika_drawable_attach_new_parasite()` | `pika_item_attach_parasite()` |
| `pika_drawable_bpp()` | `pika_drawable_get_bpp()` |
| `pika_drawable_delete()` | `pika_item_delete()` |
| `pika_drawable_get_image()` | `pika_item_get_image()` |
| `pika_drawable_get_linked()` | *N/A* |
| `pika_drawable_get_name()` | `pika_item_get_name()` |
| `pika_drawable_get_tattoo()` | `pika_item_get_tattoo()` |
| `pika_drawable_get_visible()` | `pika_item_get_visible()` |
| `pika_drawable_height()` | `pika_drawable_get_height()` |
| `pika_drawable_is_channel()` | `pika_item_is_channel()` |
| `pika_drawable_is_layer()` | `pika_item_is_layer()` |
| `pika_drawable_is_layer_mask()` | `pika_item_is_layer_mask()` |
| `pika_drawable_is_text_layer()` | `pika_item_is_text_layer()` |
| `pika_drawable_is_valid()` | `pika_item_is_valid()` |
| `pika_drawable_menu_new()` | `pika_drawable_combo_box_new()` |
| `pika_drawable_offsets()` | `pika_drawable_get_offsets()` |
| `pika_drawable_parasite_attach()` | `pika_item_attach_parasite()` |
| `pika_drawable_parasite_detach()` | `pika_item_detach_parasite()` |
| `pika_drawable_parasite_find()` | `pika_item_get_parasite()` |
| `pika_drawable_parasite_list()` | `pika_item_get_parasite_list()` |
| `pika_drawable_preview_new()` | `pika_drawable_preview_new_from_drawable()` |
| `pika_drawable_preview_new_from_drawable_id()` | `pika_drawable_preview_new_from_drawable()` |
| `pika_drawable_set_image()` | *N/A* |
| `pika_drawable_set_linked()` | *N/A* |
| `pika_drawable_set_name()` | `pika_item_set_name()` |
| `pika_drawable_set_tattoo()` | `pika_item_set_tattoo()` |
| `pika_drawable_set_visible()` | `pika_item_set_visible()` |
| `pika_drawable_transform_2d()` | `pika_item_transform_2d()` |
| `pika_drawable_transform_2d_default()` | `pika_item_transform_2d()` |
| `pika_drawable_transform_flip()` | `pika_item_transform_flip()` |
| `pika_drawable_transform_flip_default()` | `pika_item_transform_flip()` |
| `pika_drawable_transform_flip_simple()` | `pika_item_transform_flip_simple()` |
| `pika_drawable_transform_matrix()` | `pika_item_transform_matrix()` |
| `pika_drawable_transform_matrix_default()` | `pika_item_transform_matrix()` |
| `pika_drawable_transform_perspective()` | `pika_item_transform_perspective()` |
| `pika_drawable_transform_perspective_default()` | `pika_item_transform_perspective()` |
| `pika_drawable_transform_rotate()` | `pika_item_transform_rotate()` |
| `pika_drawable_transform_rotate_default()` | `pika_item_transform_rotate()` |
| `pika_drawable_transform_rotate_simple()` | `pika_item_transform_rotate_simple()` |
| `pika_drawable_transform_scale()` | `pika_item_transform_scale()` |
| `pika_drawable_transform_scale_default()` | `pika_item_transform_scale()` |
| `pika_drawable_transform_shear()` | `pika_item_transform_shear()` |
| `pika_drawable_transform_shear_default()` | `pika_item_transform_shear()` |
| `pika_drawable_width()` | `pika_drawable_get_width()` |
| `pika_edit_blend()` | `pika_drawable_edit_gradient_fill()` |
| `pika_edit_bucket_fill()` | `pika_drawable_edit_bucket_fill()` |
| `pika_edit_bucket_fill_full()` | `pika_drawable_edit_bucket_fill()` |
| `pika_edit_clear()` | `pika_drawable_edit_clear()` |
| `pika_edit_fill()` | `pika_drawable_edit_fill()` |
| `pika_edit_paste_as_new()` | `pika_edit_paste_as_new_image()` |
| `pika_edit_named_paste_as_new()` | `pika_edit_named_paste_as_new_image()` |
| `pika_edit_stroke()` | `pika_drawable_edit_stroke_selection()` |
| `pika_edit_stroke_vectors()` | `pika_drawable_edit_stroke_item()` |
| `pika_ellipse_select()` | `pika_image_select_ellipse()` |
| `pika_enum_combo_box_set_stock_prefix()` | `pika_enum_combo_box_set_icon_prefix()` |
| `pika_enum_stock_box_new()` | `pika_enum_icon_box_new()` |
| `pika_enum_stock_box_new_with_range()` | `pika_enum_icon_box_new_with_range()` |
| `pika_enum_stock_box_set_child_padding()` | `pika_enum_icon_box_set_child_padding()` |
| `pika_enum_store_set_stock_prefix()` | `pika_enum_store_set_icon_prefix()` |
| `pika_equalize()` | `pika_drawable_equalize()` |
| `pika_flip()` | `pika_item_transform_flip_simple()` |
| `pika_floating_sel_relax()` | *N/A* |
| `pika_floating_sel_rigor()` | *N/A* |
| `pika_free_select()` | `pika_image_select_polygon()` |
| `pika_fuzzy_select()` | `pika_image_select_contiguous_color()` |
| `pika_fuzzy_select_full()` | `pika_image_select_contiguous_color()` |
| `pika_gamma()` | `pika_drawable_get_format()` |
| `pika_get_icon_theme_dir()` | *N/A* |
| `pika_get_path_by_tattoo()` | `pika_image_get_vectors_by_tattoo()` |
| `pika_get_theme_dir()` | *N/A* |
| `pika_gradients_get_gradient_data()` | `pika_gradient_get_uniform_samples()` |
| `pika_gradients_sample_custom()` | `pika_gradient_get_custom_samples()` |
| `pika_gradients_sample_uniform()` | `pika_gradient_get_uniform_samples()` |
| `pika_histogram()` | `pika_drawable_histogram()` |
| `pika_hue_saturation()` | `pika_drawable_hue_saturation()` |
| `pika_image_add_channel()` | `pika_image_insert_channel()` |
| `pika_image_add_layer()` | `pika_image_insert_layer()` |
| `pika_image_add_vectors()` | `pika_image_insert_vectors()` |
| `pika_image_attach_new_parasite()` | `pika_image_attach_parasite()` |
| `pika_image_base_type()` | `pika_image_get_base_type()` |
| `pika_image_free_shadow()` | `pika_drawable_free_shadow()` |
| `pika_image_get_channel_position()` | `pika_image_get_item_position()` |
| `pika_image_get_cmap()` | `pika_image_get_colormap()` |
| `pika_image_get_layer_position()` | `pika_image_get_item_position()` |
| `pika_image_get_vectors_position()` | `pika_image_get_item_position()` |
| `pika_image_height()` | `pika_image_get_height()` |
| `pika_image_lower_channel()` | `pika_image_lower_item()` |
| `pika_image_lower_layer()` | `pika_image_lower_item()` |
| `pika_image_lower_layer_to_bottom()` | `pika_image_lower_item_to_bottom()` |
| `pika_image_lower_vectors()` | `pika_image_lower_item()` |
| `pika_image_lower_vectors_to_bottom()` | `pika_image_lower_item_to_bottom()` |
| `pika_image_menu_new()` | `pika_image_combo_box_new()` |
| `pika_image_parasite_attach()` | `pika_image_attach_parasite()` |
| `pika_image_parasite_detach()` | `pika_image_detach_parasite()` |
| `pika_image_parasite_find()` | `pika_image_get_parasite()` |
| `pika_image_parasite_list()` | `pika_image_get_parasite_list()` |
| `pika_image_raise_channel()` | `pika_image_raise_item()` |
| `pika_image_raise_layer()` | `pika_image_raise_item()` |
| `pika_image_raise_layer_to_top()` | `pika_image_raise_item_to_top()` |
| `pika_image_raise_vectors()` | `pika_image_raise_item()` |
| `pika_image_raise_vectors_to_top()` | `pika_image_raise_item_to_top()` |
| `pika_image_scale_full()` | `pika_image_scale()` |
| `pika_image_set_cmap()` | `pika_image_set_colormap()` |
| `pika_image_width()` | `pika_image_get_width()` |
| `pika_install_cmap()` | *N/A* |
| `pika_invert()` | `pika_drawable_invert()` |
| `pika_item_get_linked()` | *N/A* |
| `pika_item_set_linked()` | *N/A* |
| `pika_layer_menu_new()` | `pika_layer_combo_box_new()` |
| `pika_layer_scale_full()` | `pika_layer_scale()` |
| `pika_layer_translate()` | `pika_item_transform_translate()` |
| `pika_levels()` | `pika_drawable_levels()` |
| `pika_levels_auto()` | `pika_drawable_levels_stretch()` |
| `pika_levels_stretch()` | `pika_drawable_levels_stretch()` |
| `pika_min_colors()` | *N/A* |
| `pika_palettes_get_palette()` | `pika_context_get_palette()` |
| `pika_palettes_get_palette_entry()` | `pika_palette_entry_get_color()` |
| `pika_parasite_attach()` | `pika_attach_parasite()` |
| `pika_parasite_data()` | `pika_parasite_get_data()` |
| `pika_parasite_data_size()` | `pika_parasite_get_data()` |
| `pika_parasite_detach()` | `pika_detach_parasite()` |
| `pika_parasite_find()` | `pika_get_parasite()` |
| `pika_parasite_flags()` | `pika_parasite_get_flags()` |
| `pika_parasite_list()` | `pika_get_parasite_list()` |
| `pika_parasite_name()` | `pika_parasite_get_name()` |
| `pika_path_delete()` | `pika_image_remove_vectors()` |
| `pika_path_get_current()` | `pika_image_get_active_vectors()` |
| `pika_path_get_locked()` | *N/A* |
| `pika_path_get_points()` | `pika_vectors_stroke_get_points()` |
| `pika_path_get_point_at_dist()` | `pika_vectors_stroke_get_point_at_dist()` |
| `pika_path_get_tattoo()` | `pika_item_get_tattoo()` |
| `pika_path_import()` | `pika_vectors_import_from_file()` |
| `pika_path_list()` | `pika_image_get_vectors()` |
| `pika_path_set_current()` | `pika_image_set_active_vectors()` |
| `pika_path_set_locked()` | *N/A* |
| `pika_path_set_points()` | `pika_vectors_stroke_new_from_points()` |
| `pika_path_set_tattoo()` | `pika_item_set_tattoo()` |
| `pika_path_stroke_current()` | `pika_edit_stroke_vectors()` |
| `pika_path_to_selection()` | `pika_image_select_item()` |
| `pika_patterns_get_pattern()` | `pika_context_get_pattern()` |
| `pika_patterns_get_pattern_data()` | `pika_pattern_get_pixels()` |
| `pika_perspective()` | `pika_item_transform_perspective()` |
| `pika_posterize()` | `pika_drawable_posterize()` |
| `pika_prop_enum_stock_box_new()` | `pika_prop_enum_icon_box_new()` |
| `pika_prop_stock_image_new()` | `pika_prop_icon_image_new()` |
| `pika_prop_unit_menu_new()` | `pika_prop_unit_combo_box_new()` |
| `pika_rect_select()` | `pika_image_select_rectangle()` |
| `pika_rotate()` | `pika_item_transform_rotate()` |
| `pika_round_rect_select()` | `pika_image_select_round_rectangle()` |
| `pika_scale()` | `pika_item_transform_scale()` |
| `pika_selection_combine()` | `pika_image_select_item()` |
| `pika_selection_layer_alpha()` | `pika_image_select_item()` |
| `pika_selection_load()` | `pika_image_select_item()` |
| `pika_shear()` | `pika_item_transform_shear()` |
| `pika_stock_init()` | `pika_icons_init()` |
| `pika_text()` | `pika_text_fontname()` |
| `pika_text_get_extents()` | `pika_text_get_extents_fontname()` |
| `pika_text_layer_get_hinting()` | `pika_text_layer_get_hint_style()` |
| `pika_text_layer_set_hinting()` | `pika_text_layer_set_hint_style()` |
| `pika_threshold()` | `pika_drawable_threshold()` |
| `pika_toggle_button_sensitive_update()` | `g_object_bind_property()` |
| `pika_transform_2d()` | `pika_item_transform_2d()` |
| `pika_unit_menu_update()` | `#PikaUnitComboBox` |
| `pika_vectors_get_image()` | `pika_item_get_image()` |
| `pika_vectors_get_linked()` | *N/A* |
| `pika_vectors_get_name()` | `pika_item_get_name()` |
| `pika_vectors_get_tattoo()` | `pika_item_get_tattoo()` |
| `pika_vectors_get_visible()` | `pika_item_get_visible()` |
| `pika_vectors_is_valid()` | `pika_item_is_valid()` |
| `pika_vectors_parasite_attach()` | `pika_item_attach_parasite()` |
| `pika_vectors_parasite_detach()` | `pika_item_detach_parasite()` |
| `pika_vectors_parasite_find()` | `pika_item_get_parasite()` |
| `pika_vectors_parasite_list()` | `pika_item_get_parasite_list()` |
| `pika_vectors_set_linked()` | *N/A* |
| `pika_vectors_set_name()` | `pika_item_set_name()` |
| `pika_vectors_set_tattoo()` | `pika_item_set_tattoo()` |
| `pika_vectors_set_visible()` | `pika_item_set_visible()` |
| `pika_vectors_to_selection()` | `pika_image_select_item()` |
| `pika_zoom_preview_get_drawable_id()` | `pika_zoom_preview_get_drawable()` |
| `pika_zoom_preview_new()` | `pika_zoom_preview_new_from_drawable()` |
| `pika_zoom_preview_new_from_drawable_id()` | `pika_zoom_preview_new_from_drawable()` |
| `pika_zoom_preview_new_with_model()` | `pika_zoom_preview_new_with_model_from_drawable()`|

View File

@ -0,0 +1,451 @@
# Guide to changes to ScriptFu v3 for script authors
*Draft, until PIKA 3 is final. FIXME: rearrange and rename the cited documents*
## About
The audience is authors of Scriptfu plugins.
This discusses how to edit v2 scripts so they will run in PIKA 3.
This is only about changes to ScriptFu proper.
The PIKA PDB, which you can call in scripts, has also changed.
That also may require you to edit scripts.
- For changes in signatures of PDB procedures,
see devel-docs/PIKA3-plug-in-porting-guide/porting_scriptfu_scripts.md
- For added, removed, and replaced PDB procedures,
see devel-docs/PIKA3-plug-in-porting-guide/removed_functions.md
## Quickstart
A lucky few existing scripts may work in PIKA v3.
Some changes are most likely to break an existing plugin.:
- SF-VALUE is obsolete
- TRUE and FALSE are obsolete
- many PDB procedures are obsolete or renamed, or their signature changed
Once you edit a script for these changes, the script won't work in PIKA v2.
Other changes:
- you can install scripts like plugins in other languages
- scripts can use the new mult-layer selection feature of PIKA
- a script can abort with an error message
- a script's settings are more fully saved
Those changes might not affect an existing plugin.
You need only understand those changes when you want to use new features of PIKA.
A word of explanation: the PIKA developers understand these changes may be onerous.
Script developers might need to maintain two different versions of their scripts.
Some users will stick with PIKA 2 for a while and some will switch to PIKA 3.
But PIKA 3 is a major version change with new features.
A clean break is necessary to move forward with improvements.
The situation is similar to the disruption caused by the move from Python 2 to 3.
### SF-VALUE kind of argument is obsolete
The symbol SF-VALUE is obsolete.
You can edit v2 scripts and replace that symbol.
In v2, SF-VALUE declared a formal argument that is an unquoted, arbitrary string.
Usually, SF-VALUE was used for an integer valued argument.
In the dialog for a script, ScriptFu showed a text entry widget.
Usually the widget showed a default integer literal,
but the widget let you enter any text into the string.
You usually will replace it with an SF-ADJUSTMENT kind of formal argument,
where the "digits" field of the SF-ADJUSTMENT is 0,
meaning no decimal places, i.e. integer valued.
You must also add the other fields, e.g. the lower and upper limits.
A script that has been edited to replace SF-VALUE with SF-ADJUSTMENT
will remain compatible with PIKA 2.
Example:
SF-VALUE "Font size (pixels)" "50"
=>
SF-ADJUSTMENT "Font size (pixels)" '(50 1 1000 1 10 0 SF-SPINNER)
Here, in the seven-tuple, the 0 denotes: no decimal places.
Another example, where you formerly
used SF-VALUE to declare a formal argument that is float valued:
SF-VALUE "Lighting (degrees)" "45.0"
=>
SF-ADJUSTMENT "Lighting (degrees)" '(45.0 0 360 5 10 1 SF-SLIDER)
Here, the 1 denotes: show 1 decimal place, for example "45.0",
in the dialog widget.
#### Use SF-STRING for some use cases
In v2, a SF-VALUE argument let a user enter executable Scheme code,
say "'(1 g 1)", which is a list literal,
to be injected into a Scheme call to a plugin.
That use is no longer possible.
If you must do that, use SF_STRING to get a string,
and then your plugin can eval the string.
#### Arbitrary precision floats
In v2, a SF-VALUE argument let a user enter a float with arbitrary precision,
e.g. "0.00000001"
That is no longer possible. You as a script author must use SF-ADJUSTMENT
and specify the maximum precision that makes sense. The user won't be able to
enter a value with more precision (more digits after the decimal point.)
You should understand the math of your algorithm and know what precision
is excess in terms of visible results.
Example:
SF-ADJUSTMENT "Lighting (degrees)" '(45.0 0 360 5 10 4 SF-SLIDER)
Here, the user will only be able to enter four decimal places,
for example by typing "0.0001" into the widget.
If you actually need arbitrary precision, use SF_STRING to get a string,
and then your plugin can eval the string to get a Scheme numeric
of the maximum precision that Scheme supports.
#### Rationale
Formerly, a SF-VALUE argument let a user enter garbage for an argument,
which caused an error in the script.
SF-ADJUSTMENT is more user-friendly.
### FALSE and TRUE symbols obsolete
FALSE and TRUE symbols are no longer defined symbols in the ScriptFu language.
They never were in the Scheme language.
Instead, the Scheme language has symbols #f and #t.
In ScriptFu v2, FALSE was equivalent to 0
and TRUE was equivalent to 1.
But FALSE was not equivalent to #f.
Formerly, you could use the = operator to compare to FALSE and TRUE.
The = operator in Scheme is a numeric operator, not a logical operator.
Now you can use the eq? or eqv? operators.
In Scheme, all values are truthy except for #f.
The empty list is truthy.
The numeric 0 is truthy.
Only #f is not truthy.
A PDB procedure returning a single Boolean (a predicate)
returns a list containing one element, for example (#f) or (#t).
#### Rationale
The ScriptFu language is simpler and smaller; TRUE and FALSE duplicated concepts already in the Scheme language.
#### Example changes
Registering a script:
SF-TOGGLE "Gradient reverse" FALSE
=>
SF-TOGGLE "Gradient reverse" #f
Calling a PDB procedure taking a boolean:
(pika-context-set-feather TRUE)
=>
(pika-context-set-feather #t)
Logically examining a variable for truth:
(if (= shadow TRUE) ...
=>
(if shadow ...
### In scripts, calls to PDB procedures that return boolean yield (#t) or (#f)
In ScriptFu v2, PDB procedures returning a boolean returned 1 or 0 to a script,
that is, numeric values.
Those were equal to the old TRUE and FALSE values.
Remember that a call to the PDB returns a list to the script.
So in ScriptFu v3,
a PDB procedure that returns a single boolean (a predicate function)
returns (#t) or (#f), a list containing one boolean element.
#### Rationale
#t and #f are more precise representations of boolean values.
0 and 1 are binary, but not strictly boolean.
The ScriptFu language is smaller if concepts of truth are not duplicated.
#### Example changes
Calling a PDB procedure that is a predicate function:
(if (= FALSE (car (pika-selection-is-empty theImage))) ...
=>
(if (car (pika-selection-is-empty theImage)) ...
Here, the call to the PDB returns a list of one element.
The "car" function returns that element.
The "if" function evaluates that element for truthy.
Note that to evaluate the result of a PDB call for truth,
you should just use as above, and not use "eq?" or "eqv?".
Such a result is always a list, and a list is truthy,
but not equivalent to #t.
In the ScriptFu console:
>(eq? #t '())
#f
>(eqv? #t '())
#f
### Use script-fu-script-abort to throw an error
The function "script-fu-script-abort" is new to ScriptFu v3.
It causes the interpreter to stop evaluating a script
and yield an error of type PikaPDBStatus.
That is, it immediately returns an error to the caller.
It is similar to the "return" statement in other languages,
but the Scheme language has no "return" statement.
The function takes an error message string.
When the caller is the PIKA app,
the PIKA app will show an error dialog
having the message string.
When the caller is another PDB procedure (a plugin or script)
the caller must check the result of a call to the PDB
and propagate the error.
ScriptFu itself always checks the result of a call to the PDB
and propagates the error,
concatenating error message strings.
The function can be used anywhere in a script,
like you would a "return" statement in other languages.
Alternatively, a script can yield #f to yield a PDB error.
See below.
#### Rationale
Formerly, scripts usually called pika-message on errors,
without yielding an error to the caller.
It was easy for a user to overlook the error message.
An abort shows an error message that a user must acknowledge
by choosing an OK button.
#### Example
This script defines a PDB procedure that aborts:
(define (script-fu-abort)
(script-fu-script-abort "Too many drawables.")
(pika-message "this never evaluated")
)
...
### A script can yield #f to throw an error
Here we use the word "yield" instead of the word "return".
Neither "yield" nor "return" are reserved words in the Scheme language.
A Scheme text evaluates to, or yields, the value of its last expression.
Any value other than #f, even the empty list or the list containing #f,
is truthy.
A ScriptFu plugin
(the PDB procedure that a script defines in its run func)
whose last evaluated expression is #f
will yield an error of type PikaPDBStatus.
If you don't want a ScriptFu plugin to yield an error,
it must not evaluate to #f.
Most existing plugins won't, since their last evaluated expression
is usually a call to the PDB yielding a list, which is not equivalent to #f.
*Remember that ScriptFu does not yet let you register PDB procedures
that return values to the caller.
That is, you can only register a void procedure, having only side effects.
So to yield #f does not mean to return a boolean to the caller.*
*Also, you can define Scheme functions internal to a script
that yield #f but that do not signify errors.
It is only the "run func" that defines a PDB procedure that,
yielding #f, yields a PDB error to the caller.*
#### Examples
(define (script-fu-always-fail)
(begin
; this will be evaluated and show a message in PIKA status bar
(pika-message "Failing")
; since last expression, is the result, and will mean error
#f
)
)
### You can optionally install scripts like plugins in other languages
In v3 you can install ScriptFu scripts to a /plug-ins directory.
You must edit the script to include a shebang in the first line:
#!/usr/bin/env pika-script-fu-interpreter-3.0
In v2 all ScriptFu scripts were usually installed in a /scripts directory.
In v3 you may install ScriptFu scripts with a shebang
in a subdirectory of a /plug-ins directory.
Installation of scripts with a shebang must follow rules for interpreted plugins.
A script file must:
- have a shebang on the first line
- be in a directory having the same base name
- have executable permission
- have a file suffix corresponding to an interpreter
An example path to a script:
~/.config/PIKA/2.99/plug-ins/myScript/myScript.scm
Such a script will execute in its own process.
If it crashes, it doesn't affect PIKA or other scripts.
In v2, all scripts in the /scripts directory are executed by the long-lived
process "extension-script-fu."
If one of those scripts crash, menu items implemented by ScriptFu dissappear
from the PIKA app, and you should restart PIKA.
### Use script-fu-register-filter to register PDB procedures that take images
The function *script-fu-register-filter* is new to v3.
It lets you declare a script that:
- is multi-layer capable filter, taking an image and many drawables
- can save its settings between sessions
You don't specify the first two arguments "image" and "drawable"
as you do with script-fu-register in v2.
Those arguments are implicit.
As a convenience, ScriptFu and PIKA registers those arguments in the PDB for you.
The run func that you define in your script
must have those formal arguments. For example:
(define script-fu-my-plugin (image drawables arg1 arg2) body)
ScriptFu passes a Scheme vector of drawables, not just one, to a script
registering with script-fu-register-filter.
#### Multi-layer capabilily
script-fu-register-filter has an argument "multilayer-capability".
Some documents may refer to the argument as "drawable arity."
The argument follows the "image types" argument
and precedes the argument triples that declare formally the "other" arguments
of your plugin.
Here is an abbreviated example:
(script-fu-register-filter "script-fu-test-sphere-v3"
"Sphere v3..."
"Test script-fu-register-filter: needs 2 selected layers."
"authors"
"copyright holders"
"copyright dates"
"*" ; image types any
SF-TWO-OR-MORE-DRAWABLE ; multi-layer capability argument
SF-ADJUSTMENT "Radius (in pixels)" (list 100 1 5000 1 10 0 SF-SPINNER)
The "multilayer-capability" argument can have the following values:
SF_ONE_DRAWABLE expects exactly one drawable
SF_ONE_OR_MORE_DRAWABLE expects and will process one or more drawables
SF_TWO_OR_MORE_DRAWABLE expects and will process two or more drawables
This is only a declaration; whether your run func does what it promises is another matter.
A script declaring SF_ONE_DRAWABLE still receives a vector of drawables,
but the vector should be of length one.
These do not specify how the script will process the drawables.
Typically, SF_ONE_OR_MORE_DRAWABLE means a script will filter
the given drawables independently and sequentially.
Typically, SF_TWO_OR_MORE_DRAWABLE means a script will
combine the given drawables, say into another drawable by a binary operation.
The "multilayer-capability" argument tells PIKA to enable the script's menu item
when a user has selected the appropriate count of drawables.
#### Settings are handled by PIKA, not ScriptFu
Scripts declared with script-fu-register-filter have settings that are persisted
within and between Pika sessions. That is, the next time a user chooses the filter,
the dialog will show the same settings as the last time they chose the filter.
This is not true for v2 script-register-filter,
where settings are only kept during a PIKA session.
The dialog for a script declared with script-fu-register-filter
will also have buttons for resetting to initial or factory values of settings.
#### A script should check how many drawables were passed
A well-written script should throw an error if a caller does not pass the expected number of drawables, either more or fewer than declared. See below.
### Deprecated: using script-fu-register-filter to register PDB procedures that take images
Existing scripts that use script-fu-register to declare a procedure
that takes an image and single drawable,
are deprecated.
They will still work and have a correct dialog in v3.
In some future version of PIKA,
such scripts may become obsolete.
All newly written scripts taking an image and one or more drawables
should use script-fu-register-filter.
PIKA enables the menu item for such deprecated scripts if and only if a user
selects exactly one drawable (layer or other.)
### ScriptFu plugins are expected to throw errors for improper count of drawables
Starting with PIKA 3,
a plugin that takes an image takes a container of possibly many drawables.
This is the so-called "multi-layer selection" feature.
Existing plugins that don't are deprecated,
and may become obsoleted in a future version of PIKA.
Plugins should declare how many drawables they can process,
also called the "multi-layer capability" or "drawable arity" of the algorithm.
The declared drawable arity
only describes how many drawables the algorithm is able to process.
The declared drawable arity does not denote the signature of the PDB procedure.
Well-written image procedures always receive a container of drawables.
For calls invoked by a user, the drawable arity describes
how many drawables the user is expected to select.
PIKA disables/enables the menu item for a plugin procedure
according to its declared drawable arity.
So a plugin procedure invoked directly by a user should never receive
a count of drawables that the plugin can't handle.
*But PDB procedures are also called from other PDB procedures.*
A call from another procedure may in fact
pass more drawables than declared for drawable arity.
That is a programming error on behalf of the caller.
A well-written callee plugin that is passed more drawables than declared
should return an error instead of processing any of the drawables.
Similarly for fewer than declared.
A ScriptFu plugin can use script-fu-script-abort to declare an error
when passed an improper count of drawables.