FutureBasic Logo

<<    Index    >> FutureBasic 5

appearance button   statement

appearance button [-] btnNum[, [state][, [value][,¬
min][, [max][, [title][,[rect][, [type]]]]]]]

The appearance button statement puts a new control in the current output window, or alters an existing control's characteristics. After you create a button using the appearance button statement, you can use the dialog function to determine whether the user has clicked it. You can use the button close 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 type. If you later want to modify that button's characteristics, execute button again with the same ID, and specify one or more of the other parameters (except type, 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.
state The state may be:
_grayBtn (0/disabled)
_activebtn (1/default/active)
_markedBtn (2/selected)
value, min, max generally an integer value for the initial, minimum, and maximum values of a control
title a string expression. As of FB 5.7.102 this must be a Core Foundation(CF) String. This parameter also serves to set the text of buttons defined with _kControlStaticTextProc or _kControlEditUnicodeTextProc.
a rectangle in local window coordinates. You can express it in either of two forms:
Two diagonally opposite corner points.
Pointer variable which points to a Rect type.
any of the many types listed in the following text.

Things To Keep In Mind
On button creation, default values supplied for missing parameters (if any) are:
state _activeBtn
value 1
min 0
max 1
title null string

You can hide the control with either button -1 or appearance button -1 and you can deactivate the control with either button 1, _grayBtn or appearance button 1, _grayBtn. 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 x = button( id ) or
x = button( id, _FBGetCtlRawValue )

Summary of Appearance Helpers:
The following utility routines help access information related to appearance buttons:

Pascal string helpers:
actualSize = fn ButtonDataSize( btnID, part, tagName )
pascalString = fn ButtonTextPascalString( btnID )

Core Foundation (CF) string helpers:
CFStringRef = fn ButtonCopyText( btnID )
fn ButtonSetText( btnID, @"My Button" )

Button Types:
The following describes some of Apple's controls with examples on how each might be implemented

Push Buttons:
Common push buttons are shown below.

Appearance Button Push Buttons Image
Push buttons

So that you may see how each button was displayed, the following code shows that source used to generate the displays.
appearance button [-] btnNum[, [state][, [value][,¬
   [min][, [max][, [title][,[rect][, [type]]]]]]]

appearance button btnNum,_activeBtn,0,0,1,¬

appearance button btnNum,_activeBtn,0,0,1,¬

appearance button btnNum,_activeBtn,0,0,1,¬

appearance button btnNum,_activeBtn,0,0,1,¬

// "value" is menu ID
appearance button btnNum,_activeBtn,101,0,1,¬
   _kControlBevelButtonSmallBevelProc + ¬

// max value is cicn ID
appearance button btnNum,_activeBtn,0,0,256,¬
   "_kControlPushButRightIconProc",@r, ¬

appearance button btnNum,_activeBtn,0,0,256,¬

// get rect from pict to determine button size
h = fn GetPicture(256)
long if h
  pR;8 = @h..picFrame%
// control "value" is pict ID
appearance button btnNum,_activeBtn,256,0,1,¬
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
_kControlBevelButtonLargeBevelProc + _kControlBevelButtonMenuOnRight
Other button types that you may wish to investigate are:

Using Buttons to Group or Separate:
FutureBasic 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 youmay 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 btnNum,_activeBtn,0,0,1,¬

appearance button btnNum,_activeBtn,0,0,1,¬

appearance button btnNum,_activeBtn,1,0,1,¬

appearance button btnNum,_activeBtn,1,0,1,¬

// min value is menu ID
appearance button btnNum,_activeBtn,1,101,1,¬

appearance button btnNum,_activeBtn,1,101,1,¬

appearance button btnNum,_activeBtn,1,0,1,¬

appearance button btnNum,_activeBtn,1,0,1,¬

Appearance Button Groups And Separators Image
Groups and Separators in MacOS X

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 button()function) of the parent button.

dim r as Rect
pR as Rect
h as Handle
btnNum as long
err as OSStatus
// setup
_btnHt = 20
_btnWd = 80
_btnMargin = 8
btnNum = 1

// create a window

appearance window 1,,@r
err = fn SetThemeWindowBackground (window( _wndPointer ),¬
   _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

appearance button btnNum,_activeBtn,0,0,1,¬

btnNum ++
appearance button btnNum,_activeBtn,0,0,1,¬
   "Radio 1",@r,_kControlRadioButtonProc
def EmbedButton(btnNum,1)

btnNum ++ : offsetrect(r,0,_btnHt_btnMargin)
appearance button btnNum,_activeBtn,0,0,1,¬
   "Radio 2",@r,_kControlRadioButtonProc
def EmbedButton(btnNum,1)

btnNum ++ : offsetrect(r,0,_btnHt_btnMargin)
appearance button btnNum,_activeBtn,0,0,1,¬
   "Radio 3",@r,_kControlRadioButtonProc
def EmbedButton(btnNum,1)

local fn handleDialog
  dim as long action,reference
  action = dialog(0)
  reference = dialog(action)
  long if action = _btnclick
    print "Current Button "; button(1);
  end if
end fn

on dialog fn handleDialog
until gFBQuit

Appearance Button Embed Buttons Image
Embedded Buttons

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 (_kControlCheckBoxMixedValue = 2) to the control's range.
Possible check box values now include:

Appearance Button Check Box Image
Check Boxes

The buttons in the screen shot above were created using the following lines of code:
appearance button btnNum,_activeBtn,¬
   "Unchecked Check Box",@r,_kControlCheckBoxProc

appearance button btnNum,_activeBtn,¬
   "Mixed Value Check Box",@r,_kControlCheckBoxProc

appearance button btnNum,_activeBtn,¬
   "Checked Check Box",@r,_kControlCheckBoxProc

You cannot use button btnNum,state to tick and untick group buttons of type _kControlGroupBoxCheckBoxProc and _kControlGroupBoxSecondaryCheckBoxProc. Use appearance button btnNum,,state-1 instead. (button btnNum,0 and button btnNum,1 will however inactivate and activate the button respectively).

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.

Appearance Button Wait States Image
Wait States

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 btnNum,_activeBtn,0,0,1,,@r,¬

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 btnNum,_activeBtn,50,0,100,,@r,¬

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 btnNum,,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 btnNum,_activeBtn,1,0,1,,@r,¬

dim b   as Boolean
dim err as OSStatus

b = _true
err = fn SetControlData(btnNum, 0,¬
   _kControlProgressBarIndeterminateTag,sizeof(Boolean), @b)

Range Selectors (Sliders and Arrows):
There are many variations of the slider. Each begins with the simple type constant of _kControlSliderProc. Additional parameters are added to this constant to add features to the control. The following constants are available for slider variations: _kControlSliderLiveFeedback

To create a slider that uses an upward pointing indicator and has tickmarks, the following type would be used:
_kControlSliderProc + ¬
   _kControlSliderHasTickMarks + ¬

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.

Appearance Button Sliders And Arrows Image
Sliders and Little Arrows

The following source lines show how this display was created:
appearance button btnNum,_activeBtn,1,1,10,,@r,¬
appearance button btnNum,_activeBtn,10,1,10,,@r,¬
appearance button btnNum,_activeBtn,1,1,10,,@r,¬
appearance button btnNum,_activeBtn,1,1,10,,@r,¬
appearance button btnNum,_activeBtn,10,1,10,,@r,¬
   _kControlSliderProc_kControlSliderHasTickMarks +¬

// vert orientation
appearance button btnNum,_activeBtn,10,1,10,,@r,¬
appearance button btnNum,_activeBtn,10,1,10,,@r,¬
appearance button btnNum,_activeBtn,10,1,10,,@r,¬
   _kControlSliderProc_kControlSliderHasTickMarks +¬

appearance button btnNum,_activeBtn,0,0,1,,@r,¬

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 MacOS 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 btnNum,_activeBtn,menuID,0,1,¬
   @r,_kControlBevelButtonSmallBevelProc + ¬

When bevel-button menus are created, the initial value for the control is the resource ID number of the menu. Three specific button function commands may be used to extract information from the control.
handle       = button(btnNum, _FBgetBevelControlMenuHandle)
currentItem  = button(btnNum, _FBgetBevelControlMenuVal)
previousItem = button(btnNum, _FBgetBevelControlLastMenu)

Appearance Button PopUp Menu Buttons Image
Pop-Up Menu Buttons

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 def SetButtonData (btnNum, _kControlMenuPart, _kControlPopupButtonMenuHandleTag, sizeof( handle), @yourMenuHndl )). You can pass -1 in the max 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 btnNum,,value,min,max
The standard pop-up button menu in the above illustration was created with the following code:
appearance button btnNum,_activeBtn,0,101,-1,"Pop Title:"¬

A single button function provides access to the menu handle. Remember: standard and beveled pop-up menus do not use the same button function constants.
menuHandle = button(btnNum, _FBgetControlMenuHandle)
You can retrieve the current pop-up menu item with:
mItem = button(btnNum)

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 button 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 def SetButtonData . Then a user pane is inserted for each tab. These are embedded in the tab shell using def EmbedButton. 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 dialog handler that maintains the buttons.

Appearance Button Tab Buttons Image
Tab Buttons

There are many styles of tab buttons:

This example uses _kControlTabSmallProc, but you should experiment with other types to see the results.
dim r       as Rect
dim x       as long
dim btnNum    as long
dim infoRec as ControlTabInfoRec

// Names of the individual tabs
_tabCount = 3
dim as Str255 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,¬
  _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, & 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,¬

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, ¬
     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 btnNum = -x else btnNum = x
   appearance button btnNum,,¬
   _kControlSupportsEmbedding,,,, @r,¬
   def EmbedButton( x, _tabBtnRef )

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,,,,¬
  "Pane #1", @r, _kControlPushButtonProc def EmbedButton( 10, 1 )

OffsetRect( r, 8, 8 )
appearance button 20, _activeBtn,,,,¬
  "Pane #2", @r, _kControlPushButtonProc def EmbedButton( 20, 2 )

OffsetRect( r, 8, 8 )
appearance button 30, _activeBtn,,,,¬
  "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
        button -j
      end if
  end if
end fn

on dialog fn doDialog
until gFBQuit

See Also:
button&; button function; button close; scroll button; dialog function