4D Plugin API



Developers know how painful the creation/management of dialogs can be using an OS API -- for either MacOS or Windows.

4D Plug-in API gives Plug-in developers the ability to use a dialog created with the 4D Form Editor. The dialog can use any 4D object and can have object and form methods. Changing the state of an object, its color, its visibility, etc. is done through the 4D Language, a language much easier than a native Language. The API lets the Plug-in get the value of any variable used in the dialog at any time. It can set the values of objects, move them, etc. within its own C/C++ code, even if it is probably much easier to write this within the form itself using the 4D Language.

Beyond this facility to create a dialog, an other advantage is that by doing dialogs this way, the Plug-in developer can take advantage of the 4D virtual platform interface. The dialogs will always look nice on each platform.

4D Dialogs within a plug-in can be called anywhere from plug-in code, but a more usual usage is probably from External Areas, in the Advanced Properties dialog, or at Runtime for setting preferences or properties of an area.

To open and manage a dialog from a plug-in, the developer has to follow those 3 steps :

- Create and open the dialog ( PA_NewDialog , PA_OpenDialog )
- Then, in a loop, call PA_ModalDialog , until the user cancels or validates the dialog. The Plug-in can interact with the user from the 4D Dialog itself, or by using some of this API's routines ( PA_Dial4DSetLong , PA_Dial4DGetDate )
- Finally, the plug-in closes the dialog ( PA_CloseDialog ).

Sample use

This screen shot shows a sample form that uses 2 buttons ("OK" and "Cancel") with automatic action, a static prompt string, and 3 radio buttons 3D (r1 to r3) :

The form is named "TextAlignment" and saved in the plug-in resource file (we'll learn how to do this later).

The C source code to handle this dialog looks as follows:

// Return 0, 1, or 2 for the text alignment of a private data.
// -1 means no change (user cancelled the dialog)
short DoTextAlignmentDialog ()
{
   PA_Dialog      dialog;
   char      lastVarName[256];
   char      okOrCancel;
   char      alignment = -1; // No change as default
 
// Create a dialog context
   dialog = PA_NewDialog();
// Open the saved dialog, without close box
   PA_OpenDialog( dialog, "TextAlignement", 0 );
// Loop until the user validates/cancels the dialog
   do {
      okOrCancel = PA_ModalDialog( dialog, lastVarName );
   } while ( okOrCancel == 0 );
 
   // if user validates the dialog, read the picture
   // radio button variables to get the selected value
   if ( okOrCancel == 1 )
   {
      // Look which radio button is 1
      if ( PA_Dial4DGetLong( dialog, "r1" ) == 1 )
         alignment = 0; 
      else if ( PA_ Dial4DGetLong ( dialog, "r2" ) == 1 )
         alignment = 1; 
      else if ( PA_ Dial4DGetLong ( dialog, "r3" ) == 1 )
         alignment = 2; 
   }
// At least, close the dialog
   PA_CloseDialog( dialog );
// return the correct alignment
   return alignment;
}
 

Few lines of code are needed to handle this dialog. The same simple dialog in native Language and OS API would have take considerable time to write and even longer if the plug-in is cross platform.

In version v14 and below, Save dialogs as 'FO4D' resources: ctrl - Action

Saving dialogs as "FO4D" resources is a basic operation: in Forms tab press ctrl+Action button, then choose "Generate 'Dial4D Resources' folder" item .

4D generates one resource file per table in the structure folder. Those files are ResEdit files under MacOS and .RSR files under Windows.

Each resource fork contains as many 'FO4D' resources as the table has forms, plus the linked 'CC4D' (which contain the form/object methods), plus some 'STL#' resources that handle the styles used in the forms.

At least, each 'FO4D' resource have the name of the form. This is important since this name is used by the PA_OpenDialog routine.

IMPORTANT NOTES

As 4D generates one file per table, the developer should create one structure and build dialogs in the first table. Doing this avoid the creation by 4D of multiples files containing multiples FO4D resources.

Once the dialog has been saved on disk, the developer can move the dialog resources to the Plug-in resource fork. This is a basic operation on Macintosh, using ResEdit.

In future version (v14R5 and above), Save dialogs in plugin resource

You create a 4D Database with your dialogs, named by example dials.4dbase.

Without PluginWizard

Save dials.4dbase in "Plugin.Bundle/Resources/Internal Components”. PA_OpenDialog will find any of your 4D dialog in any of the databases located in the "Resources/Internal Components” folder.

With PluginWizard

Check the checkbox “Use 4D Component (Dials) and select your dials.4dbase. The PluginWizard will copy dials.4dbase in "Plugin.Bundle/Resources/Internal Components" of the target directory/Sample.4dbase/plugins.

 
 
 

Quick overview of the 4D Dialog routines

Main routines used in the implementation of a 4D dialog:

- PA_NewDialog creates a 4D context (discussed below),
- PA_OpenDialog opens and uses a dialog in plugin resource,
- PA_ModalDialog provides information on the last variable used and the validation cycle,
- PA_Dial4DSet / Getxxx let the Plug-in retrieve or modify object values
- Some routines let the developer create variables on the fly, build arrays or hierarchical list of tables/fields names, etc.
- PA_CloseDialog closes the dialog and frees the memory used.

PA_NewDialog and the "Dialog context"

We have seen that PA_NewDialog creates a "4D context". Such a context is a kind of environment given by 4D to the dialog. In this environment, 4D deals with the dialog in interpreted mode so the plug-in can use this dialog even in a compiled database. Thus, the plug-in can use variables (and even create variables on the fly) that are unknown to the Compiler.

As a result, a Plug-in can't directly access to any other variable while using a 4D Dialog . If the plug-in needs to access other process variables, it must call PA_Dial4DsaveVariables which switch from dialog variables to current process variables, then it uses the process variables and call PA_Dial4DrestoreVariables , which switch from current process variables to dialog variables.

At least, in the object/form methods of the dialog itself, never call any other variables than the one used in the dialog.

PA_OpenDialog

PA_OpenDialog

opens and display the dialog stored in plugin resource. 4D does almost everything for the developer: create the window at the correct size, give it the correct kind,

PA_ModalDialog

Once the dialog is opened, the plug-in loops, calling PA_ModalDialog . This routine returns 0 while the dialog is not validated or cancelled. Each time an object is modified or hit, the routine returns the name of the modified object.

Get/Set variables

During the loop time, the Plug-in can do a lot of things, such as set/get values of variables. There are plenty of accessors for that: PA_Dial4DGetLong , PA_Dial4DSetLong , PA_Dial4DGetDate , PA_Dial4DSetDate . To make things easier, 4D takes care of the type casting when necessary (i.e. calling PA_Dial4DGetLong with a 4D real variable).

Some routines deal with arrays of any kind, letting the plug-in create an array, get/set values in an array, resize the array, find in the array

NOTE

When variables are modified, the modification must be surrounded by calls to PA_Dial4DBeginUpdateVariables and PA_Dial4DEndUpdateVariables . This tells 4D to redraw the modified variables.

Utility routines

Some routines give the Plug-in tools to:

- build arrays from resources, from text ( PA_Dial4DSetArrayTextFromResource , PA_Dial4DSetArrayTextFromTTR , PA_Dial4DSetArrayPictFromResources )
- Find in arrays ( PA_Dial4DFindArrayLong ),
- build tables/fields arrays or hierarchical list ( PA_Dial4DNewTableFieldHList , PA_Dial4DSetArrayTextFromTableList ),
- change current page ( PA_Dial4DGotoPage , PA_Dial4DGetCurrentPage ),
- use External areas ( PA_Dial4DsetAreaHandler ),
- Change properties of objects ( PA_Dial4DsetMin , PA_Dial4DsetEnterable , PA_Dial4DsetObjectTitle , PA_Dial4DshowHideObject ).

PA_CloseDialog

disposes of the dialog and of all linked objects.

Conclusion

Using 4D Dialogs saves development time and preserves the "persistence of user interface".

A 4D Dialog evolves in its own context using its own variables that can be created on the fly. The easiest way to handle such dialog is to write the code using as much as possible the 4D Language, in object/form methods.