Syntax: cpiAddInteger(const char *name, const char *label, CPI_Int32 default, CPI_Int32 min_val, CPI_Int32 max_val, CPI_Int32 flags, const char *help, const char *html);
Example: cpiAddInteger("integer", "Integer", 1, 0, 10, CPI_PARM_ANIMATABLE, "Number of loops", NULL); Get Value: cpiGetInteger( &intval, "integer", myTime );
Syntax: cpiAddFloat(const char *name, const char *label, CPI_Float32 default, CPI_Float32 min_val, CPI_Float32 max_val, CPI_Int32 flags, const char *help, const char *html);
Example: cpiAddFloat("float", "Float", 1.0, 0.0, 10.0, CPI_PARM_ANIMATABLE, "Float value parameter", NULL); Get Value: cpiGetFloat( &fval, "float", myTime );
Syntax: cpiAddIntPair(const char *nameTop, const char *labelTop, const char *name1, const char *label1, CPI_Int32 default1, const char *name2, const char *label2, CPI_Int32 default2, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddIntPair("int_pair", "Int pair", "w", "Width", 720, "h", "Height", 486, CPI_PARM_DEFAULT, "Pair of integer parameters", NULL ); Get Values: cpiGetInteger( &width, "int_pair.w", myTime ); cpiGetInteger( &height, "int_pair.h", myTime );
Syntax: cpiAddFloatPair(const char *nameTop, const char *labelTop, const char *name1, const char *label1, CPI_Float32 default1, const char *name2, const char *label2, CPI_Float32 default2, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddFloatPair("float_pair", "Float pair", "x", "X", 1.0, "y", "Y", 0.75, CPI_PARM_DEFAULT, "Pair of floating point values", NULL ); Get Values: cpiGetFloat( &width, "float_pair.x", myTime ); cpiGetFloat( &height, "float_pair.y", myTime );
Syntax: cpiAddMenu(const char *name, const char *label, CPI_Uint8 default, const char *menulist, const char *help, const char *html); Example: static const char *mymenu[]= { "lion", "tiger", "bear", NULL }; cpiAddMenu( "menu", "Menu", 0, mymenu, "Choose which type of animal from menu", NULL ); Get Values: CPI_Int32 menuval; cpiGetInteger ( &menuval, "menu", myTime ); // In this example, 0 == lion, 1 == tiger, 2 == bear
Syntax: cpiAddFile(const char *name, const char *label, const char *default, const char *help, const char *html); Example: cpiAddFile("file", "File", "/tmp/myfile", "Please enter a file name", NULL ); Get Values: #define MAXSIZE 128 char fname[MAXSIZE]; cpiGetString( fname, MAXSIZE, "file.file_id", myTime );
Syntax: cpiAddString(const char *name, const char *label, const char *val1, CPI_Bool multiline, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddString("string", "String", "default string", CPI_FALSE, CPI_PARM_DEFAULT, "Enter a single line string", NULL ); Get Values: #define MAXSIZE 128 char strval[MAXSIZE]; cpiGetString( strval, MAXSIZE, "string", myTime );
Syntax: cpiAddString(const char *name, const char *label, const char *val1, CPI_Bool multiline, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddString("text", "Text Entry", "default string", CPI_TRUE, CPI_PARM_DEFAULT, "Enter a block of input text", NULL ); Get Values: #define MAXSIZE 512 char strval[MAXSIZE]; cpiGetString( strval, MAXSIZE, "text", myTime );
Syntax: cpiAddDisplayString(const char *name, const char *label, const char *string); Example: cpiAddDisplayString("disp_text", "Display text", "rest of string");
Syntax: cpiAddToggle(const char *name, const char *label, CPI_Bool default, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddToggle( "toggle", "Toggle", CPI_TRUE, CPI_PARM_DEFAULT, "Toggle button which defaults to true", NULL ); Get Values: cpiGetInteger( &toggle, "toggle", myTime ); // 0 = off, 1 == on
Syntax: cpiAddIconToggle(const char *name, const char *iconName, CPI_Bool default, CPI_Int32 flags, const char *help, const char *html); Example:You must first define the icon. The best way to do this is to compile the icon in as an array of Uint8 elements. The utility rayz_iconreader can be used to create a header file which is a C image of a tiff file. Once that is done, the header file is included in the plugin, and the following lines are used:
cpiRegisterIconData( "Thing", 24, 18, thing_data, 255, 0, 255 );The above takes an array of Uint8s called thing_data and names it "Thing" for internal reference. Then the icon is defined as using that named icon:
cpiDefineIcon( "Thing", "Thing", NULL, NULL, NULL, NULL, NULL, 255, 0, 255 );Finally, the toggle itself is defined:
cpiAddIconToggle( "toggle", "Thing", CPI_TRUE, CPI_PARM_DEFAULT, "Toggle button which defaults to true", NULL ); Get Values: cpiGetInteger( &toggle, "toggle", myTime ); // 0 = off, 1 == on
Syntax: cpiAddButton(const char *name, const char *label, void *callback, CPI_Int32 flags, const char *help, const char *html); Example: void WidgetCallback( const char *nodename, const char *parmname, CPI_Float32 time ) { printf ("Got a button callback for node %s, parm %s at time %5.5f\n", nodename, parmname, time); cpiSetInteger( (CPI_Int32)time, "Integer", time); } ... cpiAddButton("push", "push me", WidgetCallback, CPI_PARM_DEFAULT, "This prints something when pressed", NULL ); Get Values: This does not return a value - when pressed, it causes the immediate execution of the named function.
Syntax: cpiAddButton(const char *name, const char *label, void *callback, CPI_Int32 flags, const char *help, const char *html); Example:You must first define the icon. The best way to do this is to compile the icon in as an array of Uint8 elements. The utility rayz_iconreader can be used to create a header file which is a C image of a tiff file. Once that is done, the header file is included in the plugin, and the following lines are used:
cpiRegisterIconData( "Atomic", 32, 24, atomic_data, 255, 0, 255 );The above takes an array of Uint8s called atomic_data and names it "Atomic" for internal reference. Then the icon is defined as using that named icon:
cpiDefineIcon( "Atomic", "Atomic", NULL, NULL, NULL, NULL, NULL, 255, 0, 255 );You must also define a callback function to be executed when the button is pushed.
void WidgetCallback( const char *nodename, const char *parmname, CPI_Float32 time ) { printf ("Got a button callback for node %s, parm %s at time %5.5f\n", nodename, parmname, time); cpiSetInteger( (CPI_Int32)time, "Integer", time); } ...Finally, the button is defined:
cpiAddButton("push", "push me", WidgetCallback, CPI_PARM_DEFAULT, "This prints something when pressed", NULL ); Get Values: This does not return a value - when pressed, it causes the immediate execution of the named function.
Syntax: cpiAddButtonStrip(const char *name, const char *label, CPI_Int32 default, CPI_Int32 flags, const char *buttonLabels[], const char *help, const char *html); Example: static const char *mymenu[]= { "lion", "tiger", "bear", NULL }; cpiAddButtonStrip( "button_strip", "Button Strip", 0, CPI_PARM_DEFAULT, mymenu, "", NULL ); Get Values: CPI_Int32 whichBut; cpiGetInteger ( &whichBut, "button_strip", myTime ); // In this example, 0 == lion, 1 == tiger, 2 == bear
Syntax: cpiAddIconButtonStrip(const char *name, const char *label, CPI_Int32 default, CPI_Int32 flags, const char *iconNames[], const char *help, const char *html); Example:You must first define the icons. The best way to do this is to compile the icons in as an array of Uint8 elements. The utility rayz_iconreader can be used to create a header file which is a C image of a tiff file. Once that is done, the header file is included in the plugin, and the following lines are used:
static const char *icons[] = { "Add", "Subtract", "Multiply", "Divide", NULL }; cpiRegisterIconData( icons[0], 24, 18, add_data, 255, 0, 255 ); cpiRegisterIconData( icons[1], 24, 18, subtract_data, 255, 0, 255 ); cpiRegisterIconData( icons[2], 24, 18, multiply_data, 255, 0, 255 ); cpiRegisterIconData( icons[3], 24, 18, divide_data, 255, 0, 255 );The above takes a set of defined icons (the *_data labels) and associates them with a list of names in the icons[] array. Then each name in the icons[] array is defined as an icon, with the following loop:
for ( CPI_Int32 i = 0; i < 4; ++i ) cpiDefineIcon( icons[i], icons[i], NULL, NULL, NULL, NULL, NULL, 255, 0, 255 );Finally, the toggle itself is defined:
cpiAddIconButtonStrip( "icon_strip", "Icon Button Strip", 0, CPI_PARM_DEFAULT, icons, "This is a button strip with icons", NULL ); Get Values: CPI_Int32 whichBut; cpiGetInteger ( &whichBut, "icon_strip", myTime ); // In this example, 0 == lion, 1 == tiger, 2 == bear
Syntax: cpiStartGroup(const char *name, const char *label, CPI_Int32 flags, const char *help, const char *html); // add parameters here cpiEndGroup(); Example: cpiStartGroup("group1", "Group 1", CPI_PARM_DEFAULT, "This is a nested group of parameters", NULL ); cpiAddFloat("float2", "Float 2", 0.0, -1.0, 1.0, CPI_PARM_ANIMATABLE, "Floating point parameter", NULL ); cpiEndGroup();
Get Values: cpiGetFloat( &floatval, "group1.float2", myTime );
Syntax: cpiAddColorGroup(const char *name, const char *label, CPI_Float32 *defaults, CPI_Int32 numargs, CPI_Int32 flags, const char *help, const char *html); Example: CPI_Float32 def[4] = {0.5, 0.2, 0.9, 1.0}; cpiAddColorGroup("color", "Color", def, 4, CPI_PARM_DEFAULT, "This is a color selector", NULL ); Get Values: CPI_Float32 red, green, blue, alpha; cpiGetFloat( &red, "color.red", myTime ); cpiGetFloat( &green, "color.green", myTime ); cpiGetFloat( &blue, "color.blue", myTime ); cpiGetFloat( &alpha, "color.alpha", myTime );
Syntax: cpiAddHueCircle(const char *name, const char *label, CPI_Float32 default, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddHueCircle("hue", "Hue Circle", 0.0, CPI_PARM_DEFAULT, "A hue adjustment circle", NULL ); Get Values: cpiGetFloat( &hue, "hue", myTime );
Syntax: cpiAddIntRGBAOGroup(const char *name, const char *label, CPI_Int32 defval, CPI_Int32 minval, CPI_Int32 maxval, CPI_Int32 numchans, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddIntRGBAOGroup("int_group", "Int Group", 0, 0, 100, 3, CPI_PARM_DEFAULT, "A related group of 3 integer channels", NULL ); Get Values: cpiGetInteger( &overall, "int_group.int_group", myTime ); cpiGetInteger( &red, "int_group.red", myTime ); cpiGetInteger( &green, "int_group.green", myTime ); cpiGetInteger( &blue, "int_group.blue", myTime );
Syntax: cpiAddFloatRGBAOGroup(const char *name, const char *label, CPI_Float32 defval, CPI_Float32 minval, CPI_Float32 maxval, CPI_Int32 numchans, CPI_Int32 flags, const char *help, const char *html); Example: cpiAddFloatRGBAOGroup("float_group", "Float Group", 0.0, -1.0, 1.0, 5, CPI_PARM_DEFAULT, "A related group of 5 float channels", NULL ); Get Values: cpiGetFloat( &overall, "float_group.float_group", myTime ); cpiGetFloat( &red, "float_group.red", myTime ); cpiGetFloat( &green, "float_group.green", myTime ); cpiGetFloat( &blue, "float_group.blue", myTime ); cpiGetFloat( &alpha, "float_group.alpha", myTime ); cpiGetFloat( &other, "float_group.other", myTime );
Normally (as in Track), a button is presented to the user to create a new entry. This button is optional. Entries can also be added programatically.
Syntax: To define a Var List: cpiStartVarList(); cpiDefineVarListGroup( const char *name, const char *label, (void *)addFunction, ); cpiEndVarList(const char *name, const char *listname, CPI_Int32 flags, CPI_Bool addButtons ); To manipulate a Var List: cpiAddVarListGroup( const char *varlistname, const char *entryname ); cpiRemoveVarListGroup( const char *varlistname, CPI_Uint32 entrynum ); cpiMoveVarListGroup( const char *varlistname, CPI_Uint32 entryToMove, CPI_Uint32 moveBefore ); cpiGetVarListSize( const char *varlistname, CPI_Uint32 *size ); All routines return CPI_Bool which is CPI_TRUE if the call succeeded. Example:First, you define a routine which creates the contents of a specific entry in the list:
void addNewElement( void ) { cpiAddInteger( "new_thing", "new thing", 0, 0, 10, CPI_PARM_DEFAULT, "This was added to the var list", NULL ); }And then in the Init() routine, you would add the following lines. The middle statement defines what happens when an entry is added to the list, and optionally adds a button to create a new entry.
... cpiStartVarList(); cpiDefineVarListGroup( "add_new", "Add New Element", (void *)addNewElement, CPI_TRUE ); cpiEndVarList( "add_new", "Var List", CPI_PARM_DEFAULT); Get Values:Each element is addressed with '(n)' where n is the position in the list created by the user. n begins at 0.
cpiGetInteger( &intval, "var_list(0).add_new.new_thing", myTime);
Syntax: cpiAddChannelSelect(const char *help, const char *html); Example: cpiAddChannelSelect("Select channels to operate on", NULL); Get Values: CPI_Int32 chan; cpiGetChannelSelect( &chan );
Syntax: cpiAddSequenceRange(CPI_Int32 startFrameDef, CPI_Int32 endFrameDef, CPI_Int32 flags, const char *helpText, const char *helpHTML ); Example: cpiAddSequenceRange(1, 100, CPI_PARM_DEFAULT, "Select channels to operate on", NULL);Note that there is no name or label, since there can be only one sequence range widget in a node.
Get Values: CPI_Int32 startF, endF; cpiGetSequenceRange( &startF, &endF );
The function for this is the very simply defined
as
void cpiEnableParameter( const char *parmname, CPI_Bool enable )Two examples of the use of this: in the first, we enable or disable parameters based on the presence or absence of a second input. This is done by defining the InputChanged function, and responding to that event by checking the number of connected inputs. That looks like
void BlurXYInputChanged( CPI_Uint32 inputnum ) { CPI_Uint32 numInputs; CPI_Bool enable; cpiGetNumInputs( &numInputs ); // enable/disable the mask parameters depending on the presence // if the mask input enable = CPI_FALSE; if ( numInputs == 2 ) enable = CPI_TRUE; cpiEnableParameter( "mask_action", enable ); cpiEnableParameter( "mask_channel", enable ); }
In the second example, the user can choose between entering values as
float values or as pixel values, and he tells the plugin which he
is using via a menu widget. To implement this, we define the ParmChanged
function. This is called whenever a parameter value changes, and it is
called with the internal name of the parameter. It is called with
the name string set to NULL when the node is first initialized. Our
example looks like this
static const char *unitmenu[]= { "pixels", "fractions", NULL }; // This shows the definitions of the parameters we are using static CPI_Bool EnableInit( void ) { cpiAddMenu( "units", "Units", 0, unitmenu, "Choose which units to enter values in", NULL ); cpiAddIntPair( "pixels", "Pixels", "x", "Width", 10, "y", "Height", 10, CPI_PARM_DEFAULT, NULL, NULL ); cpiAddFloatPair( "fractions", "Fractions", "x", "Width", 0.1, "y", "Height", 0.1, CPI_PARM_DEFAULT, NULL, NULL ); return CPI_TRUE; } // This is where the parameter changes are handled static void EnableParmChanged( const char *name ) { CPI_Int32 units; // this is the situation when the node is initialized if ( name == NULL ) { cpiEnableParameter( "pixels", CPI_TRUE ); cpiEnableParameter( "fractions", CPI_FALSE ); return; } // if the relevant param is changed, pick up its new value // and enable/disable based on that if ( strcmp( name, "units" ) == 0 ) { cpiGetInteger( &units, "units", 1.0F ); if ( units == 0 ) { cpiEnableParameter( "pixels", CPI_TRUE ); cpiEnableParameter( "fractions", CPI_FALSE ); } else { cpiEnableParameter( "pixels", CPI_FALSE ); cpiEnableParameter( "fractions", CPI_TRUE ); } } }
In our example, we have the (totally arbitrary) values of 10 pixels and 0.1 fractional values as initial parameter values. So if the user changes the X value of the pixels parameter to 15, we might expect the fractional X value to change to 0.15 to stay in sync.
To do this, we use the one of the following routines
cpiSetFloat( fltval, parmname, evaltime, isUserSet ) cpiSetInteger( intval, parmname, evaltime, isUserSet ) cpiSetString( stringval, parmname, evaltime, isUserSet )This makes our example a little more complicated, as we now have to calculate the value for the other, unchanged parameter, and then set it. For this example, we have invented a completely arbitrary relationship between the pixel and fraction parameters; this relationship says that 1.0 == 100 pixels, so that in general
static void EnableParmChanged( const char *name ) { CPI_Int32 units, pval; CPI_Float32 fval; // this is the situation when the node is initialized if ( name == NULL ) { cpiEnableParameter( "pixels", CPI_TRUE ); cpiEnableParameter( "fractions", CPI_FALSE ); return; } // if the relevant param is changed, pick up its new value // and enable/disable based on that if ( strcmp( name, "units" ) == 0 ) { cpiGetInteger( &units, "units", 1.0F ); if ( units == 0 ) { cpiEnableParameter( "pixels", CPI_TRUE ); cpiEnableParameter( "fractions", CPI_FALSE ); } else { cpiEnableParameter( "pixels", CPI_FALSE ); cpiEnableParameter( "fractions", CPI_TRUE ); } } // if a value is changed, update the other set to stay // in sync // These are based on the arbitrary relationship that // fractions = pixels / 100 // and so // pixels = fractions * 100 else if ( strcmp( name, "pixels.x" ) == 0 ) { cpiGetInteger( &pval, "pixels.x", 0.0F ); fval = pval / 100.0F; cpiSetFloat( fval, "fractions.x", 0.0F, CPI_FALSE ); } else if ( strcmp( name, "pixels.y" ) == 0 ) { cpiGetInteger( &pval, "pixels.y", 0.0F ); fval = pval / 100.0F; cpiSetFloat( fval, "fractions.y", 0.0F, CPI_FALSE ); } else if ( strcmp( name, "fractions.x" ) == 0 ) { cpiGetFloat( &fval, "fractions.x", 0.0F ); pval = fval * 100.0F; cpiSetInteger( pval, "pixels.x", 0.0F, CPI_FALSE ); } else if ( strcmp( name, "fractions.y" ) == 0 ) { cpiGetFloat( &fval, "fractions.y", 0.0F ); pval = fval * 100.0F; cpiSetInteger( pval, "pixels.y", 0.0F, CPI_FALSE ); } }Things to Note: First, the Get and Set functions all take a time argument, which would normally be related to the current frame. But when a user changes a parameter, there is no time - the animation is not running. That is why the current time is not passed into the ParmChanged function. So the time parameter is set to 0.0 in both the Set and Get case.
Second, the last parameter of the Set functions is set to CPI_FALSE in each case above. This is the UserSet parameter - this tells RAYZ whether the parameter was changed by the user directly, or by the plugin indirectly. This matters when the node is saved to a .rayz file. Parameters which are not user set are not saved in the file, since they can be recalculated when the file is brought back into RAYZ. But if a parameter was directly changed by a user, then that change does need to be saved to the .rayz file, so that it can override the value it might otherwise have.
In general, you will want to set this flag to CPI_FALSE if you are
setting values from within your plugin - the flag is automatically set
to CPI_TRUE by RAYZ when a user adjusts a value directly. It is
possible to discover the state of the UserSet flag for any given
parameter by the use of the call
CPI_Bool cpiIsParmUserSet( const char *parmname )
cpiAddInteger( "cent", "Center", 1, 0, 150, CPI_PARM_DEFAULT, NULL, NULL );Then when you want to get the value of the "Center" field, you will do this
cpiGetInteger( "cent", result->time, ¢er )This tells the software to get the value associated with the field you called "cent" at the current time. We will cover this in depth in a moment.
The default parameter is just that, a value to initialize the gadget
with when it first appears.
min_val and max_val are values to put at the ends
of the slider associated with the gadget. If the appropriate flag is
set (see below), then these values are enforced - if not, they just
appear as a guide to the user of a reasonable range of values.
flags may be any of the following:
CPI_PARM_DEFAULT | Use default settings for the parameter |
CPI_PARM_ANIMATABLE | The parameter can be animated. This causes the little animate icon to appear at the right edge of the parameter. If this is not set, the value of the parameter will be used across all frames. |
CPI_PARM_CLAMPMIN | Enforce the minimum value as a hard limit |
CPI_PARM_CLAMPMAX | Enforce the maximum value as a hard limit |
CPI_PARM_CLAMPMINMAX | Enforce both min and max values as hard limits |
CPI_PARM_FULL_SIZE_X | Display the value as a pixel version of a float value, scaled by the X size of the input image's full size. Float parameters only. The purpose is to maintain float values internally, for resolution independence, while displaying more friendly pixel values to the user. |
CPI_PARM_FULL_SIZE_Y | Display the value as a pixel version of a float value, scaled by the Y size of the input image's full size. Float parameters only. The purpose is to maintain float values internally, for resolution independence, while displaying more friendly pixel values to the user. |
CPI_PARM_FULL_SIZE_XY | Display the value as a pixel version of a float value, scaled by the X and Y sizes of the input image's full size. This is used for FloatPair widgets only. The purpose is to maintain float values internally, for resolution independence, while displaying more friendly pixel values to the user. |
CPI_PARM_INVISIBLE | Don't show the parameter to the user, but save and load it in .rayz files. This is used to create state variables that you want to keep around from session to session. |
CPI_PARM_NOMODIFIES | Makes it so that the parameter cannot be modified by the user |
CPI_PARM_PIXEL_VALUE | Displays a float parameter as an integer value based on the pixel depth of the input image, for example 0 to 255 for 8-bit images. The purpose is to maintain float values internally, for image independence, while displaying more friendly color values to the user. |
CPI_PARM_READONLY | This is similar to CPI_PARM_NOMODIFIES, except that it applies only to strings. |
CPI_PARM_EXPANDBYDEFAULT | this only applies to groups, var lists, etc, and tells RAYZ to draw them as expanded when the node is first created. |
cpiAddInteger( "rad", "Radius", 1, 0, 150, CPI_PARM_ANIMATABLE | CPI_PARM_CLAMPMIN, NULL, NULL );sets up a radius parameter which can be animated, and which cannot go below zero.
void cpiError(const char *format, ...)For example:
cpiError("Must have alpha channel to proceed"); cpiError("Can't open file %s", filename);There is also a call to generate a warning, which is
void cpiError(const char *format, ...)The difference between the two is the cpiError() will stop execution, while cpiWarning() will color the node yellow, but continue execution. The warning message appears in the status line for the user.
These calls are generally placed in the GetErrors() function, which is
called before processing begins. For example
static CPI_Bool RegionsGetErrors( CPI_Float32 time ) { CPI_ImageContext inputA; CPI_ImageContext inputB; CPI_Bool retval = CPI_TRUE; if ( cpiGetInputContext( &inputA, 0, time ) && cpiGetInputContext( &inputB, 1, time ) ) { if ( inputA.channels != inputB.channels ) { cpiError( "Inputs A and B must have the same number of channels" ); retval = CPI_FALSE; } else if ( inputA.bitsPerPel != inputB.bitsPerPel ) { cpiError( "Inputs A and B must have the same bit depth" ); retval = CPI_FALSE; } } else { cpiError( "Couldn't get input image contexts" ); retval = CPI_FALSE; } return retval; }It is also possible to generate an error in other places, notably the Exec function, but that error will not be seen by the user unless Exec returns NULL. For example
static CPI_ImageOp RegionsExec( CPI_Float32 myTime, CPI_Uint8 quality, CPI_Uint32 nodeOutput, CPI_Uint32 viewerOutput, CPI_Float32 scaleX, CPI_Float32 scaleY ) { CPI_Bool fillWithColor; CPI_ImageOp myInputs[2]; CPI_Metadata myParms = cpiCreateMetadata(); CPI_ImageOp retval = NULL; myInputs[0] = cpiGetInputOp( 0, myTime, quality, scaleX, scaleY ); myInputs[1] = cpiGetInputOp( 1, myTime, quality, scaleX, scaleY ); if ( cpiGetInteger( &fillWithColor, "fill", myTime ) ) { cpiSetMetaBool( myParms, "color", 0 != fillWithColor ); if ( NULL != myInputs[0] && NULL != myInputs[1] ) retval = cpiAddImageOp( "regions", myParms, myInputs, 2 ); cpiDeleteMetadata( myParms ); } else cpiError( "Couldn't get toggle value" ); return retval; }