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 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:
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:
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:
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.
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. |
The following functions can be used to work with the widget family hierarchy, and may be useful in setting the focus order:
You can add and remove callbacks in your code as well as from PhAB - just watch for differences between the two types!
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, NULL); }
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.
When called, the callback function is invoked with the following parameters:
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. |
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.
You can remove one or more callbacks from a callback list associated with a widget resource using the PtRemoveCallbacks() and PtRemoveCallback() functions.
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.
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 ) break; }
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.
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:
The arguments to PtAddEventHandlers() are:
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().
You can remove event handlers by calling either the PtRemoveEventHandler() or PtRemoveEventHandlers() function.
Don't remove event handlers that were added through PhAB; unexpected behavior may result. |
The parameters to PtRemoveEventHandler() are:
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:
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.
When invoked, event handlers receive the same arguments as callback functions, i.e. the parameters are:
The client data passed to this event handler isn't the same as the apinfo data passed to an event handler added through PhAB. |
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.