The ability to extend the itools is one of their main strengths. This can be adding a button for an operation (like our example here), the capability to read/write new file types, new visualizations, or new ways to manipulate visualizations. Plus, the user interface can be customized to various levels. Toolbars and panels can be added to the standard configuration, but a totally custom interface can be created also. Capabilities can also be removed to provide a simpler interface for a specific task.
This example adds an adaptive histogram equalization operation to `IIMAGE`.
There are two files for this demo program: [`mgitopadapthistequal__define.pro`](http://michaelgalloy.com/demos/itools/mgitopadapthistequal__define.pro) (
doc) to define the operation and [`mg_dataop_demo.pro`](http://michaelgalloy.com/demos/itools/mg_dataop_demo.pro) ( doc) to setup using the operation. To run the demo, make sure both files are compiled or in your path and run `MG_DATAOP_DEMO`.
You'll probably want to look at the documentation for the parent classes of our class: `IDLitComponent`, `IDLitIMessaging`, `IDLitOperation`, and `IDLitDataOperation` during the course of this tutorial.
### Define the member variables ###
The member variables will include all the properties of the operation, plus whatever else is needed to be stored during the life of the operation. The properties will be registered in the `init` method using the names defined here.
### The `init` and `cleanup` methods ###
The `init` method has several jobs:
1. call `IDLitDataOperation::init`> with the proper keywords (`TYPES` and `_EXTRA`),
2. register properties, and
3. initialize member variables (properties).
As usual for a subclass' `init` method, the first task is to call the parent's `init` method:
if (~self->idlitdataoperation::init(types=['IDLARRAY2D'], $
name='Adapt Hist Eq', $
_extra=e)) then return, 0L
Note that it is important that it get passed `_EXTRA`. The `TYPES` determines which itools data types the operation will act on. The `REVERSIBLE_OPERATION` and `EXPENSIVE_OPERATION` keywords relate to the undo/redo system. `REVERSIBLE_OPERATION` determines what happens when the user undo's the operation. If `REVERSIBLE_OPERATION` is set, then the `undoExecute` method is called. If `REVERSIBLE_OPERATION` is not set, then the itools will cache data before the operation is executed so that it can be restored when it is undone. `EXPENSIVE_OPERATION` determines the behavoir after the operation is undone. If `EXPENSIVE_OPERATION` is set, then the result of the operation is cached so it can be redone without having to calculate it again. If not set it must be calculated again via the `execute` method if it is redone.
self->registerProperty, 'clip', /float, $
description='Slope limit of histogram', $
Register properties of the operation via `IDLitComponent::registerProperty` (`IDLitComponent` is a parent class of `IDLitDataOperation`). The positional parameter is the member variable name. The type is specified using the `INTEGER` and `FLOAT` keywords (others are available, though not corresponding to all the IDL types), but could be specifed via a code as the second positional parameter.
The cleanup method simply calls `IDLitDataOperation::cleanup`.
### The `setProperty` and `getProperty` methods ###
The `setProperty` and `getProperty` methods are fairly standard. They *must* provide access to all registered properties and *must* pass keywords on to `IDLitDataOperation::setProperty` and `IDLitDataOperation::getProperty`.
### The `doExecuteUI`, `execute`, and `undoExecute` methods ###
The `doExecuteUI` method is called to present a GUI for the user to modify properties, see a preview, etc. before the operation is executed. It gets the tool object reference, does a quick sanity check, and does a UI service:
otool = self->getTool()
if (~otool) then return, 0L
return, otool->doUIService('OperationPreview', self)
Documented predefined choices for services are: 'PropertySheet' or 'OperationPreview'. You can also write your own UI service. Note that this method will not be called if the `SHOW_EXECUTION_UI` property of the operation is not set.
The `execute` method actually does the calculations of the operation. The function accepts a single positional parameter which is an input for the original data and an output for the operated upon data. This is the statement that actually does the adaptive histogram equalization:
data = adapt_hist_equal(bytscl(data), $
The status of the execution is returned (1 for success, 0 for failure).
The `undoExecute` method is not needed for this operation because `REVERSIBLE_OPERATION` is not set.
### Using the operation ###
`MG_DATAOP_DEMO` puts `MGitOpAdaptHistEqual` into `IIMAGE` and loads some default data. The itool is created with a data set in the standard way:
f = filepath('endocell.jpg', subdir=['examples', 'data'])
endo = read_image(f)
id = itGetCurrent(tool=otool)
Here, `ITGETCURRENT` gets the itool identifier and object reference. We only need the object reference, but are required to get the identifier. Be sure to use `ITGETCURRENT` right after creating the itool, because if another itool is created or even becames the current window in the OS, it will be the current itool.
otool->registerOperation, 'AdaptHistEqual', $
This registers the operation on our itool. The positional parameters give a name for our operation and the classname that defines the operation. The `IDENTIFIER` keyword locates the operation in the menu system. For instance, the identifier 'File/AdaptHistEqual' would put this in the File menu of the itool. More usefully, 'Operations/My Operations/AdaptHistEqual' would create a new submenu in the Operations menu and put this operation in it. The `ICON` keyword specifies an icon for the operation in the operation browser. In this case, `icon='image'` is equivalent to
icon=filepath('image.bmp', subdir=['examples', 'data'])
Hopefully, this will provide a template for further operations. I hope to provide more demos/templates/tutorials for other methods of extending the itools including file readers, file writers, general operations, manipulators, visualizations, UI services, user interface panels, and full-blown user interfaces.