Example: A Simple UI Panel
The following example creates a simple user interface panel consisting of two buttons: Rotate and Hide/Show. The Rotate button rotates the selected iTool component 90 degrees, if possible. The Hide/Show button toggles the value of the HIDE property of the selected object.
Note
This example is intended to demonstrate the concepts involved in creating a user interface panel. For examples of more useful panels, see the files idlitwdimgmenu.pro and idlitwdvolmenu.pro, which create the user interface panels for the IIMAGE and IVOLUME iTools, respectively. Both files are located in the lib/itools/ui_widgets subdirectory of the IDL installation directory.
To display a user interface panel named Example4_panel, this example creates the following items:
Example Code
The code for this example user interface panel is included in the file example4_panel.pro in the examples/doc/itools subdirectory of the IDL distribution. Run the example procedure by entering example4_panel at the IDL command prompt or view the file in an IDL Editor window by entering .EDIT example4_panel.pro.
Panel Creation Routine
The user interface panel creation routine (beginning with the line PRO Example4_panel, wPanel, oUI) does the work of displaying the IDL widgets that make up the UI panel display.
PRO Example4_panel, wPanel, oUI ; Set the title used on the panel's tab. WIDGET_CONTROL, wPanel, BASE_SET_TITLE = 'Example Panel' ; Specify the event handler WIDGET_CONTROL, wPanel, EVENT_PRO = "Example4_panel_event" ; Register the panel with the user interface object. strObserverIdentifier = oUI->RegisterWidget(wPanel, "Panel", $ 'Example4_panel_callback') ; Register to receive selection events on visualizations. oUI->AddOnNotifyObserver, strObserverIdentifier, $ 'Visualization' ; Retrieve a reference to the current iTool. oTool = oUI->GetTool() ; Create a base widget to hold the contents of the panel. wBase = WIDGET_BASE(wPanel, /COLUMN, SPACE = 5, /ALIGN_LEFT) ; Create panel contents. wLabel = WIDGET_LABEL(wBase, VALUE = "Choose an Action:", $ /ALIGN_LEFT) ; Get the Operation ID of the rotate operation. If the operation ; exists, create the "Rotate Item" button and monitor whether ; the operation is available for the selected item. opID = 'Operations/Operations/Rotate/RotateLeft' oRotate = oTool->GetByIdentifier(opID) IF (OBJ_VALID(oRotate)) THEN BEGIN idRotate = oRotate->GetFullIdentifier() wRotate = WIDGET_BUTTON(wBase, VALUE = "Rotate Item", $ UVALUE="ROTATE") ; Monitor for availablity of the Rotate operation. oUI->AddOnNotifyObserver, strObserverIdentifier, idRotate ENDIF ELSE $ idRotate = 0 wHide = WIDGET_BUTTON(wBase, VALUE = "Show/Hide Item", $ UVALUE = "HIDE") ; Pack up the state structure and store in first child. state = {oTool:oTool, $ oUI:oUI, $ idRotate : idRotate, $ wPanel:wPanel, $ wBase:wBase, $ wRotate:wRotate, $ wHide:wHide $ } wChild = WIDGET_INFO(wPanel, /CHILD) IF wChild NE 0 THEN $ WIDGET_CONTROL, wChild, SET_UVALUE = state, /NO_COPY END
Discussion
It is beyond the scope of this chapter to describe the IDL widget concepts employed in the Example4_panel example; the comments in the code that creates the user interface panel describe most of the features. The following points are worth noting, however:
- The panel creation routine accepts two arguments: the widget ID of the panel widget (stored in the variable
wPanel, in this example), and an object reference to the IDLitUI object associated with the iTool (stored in the variableoUI). - The example uses the EVENT_PRO keyword to the WIDGET_CONTROL procedure to establish an event-handling routine,
Example4_panel_event. This event-handling routine is described in Panel Event Handler Routine. - The example registers a single callback routine,
Example4_panel_callback, using the RegisterWidget method of the IDLitUI class. The callback routine is described in Panel Callback Routine. - The example adds an OnNotifyObserver for the
Visualizationcomponent described in Adding Observers. - The example uses the GetTool method of the IDLitUI object to retrieve an object reference to the iTool with which the panel is associated. This reference is later used to retrieve a reference to the IDLitOperation object that performs the
Rotate Leftoperation, placing it in the variableoRotate. - If the
Rotate Leftoperation is available to the iTool, the example places theRotatebutton on the user interface panel. It also establishes an observer to watch for changes in the availability of theRotate Leftoperation, which will change based on the item selected. The callback routine uses the messages received by this observer to sensitize and desensitize theRotatebutton as necessary. - The example packages important information in a state structure, and assigns this structure to the user value of the first child widget of the panel widget. The event-handling and callback routines will retrieve this state structure and use the information contained therein.
Panel Event Handler Routine
The event-handler routine (beginning with the line PRO Example4_panel_event, event) receives widget events generated by the widgets that make up the user interface panel, and acts accordingly.
PRO Example4_panel_event, event ; Retrieve the widget ID of the first child widget of ; the UI panel. wChild = WIDGET_INFO(event.handler, /CHILD) ; Retrieve the state structure from the user value of ; the first child widget. WIDGET_CONTROL, wChild, GET_UVALUE = state ; Retrieve the user value of the widget that generated ; the event. WIDGET_CONTROL, event.id, GET_UVALUE = uvalue ; Now do the work for each panel item. SWITCH STRUPCASE(uvalue) OF 'ROTATE': BEGIN ; Apply the Rotate Left operation to the selected item. success = state.oUI->DoAction(state.idRotate) RETURN END 'HIDE': BEGIN ; Hide the selected item. ; oTargets = state.oTool->GetSelectedItems(count = nTarg) IF nTarg GT 0 THEN BEGIN ; If there are selected items, use only the last item ; selected, which is stored in the first element of ; the returned array. oTarget = oTargets[0] ; Get the iTool identifier of the selected item. name = oTarget->GetFullIdentifier() ; Retrieve the setting of the HIDE property. oTarget->GetProperty, HIDE = hide ; Change the value of the HIDE property from 0 to 1 ; or from 1 to 0. Use the DoSetProperty and ; CommitActions method to ensure that the change ; is entered into the undo/redo transaction buffer. void = state.oTool->DoSetProperty(name, "HIDE", $ ((hide+1) MOD 2)) state.oTool->CommitActions ENDIF BREAK END ELSE: ENDSWITCH ; Refresh the iTool window. state.oTool->RefreshCurrentWindow END
Discussion
It is beyond the scope of this chapter to describe the IDL widget concepts employed in the Example4_panel event handler; the comments in the code describe most of the features. The following points are worth noting, however:
- If the event received by the event handler routine is generated by the
Rotatebutton, the example calls the DoAction method of the IDLitUI object, with the identifier of theRotate Leftoperation as its argument. - If the event received by the event handler routine is generated by the
Hide/Showbutton, the example does the following: - Use the reference to the iTool object stored in the state structure to retrieve the list of selected items using the GetSelectedItems method.
- Retrieve the object identifier of the last item selected. (Note that the last item selected is stored in the first element of the returned array.)
- Retrieve the value of the HIDE property of the selected item.
- Use the DoSetProperty method of the IDLitTool object to toggle the value of the HIDE property for the selected item.
- Commit the property change in the undo/redo transaction buffer using the CommitActions method of the IDLitTool object.
- After the iTool display has been changed, call the RefreshCurrentWindow method of the IDLitTool object to redraw the iTool window.
Panel Callback Routine
The user interface panel callback routine is called whenever a component, for which an OnNotifyObserver has been registered, generates a message. It parses the message received and takes action as necessary.
PRO Example4_panel_callback, wPanel, strID, messageIn, component ; Make sure we have a valid widget ID. IF ~ WIDGET_INFO(wPanel, /VALID) THEN RETURN ; Retrieve the widget ID of the first child widget of ; the UI panel. wChild = WIDGET_INFO(wPanel, /CHILD) ; Retrieve the state structure from the user value of ; the first child widget. WIDGET_CONTROL, wChild, GET_UVALUE = state ; Process as necessary, depending on the message received. SWITCH STRUPCASE(messageIn) OF ; This section handles messages generated when the rotate ; operation becomes available or unavailable, and sensitizes ; or desensitizes the "Rotate" button accordingly. 'SENSITIVE': 'UNSENSITIVE': BEGIN WIDGET_CONTROL, state.wRotate, $ SENSITIVE = (messageIn EQ 'SENSITIVE') BREAK END ; This section handles messages generated when the ; item selected in the iTool window changes and changes ; the sensitivity of the "Hide/Show" and "Rotate" buttons ; accordingly. 'SELECTIONCHANGED': BEGIN ; Retrieve the item that was selected last, which is ; stored in the first element of the returned array. oSel = state.oTool->GetSelectedItems() oSel = oSel[0] ; If the last item selected is not a visualization, ; desensitize the "Hide/Show" and "Rotate" buttons. IF (~OBJ_ISA(oSel, 'IDLITVISUALIZATION')) THEN BEGIN WIDGET_CONTROL, state.wHide, SENSITIVE = 0 WIDGET_CONTROL, state.wRotate, SENSITIVE = 0 ENDIF ELSE BEGIN ; If the selected object is a visualization, sensitize ; the "Hide/Show" and "Rotate" buttons. WIDGET_CONTROL, state.wHide, SENSITIVE = 1 WIDGET_CONTROL, state.wRotate, SENSITIVE = 1 ENDELSE BREAK END ELSE: ENDSWITCH END
Discussion
The example panel's callback routine performs the following tasks:
- Uses the widget ID provided in the
wPanelargument to retrieve the widget state structure stored in the first child widget of the panel widget. - If the value of the
messageInargument is eitherSENSITIVEorUNSENSITIVE, change the sensitivity of theRotatebutton (stored in thewRotatefield of the widget state structure) as necessary. - If the value of the
messageInargument isSELECTIONCHANGED, perform the following tasks: - Use the reference to the iTool object stored in the
oToolfield of the state structure to retrieve a reference to the last selected component. (Note that the last object selected is stored in the first element of the returned array.) - If the selected component is not a visualization, desensitize the
Hide/Showbutton. - If the selected component is a visualization, sensitize the
Hide/Showbutton.
Panel Type Specification
In order to display the Example4_panel user interface panel along with an iTool, the following two things must happen:
For the purposes of this example, we will create an iTool named example4tool, with a launch routine named example4tool.pro, and an iTool object definition routine named example4tool__define.pro.
Example Code
Both example4tool.pro, and example4tool__define.pro are included in the examples/doc/itools subdirectory of the IDL distribution. Run these example procedures by entering example4tool or example4tool__define at the IDL command prompt or view the files in an IDL Editor window by entering .EDIT example4tool.pro or .EDIT example4tool__define.pro.
In the example4tool.pro file, we included the following statement:
Setting the TYPE keyword equal to the string EXAMPLE specifies that the panel should be displayed for all iTools of this type.
In the example4tool__define.pro file, we include the string EXAMPLE in the TYPE property specified in the Init method:
FUNCTION example4tool::Init, _REF_EXTRA = _extra IF (self->IDLitToolbase::Init(_EXTRA = _extra, $ TYPE = 'EXAMPLE') EQ 0) $ THEN RETURN, 0
Since the TYPE specified for the user interface panel in the call to IREGISTER matches the TYPE defined for our example iTool class, calling the launch routine example4tool at the IDL Command Line creates a new iTool and displays the Example4_panel panel on the right side of the iTool window.
