Specifying arguments for plugin generation and dialog boxes

Last modified: September 16, 2022

Contents

Introduction

Gamera includes a rich way to specify what arguments a plugin method can take. This serves two main purposes:

  1. To generate the code necessary to call a C++ function from Python.
  2. To generate basic dialogs that help the user call the method from the GUI. (See example below.)
images/erode_dilate_dialog.png

All of the classes necessary to make this happen are in gamera/args.py, which is included in gamera/plugin.py. You can refer to those files for more information if necessary.

This document will first describe the common case of using args.py for specifying the type metadata of a plugin method. Then advanced usage of args.py for other custom purposes is covered.

Specifying the type metadata of a plugin method

Specifying the arguments of a plugin method is done by setting the args member variable of a subclass of the PluginFunction metadata class. This is discussed in Writing Gamera Plugins.

The args member must be an instance of the Args class. The Args class is constructed as:

Args(list)

The list argument is a list of Arg instances, in the order the arguments appear in the function call. For instance, to call a C++ function with the following signature:

Image* resize_copy(T& image, int nrows, int ncols, int resize_quality);

the Args constructor call would look like:

args = Args([Int("nrows", default=32), Int("ncols", default=32),
             Choice("Interpolation Type", ["None", "Linear", "Spline"])])

As you can see, Gamera's system is a much richer type information system than C, including things such as ranges, enumerations and default values.

The same type objects are also used for the self_type and return_type member variables in the plugin method metadata.

The argument types include Int, Real, String, Class, ImageType, Choice, ChoiceString, FileOpen, FileSave, Directory, Check, Region, RegionMap, ImageInfo, FloatVector, IntVector, ImageList, Info and Radio. Each of these is discussed in greater detail below.

This dialog box shows how the most common argument types are presented in the GUI:

images/arguments_dialog.png

Incidentally, it was produced by the following code:

args = Args([Int("Int"),
             Real("Real"),
             String("String"),
             Class("Class"),
             ImageType(ALL, "ImageType"),
             FileOpen("FileOpen"),
             FileSave("FileSave"),
             Directory("Directory"),
             Radio("Radio 1", "Tastes great"),
             Radio("Radio 2", "Less filling"),
             Check("Check", "Power"),
             Info("Info: This is just for information"),
             Pixel("Pixel"),
             Point("Point"),
             FloatPoint("FloatPoint")])

Enabling default values beyond the GUI

The default parameter in the Args specification is only used in the GUI for the argument dialog box. If you need an actual default argument for your plugin function, you must define the __call__ method in your plugin, e.g.

# wrapper for passing a default argument
def __call__(self, nrows, ncols, interpolation="Linear"):
    return _example.resize_copy(self, nrows, ncols, interpolation)
__call__ = staticmethod(__call__)

_example must be replaced by the actual name of your source file plus a leading underscore.

Plugin types reference

Int

Int (string name, tuple range, int default = 0)

A signed integers argument. Corresponds to the C int type.

Optionally, a range can be given as the tuple (lower_bound, upper_bound) and a default value. The latter can be set to NoneDefault for forcing the default to None in the GUI.

Note

Ranges and defaults are used for the benefit of the GUI only. There is no range-checking performed for you.

In the GUI, this is presented as a text entry field.

Real

Real (string name, tuple range, int default = 0.0)

A real (floating-point) argument. Corresponds to the C double type.

Optionally, a range can be given as the tuple (lower_bound, upper_bound), and a default value.

Note

Ranges and defaults are used for the benefit of the GUI only. There is no range-checking performed for you.

String

String (string name, int default = "")

A string argument. Corresponds to the C char * or C++ std::string type.

Optionally, a default value can be given.

Class

Class (string name, PyObject klass, bool list_of = False)

Class is a general purpose argument type. Corresponds to the C PyObject * type. See Custom data types in plugins for details how to pass generic PyObject* data types to and from C++ plugins.

The given klass is any Python type (built-in or otherwise) that is to be accepted as an argument. For example, to accept any Python dictionary, use:

Class("dict", dict)

If the optional list_of is True, then this argument refers to a Python list, in which all of its elements are instances of klass.

Class arguments are displayed in the GUI as a drop-down list of instances of that class. If you want to have None as the first entry in this list, you can set the default to NoneDefault, which is a special object that translates to None when used as a default value.

ImageType

ImageType (list pixel_types, string name, bool list_of = False, default = None)

A Gamera Image. Corresponds to the subclasses of gamera::Image & on the C++ side.

The accepted pixel types of the image are restricted to the given list of pixel types. For example to accept only GreyScale and OneBit images:

ImageType([GREYSCALE, ONEBIT])

For convenience you can use the constant ALL, which is the list of all pixel types.

If the optional list_of is True, this argument refers to a Python list of Gamera Images, and on the C++ side will be passed in as a std::vector<gamera::Image*>.

To allow for an optional image argument, it is possible to set the default argument to NoneDefault, which will be translated by the GUI entry mask to None. In this case, make sure that you overwrite the __call__ method in the python plugin wrapper, so that the missing argument is correctly caught.

ImageList

ImageList (string name)

ImageList is a convenience alias for ImageType(ALL, name , list_of=True).

Like Class, this argument is displayed in the GUI as a drop-down list of instances of image lists. If you want to have None as the first entry in this list, you can set the default to NoneDefault, which is a special object that translates to None when used as a default value.

Choice

Choice (string name, list choices = [], int default = 0)

An enumeration. Corresponds to the C type enum or int.

When an integer value is really logically a set of options, Choice should be used so the user is presented with a drop-down list of named options. For example, from the resize plugin method:

args = Args([Int("nrows"), Int("ncols"),
             Choice("interp_type", ["None", "Linear", "Spline"])])

In some cases, it might be necessary to know whether the user actually has made a choice. An alternative to defining a special choice index for 'no choice', you can alternatively set the default to NoneDefault, which is a special object that translates to None when used as a default value:

args = Args([Choice("bla", ["Choice1", "Choice2"], default=NoneDefault)])

ChoiceString

ChoiceString (string name, list choices = [], string default = None, strict = True)

A set of choices of strings. Corresponds to the C type char *.

To be used when a string argument can be one of a fixed set of values.

If strict is True (the default), the GUI will present a drop-down list box of these choices. When strict is False, a combo box will be presented which will allow the user to enter in a value that is not in the list of choices.

Note that outside of the GUI, the plugin system does not verify the value of the string, so the plugin method must gracefully accept any string as input and deal with it accordingly.

FileOpen

FileOpen (string name, string default = "", extension = "*.*")

A filename for opening. Corresponds to the C char * or C++ std::string type.

In the GUI, this is presented as a text box with a browse button. When the browse button is pressed, a file selection dialog is presented.

extensions can be specified to limit the file types that are displayed in the file selection dialog. Extensions is a string with one or more wildcard expressions separated by semicolons. For example, to display TIFF and PNG images:

*.tiff;*.tif;*.TIF;*.png

Since FileOpen is used exclusively for opening files, the GUI ensures that the file already exists before passing the value along to the underlying plugin method.

FileSave

FileSave (string name, string default = "", extension = "*.*")

The counterpart to FileOpen, except for saving files.

If the file already exists, the user is presented with an "Are you sure?" dialog.

Directory

Directory (string name, string default = "")

A directory name. Corresponds to the C char * or C++ std::string type.

The GUI ensures that the directory exists before passing the path name to the underlying plugin method.

Check

Check (string name, string check_box = "", bool default = False)

A boolean value. Corresponds to the C int or C++ bool.

In the GUI, this is presented as a check box.

check_box is an additional piece of text that will be placed to the right of the check box in the GUI.

Rect

Rect (string name)

A Gamera Rect object. Corresponds to gamera::Rect* on the C++ side.

Region

Region (string name)

A Gamera Region object. Corresponds to gamera::Region & on the C++ side.

RegionMap

RegionMap (string name)

A Gamera RegionMap object. Corresponds to gamera::RegionMap & on the C++ side.

ImageInfo

ImageInfo (string name)

A Gamera ImageInfo object. Corresponds to gamera::ImageInfo & on the C++ side.

FloatVector

FloatVector (string name, int length = -1)

A vector of floating-point values. On the Python side this is an array('d') object. On the C++ side, this is a FloatVector * which is a typedef for std::vector<double> *.

The optional length argument should be given when the length of the argument is fixed.

IntVector

IntVector (string name, int length = -1)

A vector of integer values. On the Python side this is an array('i') object. On the C++ side, this is a IntVector * which is a typedef for std::vector<int> *.

The optional length argument should be given when the length of the argument is fixed.

Pixel

Pixel (string name)

A pixel value corresponding to the type of the "self" image. For instance, if the method is operating on a FLOAT image, this argument will take a FLOAT value.

Setting a default value for a pixel is generally of little use because the value depends on the pixel type. You can however set the default to NoneDefault, which is a special object that translates to None when used as a default value. This can then be queried in the function, as shown in the following example:

args = Args([Pixel("PixelValue", default=NoneDefault)])
def __call__(self, PixelValue=None):
    if (PixelValue == None):
        PixelValue = self.white()

Point

Point (string name, default = (0, 0))

A Point object for representing coordinates as unsigned integers. This will be displayed in the automatically-generated dialog box as a pair of numbers.

PointVector

PointVector (string name)

A Python sequence of Points.

FloatPoint

FloatPoint (string name, default = (0.0, 0.0))

A FloatPoint object for representing coordinates as floating point values. This will be displayed in the automatically-generated dialog box as a pair of numbers.

Info

Info (string name)

This class is just for displaying information in a dialog box. It does not affect in any way the passing of arguments to a plugin.

Radio

Radio (string name)

Advanced usage

We've just seen how the args.py classes are used for specifying plugin method metadata. Of course, it can also be used whenever a one-liner quick-and-dirty dialog box is needed. For more complex tasks, you may still need to write a dialog box using the underlying wxPython toolkit.

For example, we can create a simple dialog box with code below:

>>>from gamera.args import *
>>>dialog = Args([Int("your favorite number")], name="What is your favorite number?")

The optional name argument was used to change the title bar text. To display the dialog to the user, we just use the .show() method:

>>>dialog.show()

This displays the following window:

images/arguments_example.png

When the user clicks Ok, the results are returned in a list:

[6]

If the user clicks Cancel, None is returned:

None

Under the hood...

For a detailed view of how this works, I suggest looking at the source code... [wink]

But seriously, to help with that it should be noted that there are three different source files at work here:

gamera/args.py
The main file that defines a class for each of the argument types. Only very basic functionality, such as storing the range of Int, are implemented here.
gamera/args_wrappers.py
Defines how the types are converted between C++ and Python.
gamera/gui/args_gui.py
Defines how the arguments are mapped to widgets in the GUI.

The args.py file loads the other two (if necessary) and "mixes-in" the methods in the extension classes to the core classes.