===========================================================
Specifying arguments for plugin generation and dialog boxes
===========================================================

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.)

.. image:: 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`__.

.. __: writing_plugins.html

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:

.. image:: images/arguments_dialog.png

Incidentally, it was produced by the following code:

.. code:: Python

   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.

.. code:: Python

      # 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.

.. __: plugins_custom_types.html

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.

.. _wxPython: http://www.wxpython.org

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:

.. image:: 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.
