[Previous] [Contents] [Index] [Next]

Creating Widgets in Application Code

We recommend that you create your application's UI in PhAB - it's easier than doing it in your code. However, if the interface is dynamic, you'll probably have to create parts of it "on the fly."

This chapter discusses:

in application code.

Creating widgets

Creating a widget in your application code is a bit more work than creating it in PhAB. That's because PhAB looks after a lot of the physical attributes for you, including size, location, and so on. If you create the widget in your code, you'll have to set these resources yourself.

To create a widget in your code, call PtCreateWidget(). The syntax is as follows:

PtWidget_t *PtCreateWidget( 
                PtWidgetClassRef_t *class,
                PtWidget_t *parent,
                unsigned n_args,
                PtArg_t *args );

The arguments are:

The type of widget to create (e.g. PtButton)
The parent of the new widget. If this is NULL, the new widget is a child of the default parent, which is the most recently created container-class widget.
The number of elements in the args array.
An array of settings for the widget's resources. These settings are like the ones used for PtSetResources(); see the Manipulating Resources in Application Code chapter.

You can specify the default parent (used if the parent argument to PtCreateWidget() is NULL) by calling PtSetParentWidget(). To assign a widget to a different container, call PtReParentWidget().

Here are a few things to note about widgets created in application code:

Ordering widgets

The order in which widgets are given focus depends on the order in which they were created or on the widget order specified in PhAB (see "Ordering widgets" in the Creating Widgets in PhAB chapter). The backmost widget is the first in the tab order; the frontmost widget is the last.

If you're creating widgets programatically, you can creating them in the order in which you want them to get focus, or you can use these functions to change the order:

Insert a widget in the widget family hierarchy
Move a widget behind all its brothers
Move a widget in front of all its brothers

Alternatively, you can use a widget's Pt_CB_LOST_FOCUS callback (defined by PtBasic) to override the tab order by giving focus to another widget.

In the lost-focus callback, use PtContainerGiveFocus() to give focus to the desired widget, and return Pt_END from the callback to prevent focus from being given to the original target of the focus change.

Note: The Pt_CB_LOST_FOCUS callback is called a second time as focus is removed from the widget to go to the new target. To avoid an endless loop, use a static variable to indicate that this callback has already redirected focus.

All in the widget family

The following functions can be used to work with the widget family hierarchy, and may be useful in setting the focus order:

Determine the relationship between two widgets
Find the closest focusable child widget
Find the widget responsible for another widget's actions
Find the nearest widget with the same parent class
Return the current default widget parent
Get a pointer to the next top-level widget
Identify a valid parent for a widget
Get the brother behind a widget
Get the brother in front of a widget
Get the child that's farthest back in a container
Get the child at the very front of a container
Traverse the widget hierarchy
Get a widget's parent
Skip to a widget in the next hierarchy
Walk the widget tree from front to back
Walk the widget family hierarchy from front to back

Manipulating callbacks in your code

You can add and remove callbacks in your code as well as from PhAB - just watch for differences between the two types!

Adding callbacks

An application registers callbacks by manipulating the widget's callback resources. The Photon widget classes employ a naming convention for these resources - they all begin with Pt_CB_.

Callbacks can be added to the callback list kept by these resources using PtAddCallbacks() to add several callback functions to the list or PtAddCallback() to add just one. In either case, the first two arguments to the function are the widget and the name of the callback resource to be augmented. The remaining arguments depend on which function is used.

The third argument to PtAddCallbacks() is an array of callback records. Each record contains a pointer to a callback function and the associated client data pointer that will be passed to the callback function when it's invoked. Each of these callback records is copied to the widget's internal callback list.

For example, we might want to have the application perform some action when the user selects (i.e. presses) a button. The PtButton widget class provides the Pt_CB_ACTIVATE callback resource for notifying the application when the button has been pressed. To create the widget and attach a callback function to this callback resource, we'd have to use code like this:

   PtWidget_t *button;
   int push_button_cb( PtWidget_t *, void *,
                       PtCallbackInfo_t *);
   PtCallback_t callbacks[] = { {push_button_cb, NULL} };


   button = PtCreateWidget(PtButton, window, 0, NULL);
   PtAddCallbacks(button, Pt_CB_ACTIVATE, callbacks, 1);

where push_button_cb is the name of the application function that would be called when the user presses the button.

When adding only one callback function to the callback list (as in this case), it's simpler to use PtAddCallback(). This function takes the pointer to the callback function as the third argument, and the client data pointer as the final argument. The above code fragment could be written more concisely as:

   PtWidget_t *button;
   int push_button_cb( PtWidget_t *, void *, 
                       PtCallbackInfo_t *);
   button = PtCreateWidget(PtButton, window, 0, NULL);
   PtAddCallback(button, Pt_CB_ACTIVATE, push_button_cb,

You can also give an array of callback records as the value for the callback resource when using argument lists in conjunction with PtCreateWidget() or PtSetResources(). Since the callback list is an array, you should specify the array's base address as the third argument to PtSetArg(), and the number of elements as the final argument. In this case, the callback records are added to the current callback list, if there is one. This gives us another way to specify the callback for the above example:

   PtArg_t arg[5];
   int push_button_cb( PtWidget_t *, void *,
                       PtCallbackInfo_t *);
   PtCallback_t callbacks[] = { {push_button_cb, NULL} };
   PtSetArg(&args[0], Pt_CB_ACTIVATE, callbacks, 1);
   PtCreateWidget(PtButton, window, 1, arg);

Each of these methods has its advantages. PtAddCallback() is of course simple. PtAddCallbacks() is more efficient when there are several callbacks. Using PtSetArg() and passing the result to PtCreateWidget() allows the widget creation and callback list attachment to be performed atomically.

Callback invocation

When called, the callback function is invoked with the following parameters:

PtWidget_t *widget
The widget that caused the callback function to be called, i.e. the one on which the action took place.
void *client_data
Application-specific data that was associated with the callback when it was registered with the widget.
Note: The client data that's passed to a callback you add from your code isn't the same as the apinfo data passed to a PhAB callback.

PtCallbackInfo_t *call_data
data specific to this invocation of the callback. It relates to the reason the callback was called and may have data specific to the callback's behavior.

The PtCallbackInfo_t structure is defined as:

typedef struct Pt_callback_info {
        unsigned long     reason;
        unsigned long     reason_subtype;
        PhEvent_t         *event;
        void              *cbdata;
} PtCallbackInfo_t;

The elements of PtCallbackInfo_t have the following meaning:

For more information, see the descriptions of the callbacks defined for each widget in the Widget Reference.

Removing callbacks

You can remove one or more callbacks from a callback list associated with a widget resource using the PtRemoveCallbacks() and PtRemoveCallback() functions.

Caution: Don't try to remove a callback that was added through PhAB; unexpected behavior may result.

PtRemoveCallbacks() takes an array of callback records as an argument and removes all the callbacks specified by it from the callback list. PtRemoveCallback() removes just one callback function from the callback list. Both functions take the widget as the first argument and the widget resource as the second argument.

To remove the callback from the button we've created above, we could do this:

int push_button_cb( PtWidget_t *, void *, 
                    PtCallbackInfo_t *);
PtCallback_t callbacks[] = { {push_button_cb, NULL} };
PtRemoveCallbacks(button, Pt_CB_ACTIVATE, callbacks, 1);

or this:

int push_button_cb( PtWidget_t *, void *,
                    PtCallbackInfo_t *);
PtRemoveCallback(button, Pt_CB_ACTIVATE, push_button_cb,

Both the callback function pointer and the client data pointer are important when removing callbacks. Only the first element of the callback list that has both the same callback function and the same client data pointer will be removed from the callback list.

Examining callbacks

You can examine the callback list by getting the value of the appropriate callback list resource. The type of value you get from a callback list resource is different from the value used to set the resource. Although this resource is set with an array of callback records, the value obtained by getting the resource is a pointer to a list of callback records. The type of the list is PtCallbackList_t. Each element of the list contains a cb member (i.e. the callback record) and a next pointer (which points to the next element of the list).

The following example shows how you can traverse through the Pt_CB_ACTIVATE callback list for widget to find all instances of a particular callback function, cb:

    PtCallbackList_t *cl;

    PtSetArg(&arg[0], Pt_CB_ACTIVATE, &cl, 0);
    PtGetResources(widget, 1, arg);
    for ( ; cl; cl = cl->next )
        if ( cl->cb.func == cb )

Manipulating event handlers in your code

You can add and remove event handlers in your application code as well as in PhAB - however, there are some differences between the two types.

The PtWidget widget class provides a special form of callback - Pt_CB_RAW. This callback will be called every time a Photon event that matches a filter mask (provided by the application) is received. Since all the widget classes in the Photon widget library are descended from the PtWidget, this callback can be used with any widget from the Photon widget library.

Whenever a Photon event is received, it's passed to the appropriate widget, which handles the event and may consume it. A widget's internal event handlers are always invoked before any that you register in your application. If the widget doesn't consume the event, it's then passed on to the widget's parent, and so on up the widget family until it's consumed.

The widget invokes each event handler that has an event mask matching an incoming event. Any event handler may consume the event so that it's not passed on to the remaining event handlers or to the widget's ancestors in the widget family.

Adding event handlers

As with callbacks, you can also set or examine event handlers by performing a set or get directly on the event handler resource (e.g. Pt_CB_RAW). The set operation requires an array of event handler records of type PtRawCallback_t. These are similar to the callback records mentioned above, having event_mask, event_f, and data fields.

The event mask is a mask of Photon event types indicating which events will cause the callback function to be invoked. The event_f and data members are the event handler function and client data, respectively.

A get operation yields a PtRawCallbackList_t * list of event handler records. As with callback lists, the list contains two members: next and cb. The cb member is an event handler record.

You can add event handlers using either the PtAddEventHandler() or PtAddEventHandlers() function.

The arguments to PtAddEventHandler() are:

Widget to which the event handler should be added.
Event mask specifying which events should cause the event handler to be called.
Event-handling function.
A pointer to pass to the event handler as client data.

The arguments to PtAddEventHandlers() are:

Widget to which the event handlers should be added.
Array of event handler records.
Number of event handlers defined in the array.

If you add an event handler to a widget and the widget's region is not sensitive to one of the events contained in the event mask, then the event is added to the set to which the region is sensitive. This is done with a call to PhRegionChange().

Removing event handlers

You can remove event handlers by calling either the PtRemoveEventHandler() or PtRemoveEventHandlers() function.

Caution: Don't remove event handlers that were added through PhAB; unexpected behavior may result.

The parameters to PtRemoveEventHandler() are:

Widget from which the event handler should be removed.
Event mask specifying the events the handler is responsible for.
Event-handling function.
Client data associated with the handler.

This looks for an event handler with the same signature - i.e. the same event_mask, data and event_f - in the widget and removes one if it's found.

The parameters to PtRemoveEventHandlers() are:

Widget from which the event handlers should be removed.
Array of event-handler records.
Number of event handlers defined in the array.

As with PtRemoveEventHandler(), an event handler is removed only if it has the exact same signature as one of the event handler specifications in the array of event handler records.

Event handler invocation

When invoked, event handlers receive the same arguments as callback functions, i.e. the parameters are:

Event handlers return an integer value that the event handler must use to indicate whether or not further processing should be performed on the event. If the event handler returns the value Pt_END, this indicates that no further processing is to be performed on the Photon event, and the event is consumed.

The event member of the info parameter contains a pointer to the event that caused the event handler to be invoked. You should check the type member of this event to determine how to deal with the event. It will be one of the event types specified in the event_mask given when the event handler was added to the widget.

To retrieve the data associated with the particular event, call the PhGetData() with the pointer to the event as a parameter. This will return a pointer to a structure with the data specific to that particular event type. This structure's type depends on the event type.

[Previous] [Contents] [Index] [Next]