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 and valueGet. 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;
}