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: Macintosh Toolbox Essentials /
Chapter 5 - Control Manager / Using the Control Manager


Determining and Changing Control Settings

Using either the control resource or the parameters to the NewControl function, your application specifies a control's various default values--such as its current setting and minimum and maximum settings--when it creates the control.

When the user clicks a control, however, your application often needs to determine
the current setting and other possible values of that control. When the user clicks a checkbox, for example, your application must determine whether the box is checked before your application can decide whether to clear or draw a checkmark inside the checkbox. When the user moves the scroll box, your application needs to determine what part of the document to display.

Applications must adjust some controls in response to events other than mouse events in the controls themselves. For example, when the user resizes a window, your application must use the Control Manager procedures MoveControl and SizeControl to move and resize the scroll bars appropriately.

Your application can use the GetControlValue function to determine the current setting of a control, and it can use the GetControlMaximum function to determine a control's maximum setting.

You can use the SetControlValue procedure to change the control's setting and redraw the control accordingly. You can use the SetControlMaximum procedure to change a control's maximum setting and to redraw the indicator or scroll box to reflect the new setting.

In response to user action involving a control, your application often needs to change the setting and possibly redraw the control. When the user clicks a checkbox, for example, your application must determine whether the checkbox is currently selected or not, and then switch its setting. When you use SetControlValue to switch a checkbox setting, the Control Manager either draws or removes the X inside the checkbox, as appropriate. When the user clicks a radio button, your application must determine whether the radio button is already on and, if not, turn the previously selected radio button off and turn the newly selected radio button on.

Figure 5-15 on page 5-31 shows a checkbox in the Play Sounds window. When the user clicks the checkbox to turn it on, the application adds a drum roll to the sound it plays whenever the user clicks the Play button.

Listing 5-13 shows the application-defined routine DoDrumRollCheckBox, which responds to a click in a checkbox. This routine uses the GetControlValue function to determine the last value of the checkbox and then uses the SetControlValue procedure to change it. The GetControlValue function returns a control's current setting, which is stored in the contrlValue field of the control record. The SetControlValue procedure sets the contrlValue field to the specified value and redraws the control to reflect the new setting. (For checkboxes and radio buttons, the value 1 fills the control with the appropriate mark, and the value 0 removes the mark. For scroll bars, SetControlValue redraws the scroll box at the appropriate position along the scroll bar. For a pop-up menu, SetControlValue displays in its pop-up box the name of the menu item corresponding to the specified value.)

Listing 5-13 Responding to a click in a checkbox

PROCEDURE DoDrumRollCheckBox (mouse: Point; control: ControlHandle);
VAR
   checkbox:Integer;
BEGIN          
   IF TrackControl(control, mouse, NIL) <> 0 THEN  {user clicks checkbox}
   BEGIN
      checkbox := GetControlValue(control);  {get last value of checkbox}
      checkbox := 1 - checkbox;              {toggle value of checkbox}
      SetControlValue(control, checkbox);    {set checkbox to new value}
      IF checkbox = 1 THEN                   {the checkbox is checked}
         gPlayDrumRoll := TRUE {play a drum roll next time user clicks Play}
      ELSE
         gPlayDrumRoll := FALSE;
   END;
END;
The DoDrumRollCheckBox routine uses TrackControl to determine which control the user selects. When TrackControl reports that the user clicks the checkbox, DoDrumRollCheckBox uses GetControlValue to determine whether the user last selected the checkbox (that is, whether the control has a current setting of 1) or deselected it (in which case, the control has a current setting of 0). By subtracting the control's current setting from 1, DoDrumRollCheckBox toggles to a new setting
and then uses SetControlValue to assign this new setting to the checkbox. The SetControlValue procedure changes the current setting of the checkbox and redraws it appropriately, by either drawing an X in the box if the new setting of the control is 1 or removing the X if the new setting of the control is 0.

Listing 5-4 on page 5-20 shows the control resources that specify a window's scroll bars, and Listing 5-5 on page 5-21 shows an application's DoNew routine for creating a document window with these scroll bars. This routine uses the GetNewControl function to create the scroll bars and then calls an application-defined routine, MyAdjustScrollBars. Listing 5-14 shows MyAdjustScrollBars, which in turn
calls other application-defined routines that determine the proper sizes, locations,
and maximum settings of the scroll bars.

Listing 5-14 Adjusting scroll bar settings and locations

PROCEDURE MyAdjustScrollBars (window: WindowPtr; 
                              resizeScrollBars: Boolean);
VAR
   myData: MyDocRecHnd;
BEGIN
   myData := MyDocRecHnd(GetWRefCon(window));
   HLock(Handle(myData));
   WITH myData^^ DO
   BEGIN
      HideControl(vScrollBar);   {hide the vertical scroll bar}
      HideControl(hScrollBar);   {hide the horizontal scroll bar}
      IF resizeScrollBars THEN   {move and size if needed}
         MyAdjustScrollSizes(window);
      MyAdjustScrollValues(window, NOT resizeScrollBars);
      ShowControl(vScrollBar);   {show the vertical scroll bar}
      ShowControl(hScrollBar);   {show the horizontal scroll bar}
   END;
   HUnLock(Handle(myData));
END; {of MyAdjustScrollbars}
When calling the DoOpen routine to open an existing document in a window,
SurfWriter also uses this MyAdjustScrollBars procedure to size and adjust the
scroll bars. When the user changes the window's size, the SurfWriter application
uses MyAdjustScrollBars again.

The MyAdjustScrollBars routine begins by getting a handle to the window's document record, which stores handles to the scroll bars as well as other relevant data about the document. (See the chapter "Window Manager" in this book for information about creating your application's own document record for a window.)

Before making any adjustments to the scroll bars, MyAdjustScrollBars passes the handles to these controls to the Control Manager procedure HideControl, which makes the controls invisible. The MyAdjustScrollBars routine then calls another application-defined procedure, MyAdjustScrollSizes (shown in Listing 5-24 on page 5-61), to move and resize the scroll bars appropriately. After calling yet another application-defined procedure, MyAdjustScrollValues, to set appropriate current and maximum settings for the scroll bars, MyAdjustScrollBars uses the Control Manager procedure ShowControl to display the scroll bars in their new locations.

Listing 5-15 shows how the MyAdjustScrollValues procedure calls another application-defined routine, MyAdjustHV, which uses Control Manager routines to assign appropriate settings to the scroll bars.

Listing 5-15 Assigning settings to scroll bars

PROCEDURE MyAdjustScrollValues (window: WindowPtr);
VAR
   myData: MyDocRecHnd;
BEGIN
   myData := MyDocRecHnd(GetWRefCon(window));
   HLock(Handle(myData));
   WITH myData^^ DO
   BEGIN
      MyAdjustHV(TRUE, vScrollBar, editRec);
      MyAdjustHV(FALSE, hScrollBar, editRec);
   END;
   HUnLock(Handle(myData));
END; {of MyAdjustScrollValues}
To prevent the user from scrolling past the edge of the document and seeing a blank window, you should limit the scroll bars' maximum settings, as illustrated in Figure 5-6 on page 5-9. If the window is larger than the document (which can easily happen with small documents on large monitors), your application should make the maximum scroll bar settings identical to their minimum settings. In this case, the Control Manager then makes the scroll bars inactive, which is appropriate when all the information fits in
the window.

Listing 5-16 shows the application-defined MyAdjustHV procedure, used for adjusting the current and maximum settings for a scroll bar. When passed TRUE in the isVert parameter, MyAdjustHV calculates and adjusts the maximum and current settings for the vertical scroll bar; when passed FALSE, it calculates and adjusts those settings for the horizontal scroll bar.

In this example, the document consists of monostyled text stored in a TextEdit edit record. The viewRect field of a TextEdit edit record specifies the rectangle where the text is visible; because viewRect already excludes the scroll bar regions, MyAdjustHV does not need to subtract the scroll bar regions from the window height or width when calculating the maximum settings for these scroll bars. (For more information about TextEdit in general and the edit record in particular, see Inside Macintosh: Text.)

Listing 5-16 Adjusting the maximum and current settings for a scroll bar

PROCEDURE MyAdjustHV (isVert: Boolean; control: ControlHandle; 
                      editRec: TEHandle);
VAR
   oldValue, oldMax, width:   Integer;
   max, lines, value:         Integer;
BEGIN
   {calculate new maximum and current settings for the vertical or }
   { horizontal scroll bar}
   oldMax := GetControlMaximum(control);
   oldValue := GetControlValue(control);
   MyGetDocWidth(width);
   IF isVert THEN    {adjust max setting for the vertical scroll bar}
   BEGIN
      lines := editRec^^.nLines;
      {since nLines isn't right if the last character is a carriage }
      { return, check for that case}
      IF Ptr(ORD(editRec^^.hText^) + editRec^^.teLength - 1)^ = kCRChar THEN
         lines := lines + 1;
      max := lines - ((editRec^^.viewRect.bottom - editRec^^.viewRect.top)
                      DIV editRec^^.lineHeight);
   END
   ELSE           {adjust max setting for the horizontal scroll bar}
      max := width - (editRec^^.viewRect.right - editRec^^.viewRect.left);
   IF max < 0 THEN
      max := 0;   {check for negative settings}
   SetControlMaximum(control, max); {set the max value of the control}
   IF isVert THEN {adjust current setting for vertical scroll bar}
      value := (editRec^^.viewRect.top - editRec^^.destRect.top)
                DIV editRec^^.lineHeight
   ELSE           {adjust current setting for the horizontal scroll bar}
      value := editRec^^.viewRect.left - editRec^^.destRect.left;
   IF value < 0 THEN
      value := 0
   ELSE IF value > max THEN
      value := max;  {don't allow current setting to be greater than the }
                     { maximum setting}
   SetControlValue(control, value);
END; {of MyAdjustHV}
The MyAdjustHV routine first uses the GetControlMaximum and GetControlValue functions to determine the maximum and current settings for the scroll bar
being adjusted.

Then MyAdjustHV calculates a new maximum setting for the case of a vertical scroll bar. Because the window displays a text-only document, MyAdjustHV uses the nLines field of the edit record to determine the total number of lines in--and hence, the length of--the document. Then MyAdjustHV subtracts the calculated height of the window from the length of the document, and makes this value the maximum setting for the vertical scroll bar.

To calculate the total height in pixels of the window, MyAdjustHV begins by subtracting the top coordinate of the view rectangle from its bottom coordinate. (The upper-left corner of a window is normally at point [0,0]; therefore the vertical coordinate of a
point at the bottom of a rectangle has a larger value than a point at the top of the rectangle.) Then MyAdjustHV divides the pixel height of the window by the value of
the edit record's lineHeight field, which for monostyled text specifies the document's line height in pixels. By dividing the window height by the line height of the text, MyAdjustHV determines the window's height in terms of lines of text.

The MyAdjustHV routine uses another application-defined routine, MyGetDocWidth,
to determine the width of the document. To calculate the width of the window, MyAdjustHV subtracts the left coordinate of the view rectangle from its right coordinate. By subtracting the window width from the document width, MyAdjustHV derives the maximum setting for the horizontal scroll bar.

For both vertical and horizontal scroll bars, MyAdjustHV assigns a maximum setting of 0 whenever the window is larger than the document--for instance, when a window is created for a new document that contains no data yet. In this case, MyAdjustHV assigns the same value, 0, to both the maximum and current settings for the scroll bar. The standard control definition function for scroll bars automatically makes a scroll bar inactive when its minimum and maximum settings are identical. This is entirely appropriate, because whenever the user has nowhere to scroll, the scroll bar should be inactive. When you make the maximum setting exceed the minimum, the control definition function makes the scroll bar active again.

The MyAdjustHV routine then uses the Control Manager procedure SetControlMaximum to assign the newly calculated maximum settings to either
scroll bar. The SetControlMaximum procedure revises the control to reflect the new maximum setting; for example, if the user deletes a large portion of the document, thereby reducing the maximum setting, SetControlMaximum moves the scroll box
to indicate the new position relative to the smaller document.

When the user adds information to or removes information from a document or adjusts its window size, your application may need to adjust the current setting of the scroll bar as well. The MyAdjustHV routine calculates a new current setting for the control and then uses SetControlValue to assign that setting to the control as well as to reposition the scroll box accordingly.

The destination rectangle, specified in the destRect field of the edit record, is the rectangle in which the text is drawn, whereas the view rectangle is the rectangle in which the text is actually visible. By subtracting the top coordinate of the destination rectangle from the top coordinate of the view rectangle, and dividing the result by the line height, MyAdjustHV derives the number of the line currently displayed at the top of the window. This is the line number MyAdjustHV uses for the current setting of the vertical scroll bar.

To derive the current setting of the horizontal scroll bar in terms of pixels, MyAdjustHV subtracts the left coordinate of the destination rectangle from the left coordinate of the view rectangle.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
11 JUL 1996