Tutorial Five: Advanced Techniques

 

Tutorial Five: Advanced Techniques

In this example you will experiment with some advanced Builder Xcessory techniques. Topics covered include the following:

· Constraint resources

· Geometry management of the Form widget

· Adding header files

· Customizing the creation routine

· Editing the Main file

· Passing widget IDs between structures

The interface that you create will contain a Form widget and four children: two PushButtons, a Text widget, and a List widget. You will be able to enter text into the Text widget. Clicking one PushButton will add the contents of the Text widget into the List widget. Clicking the other PushButton will dismiss the window.

Constructing the Interface

If you have questions about the following procedures, review Clearing an Interface , Creating and Resizing a Widget Instance , Placing a Child Widget , or Placing an Automatically Resized Widget .

The Form widget will no longer resize to match the dimensions of its children.
Your interface should now look like Widget Collection :
  1. Clear the Builder Xcessory display by selecting New from the Browser File menu.
  2. Create a Form widget, resized to approximately two inches high and four inches wide.
  3. Set the resizePolicy resource to XmRESIZE_NONE.
  4. Place a List widget so that it fits within the topmost half of the Form.
  5. Place a Text widget within the Form and under the List.
  6. Resize the Text widget so that there is enough room underneath it within the Form to place a PushButton.
  7. Resize a PushButton to about one half inch high and one inch wide, and place it to occupy the leftmost third of the space under the Text widget within the Form.
  8. Place a second PushButton in the rightmost third of the space under the Text widget within the Form.

Widget Collection

Creating the Header File

Before setting callbacks, you must use a text editor to create the header file defs.h , which must contain the declarations of the structures WidStruct and Globals. Put this file in the directory to which you will write the tutorial output files.

Some of the callbacks that you set will need to access the widget IDs of each of the four widgets in your interface. The way to do this is to save the widget IDs in a global structure, WidStruct. In the sample file below, you also place WidStruct into the structure Globals. In a more complex interface, you would wish to include not only WidStruct but any other global structures within Globals.

typedef struct _WidStruct
{
Widget list;
Widget add;
Widget dismiss;
Widget text;
} WidStruct;
typedef struct _Globals
{
WidStruct wids;
/* any other global structures would go here */
} Globals;
  1. In a text editor, create the defs.h file:
  2. Save and close the file.

Setting the Resources

  1. Select the widget instance name list1 on the Browser, and update the Resource Editor.
  2. Confirm that the Resource Editor is displaying all of the resources of the currently selected widget by selecting All Resources from the Resource Editor Resources menu.
  3. Set the value of the visibleItemCount resource to 5.

Setting the createCallback resource

In the Procedure Name field, enter:
creation
Remember to press return or click the OK button.
Confirm that you wish to create a procedure.
In the Parameter Type field, enter:
Widget
Confirm that you wish to create a new user-defined type.
In the Parameter field, enter:
&(globals->wids.list)
Confirm that you wish to create a new identifier.
Click the Apply button at the bottom of the Callback Editor to apply this value to the createCallback resource for list1:
creation(&(globals->wids.list))
If you have questions about any of the above procedures, review Setting Callback Resources .
The callback that you have just created passes the address of the member of the data structure into which you will write the widget ID of the List widget.
  1. In the Callback Editor, set the createCallback resource for list1 as follows.

Using the Callback Editor

creation(&(globals->wids.text))
Edit the callback at this point by clicking the Edit button and then entering the code described in Editing the Callback Structures .
  1. Use the Callback Editor to set the createCallback resource for the widget instance "text" to the following:

Setting the activateCallback resource

In the Procedure Name field, enter:
AddWord
Remember to press return or click the OK button.
Confirm that you wish to create a procedure.
In the Parameter Type field, enter:
Globals*
Confirm that you wish to create a new user-defined type.
In the Parameter Name field, enter:
globals
Confirm that you wish to create a new identifier.
Click the Apply button at the bottom of the Callback Editor to apply this value to the activateCallback resource for pushButton:
AddWord(globals)
If you have questions about any of the above procedures, review Setting Callback Resources .
Edit the callback at this point by clicking the Edit button and then entering the code described in Editing the Callback Structures .
  1. In the Callback Editor, set the activateCallback resource for pushButton as follows.

Setting resources for pushButton

activateCallback = AddWord(globals)
createCallback = creation(&(globals->wids.add))
labelString = ADD
The activateCallback value passes the pointer to the entire list, since you need both the Text and List widget IDs.
activateCallback = Dismiss()
createCallback = creation(&(globals->wids.dismiss))
labelString = DISMISS
Note that Builder Xcessory extended editors are specific to a given resource. For example, the Callback Editor for activateCallback is completely separate from those for createCallback.
  1. For pushButton, set:
  2. For pushButton1, set:

Setting Constraint Resources

Children of a Form widget possess constraint resources, which control geometry management within the Form. Constraint resources are displayed in the Resource Editor in a separate list at the bottom of the resource list.

For detailed information on geometry management with the Form widget, see the manpage in the OSF/Motif Programmers Reference .

Using Builder Xcessory extended editors, you will set the following constraint resources for the children of the Form widget. Note that some of these values may have been set by Builder Xcessory by default.

If you have questions about using the Form Editor, refer to See Form Editor .

bottomAttachment = XmATTACH_POSITION
bottom Position = 50
leftAttachment = XmATTACH_FORM
leftOffset = 10
rightAttachment = XmATTACH_FORM
rightOffset = 10
topAttachment = XmATTACH_FORM
topOffset = 10
bottomAttachment = XmATTACH_POSITION
bottomPosition = 70
leftAttachment = XmATTACH_FORM
leftOffset = 10
rightAttachment = XmATTACH_FORM
rightOffset = 10
topAttachment = XmATTACH_POSITION
topPosition = 55
bottomAttachment = XmATTACH_FORM
bottomOffset = 10
leftAttachment = XmATTACH_FORM
leftOffset = 10
rightAttachment = XmATTACH_POSITION
rightPosition = 33
topAttachment = XmATTACH_POSITION
topPosition = 75
bottomAttachment = XmATTACH_FORM
bottomOffset = 10
leftAttachment = XmATTACH_POSITION
leftPosition = 66
rightAttachment = XmATTACH_FORM
rightOffset = 10
topAttachment = XmATTACH_POSITION
topPosition = 75
Your interface should now appear like the following figure:
  1. For list1, set:
  2. For text, set:
  3. For pushButton, set:
  4. For pushButton1, set:
  5. Dismiss any extended editors that remain on your display, including the Callback Editor.

Interface with Resources Set

Customizing the Creation Routine

You can customize the creation output file without leaving Builder Xcessory. In this case, you will change the creation file so that the routine that creates the widget tree, createForm, is passed the parameter "globals" in addition to the default, "parent".

The Creation Routine dialog is displayed.
Procedure Name = createForm
Parameter Type = Globals*
Parameter Name = globals
Click the OK button to right of each text field. Then click Apply to set these values for Form.
  1. Select the Form widget instance on the Browser.
  2. Select Creation Routine from the Resource Editor Component menu.
  3. Enter the following values in their respective text fields:
  4. Click Dismiss to remove the Creation Routine dialog.

Adding Header Files

Some structures referred to in the callbacks above will be declared in a header file that you will write before compilation. You need to add the #include for this file before writing out code from Builder Xcessory.

The File Names tab of the Language Settings dialog is displayed.
#include "defs.h"
Make sure to click the OK button below the C Output Include Information field.
  1. Select Code Generation Preferences from the Browser Options menu.
  2. Select the Include Info tab. In the text field labeled C Output Include Information, type:
  3. Click Dismiss to remove the dialog.

Testing Look and Feel

The major windows of Builder Xcessory are desensitized, but you are still able to make selections from the Browser menus. You should be able to enter text in the Text widget and click the "ADD" and "DISMISS" PushButtons. The functionality of these callbacks has not yet been connected, however, so they will not execute the appropriate functions.
Because you have set the interior attachments to XmATTACH_POSITION, the list, text, and PushButton widgets that make up the interface should resize proportionally.
  1. Select Play Mode from the Browser Project menu.
  2. Resize the topLevelShell to test the geometry management of the children of the Form widget.
  3. Return to Build Mode from the Browser Project menu before continuing.

Generating Code

You will save the interface code by writing a combination of C and UIL files. Then you will edit the file containing the callback structures to connect the functionality of the interface.

Saving the interface

Save the UIL file and generate C code for your interface. If you have questions about these procedures, review Generating Code .

Editing the Callback Structures

  1. Load <tutorial_path>/Tut5/callbacks-c.c into a text editor.
  2. Note: Don't forget that if you have previously generated code, the file callback-c.c is not overwritten, but just appended to. For these tutorials, delete any earlier versions of callback-c.c before you generate code.

Note: The text that you entered in the Output Include Information text field of the Include Info tab, #include "defs.h" is included in the header of the file.

#include <Xm/Text.h>
Because the example uses the text widget, you need to include this header file in the callbacks-c.c file.
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
add the following:
Widget *setme = (Widget*)client_data;
*setme = w;
client_data is the generic name of the parameter sent to the callback. Recall that for each of the four callbacks, a pointer is passed to the location in which the widget ID is stored.
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
add the following:
Globals *globals=(Globals*)client_data;
char *textValue;
XmString xmTextValue;
textValue = XmTextGetString(globals->wids.text);
These lines place the string value in the text field into the variable textValue.
Then add:
xmTextValue = XmStringCreateSimple(textValue);
XmListAddItem(globals->wids.list,xmTextValue, 0);
These lines create an XmString value from the value in the text field and then place it at the end of the List widget, which expects its items to be of type XmString.
Then add:
XmStringFree(xmTextValue);
XtFree(textValue);
These lines free the data.
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
add the line:
exit(0);
  1. After the #include line, enter the following:
  2. Inside the procedure "creation", after the line:
  3. Inside the procedure AddWord, after the line:
  4. Inside the procedure Dismiss, after the line:

Reviewing the Edited Stubs

The callbacks-c.c stubs, with your additions marked in bold , should now look like this:

Creation stub

void creation(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
Widget *setme=(Widget*)client_data;
*setme = w;
}

AddWord stub

void
AddWord(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
Globals *globals=(Globals*)client_data;
char *textValue;
XmString xmTextValue;
textValue=XmTextGetString(globals->wids.text);
xmTextValue = XmStringCreateSimple(textValue);
XmListAddItem(globals->wids.list, 
xmTextValue,0);
XmStringFree(xmTextValue);
XtFree(textValue);
}

Dismiss stub

void
Dismiss(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
XmAnyCallbackStruct
*acs=(XmAnyCallbackStruct*)call_data;
exit(0);
}
  • Save and close the file.

Adding a Declaration to the Main File

You will edit the main-c.c file to declare and allocate memory for the variable globals .

Globals *globals;
globals = (Globals*)XtCalloc(1,sizeof(Globals));
  1. Load <tutorial_path>/Tut5/main-c.c into a text editor.
  2. Inside the procedure main, inside the user code block <declarations>, add the following:
  3. Save and close the file.

Compiling and Running

Compile and run your program. If you have questions about these procedures, review Compiling and Running .

Testing the Interface

The application shell collection should appear on your display.

This displays the contents of the text field as the first item in the list above.
  1. Click MB1 within the text field and enter something.
  2. Click the ADD PushButton.
  3. Continue adding entries to the list.
  4. Note: The maximum number of entries that the list will display is five, because you have set the list's visibleItemCount resource to 5.
  1. Click the DISMISS PushButton to remove the window.

You have now completed Tutorial Five.

 

Documentation: