UpPreviousNext

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 .

  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. The Form widget will no longer resize to match the dimensions of its children.
  5. Place a List widget so that it fits within the topmost half of the Form.
  6. Place a Text widget within the Form and under the List.
  7. Resize the Text widget so that there is enough room underneath it within the Form to place a PushButton.
  8. 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.
  9. Place a second PushButton in the rightmost third of the space under the Text widget within the Form.
  10. Your interface should now look like Widget Collection :
 

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.

  1. In a text editor, create the defs.h file:
  2. 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;
  3. 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

  1. In the Callback Editor, set the createCallback resource for list1 as follows.
  2. 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.

Using the Callback Editor

  1. Use the Callback Editor to set the createCallback resource for the widget instance "text" to the following:
  2. 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 .

Setting the activateCallback resource

  1. In the Callback Editor, set the activateCallback resource for pushButton as follows.
  2. 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 .

Setting resources for pushButton

  1. For pushButton, set:
  2. 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.
  3. For pushButton1, set:
  4. 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.

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 .

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

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".

  1. Select the Form widget instance on the Browser.
  2. Select Creation Routine from the Resource Editor Component menu.
  3. The Creation Routine dialog is displayed.
  4. Enter the following values in their respective text fields:
  5. 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.
  6. 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.

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

Testing Look and Feel

  1. Select Play Mode from the Browser Project menu.
  2. 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.
  3. Resize the topLevelShell to test the geometry management of the children of the Form widget.
  4. Because you have set the interior attachments to XmATTACH_POSITION, the list, text, and PushButton widgets that make up the interface should resize proportionally.
  5. 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.
  1. After the #include line, enter the following:
  2. #include <Xm/Text.h>
    Because the example uses the text widget, you need to include this header file in the callbacks-c.c file.
  3. Inside the procedure "creation", after the line:
  4. 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.
  5. Inside the procedure AddWord, after the line:
  6. 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.
  7. Inside the procedure Dismiss, after the line:
  8. XmAnyCallbackStruct
    *acs=(XmAnyCallbackStruct*)call_data;
    add the line:
    exit(0);

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 .

    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. Globals *globals;
      globals = (Globals*)XtCalloc(1,sizeof(Globals));
    4. 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.

    1. Click MB1 within the text field and enter something.
    2. Click the ADD PushButton.
    3. This displays the contents of the text field as the first item in the list above.
    4. Continue adding entries to the list.

    5. 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.

    UpPreviousNext