Futurebasic/Language/Reference/appearance button

Statement
✔ Appearance χ Standard χ Console

Syntax
appearance button[#] [-] id&[, [state][, [value][, [min][, [max][, ¬ [title$][,[rect][, [type]]]]]]]

Revided
Feb 2002 (Release 6)

Description
The  statement puts a new control in the current output window, or alters an existing control's characteristics. After you create a button using the  statement, you can use the   function to determine whether the user has clicked it. You can use the statement if you want to dispose of the button without closing the window.

When you first create a button with a specific ID (in a given window), you must specify all the parameters up to and including. If you later want to modify that button's characteristics, execute  again with the same ID, and specify one or more of the other parameters (except , which cannot be altered). The button will be redrawn using the new characteristics that you specified; any parameter that you don't specify will not be altered.

a positive or negative integer whose absolute value is in the range 1 through 2147483647. The number you assign must be different from all other scroll bars or buttons in that window. Negative values build invisible buttons. Positive values build visible buttons. The state may be:

(0/disabled) (1/default/active) (2/selected)

,,   generally an integer value for the initial, minimum, and maximum values of a control a string expression. This parameter is not used to set the text of buttons defined with  or. See  for information on how this may be accomplished.

a rectangle in local window coordinates. You can express it in either of two forms:

Two diagonally opposite corner points.

Long integer expression or  variable which points to an 8-byte struct such as a   type.

any of the many types listed in the following text.

New Things To Keep In Mind
On button creation, default values supplied for missing parameters (if any) are: 1    0     1     null string

You can hide the control with either  or    and you can deactivate the control with either ,   or. Buttons are commonly hidden and revealed as tab panes are brought into or removed from view. The same is true of panes that are changed in response to items such as group pop-up placards. To read an appearance button's value, use either  or

Summary of Appearance Helpers
The following utility routines will help access information regarding the new appearance buttons:

Button Types
The Appearance Manager introduces many new control definitions. While it is not our intention to completely document all of Apple's new buttons, a few possible types are shown below with examples on how each might be implemented.

Push Buttons
Since the Appearance Manager works in both System 9 and OS X, you will see major differences in how each control is presented. Common push buttons are shown below in both versions.

So that you may see how each button was displayed, the following code shows that source used to generate the displays. /* appearance button [#] [-] id&amp;[, [state][, [value][,&not; [min][, [max][, [title$][,[rect][, [type]]]]]]] appearance button bRef,_activeBtn,0,0,1,&not; "_kControlPushButtonProc",@r,_kControlPushButtonProc appearance button bRef,_activeBtn,0,0,1,&not; "_kControlBevelButtonSmallBevelProc",@r,&not; _kControlBevelButtonSmallBevelProc appearance button bRef,_activeBtn,0,0,1,&not; "_kControlBevelButtonNormalBevelProc",@r,&not; _kControlBevelButtonNormalBevelProc appearance button bRef,_activeBtn,0,0,1,&not; "_kControlBevelButtonLargeBevelProc",@r,&not; _kControlBevelButtonLargeBevelProc // "value" is menu ID appearance button bRef,_activeBtn,101,0,1,&not; "Bevel+_kControlBevelButtonMenuOnRight",@r,&not; _kControlBevelButtonSmallBevelProc + &not; _kControlBevelButtonMenuOnRight // max value is cicn ID appearance button bRef,_activeBtn,0,0,256,&not; "_kControlPushButRightIconProc",@r, &not; _kControlPushButRightIconProc appearance button bRef,_activeBtn,0,0,256,&not; "_kControlPushButLeftIconProc",@r,&not; _kControlPushButLeftIconProc // get rect from pict to determine button size h = fn GetPicture( 256 ) long if h pR;8 = @h..picFrame% OffsetRect( pR, -pR.left, -pR.top ) OffsetRect( pR, r.left, r.top ) // control "value" is pict ID appearance button  bRef,_activeBtn,256,0,1,&not; "_kControlPictureProc",@pR,_kControlPictureProc end if Not all possible push buttons (and their variations) are shown here. For example, the control that displays an arrow to indicate the presence of a menu was built with a small bevel. It would have been created with a large bevel by using

Other button types that you may wish to investigate are: _kControlIconProc _kControlIconNoTrackProc _kControlIconSuiteProc _kControlIconSuiteNoTrackProc _kControlPictureNoTrackProc

Using Buttons to Group or Separate
FB buttons (which are Control Manager controls) can be grouped together, placed in placards or separated by lines. The following example creates buttons on a plain white background so that you may more easily see the drawing that is implemented by the control definition. We begin with the source code statements used to create the buttons. appearance button bRef,_activeBtn,0,0,1,&not; "_kControlGroupBoxTextTitleProc",@r,&not; _kControlGroupBoxTextTitleProc appearance button bRef,_activeBtn,0,0,1,&not; "_kControlGroupBoxSecondaryTextTitleProc",@r,&not; _kControlGroupBoxSecondaryTextTitleProc appearance button bRef,_activeBtn,1,0,1,&not; "_kControlGroupBoxCheckBoxProc",@r,&not; _kControlGroupBoxCheckBoxProc appearance button bRef,_activeBtn,1,0,1,&not; "_kControlGroupBoxSecondaryCheckBoxProc",@r,&not; _kControlGroupBoxSecondaryCheckBoxProc // min value is menu ID appearance button bRef,_activeBtn,1,101,1,&not; "",@r,_kControlGroupBoxPopUpButtonProc appearance button bRef,_activeBtn,1,101,1,&not; "",@r,_kControlGroupBoxSecondaryPopUpButtonProc appearance button bRef,_activeBtn,1,0,1,&not; "",@r,_kControlPlacardProc appearance button bRef,_activeBtn,1,0,1,&not; "",@r,_kControlSeparatorLineProc

Embedding Buttons
Part of the strength of Appearance Manager buttons is that one button may be embedded in another. By disabling or hiding the parent button (called a super control), all embedded controls would automatically be disabled or hidden. Each window has a primary control known as a root control. The following example builds a window with a parent radio group button. Inside of that parent are three radio buttons. We can determine which of the three buttons has been selected by getting the value (via the  function) of the parent button. // create a window SetRect( r, 0, 0, _btnWd_btnMargin_btnMargin, 120 ) appearance window 1,,@r err = fn SetThemeWindowBackground( window( _wndPointer ),&not;  _kThemeActiveDialogBackgroundBrush, _zTrue ) // button #1 is the papa button // note that the parent button has sufficient space so that // it holds all embedded buttons within its own rectangle SetRect( r ,_btnMargin, _btnMargin,&not;  _btnMargin_btnWd, (_btnMargin_btnHt)*3 ) appearance button bRef, _activeBtn, 0, 0, 1,&not; "", @r, _kControlRadioGroupProc bRef ++ SetRect( r, _btnMargin, _btnMargin, _btnMargin_btnWd,&not;  _btnMargin_btnHt ) appearance button bRef, _activeBtn, 0, 0, 1,&not; "Radio 1", @r, _kControlRadioButtonProc def EmbedButton( bRef, 1 ) bRef ++ : OffsetRect( r, 0, _btnHt_btnMargin ) appearance button bRef, _activeBtn, 0, 0, 1,&not; "Radio 2", @r, _kControlRadioButtonProc def EmbedButton( bRef, 1 ) bRef ++ : OffsetRect( r, 0, _btnHt_btnMargin ) appearance button bRef, _activeBtn, 0, 0, 1,&not; "Radio 3", @r, _kControlRadioButtonProc def EmbedButton( bRef, 1 ) local fn HandleDialog dim as long action,reference action = dialog( 0 ) reference = dialog( action ) long if action = _btnclick MoveTo( 8, 100 ) print "Current Button "; button( 1 ); end if end fn on dialog fn HandleDialog do HandleEvents until gFBQuit

Check Boxes
Other than the obvious differences in physical appearance, check boxes generally follow the same guidelines as they have for many years. One notable exception to this rule is the ability to create a mixed check box. This box contains a dash instead of a check mark to show that part, but not all, of the current selection has a specific feature. This adds a new possible maximum value of 2 to the control's range.

Possible check box values now include:

The buttons in the screen shot above were created using the following lines of code: appearance button bRef, _activeBtn,&not; _kControlCheckBoxUncheckedValue, 0,&not; _kControlCheckBoxMixedValue,&not; "Unchecked Check Box", @r, _kControlCheckBoxProc appearance button bRef, _activeBtn,&not; _kControlCheckBoxMixedValue, 0,&not; _kControlCheckBoxMixedValue,&not; "Mixed Value Check Box", @r, _kControlCheckBoxProc appearance button bRef, _activeBtn,&not; _kControlCheckBoxCheckedValue, 0,&not; _kControlCheckBoxMixedValue,&not; "Checked Check Box", @r, _kControlCheckBoxProc Note: You cannot use  to tick and untick group buttons of type   and. Use  instead. ( and   will however inactivate and activate the button respectively).

Time and Date Buttons
In addition to more common controls, the Appearance Manager can create buttons that manage dates and times. Special data structures are maintained to access the information from these controls, but by following a few simple examples, you can quickly master these skills.

The enhanced  function is useful for extracting complex data from controls. Two specific items come in to play: ignored = button( btnRef, _FBGetControlDate ) ignored = button( btnRef, _FBGetControlTime ) Referencing either of these functions will fill a global date/time record named  and another named. The variable named  is a signed 64 bit variable which may be saved in a file or used in any variable where compressed storage is required.

The format for  is that of a   which follows the layout of the structure below: begin record LongDateRec dim era       as short dim year      as short dim month     as short dim day       as short dim hour      as short dim minute    as short dim second    as short dim dayOfWeek as short dim dayOfYear as short dim weekOfYear as short dim pm        as short dim res1      as short dim res2      as short dim res3      as short end record After calling the  function to examine the contents of a control, you may extract portions of the date/time as follows: dayOfMonth = gFBControlLongDate.day thisYear  = gFBControlLongDate.year Another variable is maintained that holds the text for a specific date/time control. The contents of  (a Pascal string) are determined by the second   function parameter. When  used, it is the control's date. When  is used, it is the control's time.

In addition to setting specific types when creating a date/time control, you must set an initial value of one of the following: _kControlClockNoFlags _kControlClockIsDisplayOnly _kControlClockIsLive The specific statements used to create the Time/Date example follow: appearance button bRef, _activeBtn, 0, 0, 1,, @r,&not; _kControlClockTimeProc appearance button bRef, _activeBtn, _kControlClockIsLive, 0, 1,,&not; @r ,_kControlClockTimeSecondsProc appearance button bRef, _activeBtn, _kControlClockNoFlags,&not; 0, 1,, @r, _kControlClockDateProc appearance button bRef, _activeBtn, _kControlClockNoFlags,&not; 0, 1,, @r, _kControlClockMonthYearProc appearance button bRef, _activeBtn, &not; _kControlClockIsLive_kControlClockIsDisplayOnly,&not; 0, 1,, @r, _kControlClockTimeSecondsProc To extract and display the contents of a control, the following statements were created: err = button( bRef, _FBgetControlTime ) edit field bRef, gFBControlText, @r

Wait States
The Appearance Manager provides several methods for telling the user that your application is busy with a task. These include chasing arrows, and finite and indeterminate progress bars.

The chasing arrows control is easy to create and is self maintaining. Each time your program scans for events, the arrows are animated. The following statement creates a chasing arrows control:

appearance button bRef, _activeBtn, 0, 0, 1,, @r,&not; _kControlChasingArrowsProc Progress bars are also easy to create, but you need to keep a couple of things in mind. First, the progress bar operates in a range of -32,768 to +32,767. If your task involves a greater number of steps, you will have to calculate a ratio to keep things within range. Second, the progress bar is updated by your program. This is as easy as setting a new value for the button, but it is code that you must write.

The minimum and maximum values for the control become the minimum and maximum values for the progress bar. The initial and current value show the current rate of progress. In the example above, the button was created using the following source: appearance button bRef, _activeBtn, 50, 0, 100,, @r,&not; _kControlProgressBarProc The minimum value was zero; maximum was 100. At the time of creation, the control value was 50, so the indicator shows colorization half way across the bar. If we wanted to indicate that the next step had been completed, we would use the following code:

appearance button bRef,, 51 Indeterminate progress bars are more complex. After the button is created, you must set the control's internal data to a new value. The following code shows how: appearance button bRef, _activeBtn, 1, 0, 1,, @r,&not; _kControlProgressBarProc dim b  as boolean dim err as OSErr b = _true err = fn SetControlData( bRef, 0,&not;  _kControlProgressBarIndeterminateTag, sizeof( boolean ), @b )

Range Selectors (Sliders and Arrows)
There are many variations of the slider. Each begins with the simple type constant of. Additional parameters are added to this constant to add features to the control. The following constants are available for slider variations: _kControlSliderLiveFeedback _kControlSliderHasTickMarks _kControlSliderReverseDirection _kControlSliderNonDirectional To create a slider that uses an upward pointing indicator and has tickmarks, the following type would be used: _kControlSliderProc + ¬ _kControlSliderHasTickMarks + ¬ _kControlSliderReverseDirection Vertical sliders are created by building the button with a vertical dimension that is greater than the horizontal dimension. The control definition handles the new orientation automatically.

Range Selectors Sliders and Little Arrows

The following source lines show how this display was created: appearance button bRef, _activeBtn, 1, 1, 10,, @r,¬ _kControlSliderProc appearance button bRef, _activeBtn, 10, 1, 10,, @r,¬ _kControlSliderProc_kControlSliderHasTickMarks appearance button, _activeBtn, 1, 1, 10,, @r,¬ _kControlSliderProc_kControlSliderNondirectional appearance button bRef, _activeBtn, 1, 1, 10,, @r,¬ _kControlSliderProc_kcontrolSliderReverseDirection appearance button bRef, _activeBtn, 10, 1, 10,, @r,¬ _kControlSliderProc_kControlSliderHasTickMarks +¬ _kcontrolSliderReverseDirection

// vert orientation appearance button bRef, _activeBtn, 10, 1, 10,, @r,¬ _kControlSliderProc appearance button bRef, _activeBtn, 10, 1, 10,, @r,¬ _kControlSliderProc_kControlSliderNondirectional appearance button bRef, _activeBtn, 10, 1, 10,, @r,¬ _kControlSliderProc_kControlSliderHasTickMarks +¬ _kcontrolSliderReverseDirection

appearance button bRef, _activeBtn, 0, 0, 1,, @r,¬ _kControlLittleArrowsProc When sliders are created, the number of tick marks is set by the initial value of the control. After the control is created, the value is reset to the control minimum. Sliders range from a minimum value of -32,768 to a maximum of +32,767. The number of tick marks is something that you need to determine by balancing the size of the control against the range of the control's minimum/maximum value.

The little arrows (shown in the screen shot above) are used to increment and decrement a related visual counter (usually an edit field with a specific range of numbers). The current version of the OS X control definition is intolerant of variations in the value used for the height of this type of control. Our tests show that it must be exactly 22 pixels tall. Other values offset the arrows inside of the beveled area or, in more extreme cases, can place the arrows entirely outside of the beveled area.

Pop-Up Menus
There are two distinct types of pop-up menus: beveled, and standard. Both are valid types and the particular use of one over the other is something that should be guided by your individual application and by Apple's Human Interface Guidelines. Beveled buttons are created as follows: appearance button bRef, _activeBtn, menuID, 0, 1,&not; "Bevel+_kControlBevelButtonMenuOnRight",&not; @r, _kControlBevelButtonSmallBevelProc + &not; _kControlBevelButtonMenuOnRight When bevel-button menus are created, the initial value for the control is the resource ID number of the menu. Three specific  function commands may be used to extract information from the control. handle      = button( bRef, _FBgetBevelControlMenuHandle ) currentItem = button( bRef, _FBgetBevelControlMenuVal ) previousItem = button( bRef, _FBgetBevelControlLastMenu )

Standard pop-up buttons follow slightly different syntax. When creating, the minimum value specifies the menu resource ID and the maximum value is the width of the title for the menu. Passing in a menu ID of -12345 causes the popup not to try and get the menu from a resource. Instead, you can build the menu and later stuff the menuhandle field in the popup data information (using ). You can pass -1 in the  parameter to have the control calculate the width of the title on its own instead of guessing and then tweaking to get it right. It adds the appropriate amount of space between the title and the popup. A maximum value of zero means, "Don't show the title."

After creation you might need to change the value, minimum and maximum to the correct settings for your pop-up menu with: appearance button id&amp;,, value, min, max The standard pop-up button menu in the above illustration was created with the following code: appearance button bRef, _activeBtn, 0, 101, -1, "Pop Title:"&not; ,@r, _kControlPopUpButtonProc A single  function provides access to the menu handle. Remember: standard and beveled pop-up menus do not use the same  function constants. menuHandle = button( bRef, _FBgetControlMenuHandle ) You can retrieve the current pop-up menu item with: mItem = button( bRef )

List Boxes
Lists generally use an auxiliary resource to define their format. The resource type used is 'ldes' and a definition for it can be created using Resourcerer 2.4 or later or by creating a template in any resource editor. You may also format a handle to match the  record and save that handle as a resource. The resource ID for the ldes is passed in the ' ' parameter when creating the control. You may pass zero in value which would tell the List Box control to not use a resource. The list will be created with default values, and will use the standard. You can change the list by getting the list handle. You can set the LDEF by using the tag below in conjunction with.

A list box resource is defined as follows: begin record ldes dim versionNumber  as short dim numberOfRows   as short dim numberOfColumns as short dim cellHeight     as short dim cellWidth      as short dim hasVertScroll  as boolean dim filler1        as byte dim hasHorizScroll as boolean dim filler2        as byte dim LDEFresID      as short dim hasSizeBox     as boolean dim reserved       as byte end record The following example creates a list box from a resource with an ID of 256. Then it fills the list with item text.

To simplify this example, Resourcerer was used to create the list box resource.

appearance button bRef, _activeBtn, 256, 0, 1,&not; "List Box", @r, _kControlListBoxProc dim cH         as handle        //control handle dim @bufferSize as long dim @lH        as handle        //list handle dim y,t$ dim @celly,cellX                //cell "point" record cH = button&amp;( bRef ) err = fn GetControlData( cH, 0,&not;  _kControlListBoxListHandleTag, &not;   sizeof( handle ),  lH, bufferSize ) cellX = 0 for cellY = 0 to 9 t$ = &quot;Item #&quot; + mid$( str$( cellY + 1 ), 2 ) LSetCell( @t$[1], t$[0], celly, lH ) next

Tab Buttons
Tab buttons will require more work than other controls. This stems from the fact that tabs are really several controls that act in unison. First is the main tab control. When this is created you specify the number of tabs that will be present by setting the max value of the control. It is generally better to create the tab button invisibly (by using a negative button reference number) then show it by issuing a  statement with the positive version of the reference number.

After the initial shell is built for the tab, you must set the title for each tab using. Then a user pane is inserted for each tab. These are embedded in the tab shell using. Buttons that will reside in each user pane are created and embedded in the user pane.

When a dialog event is encountered, the value of the tab shell button corresponds to the position of the clicked tab in the tab list. Your program must loop through each user pane and show or hide them so that the display matches the clicked tab.

Study the following example to see how a working tab button is created. Be sure to note the simple  handler that maintains the buttons.

There are many styles of tab buttons: _kControlTabLargeProc _kControlTabSmallProc _kControlTabLargeNorthProc _kControlTabSmallNorthProc _kControlTabLargeSouthProc _kControlTabSmallSouthProc _kControlTabLargeEastProc _kControlTabSmallEastProc _kControlTabLargeWestProc _kControlTabSmallWestProc This example uses, but you should experiment with other types to see the results. dim r      as Rect dim x      as long dim bRef   as long dim infoRec as ControlTabInfoRec // Names of the individual tabs _tabCount = 3 dim tabTitles$(_tabCount) tabTitles$(1) = "One" tabTitles$(2) = "Two" tabTitles$(3) = "Three" // create a window SetRect( r, 0, 0, 300, 200 ) appearance window 1, "Tabs", @r, _kDocumentWindowClass def SetWindowBackground( _kThemeActiveDialogBackgroundBrush,&not; _zTrue ) /* Button 100 is the tab 'shell'. In this example, it is made to be the full size of the window, less a small margin. Buttons 1, 2, &amp; 3 will be the embedded user panes that contain information to be displayed for each tab. A tab control is usually built as invisible. This is because the information contained in the tabs will be modified as the control is being constructed. Making it visible after all modifications have been completed provides a cleaner window build. _tabBtnRef = 100 _btnMargin = 8 InsetRect( r, _btnMargin, _btnMargin ) appearance button -_tabBtnRef, 0, 0, 2, _tabCount,, @r,&not; _kControlTabSmallNorthProc /* Fix the tab to use a small font. This is not a requirement, but it is information which many will find useful. dim cfsRec as ControlFontStyleRec cfsRec.flags = _kControlUseSizeMask cfsRec.size = 9 def SetButtonFontStyle( _tabBtnRef, cfsRec ) /* Adapt a rectangle that can be used for the content area of each tab. InsetRect( r, _btnMargin, _btnMargin ) r.top += 20 // Loop thru the tabs and set up individual panes for x = 1 to _tabCount infoRec.version    = _kControlTabInfoVersionZero infoRec.iconSuiteID = 0 infoRec.Name       = tabTitles$(x) def SetButtonData( _tabBtnRef, x, _kControlTabInfoTag, &not;    sizeof( infoRec ), infoRec ) /*    Each of these panes is a button that is embedded in the tab button. The first   one will be visible. All others will be invisible because information from only one tab at a time can be viewed. Remember: negative button reference numbers make invisible buttons. Once a new pane button (_kControlUserPaneProc) is created, it is embedded into the larger tab button. */  if x != 1 then bRef = -x else bRef = x   appearance button bRef,,&not; _kControlSupportsEmbedding,,,, @r,&not; _kControlUserPaneProc def EmbedButton( x, _tabBtnRef ) next /* Now we have a tab shell (_tabBtnRef = 100) and in it we have embedded three tab panes (1,2, and 3). To demonstrate how these can contain separate info, we will place a simple button in each of the three panes. Button 10 in pane 1 Button 20 in pane 2 Button 30 in pane 3 InsetRect( r, 32, 32 ) r.bottom = r.top + 24 r.right = r.left + 128 appearance button 10, _activeBtn,,,,&not; "Pane #1", @r, _kControlPushButtonProc def EmbedButton( 10, 1 ) OffsetRect( r, 8, 8 ) appearance button 20, _activeBtn,,,,&not; "Pane #2", @r, _kControlPushButtonProc def EmbedButton( 20, 2 ) OffsetRect( r, 8, 8 ) appearance button 30, _activeBtn,,,,&not; "Pane #3", @r, _kControlPushButtonProc def EmbedButton( 30, 3 ) button _tabBtnRef, 1 // make visible /* Only one event (a button click in the tab shell button) gets a response from out dialog routine. The value returned (1,2, or 3) corresponds to buttons 1,2, or 3 that were embedded into the tab parent. Our only action is to show (BUTTON j) or hide (BUTTON -j) the proper tab pane. All controls embedded in those panes will automatically be shown or hidden. local fn doDialog dim as long action, reference, j action    = dialog( 0 ) reference = dialog( action ) long if action == _btnClick and reference == _tabBtnRef for j = 1 to _tabCount long if j == button( _tabBtnRef ) button j     xelse button -j end ifF next end if end fn on dialog fn doDialog do HandleEvents until gFBQuit