A user interface service is responsible for creating a user interface element that is displayed when an iTool user takes some action. A simple UI service may do no more than display the "hourglass" cursor while an operation is being performed; more complicated UI services may be small applications unto themselves.
For simple operations the UI service routine can contain everything necessary to implement the UI service. For more complex interfaces, however, it is often practical to separate the actual user interface code (that is, the widget creation and event-handling routines) from the logic of the UI service itself. The latter is the strategy used by many of the UI services included with the standard iTools.
The process of creating a user interface service is outlined in the following sections:
The user interface service routine performs the following tasks:
To accomplish these things, the UI service routine needs a reference to the iTool component on which the service will act, and a reference to the IDLitUI object associated with the current iTool. As a result, the user interface service routine has the following signature:
FUNCTION ServiceName, oUI, oRequester
where ServiceName is the name of the function, oUI is an object reference to the IDLitUI object associated with the iTool, and oRequester is an object reference to the iTool component specified in the call to the DoUIService method.
The user interface service routine should return 1 if the action succeeds, or 0 otherwise.
The oRequester argument to the user interface service function contains an object reference to the iTool component on which the UI service was invoked. Use this reference to retrieve any properties of the object that are relevant to the operation being performed by the user interface.
For example, the standard
ScaleFactor user interface service displays a dialog that lets the user set the SCALE_FACTOR property of an object. The service uses the following statement to retrieve the current scale factor from the selected object:
oRequester->GetProperty, SCALE_FACTOR = factor
The oUI argument to the user interface service function contains an object reference to the IDLitUI object associated with the current iTool. You can use this reference to retrieve the IDL widget identifier of the widget that is the group leader of the iTool user interface itself (the iTool window); the ID is stored in the GROUP_LEADER property of the IDLitUI object. Having this widget ID allows you to retrieve screen geometry information that allows you to calculate the position at which your user interface should be displayed.
For example, the
ScaleFactor user interface service uses the following code to calculate the X and Y offsets that will be used to position its own user interface over the current iTool:
; Retrieve the widget ID of top-level base. oUI->GetProperty, GROUP_LEADER = groupLeader IF (WIDGET_INFO(groupleader, /VALID)) THEN BEGIN geom = WIDGET_INFO(groupLeader, /GEOMETRY) xoffset = geom.scr_xsize + geom.xoffset - 80 yoffset = geom.yoffset + (geom.ysize - 400)/2 ENDIF
The UI service goes on to use the calculated
yoffset values when positioning the IDL widgets that make up the interface displayed by the service.
If the user interface being displayed by the UI service is simple, it may be convenient to include the code for creating it directly in the definition of the user interface service itself. For example, the following is the complete definition of the
HourGlassCursor user interface service:
FUNCTION IDLitUIHourGlass, oUI, oRequester WIDGET_CONTROL, /HOURGLASS RETURN, 1 END
As you can see, no information about the IDLitUI object or the selected iTool component is used, and the displayed item itself is very simple.
In most cases, the user interface service is significantly more complex. In these cases it is often useful to separate the routine that creates the service's user interface from the code that displays it. For example, the user interface for the ScaleFactor service is displayed by the following statement:
result = IDLitwdScaleFactor(GROUP_LEADER = groupLeader, $ FACTOR = factor, XOFFSET = xoffset, YOFFSET = yoffset) IF result EQ 1 THEN RETURN, 0
This statement calls another function - IDLitwdScaleFactor - to actually display the required user interface elements, supplying the information retrieved by other portions of the user interface service routine. The IDLitwdScaleFactor function returns the scale factor value selected by the user, or returns the value 1 (indicating no scaling) if the value supplied by the user is invalid. If the returned scale factor is 1 (either because the user entered 1 the value, or because the entered value was not a valid value), no scaling will be performed, so the UI service itself returns the failure value (integer 0). The process of creating user interface elements is discussed in greater detail in Creating Supporting User Interface Elements.
If the user has selected a new value for any of the object's properties, that value must be changed on the object by a call to the SetProperty method. In our example, if the user sets a new scale factor, the following statement updates the property value, notifies the selected object that the value has changed, and inserts the change into the undo-redo transaction buffer:
oRequester->SetProperty, SCALE_FACTOR = result
Note that not every user interface will modify properties of the selected object.
The following example routine is the full definition of the
ScaleFactor user interface service described in the previous sections. It is presented here again for completeness, so you can see the entire function at once.
FUNCTION IDLituiScaleFactor, oUI, oRequester ; Retrieve widget ID of top-level base. oUI->GetProperty, GROUP_LEADER = groupLeader ; Retrieve geometry information and calculate offsets. IF (WIDGET_INFO(groupleader, /VALID)) THEN BEGIN geom = WIDGET_INFO(groupLeader, /GEOMETRY) xoffset = geom.scr_xsize + geom.xoffset - 80 yoffset = geom.yoffset + (geom.ysize - 400)/2 ENDIF ; Retrieve the current scale factor from the selected object. oRequester->GetProperty, SCALE_FACTOR = factor ; Display the IDL widget interface allowing the user to ; change the scale factor. The new scale factor is returned ; as the result of this function. If the specified value is ; not a valid scale factor, the integer 1 is returned in ; result. result = IDLitwdScaleFactor( GROUP_LEADER = groupLeader, $ FACTOR = factor, XOFFSET = xoffset, YOFFSET = yoffset) IF result EQ 1 THEN RETURN, 0 ; Set properties on the selected object. oRequester->SetProperty, SCALE_FACTOR = result ; Return success. RETURN, 1 END
It is beyond the scope of this manual to provide general information on the creation of user interfaces. For information on creating a user interface using the IDL widget toolkit, see Creating Graphical User Interfaces in IDL. The following are some suggestions for creating IDL widget interface code for iTool user interface services.
Create your user interface routine (the routine that creates the IDL widgets that make up the user interface displayed by your UI service) as a function, returning the data values collected by the interface in the function's return value. If you are collecting several values of different data types, return a structure variable containing the data. The user interface and event-handling code should never change data or property values within the iTool itself; all changes should be made via the SetProperty mechanism.
If your user interface code creates pointer or object heap variables, be sure to destroy them before the interface code exits. If extra "hanging" heap variables are left undestroyed, IDL can potentially run out of resources if the interface is displayed numerous times.
Pass the widget ID contained in the GROUP_LEADER property of the IDLitUI object to your user interface code, and set the GROUP_LEADER keyword of the top-level base widget to this value. Setting the widget group leader to the leader of the iTool's own widget hierarchy ensures that your user interface will be destroyed if the iTool itself is destroyed.