This document covers the following topics:
A dialog bar is similar to a tool bar control in that it can either docked to one of the interior sides of the dialog's frame or (optionally) floated in its own separate window. Unlike tool bar controls, however, dialog bar controls are conceived general-purpose container controls and are not dedicated to containing primarily tool bar items. Furthermore, there are a number of other visual and behavioral differences between tool bar controls and dialog bars, some of which are discussed below.
A good example of a dialog bar control is the library workspace window in Natural Studio.
Dialog bar controls are created in the
dialog editor
in the same way as other standard controls (such as list boxes or push buttons)
are. That is, they are either created statically in the
dialog editor
via the menu or by drag and drop from the Insert tool
bar, or dynamically at run-time by using a PROCESS GUI ACTION
ADD
statement with the
TYPE
attribute set to
DIALOGBAR
.
A dialog bar control can exist in one of the following three basic forms (in order of complexity):
Neither dockable nor sizeable.
Dockable, but not sizeable.
Dockable and sizeable.
The dialog bar control is dockable if its
DRAGGABLE
attribute is
set. It is sizeable if the "Dynamic (Y)"
STYLE
flag is set.
The following example shows an example of a non-dockable, non-sizeable dialog bar. The edit area on the right fills the entire client area of the dialog. The dialog bar cannot be dragged by the user and extends to fill the entire length of the side on which it is positioned:
Setting the "dockable" state in the Dialog Bar Attributes window in the dialog editor causes the window to be draggable by the user. Note also that the dialog bar no longer extends to occupy the full length of the side to which it is docked (another dialog bar control or tool bar control could be docked underneath it):
The user can drag the dialog bar control and re-dock it to another side of the owner dialog, or float it in its own separate window, as shown below:
If the dialog bar control is made sizeable (by checking the "Dynamic (Y)" style flag in the Attributes window), a longitudinal splitter bar appears, allowing the dialog bar control to be resized. Note that sizeable dialog bar controls expand to fill the entire length of the side they are docked to that is not occupied by non-sizeable bars:
If a gripper bar, zoom and close button are added (by setting the "Gripper (g)", "Zoom button (z)" and "Close button (x)" style flags in the Attributes window), the dialog bar control takes on the familiar appearance of the control used to display the library workspace in Natural Studio. Note that the zoom button is disabled, because there is no other sizeable dialog bar control on the same row:
If a second sizeable dialog bar control is added, and docked alongside the first on the same row, a transverse splitter bar appears allowing the relative sizes of the two dialog bar controls to be changed. Note that the zoom button is now enabled:
Clicking on the zoom button toggles between the maximized and restored states of a sizeable dialog bar control. Maximizing a dialog bar control causes the other sizeable dialog bar controls on the same row to be minimized, and the released space to be taken up by the maximized bar, as shown below:
Note that the direction of the arrow is displayed by the zoom button on the maximized bar has changed direction in order to indicate that the next time this button is pressed, the bar will be restored, rather than maximized. When a bar is restored, all sizeable dialog bars on the row revert to their normalized sizes. These are usually the sizes prior to the maximize operation, unless there has been a change in the visible bars on the row in the meantime (e.g., visible bar hidden or hidden bar shown, new bar docked on row, etc.).
Note that if the length of a bar on a row is changed via a tranverse splitter bar, all visible bars on the row are automatically restored.
A dockable dialog bar control may normally be dragged via either its gripper bar (if any) or its background. If the "UI transparent (T)" style is set, however, the bar may only be dragged via its gripper bar (if any). If such a (sizeable) bar does not have a gripper bar, resizing of the control is only possible via the splitter bar(s), which may be a desirable feature in some situations. Additionally, only allowing dragging via the gripper bar helps prevent unintentional initiation of drag operations.
The dialog's client window is reduced in size to exclude the areas
occupied by tool bar, status bar and dialog bar controls. If a dockable window
(tool bar or dialog bar control) is floated, re-docked to another side of the
owner window, or is shown or hidden, the size of the client window can change,
even though the exterior dimensions of the window have not altered. Because the
SIZE
event is reserved for changes in a
dialog's exterior size, applications which need to keep track of the size of
the client window should instead use the
CLIENT-SIZE
event for this purpose. The
actual size of the dialog client window can then be determined within this
event by means of the
INQ-INNER-RECT
action.
The close button (if present) hides a dialog bar control rather than closing it, as is also the case for the close button on floated tool bar controls. It is up to the application to provide a method of re-showing the bar. The next section provides some code for doing this (amongst other things).
Below is a full listing of an external subroutine that can, in most cases, be used "as-is" in order to allow user control over the display of tool bars and dialog bars. The code is designed to be powerful enough to cope with MDI applications, but also works with non-MDI (i.e., SDI) applications.
The subroutine appends the tool and dialog bar captions (STRING
attribute) to
the dialog's context menu. If the dialog does not have a context menu, one is
created and assigned to the dialog automatically. It assumes that, in an MDI
application, there are some tool bars and dialog bars that are global (i.e.,
relevant for all types of MDI child dialogs) and some which are private (i.e.,
relevant only for one type of MDI child dialog). For example, in Natural
Studio, the Object tool bar is an example of a global tool bar, whereas the
dialog editor
options tool bar is private to the
dialog
editor. When the user switches between MDI child dialogs, the
context menu is changed to only show the global tool bars plus any private tool
bars relevant to the currently active dialog. Furthermore, the same private
bars are displayed as the last time this dialog was displayed (if the
Save layout check box in the Dialog
Attributes window is checked, the subset of bars shown is even
retained between sessions).
The subroutine should be called in the
AFTER-ANY
event handler of the main
dialog (i.e., the MDI frame dialog for MDI applications), as follows (assuming
the main dialog's handle variable name is set to the default value of
#DLG$WINDOW
):
PERFORM PROCESS-BAR-COMMANDS #DLG$WINDOW
In addition, the following steps are optional:
The bars are listed in the context menu in the order in which they appear in the control sequence. Therefore, you may wish to re-sequence the tool and dialog bars (e.g., to ensure that the global tool bars are displayed before the private ones in MDI applications).
The code does not insert a separator before the list of available bars on the context menu. Therefore, if you are already using a context menu for the dialog, you would probably want to ensure that your context menu ends with a separator.
For MDI applications, for each private bar, you should enter the name of the dialog (e.g. "CHILD" if the dialog's file name is CHILD.NS3) to which the tool bar "belongs" into the Control ID field of the Attributes window for the bar in the dialog editor. For each global bar, leave this field empty. If you wish the bar to be displayed only when no MDI child dialog is active, enter the name of the MDI frame dialog here.
For MDI applications, you should uncheck the Enabled check box in the Attributes window for each bar that should not be displayed by default.
DEFINE DATA PARAMETER 1 #DIALOG HANDLE OF GUI LOCAL 1 #CONTROL HANDLE OF GUI 1 #ACTIVE-DLG HANDLE OF GUI 1 #CTXMENU HANDLE OF CONTEXTMENU 1 #MITEM-DYN HANDLE OF MENUITEM LOCAL USING NGULKEY1 END-DEFINE * DEFINE SUBROUTINE PROCESS-BAR-COMMANDS DECIDE ON FIRST *EVENT VALUE 'COMMAND-STATUS' PERFORM COMMAND-STATUS VALUE 'IDLE' PERFORM IDLE VALUE 'CLICK' PERFORM CLICK VALUE 'BEFORE-OPEN' PERFORM BEFORE-OPEN VALUE 'AFTER-OPEN' PERFORM AFTER-OPEN NONE IGNORE END-DECIDE * DEFINE SUBROUTINE COMMAND-STATUS /* Must enable our commands, otherwise they're automatically disabled! #CTXMENU := #DIALOG.CONTEXT-MENU #MITEM-DYN := #CTXMENU.FIRST-CHILD REPEAT WHILE #MITEM-DYN <> NULL-HANDLE IF #MITEM-DYN.CLIENT-HANDLE <> NULL-HANDLE #MITEM-DYN.ENABLED := TRUE END-IF #MITEM-DYN := #MITEM-DYN.SUCCESSOR END-REPEAT END-SUBROUTINE * DEFINE SUBROUTINE IDLE PERFORM SWITCH-BARS END-SUBROUTINE * DEFINE SUBROUTINE CLICK #CONTROL := *CONTROL IF #CONTROL.TYPE = MENUITEM AND #CONTROL.PARENT = #DIALOG.CONTEXT-MENU #MITEM-DYN := #CONTROL #CONTROL := #MITEM-DYN.CLIENT-HANDLE IF #CONTROL <> NULL-HANDLE IF #MITEM-DYN.CHECKED = CHECKED #CONTROL.ENABLED := FALSE #CONTROL.VISIBLE := FALSE ELSE #CONTROL.ENABLED := TRUE #CONTROL.VISIBLE := TRUE END-IF END-IF END-IF END-SUBROUTINE * DEFINE SUBROUTINE BEFORE-OPEN #CTXMENU := #DIALOG.CONTEXT-MENU #MITEM-DYN := #CTXMENU.FIRST-CHILD REPEAT WHILE #MITEM-DYN <> NULL-HANDLE IF #MITEM-DYN.CLIENT-HANDLE <> NULL-HANDLE #CONTROL := #MITEM-DYN.CLIENT-HANDLE IF #CONTROL.VISIBLE #MITEM-DYN.CHECKED := CHECKED ELSE #MITEM-DYN.CHECKED := UNCHECKED END-IF END-IF #MITEM-DYN := #MITEM-DYN.SUCCESSOR END-REPEAT END-SUBROUTINE * DEFINE SUBROUTINE AFTER-OPEN /* for MDI frames, unsuppress IDLE event to track active child change IF #DIALOG.TYPE = MDIFRAME #DIALOG.SUPPRESS-IDLE-EVENT := NOT-SUPPRESSED END-IF /* if dialog has no context menu, create one #CTXMENU := #DIALOG.CONTEXT-MENU IF #CTXMENU = NULL-HANDLE PROCESS GUI ACTION ADD WITH PARAMETERS HANDLE-VARIABLE = #CTXMENU TYPE = CONTEXTMENU PARENT = #DIALOG END-PARAMETERS GIVING *ERROR #DIALOG.CONTEXT-MENU := #CTXMENU END-IF /* unsuppress context menu's BEFORE-OPEN event for item update #CTXMENU.SUPPRESS-BEFORE-OPEN-EVENT := NOT-SUPPRESSED /* display bars according to context PERFORM SWITCH-BARS END-SUBROUTINE * DEFINE SUBROUTINE SWITCH-BARS IF #DIALOG.TYPE = MDIFRAME #ACTIVE-DLG := #DIALOG.ACTIVE-CHILD END-IF IF #ACTIVE-DLG = NULL-HANDLE #ACTIVE-DLG := #DIALOG END-IF IF #ACTIVE-DLG <> #DIALOG.CLIENT-HANDLE #CTXMENU := #DIALOG.CONTEXT-MENU IF #CTXMENU <> NULL-HANDLE /* Remove any dynamic menu items previously created #CONTROL := #CTXMENU.FIRST-CHILD REPEAT WHILE #CONTROL <> NULL-HANDLE #MITEM-DYN := #CONTROL.SUCCESSOR IF #CONTROL.CLIENT-HANDLE <> NULL-HANDLE PROCESS GUI ACTION DELETE WITH #CONTROL END-IF #CONTROL := #MITEM-DYN END-REPEAT /* Search for all tool bar and dialog bar controls #CONTROL := #DIALOG.FOLLOWS REPEAT WHILE #CONTROL <> #DIALOG IF #CONTROL.TYPE = TOOLBARCTRL OR #CONTROL.TYPE = DIALOGBAR #CONTROL.CLIENT-KEY := 'CONTROL-ID' IF #CONTROL.CLIENT-VALUE = ' ' OR #CONTROL.CLIENT-VALUE = #ACTIVE-DLG.NAME #CONTROL.VISIBLE := #CONTROL.ENABLED /* Create menu entry for bar PROCESS GUI ACTION ADD WITH PARAMETERS HANDLE-VARIABLE = #MITEM-DYN TYPE = MENUITEM PARENT = #CTXMENU STRING = #CONTROL.STRING SUCCESSOR = #MITEM-DYN CLIENT-HANDLE = #CONTROL END-PARAMETERS GIVING *ERROR ELSE #CONTROL.VISIBLE := FALSE END-IF END-IF #CONTROL := #CONTROL.FOLLOWS END-REPEAT END-IF /* Save handle of currently active dialog #DIALOG.CLIENT-HANDLE := #ACTIVE-DLG END-IF END-SUBROUTINE END-SUBROUTINE END