Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: More Macintosh Toolbox /
Chapter 3 - Help Manager / Using the Help Manager


Providing Help Balloons for Dynamic Windows

To create help balloons for objects whose location in the content area of windows may vary, your application needs to use Help Manager routines to display and remove balloons as the user moves the cursor.

Note
Nonprogrammers can use the BalloonWriter tool to provide you with delimited ASCII text that you can then use in conjunction with Help Manager routines to display balloons for dynamic windows. However, BalloonWriter does not create the resources or routines necessary to automatically display help balloons for these types of windows.
You should display or remove help balloons for dynamic windows at the same time that you normally check the mouse location to display or change the cursor. For example,
if you provide your own DoIdle procedure (as described in the chapter "Event Manager" in Inside Macintosh: Macintosh Toolbox Essentials), you can also check the mouse location and, if the cursor is located in a hot rectangle, you should display the associated help balloon.

To create help balloons for the content area of a dynamic window, you need to

After defining all the hot rectangles within your content region, create separate 'STR ', 'STR#', 'PICT', or 'TEXT' and 'styl' resources for the help balloons' messages. You don't have to store the help messages in these resources when using HMShowBalloon, but doing so makes your application easier to localize.

When you use the HMShowBalloon function, your application is responsible for tracking the cursor and determining when to display the help balloon. If you use the HMShowBalloon function, you can let the Help Manager track the cursor and determine when to remove the help balloon, or your application can remove the balloon when necessary by calling the HMRemoveBalloon function. If you display your own help balloons using the HMShowBalloon function, you should use the HMGetBalloons function to determine whether help is enabled before displaying a help balloon. If help is not enabled, you don't need to call any Help Manager routines that display balloons, because they won't do anything unless HMGetBalloons returns TRUE.

The HMShowBalloon function is useful for

For example, windows with scrolling icons (such as the Users & Groups dynamic window shown in Figure 3-18 on page 3-59) require you to use HMShowBalloon to display help balloons for the icons. Likewise, if you have tools--such as rulers that users configure for tab stops in a word-processing document--that scroll with a document, you'll need to use HMShowBalloon to display help balloons for the scrolling tools.

When using HMShowBalloon, you specify the help message, the balloon tip's coordinates, an alternate rectangle to use if the Help Manager needs to move the tip, an optional pointer to a function that can modify the tip and alternate rectangle coordinates, the balloon definition function, and the variation code. In the final parameter to the HMShowBalloon function, provide a constant that tells the Help Manager whether to save the bits behind the balloon.

myErr := HMShowBalloon(aHelpMsg, tip, alternateRect, tipProc, 
                       theProc, variant, method);
Specify the help message in a help message record, which you pass in the aHelpMsg parameter to the HMShowBalloon function. You can specify the help message for each hot rectangle using text strings, 'STR ' resources, 'STR#' resources, styled text resources, 'PICT' resources, handles to styled text records, or handles to pictures.

The HMMessageRecord data type defines the help message record.

TYPE HMMessageRecord = 
RECORD
   hmmHelpType:         Integer;             {type of next field}
   CASE Integer OF
      khmmString:       (hmmString: Str255); {Pascal string}
      khmmPict:         (hmmPict: Integer);  {'PICT' resource ID}
      khmmStringRes:    (hmmStringRes: HMStringResType); 
                                             {'STR#' resource }
                                             { ID and index}
      khmmTEHandle:     (hmmTEHandle: TEHandle);
                                             {TextEdit handle}
      khmmPictHandle:   (hmmPictHandle: PicHandle); 
                                             {picture handle}
      khmmTERes:        (hmmTERes: Integer); {'TEXT'/'styl' }
                                             { resource ID}
      khmmSTRRes:       (hmmSTRRes: Integer);{'STR ' resource ID}
END;
The hmmHelpType field specifies the data type of the second field of the help message record. You specify one of these constants for the hmmHelpType field.

CONST khmmString        = 1;     {Pascal string}
      khmmPict          = 2;     {'PICT' resource ID}
      khmmStringRes     = 3;     {'STR#' resource ID and index}
      khmmTEHandle      = 4;     {TextEdit handle}
      khmmPictHandle    = 5;     {picture handle}
      khmmTERes         = 6;     {'TEXT' and 'styl' resource ID}
      khmmSTRRes        = 7;     {'STR ' resource ID}
You specify the help message itself in the second field of the help message record.

You can specify the help message by using a text string, a text string stored in a resource of type 'STR ', or a text string stored as an 'STR#' resource. You can also provide the information using styled text resources, or you can provide a handle to a styled text record. If you want to provide a picture for the help message, you can use a resource of type 'PICT' or provide a handle to a picture.

Listing 3-11 illustrates how to specify a Pascal string using the khmmString constant in the help message record. (Although you can specify a string from within your code, storing the strings in resources and then accessing them through the Resource Manager makes localization easier.)

Listing 3-11 Using a string resource as the help message for HMShowBalloon

PROCEDURE DoTextStringBalloon;
VAR
   aHelpMsg:         HMMessageRecord;
   tip:              Point;
   alternateRect:    RectPtr;
   err:              OSErr;
BEGIN
   aHelpMsg.hmmHelpType := khmmString;
   aHelpMsg.hmmString := 'To turn the page, click here.';
   MySetTipAndAltRect(tip, alternateRect); {initialize values}
   err := HMShowBalloon(aHelpMsg, tip, alternateRect,
                        NIL, 0, 0, kHMRegularWindow);
END;
To use a picture, you can either store the picture as a 'PICT' resource or create the 'PICT' graphic from within your application and provide a handle to it. Because the Help Manager uses the resource itself or the actual handle that you pass to HMShowBalloon, your 'PICT' resource should be purgeable, or, when using a handle to a 'PICT' resource, you should release the handle or dispose of it when you are finished with it.

Listing 3-12 illustrates how to use the khmmPict constant for specifying a 'PICT' resource ID in a help message record. The help message record is then passed in the aHelpMsg parameter of the HMShowBalloon function.

Listing 3-12 Using a picture resource as the help message for HMShowBalloon

PROCEDURE DoPictBalloon;
VAR
   aHelpMsg:         HMMessageRecord;
   tip:              Point;
   alternateRect:    RectPtr;
   err:              OSErr;
BEGIN
   aHelpMsg.hmmHelpType := khmmPict;
   aHelpMsg.hmmPict := 128;      {resource ID of 'PICT' resource}
   MySetTipAndAltRect(tip, alternateRect); {initialize values}
   err := HMShowBalloon(aHelpMsg, tip, alternateRect,
                        NIL, 0, 0, kHMRegularWindow);
END;
Listing 3-13 illustrates how to specify a handle to a 'PICT' resource using the khmmPictHandle constant in the help message record. The help message record is then passed to the HMShowBalloon function in the aHelpMsg parameter.

Listing 3-13 Using a handle to a picture resource as the help message for HMShowBalloon

PROCEDURE DoPictBalloon2;
VAR
   pict:          PicHandle;
   aHelpMsg:      HMMessageRecord;
   tip:           Point;
   pictFrame:     Rect;
   alternateRect: RectPtr;
   err:           OSErr;
BEGIN
   MySetPictFrame(pictFrame); {initialize pictFrame}
   pict := OpenPicture(pictFrame);
   DrawString('Test Balloon');
   ClosePicture;
   aHelpMsg.hmmHelpType := khmmPictHandle;
   aHelpMsg.hmmPictHandle := pict;
   MySetTipAndAltRect(tip, alternateRect); {initialize values}
   err := HMShowBalloon(aHelpMsg, tip, alternateRect,
                        NIL, 0, 0, kHMRegularWindow);
   KillPicture(pict);
END;
To specify a help message stored in a string list ('STR#' resource) in a help message record, you must first create a Help Manager string list record. The HMStringResType data type defines a Help Manager string list record.

TYPE HMStringResType = 
RECORD
   hmmResID:   Integer;    {resource ID of 'STR#' resource}
   hmmIndex:   Integer;    {index of string}
END;
The hmmResID field specifies the resource ID of the 'STR#' resource, and the hmmIndex field specifies the index of a string within that resource.

To use a string stored in an 'STR#' resource with the HMShowBalloon function, use the khmmStringRes constant in the hmmHelpType field of the help message record, and supply the hmmStringRes field with a Help Manager string list record, as shown in Listing 3-14.

Listing 3-14 Using a string list resource as the help message for HMShowBalloon

PROCEDURE DoStringListBalloon;
VAR
   aHelpMsg:         HMMessageRecord;
   tip:              Point;
   alternateRect:    RectPtr;
   khmmStringRes:    HMStringResType;
   err:              OSErr;
BEGIN
   aHelpMsg.hmmHelpType := khmmStringRes;
   aHelpMsg.hmmStringRes.hmmResID := 1000;
   aHelpMsg.hmmStringRes.hmmIndex := 1;
   MySetTipAndAltRect(tip, alternateRect); {initialize values}
   err := HMShowBalloon(aHelpMsg, tip, alternateRect,
                        NIL, 0, 0, kHMRegularWindow);
END;
To use styled text resources with the HMShowBalloon function, use the khmmTERes constant in the hmmHelpType field of the help message record. In the next field, supply a resource ID that is common to both a 'TEXT' resource and a style scrap ('styl') resource. For example, you might create a 'TEXT' resource that contains the words "Displays your text in boldface print." You would also create a 'styl' resource (with the same resource ID as the 'TEXT' resource) that applies boldface style to the word "boldface." When you specify the HMTEResItem constant and the resource ID number of the 'TEXT' and 'styl' resources, the Help Manager employs TextEdit routines to display your text with your prescribed styles.

To use a handle to a styled text record, supply the khmmTEHandle constant in the hmmHelpType field, as illustrated in Listing 3-15.

Listing 3-15 Using styled text resources as the help message for HMShowBalloon

PROCEDURE DoStyledTextBalloon;
VAR
   aHelpMsg:         HMMessageRecord;
   tip:              Point;
   alternateRect:    RectPtr;
   hTE:              TEHandle;
   err:              OSErr;
BEGIN
   hTE := TEStyleNew(destRect, viewRect);    {or, use TENew}
   {be sure to fill in data in handle here}
   aHelpMsg.hmmHelpType := khmmTEHandle;
   aHelpMsg.hmmTEHandle := hTE;
   MySetTipAndAltRect(tip, alternateRect); {initialize values}
   err := HMShowBalloon(aHelpMsg, tip, alternateRect,
                        NIL, 0, 0, kHMRegularWindow);
END;
When using the HMShowBalloon function, you specify the tip in the tip parameter and the rectangle pointed to in the alternateRect parameter in global coordinates. The Help Manager calculates the location and size of the help balloon. If the help balloon fits onscreen, the Help Manager displays the help balloon using the specified tip.

If you use the previously described help resources to define help balloons, the Help Manager uses the hot rectangles you specify in the help resources for two purposes: first, to associate areas of the screen with help balloons and, second, to move the tip if the help balloon doesn't fit onscreen.

However, if you use the HMShowBalloon function to display help balloons, you must identify hot rectangles, create your own data structures to store their locations, track the cursor yourself, and call HMShowBalloon when the cursor moves to your hot rectangles. The Help Manager does not know the locations of your hot rectangles, so it cannot use them for moving the tip if the help balloon is placed offscreen. Instead, the Help Manager uses the alternate rectangle that you point to with the alternateRect parameter. Often, you specify the same coordinates for the alternate rectangle that you specify for your hot rectangle. However, you may choose to make your alternate rectangle smaller or larger than your hot rectangle. If you make your alternate rectangle smaller than your hot rectangle, you have greater assurance that the Help Manager will be able to fit the help balloon onscreen; if you specify an alternate rectangle that is larger than your hot rectangle, you have greater assurance that the help balloon will not obscure some object explained by the balloon.

By specifying a rectangle in the alternateRect parameter, you tell the Help Manager to call HMRemoveBalloon to automatically remove the balloon when the cursor leaves the area bounded by the rectangle. However, if you specify NIL for the alternateRect parameter, your application is responsible for tracking the cursor and determining when to remove the help balloon. When you specify NIL, the Help Manager also does not attempt to calculate a new tip position if the help balloon is offscreen.

Use the tipProc parameter (the fourth parameter to HMShowBalloon) to specify the tip function called by the Help Manager before displaying the balloon. Specify NIL to use the Help Manager's default tip function, or supply your own tip function and point to it in this parameter. Writing your own tip function is described in "Application-Defined Routines" beginning on page 3-120.

Note
When you call the HMShowBalloon function, the Help Manager does not display the help balloon or attempt to move the tip under either of these conditions:
The help balloon's tip is offscreen or in the menu bar, and you don't specify an alternate rectangle.
Both the help balloon's tip and the alternate rectangle are offscreen.
Use the parameter theProc (the fifth parameter) to specify a balloon definition function. To use the standard balloon definition function, specify 0 in this parameter. To use your own balloon definition function, specify the resource ID of the 'WDEF' resource containing your balloon definition function. Writing your own balloon definition function is described in "Writing Your Own Balloon Definition Function" on page 3-86.

Supply a variation code for the balloon definition function in the variant parameter (the sixth parameter to HMShowBalloon). Specify 0 in the variant parameter to use the default help balloon shape, specify a code from 1 to 7 to use one of the other positions provided by the standard balloon definition function, or specify a code to use one of the positions provided by your own balloon definition function.

Use the method parameter (the last parameter to HMShowBalloon) to specify how the Help Manager should draw and remove the balloon. Use the following constants for the parameter.

CONST kHMRegularWindow     = 0;  {don't save bits; just update}
      kHMSaveBitsNoWindow  = 1;  {save bits; don't do update}
      kHMSaveBitsWindow    = 2;  {save bits; do update event}
If you specify kHMRegularWindow, the Help Manager draws and removes the help balloon as if it were a window. That is, when drawing the balloon, the Help Manager does not save bits behind the balloon, and when removing the balloon, the Help Manager generates an update event. This is the standard behavior of help balloons; it is the behavior you should normally use.

If you specify kHMSaveBitsNoWindow in the method parameter, the Help Manager does not create a window for displaying the balloon. Instead, the Help Manager creates a help balloon that is more like a menu than a window. The Help Manager saves the bits behind the balloon when it creates the balloon. When it removes the balloon, the Help Manager restores the bits without generating an update event. You should use this technique only in a modal environment where the bits behind the balloon cannot change from the time the balloon is drawn to the time it is removed. For example, you might specify the kHMSaveBitsNoWindow constant when providing help balloons for pop-up menus that overlay complex graphics, which might take a long time to redraw with an update event.

If you specify kHMSaveBitsWindow, the Help Manager treats the help balloon as a hybrid having properties of both a menu and a window. That is, the Help Manager saves the bits behind the balloon when it creates the balloon, and when it removes the balloon, it both restores the bits and generates an update event. You'll rarely need this option. It is necessary only in a modal environment that might immediately change to a nonmodal environment--that is, where the bits behind the help balloon are static when the balloon is drawn, but can possibly change before the help balloon is removed.

Listing 3-16 shows a sample routine that displays help balloons for hot rectangles within the content area of a window.

Listing 3-16 Using HMShowBalloon to display help balloons

PROCEDURE FindAndShowBalloon (window: WindowPtr);
VAR
   i:          Integer;
   mouse:      Point;
   savePort:   GrafPtr;
   helpMsg:    HMMessageRecord;
   inRect:     Boolean;
   hotRect:    Rect;
   result:     OSErr;
BEGIN
   IF (window = FrontWindow) THEN      {only do frontmost windows}
   BEGIN
      GetPort(savePort);   {save the old port for later}
      SetPort(window);     {set the port to the front window}
      GetMouse(mouse);     {get the mouse location in local }
                           { coords}
      inRect := FALSE;     {clear flag saying mouse location }
                           { wasn't in any hot rectangle}
      IF PtInRect(mouse, window^.portRect) THEN 
         {if the cursor is in the window}

         FOR i := 1 TO 10 DO  {check all ten predefined hot }
                              { rectangles in the window}
            IF PtInRect(mouse, MyPredefinedRects[i]) THEN
            BEGIN             {the cursor is in a hot rectangle}
               IF (i <> gLastBalloon) THEN 
               {user moved cursor to a different hot rectangle}
               BEGIN
                  hotRect := MyPredefinedRects[i];
                  LocalToGlobal(hotRect.topLeft);
                  {converting rect to global}
                  LocalToGlobal(hotRect.botRight);
                  WITH hotRect DO   {put the tip in the middle}
                     SetPt(mouse, (right + left) div 2, 
                           (bottom + top) div 2);
                  helpMsg.hmmHelpType := khmmStringRes;
                  {get help message from an 'STR#' resource}
                  helpMsg.hmmStringRes.hmmResID := kHelpMsgsID;
                  helpMsg.hmmStringRes.hmmIndex := i;
                  result := HMShowBalloon
                              (helpMsg,   {use just-made help msg}
                               mouse,     {pointing to this tip}
                               @MyPredefinedRects[i], {use hot }
                                          { rect for alt rect}
                               NIL,       {no special tip proc}
                               0,0,       {using default balloon}
                        kHMRegularWindow);{don't save bits behind}
                  IF (result = noErr) THEN {then remember balloon}
                     gLastBalloon := i;
               END;
               inRect := TRUE;   {remember when the }
                                 { cursor is in any hot rect}
            END;
      IF not inRect THEN
         gLastBalloon := -1;     {clear last balloon global for }
                                 { no hit}
      SetPort(savePort);         {restore the port}
   END;
END;     {FindAndShowBalloon}
The FindAndShowBalloon procedure in Listing 3-16 tracks the cursor, and, if the cursor is located in a predefined hot rectangle, it displays a help balloon for that rectangle. In this example there are ten predefined rectangles (in the MyPredefinedRects array) and ten corresponding help messages in an 'STR#' resource (of ID kHelpMsgsID)--one message for each hot rectangle. Other supporting routines can update the coordinates of the hot rectangles as their locations change.

You can also use the HMShowBalloon function from the event filter function of a modal dialog box or an alert box. See the chapter "Dialog Manager" in Inside Macintosh: Macintosh Toolbox Essentials for information on event filter functions.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996