Messenger
Volume Number: 6
Issue Number: 4
Column Tag: Programmer's Workshop
Messenger Delivers 
By Kirk Chase, Anaheim, CA
Got The Message?
I was going over the editorial calendar for MacTutor a few weeks back. I was
trying to schedule all the fine articles we have on file for future publication. In short,
I was trying to do the impossible. But I do get a feeling of “accomplishment” if I come
away without feeling terrible for not placing everyone’s article or without a headache.
To continue, I came across Paul Potts article, and scheduled it for April for our
“Dialog” issue. I chided myself for not being as good with my modal dialogs. It was so
easy to make them a little more friendlier to the user. I decided to come up with a set
of useful dialog routines of my own.
When writing an application, there are many dialogs that are similar in nature.
They usually have one to three buttons with a message similar to, “Save changes to
”, “You cannot do that!”, or “I am deleting all funds in your Swiss bank account.” If
you’re like most people, you have a general dialog box and a general set of routines to
put it up with your message in it. It is usually not as robust as it should be. I decided
to write a few routines for a general message dialog, Messenger.
Messenger Structure
The heart of messenger is located in the global variable, MInfo. This structure
contains the information needed to put up a dialog box with/without an icon and from 0
to 3 buttons. The structure is declared as follows:
/* 1 */
typedef struct DialogInfo {
short defaultItem;
int Buttons;
int dPlace;
short dIcon;
Rect IconRect;
Rect Button1Rect;
Rect Button2Rect;
Rect Button3Rect;
Rect TextRect;
Rect dRect;
int Arrange;
ProcPtr AddFilter;
Str255 Button1;
Str255 Button2;
Str255 Button3;
Str255 CharEquiv;
} DialogInfo, *DialogInfoPointer, **DialogInfoHandle;
extern DialogInfo MInfo;
defaultItem: Indicates the button considered the default, or the button which
responds to return or enter key. It draws a bold, rounded rectangle around that button.
Buttons: The number of buttons in the dialog. Valid numbers are 0 through 3. If
there are 0 buttons then a mouse click, return, or enter will exit the dialog.
dPlace: The dialog is placed in the center or top third of the screen.
dIcon: Specifies the resource ID of the icon or -1 if no icon. You may call the
stop, note, or caution icons with their appropriate constant values.
IconRect, Button1Rect, Button2Rect, Button3Rect, TextRect, and dRect: These
are the enclosing rectangles for the icon, buttons, text, and dialog. You need only set
the top left point to (0,0) and the bottom right point to the width and height of the
object. The dialog handler will take care of positioning them for you.
Button1, Button2, Button3: The titles of the buttons to display.
CharEquiv: The character equivalents for the buttons. Two characters may be
specified for each button: the first two for button 1, the next two for button 2, and the
last two for button 3.
Arrange: This flag has a valid value of HORIZONTAL or VERTICAL, depending on if
you want your buttons across the bottom or down the right side.
AddFilter: In addition to the Messenger’s own filter proc which handles character
equivalents, updates, and so forth, an additional filter may be designated for further
processing. Just pass nil if none, or pass a filter proc of the form:
/* 2 */
pascal Boolean MyFilter(itemHit, theDialog);
itemHit is the item number of the dialog hit; theDialog is the dialog pointer, and
you return true if you wish to exit the modal dialog loop and false if not.
Messenger Routines and Globals
menu_height: This is a global of the height in pixels the menu is. It is initialized
in InitMessage().
InitMessage: This call is made to put valid values in the MInfo structure. You
may modify them to your default dialog style. Call this at the beginning of your
application and whenever you wish to reset the default values.
GetMInfo, SetMInfo: I like those calls to GetPort and SetPort, and so I have
implemented similar calls. With GetMInfo, you store the old values of MInfo, and with
SetMInfo, you set it to your values.
DoMessage: This is the main routine that does all the work. It takes the values in
MInfo, creates the dialog, arranges the items, sets the ParamText with the strings you
pass, and calls ModalDialog. It returns the number of the last item hit, or 0 if
something went wrong.
Message: This is a standard, general dialog routine. It handles those dialogs with
familiar button titles such as “OK”.
There are a few other routines, such as positioning a small rectangle in the
center or the top third of a larger rectangle (such as screenBits.bounds). The routine
will find the top third or center line of the larger rectangle and then centers the
smaller rectangle on that line. BoldRect() is used for hiliting the default button.
SaveChanges() allows you to pass the file name and a “before closing/quitting” string.
AnOSError() is an error handler that returns FALSE if no error is passed to it;
otherwise it puts up an appropriate dialog and returns TRUE.
The Code
Messenger.h: This is the header file for Messenger. Include this file in your
main routine to call InitMessage, and also include it in every file that makes use of the
Messenger routines.
Messenger.c: This is the code for Messenger. I would suggest, again, that you
change InitMessage to the set up that you are most likely to use in your application.
About.c: In this file, there are a couple of examples of how to use Messenger.
The D_About procedure puts up an About dialog. D_Example procedure shows the use
of the additional filter procedure.
Messenger.r: This is the resource file for messenger. Be sure to include it in