Referencing Application Variables from Resource Files

Among the information that can be included in an item resource specification is a string that determines which application variable the item controls. More...

Among the information that can be included in an item resource specification is a string that determines which application variable the item controls.

The application variable underlying a particular item is specified in the accessStr field of the item resource specification. accessStr is a NULL terminated string containing a C expression that, when evaluated at run-time, results in a variable reference. See Generating Resource Files from C Type Definitions for a general discussion of MDL's special facility for evaluating C expression strings at run-time. This facility allows the specification in a resource file of how that item affects application data.

For a C expression to be evaluated at run-time, any variables that are referenced must be published with one of the mdlDialog_publish... functions. (The lower level mdlCExpression_symbolPublish function can also be called, but the mdlDialog_publish... functions are easier to use.) In addition, if any variable is a structure or a pointer to a structure, the mdlDialog_publish... functions require that type declaration resources exist for that structure in an open resource file. Type declaration resources contain detailed information about a structure that allow it to be analyzed at run-time. The rsctype utility program converts standard C structure declarations that are #included in a type definition file, commonly known as a .mt file, into type declaration resources. See Generating Resource Files from C Type Definitions for more information on the rsctype utility and generating type declaration resources.

An underlying application variable is the application defined variable that a dialog item directly controls and that determines an item's external state. By using C expression strings in an item resource specification, the underlying application variable can be automatically modified by the dialog box manager whenever the internal value of an item changes (whether from user interaction with the item or from calls to MDL functions). Usually, no program code is necessary to have the item's appearance match the state of an item's underlying application variable.

Modeless and modal dialog boxes

Modeless dialog boxes allow the user to interact with other dialog boxes. Operations such as drawing, modification of items in other dialogs, and keying in MicroStation commands can occur while a modeless dialog is displayed. MicroStation's Command window and the Element Attributes dialog box are examples of modeless dialog boxes.

While a modal dialog box is displayed, all user interactions must be focused within that single dialog. The dialog box manager will ignore mouse presses that occur while the cursor is outside a modal dialog box. Modal dialog boxes do not have window menu buttons on the left side of the title bar or window control buttons on the right side. MicroStation's Preferences dialog box is an example of a modal dialog box. Modal dialog boxes are used when an application must have some information before it can continue, or a complete set of information must be entered before other actions can be taken.

Push button items are used to dismiss modal dialog boxes or possibly to launch another modal dialog box for more information. When dismissing a modal dialog box, users can accept the changes they have made to items within a modal dialog box by pressing a push button that is usually labeled "OK." Alternatively, users can discard any changes they have made to the items in a modal dialog box by pressing a push button that is usually labeled "Cancel." All modal dialog boxes should include one or both of the push buttons whose resource IDs are PUSHBUTTONID_OK or PUSHBUTTONID_Cancel. These predefined buttons automatically take care of all the details needed to dismiss a modal dialog box.

To implement the behavior associated with the Cancel and OK push buttons, the items in a modal dialog have their internal values decoupled from their external states. Changing the on-screen appearance of an item in a modal dialog box does not usually change the application variable that the item controls. No action is necessary to discard the changes to items within a modal dialog box because the application variables associated with the items have not been modified. However, when the user accepts the changes in the appearance of the items in a modal dialog box by clicking the OK push button, the dialog box manager must force the external state of each item to match the item's internal value.

Modal dialog boxes can be invoked in two different ways, by using the standard mdlDialog_open function or by using mdlDialog_openModal. The mdlDialog_openModal function does not return control to its caller until the user has dismissed the dialog box. The first argument of the mdlDialog_openModal function indicates which button the user pressed when dismissing the dialog box. An application should call mdlDialog_openModal when it needs more information from the user before it can continue processing.

A modal dialog box opened with mdlDialog_open must be handled differently. The mdlDialog_open function returns immediately to its callerÑit does not wait until the user has dismissed the dialog box. To determine which type of button was pressed to dismiss the modal dialog box, a dialog hook function must be attached to the dialog box. The DIALOG_MESSAGE_DESTROY message is sent when the dialog is dismissed, and the actionType field of that message indicates which button was pressed. An application should call mdlDialog_open when a complete set of information must be entered before other actions can be invoked, but the information is not needed immediately.

A modal dialog box should have the DIALOGATTR_MODAL bit set in the attributes field of its dialog box resource specification. See DialogBoxRscStructure for more information on the attributes field.

Item synchronization

An item's state has two parts as discussed in "Dialog item state: internal value versus external state." An item is synchronized when the item's internal value (and appearance) is forced to match the item's external state. In other words, after synchronization, the item's appearance on the screen is guaranteed to match the application data the item represents.

Synonym resources

In certain situations, a change in the external state of one item requires the simultaneous change in the appearance (and consequently the internal state) of other items. Synonym resources can perform this simultaneous change.

Synonym resources are simply a list of items, where each item is specified by its resource type and resource ID. Some items (such as toggle buttons, text and option buttons) can have a synonym resource ID contained in their resource item specifications. Whenever one of those item's external state changes, a synchronize message is sent to all the items contained in its associated synonym resource. This forces the synonym resource item's appearances to match the state of the application variable they control.

For example, MicroStation's Element Attributes dialog box has two dialog items in it, both of which give a different view of the active element color (both are "synonyms" for the active element color). These are the text and color picker items next to the "Color:" label. Whenever either one changes the active element color, the other item must reflect that change. Both items are associated with the following synonym resource:

{
{
{ColorPicker, COLORPICKERID_ElementColor},
}
};

Therefore, when the text item is used to change the active element color, a synchronize message is sent to the color picker item. The color picker item's appearance will be forced to match the application variable the item controlsÑin this case, the active element color. The result is that when the text item changes the active element color, the color picker's appearance will also automatically be changed. A similar sequence of events will occur if the color picker is used to change the active element color.

Remember that when a dialog box is modal, its items' states remain unchanged until the user selects the "OK" push button. If synonym resource lists need to be used within a modal dialog box, the DIALOGATTR_ALWAYSSETSTATE bit must be set in the attributes field of the dialog box resource. Here, special handling must be performed if the normal "Cancel" push button behavior (to not modify any the dialog box's underlying application variables) is needed. The values of the application variables affected by the dialog box must be stored somewhere when the dialog box is first opened, and then restored if the user activates the "Cancel" push button. These actions can be performed by a dialog hook function that handles the DIALOG_MESSAGE_CREATE and DIALOG_MESSAGE_DESTROY messages.

Keyboard focus

The dialog item that is currently processing user keystrokes is called the keyboard focus item or input focus item. The current keyboard focus item is visibly distinguishable in some way. For example, a text item with the keyboard focus contains the text cursor and a scroll bar of a list box item with the keyboard focus is darkened. When a dialog item becomes the item that receives user keystrokes, it is said to gain the focus. When the focus moves to another item, the first focus item is said to lose the focus. Not all dialog items can process user keystrokes. These items are said to be unable to accept the keyboard focus. An item that can accept the keyboard focus is said to be focusable.

A focusable dialog item can validate its contents before it gives up the keyboard focus. If the user has typed in an invalid string, the item can refuse to lose the focus. If the contents are invalid, a focusable item will typically beep and reset its contents to the previous valid value.

The dialog box that contains the keyboard focus item is called the keyboard focus dialog box.

MicroStation will usually move the keyboard focus to the MicroStation Command Window when the user clicks in a window that doesn't contain any focusable items (such as view windows). This action is called keyboard focus auto-switching. Keyboard focus auto-switching prevents the inadvertent modification of dialog items when the user is switching between modifying dialog items, performing drawing actions, and keying-in application commands. Dialog boxes can optionally turn off auto-switching if automatically moving the keyboard focus to the command window is not desired by setting the DIALOGATTR_NOAUTOSWITCH.

Sinking dialog boxes

Most modeless dialog boxes should have the DIALOGATTR_SINKABLE bit set in the attributes field of their dialog box resource specifications. See DialogBoxRscStructure for more information on the attributes field. A sinkable dialog box can be sent behind view windows by the user, and has a sink icon in the right side of its title bar. When a dialog box is "sunk," any overlapping view windows will obscure the dialog box.

Normally, modeless dialog boxes "float" in front of all view windows. It is usually impossible to bring a view window in front of a dialog box, and view windows never obscure dialog boxes. MicroStation is set up this way so the user can always see MicroStation's current settings. Dialog boxes, however, can be large and obscure too much of the view windows into the design file. In these cases, it is convenient to allow the user to sink a dialog box. The dialog box is not closed, and usually the layout of the windows can be arranged so the important parts of the dialog box are still visible. If the user needs to see the full dialog box again, clicking on any visible part of the dialog box border will "unsink" it and bring it to the front of all the windows.

The only modeless dialog boxes that should not be sinkable are those that contain tool palettes. Tool palettes should always float above the view windows.

Specifying coordinates

Positions of items within dialog boxes are specified in local coordinates. The local coordinate system has its origin in the upper left corner of the content area of a dialog box. Y values increase as one moves toward the bottom of a dialog box.

Two different units specify the locations and sizes of dialog boxes and dialog items: pixel units and dialog coordinate units. Pixel units correspond to actual screen pixels. A dialog coordinate unit is 1/12 of a dialog box's current font height.

Locations and sizes in resource files are always specified in dialog coordinate units, not pixels. By using dialog coordinates, items will be correctly placed and sized when the user changes the size of the dialog font, or moves the dialog to a screen that has a different font size associated with it. Each screen can have a different font size to handle different screen resolutions. Otherwise, a dialog box that looks fine on a 640 x 480 pixels screen will look too small on a 1280 x 1024 screen. In this case, the user will probably desire a larger font on the second screen.

To make specifying coordinates in terms of characters easier, three constants are defined in dlogbox.h:

#define DCOORD_RESOLUTION 12
#define XC (DCOORD_RESOLUTION/2)
#define YC DCOORD_RESOLUTION

XC can be thought of as the approximate width of one character, and YC as one character height. The formulas for computing dialog dimensions are as follows:

Dialog width = charWidth * XC * FontPixelHeight/DCOORD_RESOLUTION
Dialog height = charHeight * YC * FontPixelHeight/

For example, suppose that screen 0 has a dialog font that is 10 pixels high, and screen 1 has a dialog font that is 18 pixels high. In a resource file, a dialog is defined to have a width of 20*XC and a height of 10*YC. In other words, the dialog will be about 20 "characters" wide and about 10 "characters" tall. On screen 0 the dialog will be 100 pixels wide (20 * 12/2 * 10/12 = 100) and 100 pixels tall (10 * 12 * 10/12 = 100). On screen 1, with the larger dialog font, the dialog will be 120 pixels wide (20 * 12/2 * 18/12 = 120) and 180 pixels tall (10 * 12 * 18/12 = 180). Notice that the pixel width and height of the dialog is the same though different numbers of characters were specified. This is because the definition of XC assumes that a character is half as wide as it is tall.

The GENY macro, defined in dlogbox.h, can be used to convert row numbers to y dialog coordinates. This is useful if there are arranged dialog items. For example, specifying GENY(1) for the y coordinate of one item, and then GENY(2) for a second item will properly vertically position the two items, with an appropriate gap between them. The GENY macro is an example of using a C macro to aid in dialog box construction. Other macros can be created based on GENY if a different spacing scheme is needed.

If the dialog font is 12 pixels high, there is a one-to-one correspondence between dialog coordinates and pixels.

When using dialog box manager calls to perform drawing operations, positions and sizes are usually specified in pixels (not the dialog coordinates used in resource files).

All references to a point use the Point2d structure. All references to a rectangle use the BSIRect structure. Note that these structures use long ints to specify positions. The sextent structure by contrast uses shorts. It uses shorts to save space in resource files where it is used to specify the location of dialog items. Be careful not to do the following:

rect.origin = sextent.origin;

This must be done instead:

rect.origin.x = sextent.origin.x;
rect.origin.y = sextent.origin.y;

These data structures are defined in basetypes.h.

Global coordinates are used to indicate the actual position of a pixel on the screen. The origin of the global coordinate system is the upper-left corner of the screen. Y values increase as one moves toward the bottom of the screen. A screen number must always be specified when drawing directly to the screen.

Text font

All dialog boxes have a current font associated with them. Whenever the width of a character or a string is determined or text is drawn, the dialog box manager uses the current font.

Fonts are specified by a font index. For each screen, MicroStation stores several different font specifications for predefined purposes. For dialog boxes, only two fonts are of interest: those specified by the indexes FONT_INDEX_DIALOG and FONT_INDEX_BOLD. FONT_INDEX_DIALOG is the font index of the standard dialog font and FONT_INDEX_BOLD is the font index of the standard bold dialog font.

Color

Several dialog box manager built-in functions allow the specification of a colorIndex. This is not a direct reference to the MicroStation color table. Instead, it is an index into an array that locates the position within the MicroStation color table of 12 standard colors. See msdefs.h for a list of all the predefined colors.

Most dialog box programmers will not directly draw into a dialog box. If they do, they will mainly be using WHITE_INDEX, LGREY_INDEX, DGREY_INDEX and BLACK_INDEX.

The mdlWindow_lineStyleSet function allows the specification of a direct index into the current design file's color table. It should only be used in very special circumstances (like color picker dialogs). See "Graphic Functions" in the MicroStation MDL Function Reference Manual for more information on drawing with color.

The dialog box manager's internal architecture

Three major sub-systems within MicroStation handle dialog boxes: the dialog box manager functions, the item handler functions, and MDL programmer-supplied hook functions.

The sub-systems communicate by sending various messages. A message is a data structure that has a header that indicates the type of message and a union of additional information that depends on the message type. A function that is used to receive messages gets one and only one argument passed to it: a pointer to a message structure. It replies by setting various fields in the message itself.

All user interaction and most programmer interaction with a dialog box first goes through a dialog box manager routine. The dialog box manager routines control the general flow of user interaction with the dialogs. These routines know the basic information about a dialog box such as its position and size, and the position, size, and type of items within the dialog box. In particular, these routines have access to an array of DialogItem that is contained in memory for each dialog box. See DialogItemRscStructure for more information. The dialog box manager routines have no knowledge about the details of specific dialog item types. That knowledge is contained in the dialog item handlers.

A dialog item handler is a loadable MDL module that contains all the default functionality associated with a type of dialog item. Every dialog item has a resource type associated with it. This type is used to specify a structure that is initialized in a resource file-the item resource specification. It also determines which item handler will be sent messages when the dialog box manager routines need to manipulate the item.

The item handler for a dialog item type knows how to create, destroy, draw, move, resize, get the value of, and set the value of that type of item. If applicable, it also knows how to respond to mouse button presses or releases inside the item, or how to accept keystrokes. If the item type can automatically control an application variable, the item handler knows how to get and set the item's external state.

A hook function is an MDL programmer-written function that can be used to modify the default behavior of the dialog box manager functions and the item handler functions. A hook function can be attached to a dialog box, in which case it is a dialog hook function, or to an individual dialog item, in which case it is an item hook function. Item hook functions are generally used to implement inter-item communications, where changing the state of one item requires the simultaneous complex change of other items. Keep in mind that this situation can sometimes also be handled by the judicious use of synonym resources. Dialog hook functions are usually used to allocate and initialize data structures that will be used throughout the life of a dialog box by certain dialog items.

Generally, some user action will cause the dialog box manager to send a message to the appropriate item handler with an indication of which specific item is to receive the message. The item handler can then optionally pass the message on to an MDL programmer-supplied item hook function to see if the hook function wants to handle that type of message. If it does, the item handler will typically just return without further action. If the item hook function does not want to handle that type of message or if there isn't an item hook function attached to the item, then the item handler will perform its default processing for that type of message. The item handler or item hook function can set various fields in a message to return information to the function that sent the message.

Each item handler can decide whether and when to pass messages on to an attached item hook function. Therefore, it is important to carefully read the item type description of an item to determine which messages will be sent to a particular item hook function. See ItemHookFunctions for more information.

In addition to an item hook function, which is attached to a specific item and is only sent messages relevant to that item, a dialog hook function can be attached to the entire dialog box. Dialog hook functions are sent messages whenever a user interaction occurs anywhere in the dialog box to which it is attached. The dialog box manager routines directly send messages to dialog hook functions. They are not sent first to item handler functions. Whether a message is sent to a dialog hook function does not depend on the item for which the message is ultimately destined. Instead, the messages the MDL programmer has said the dialog hook function is interested in determine whether a message is sent. After that the hook function will only be sent those types of messages.

For example, suppose that the user moves a dialog box on the screen. The dialog box has one toggle button item inside it. There is a dialog hook function, which has indicated an interest in update messages, attached to the dialog box and an item hook function attached to the toggle button. The following sequence of events occurs:

Since the dialog box manager routines have no built-in knowledge about specific items (all it knows is the type of items), it is very simple to add new item types by publishing new item handlers. No changes need to be made to any of the dialog box manager routines themselves to support new item types.

Hook function IDs

When referencing hook functions within a resource file, a long integer ID is specified. To avoid conflicts with other developers, MicroStation uses negative numbers for its hook function IDs. Other developers should only use positive numbers for their hook function IDs. Note that dialog hook function IDs and item hook function IDs use the same number space. Number space is akin to name space or the concept of scope, in that it is an area reserved for references, and no members within that area can be identical. In other words, the number 1 cannot be used for both a dialog hook function ID and an item hook function ID.

Hook function ID numbers should be defined in the same file in which resource IDs (such as item resource ID numbers and dialog box resource ID numbers) are defined. This file will then be included in both an application's resource files and in the MDL program file that contains the main function.

To make an application's hook functions visible to the dialog box manager, the hook function ID numbers and hook function addresses need to be published with a call to the mdlDialog_hookPublish function. Once this function is called, the dialog box manager can determine the address of the appropriate hook function when given a hook function ID number.


Copyright © 2017 Bentley Systems, Incorporated. All rights reserved.