Dynamic Request
Availability LightWave 6.0 | Component Layout, Modeler | Header lwdyna.h
The dynamic request global returns functions that provide a simple user interface API. The requester mechanism predates both the Panels and XPanels systems and is available primarily for backward compatibility. Requesters in LightWave 6.0 and later are implemented as non-modal xpanels, so this global can be used as an alternative method of creating those.
Global Call
DynaReqFuncs *reqf; reqf = global( LWDYNAREQFUNCS_GLOBAL, GFUSE_TRANSIENT );
The global function returns a pointer to a DynaReqFuncs.
typedef struct st_DynaReqFuncs { DynaRequestID (*create) (const char *); int (*addCtrl) (DynaRequestID, const char *, DyReqControlDesc *); DynaType (*ctrlType) (DynaRequestID, int); int (*valueSet) (DynaRequestID, int, DynaValue *); int (*valueGet) (DynaRequestID, int, DynaValue *); int (*post) (DynaRequestID); void (*destroy) (DynaRequestID); LWXPanelID (*xpanel) (DynaRequestID); } DynaReqFuncs;
req = create( title )
- Create a new dynamic request dialog. The title is displayed at the top of the dialog
window. You can create as many dialogs as you like, but only one can be displayed at a
time. The requester ID returned by
create
is passed as the first argument to the other requester functions. ctl = addCtrl( req, label, descriptor )
- Add a control to the dialog. Controls are stacked vertically in the requester window in
the order in which they're added, with the first control on top. The return value is a
control index used to identify the control in calls to
ctrlType
,valueSet
andvalueGet
. The descriptor, explained below, contains the control type and other information necessary for its display. ctrlType( req, ctl )
- Returns the type of a control.
valueSet( req, ctl, value )
- Initialize the value of a control. Values are expressed as DynaValues. This function will return an error code if the DynaValue type is incompatible with the type of the control, or if the control doesn't exist.
valueGet( req, ctl, value )
- Retrieve the value of a control. This function will return an error code if the DynaValue type is incompatible with the type of the control, or if the control doesn't exist.
result = post( req )
- Display the requester. This function won't return until the user has dismissed the requester. It returns 1 if the user accepted the inputs and 0 if he or she cancelled them.
destroy( req )
- Free the requester and associated resources allocated by
create
. xpanel( req )
- Returns the panel ID for the requester. See the XPanels discussion for more about this.
Control Types
These are the kinds of controls you can create.
DY_STRING
- A single line of editable text. If you just want to display static text on the
requester, use a
DY_TEXT
control. DY_INTEGER
DY_FLOAT
DY_DISTANCE- Numeric edit fields. Distance controls display length units and handle unit conversions. Internally the value is a floating-point number of meters.
DY_VINT
DY_VFLOAT
DY_VDIST- Vector edit fields. A vector in this case is an array of three numbers.
DY_BOOLEAN
DY_CHOICE- Boolean controls are like checkboxes. Internally their states are stored as integers with values of either 0 or 1. Choice controls are like radio buttons, an array of mutually exclusive booleans. The internal representation is an integer containing a zero-based index into the choice list.
DY_SURFACE
- Lets the user choose one of the surfaces currently in Modeler's internal surface list. The underlying data for a surface control is a string containing the surface name.
DY_FONT
- Lets the user choose one of the fonts currently in Modeler's internal font list. The underlying data for a font control is an integer index into the font list.
DY_TEXT
- Static (read-only) text. Use this to write things on the requester. If you need a text
edit field, use a
DY_STRING
control instead. DY_LAYERS
- Lets the users select one or more layers. These are represented internally by set bits in an integer.
Control Descriptor
The addCtrl
function is passed a descriptor to tell it what kind of control to
create. For most controls, the descriptor is just a type code corresponding to the
DynaType of the variable it represents (one of the types in the list above), but for
string, choice and static text controls, some additional information is required to create
the control.
String
typedef struct st_DyReqStringDesc { DynaType type; int width; } DyReqStringDesc;
width
- The displayed width of the edit field, in characters.
Choice
typedef struct st_DyReqChoiceDesc { DynaType type; const char **items; int vertical; } DyReqChoiceDesc;
items
- An array of strings. Each string is the label for a choice. The
valueGet
call will return an index into this array to indicate the selected item. vertical
- A non-zero value will cause the choices to be arranged vertically on the requester. Otherwise, they're arranged horizontally.
Static Text
typedef struct st_DyReqTextDesc { DynaType type; const char **text; } DyReqTextDesc;
text
- An array of strings. Each string is displayed on its own line in the requester.
The control descriptor is a union that collects the type code and this extra information into a single structure.
typedef union un_DyReqControlDesc { DynaType type; DyReqStringDesc string; DyReqChoiceDesc choice; DyReqTextDesc text; } DyReqControlDesc;
Example
This code fragment creates a requester asking for personal information. It relies on
functions called reqAdd
, reqSet
and reqGet
to hide some of the
details. The source for these functions follows.
#include <lwserver.h> #include <lwmodeler.h> DynaRequestID req; int ctl[ 5 ], ok; char name[ 40 ] = "(Your name here)"; int age = 30, gender = 0; double height = 1.8; double measure[ 3 ] = { 0.9144, 0.6096, 0.9144 }; char *glabel[] = { "Female", "Male", NULL }; reqf = global( LWDYNAREQFUNCS_GLOBAL, GFUSE_TRANSIENT ); if ( !reqf ) return AFUNC_BADGLOBAL; req = reqf->create( "All About Me" ); if ( !req ) goto ErrorNoReq; ctl[ 0 ] = reqAdd( req, DY_STRING, "Name", NULL, 20 ); ctl[ 1 ] = reqAdd( req, DY_INTEGER, "Age", NULL, 0 ); ctl[ 2 ] = reqAdd( req, DY_CHOICE, "Gender", glabel, 1 ); ctl[ 3 ] = reqAdd( req, DY_FLOAT, "Height", NULL, 0 ); ctl[ 4 ] = reqAdd( req, DY_VDIST, "Measurements", NULL, 0 ); reqSet( req, ctl[ 0 ], name ); reqSet( req, ctl[ 1 ], &age ); reqSet( req, ctl[ 2 ], &gender ); reqSet( req, ctl[ 3 ], &height ); reqSet( req, ctl[ 4 ], measure ); ok = reqf->post( req ); if ( ok ) { reqGet( req, ctl[ 0 ], name, sizeof( name )); reqGet( req, ctl[ 1 ], &age, 0 ); reqGet( req, ctl[ 2 ], &height, 0 ); reqGet( req, ctl[ 3 ], &gender, 0 ); reqGet( req, ctl[ 4 ], measure, 0 ); } reqf->destroy( req );
The reqAdd
function creates a requester control. Most control types can be
created with only the DynaType and label, but a few require additional information. The text
argument is an array of strings used to create DY_CHOICE
and DY_TEXT
controls. The extra
argument is the string width in characters for DY_STRING
controls and the vertical flag for DY_CHOICE
controls.
int reqAdd( DynaRequestID req, DynaType type, char *label, char **text, int extra ) { DyReqControlDesc desc; desc.type = type; switch ( type ) { case DY_STRING: desc.string.width = extra; break; case DY_CHOICE: desc.choice.items = text; desc.choice.vertical = extra; break; case DY_TEXT: desc.text.text = text; break; default: break; } return reqf->addCtrl( req, title, &desc ); }
The reqSet
and reqGet
functions can set and get the value of any
control. The val
argument points to a variable of an appropriate type for the
control.
int reqSet( DynaRequestID req, int ctl, void *val ) { DynaValue dv; int *ivec; double *fvec; dv.type = reqf->ctrlType( req, ctl ); switch ( dv.type ) { case DY_STRING: case DY_SURFACE: dv.str.buf = ( char * ) val; dv.str.bufLen = 0; break; case DY_INTEGER: case DY_BOOLEAN: case DY_FONT: case DY_LAYERS: case DY_CHOICE: dv.intv.value = dv.intv.defVal = *(( int * ) val ); break; case DY_FLOAT: case DY_DISTANCE: dv.flt.value = dv.flt.defVal = *(( double * ) val ); break; case DY_VINT: ivec = ( int * ) val; dv.ivec.val[ 0 ] = ivec[ 0 ]; dv.ivec.val[ 1 ] = ivec[ 1 ]; dv.ivec.val[ 2 ] = ivec[ 2 ]; break; case DY_VFLOAT: case DY_VDIST: fvec = ( double * ) val; dv.fvec.val[ 0 ] = fvec[ 0 ]; dv.fvec.val[ 1 ] = fvec[ 1 ]; dv.fvec.val[ 2 ] = fvec[ 2 ]; break; default: return 0; } return reqf->valueSet( req, ctl, &dv ); } int reqGet( DynaRequestID req, int ctl, void *val, int len ) { DynaValue dv; int *ivec, result; double *fvec; dv.type = reqf->ctrlType( req, ctl ); if ( dv.type == DY_STRING || dv.type == DY_SURFACE ) { dv.str.bufLen = len; } result = reqf->valueGet( req, ctl, &dv ); switch ( dv.type ) { case DY_STRING: case DY_SURFACE: strcpy( val, dv.str.buf ); break; case DY_INTEGER: case DY_BOOLEAN: case DY_FONT: case DY_LAYERS: case DY_CHOICE: *(( int * ) val ) = dv.intv.value; break; case DY_FLOAT: case DY_DISTANCE: *(( double * ) val ) = dv.flt.value; break; case DY_VINT: ivec = ( int * ) val; ivec[ 0 ] = dv.ivec.val[ 0 ]; ivec[ 1 ] = dv.ivec.val[ 1 ]; ivec[ 2 ] = dv.ivec.val[ 2 ]; break; case DY_VFLOAT: case DY_VDIST: fvec = ( double * ) val; fvec[ 0 ] = dv.fvec.val[ 0 ]; fvec[ 1 ] = dv.fvec.val[ 1 ]; fvec[ 2 ] = dv.fvec.val[ 2 ]; break; default: break; } return result; }