✔ Appearance χ Standard χ Console
appearance button[#] [-] id&[, [state][, [value][, [min][, [max][, ¬ [title$][,[rect][, [type]]]]]]]
Feb 2002 (Release 6)
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
appearance 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.|
||The state may be:
||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
a rectangle in local window coordinates. You can express it in either of two forms:
||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:
You can hide the control with either
button -1 or
-1 and you can deactivate the control with either
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 will help access information regarding the new appearance buttons:
actualSize = fn ButtonDataSize( btnID, part, tagName )
def GetButtonData( btnID, part, tagName, maxSize,¬ theData, actualSize )
def SetButtonTextString( btnID, theString )
theString = fn ButtonTextString$( btnID )
def SetButtonFocus( btnID )
def GetButtonTextSelection( btnID, selStart, selEnd )
def SetButtonTextSelection( btnID, selStart, selEnd )
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.
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.
|<img src="a/appearancebutton01.gif" alt="appearancebuttonhtm01" height="496" width="328" border="0">||<img src="a/appearancebutton02.gif" alt="appearancebuttonhtm02" height="473" width="312" border="0">|
Push buttons in OS X
Push buttons in System 9
So that you may see how each button was displayed, the following code shows that source used to generate the displays.
/* appearance button [#] [-] id&[, [state][, [value][,¬ [min][, [max][, [title$][,[rect][, [type]]]]]]] */ appearance button bRef,_activeBtn,0,0,1,¬ "_kControlPushButtonProc",@r,_kControlPushButtonProc appearance button bRef,_activeBtn,0,0,1,¬ "_kControlBevelButtonSmallBevelProc",@r,¬ _kControlBevelButtonSmallBevelProc appearance button bRef,_activeBtn,0,0,1,¬ "_kControlBevelButtonNormalBevelProc",@r,¬ _kControlBevelButtonNormalBevelProc appearance button bRef,_activeBtn,0,0,1,¬ "_kControlBevelButtonLargeBevelProc",@r,¬ _kControlBevelButtonLargeBevelProc // "value" is menu ID appearance button bRef,_activeBtn,101,0,1,¬ "Bevel+_kControlBevelButtonMenuOnRight",@r,¬ _kControlBevelButtonSmallBevelProc + ¬ _kControlBevelButtonMenuOnRight // max value is cicn ID appearance button bRef,_activeBtn,0,0,256,¬ "_kControlPushButRightIconProc",@r, ¬ _kControlPushButRightIconProc appearance button bRef,_activeBtn,0,0,256,¬ "_kControlPushButLeftIconProc",@r,¬ _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,¬ "_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
_kControlBevelButtonLargeBevelProc + _kControlBevelButtonMenuOnRight
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,¬ "_kControlGroupBoxTextTitleProc",@r,¬ _kControlGroupBoxTextTitleProc appearance button bRef,_activeBtn,0,0,1,¬ "_kControlGroupBoxSecondaryTextTitleProc",@r,¬ _kControlGroupBoxSecondaryTextTitleProc appearance button bRef,_activeBtn,1,0,1,¬ "_kControlGroupBoxCheckBoxProc",@r,¬ _kControlGroupBoxCheckBoxProc appearance button bRef,_activeBtn,1,0,1,¬ "_kControlGroupBoxSecondaryCheckBoxProc",@r,¬ _kControlGroupBoxSecondaryCheckBoxProc // min value is menu ID appearance button bRef,_activeBtn,1,101,1,¬ "",@r,_kControlGroupBoxPopUpButtonProc appearance button bRef,_activeBtn,1,101,1,¬ "",@r,_kControlGroupBoxSecondaryPopUpButtonProc appearance button bRef,_activeBtn,1,0,1,¬ "",@r,_kControlPlacardProc appearance button bRef,_activeBtn,1,0,1,¬ "",@r,_kControlSeparatorLineProc
|<img src="a/appearancebutton03.gif" alt="appearancebuttonhtm03" height="435" width="346" border="0">||<img src="a/appearancebutton04.gif" alt="appearancebuttonhtm04" height="429" width="349" border="0">|
Groups and Separators in OS X
Groups and Separators in System 9
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 dim pR as Rect dim h as handle dim bRef as long dim err as OSErr // setup _btnHt = 20 _btnWd = 80 _btnMargin = 8 bRef = 1
|<img src="a/appearancebutton05.gif" alt="appearancebuttonhtm05" height="152" width="103" border="0">|
// create a window SetRect( r, 0, 0, _btnWd_btnMargin_btnMargin, 120 ) 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 SetRect( r ,_btnMargin, _btnMargin,¬ _btnMargin_btnWd, (_btnMargin_btnHt)*3 ) appearance button bRef, _activeBtn, 0, 0, 1,¬ "", @r, _kControlRadioGroupProc bRef ++ SetRect( r, _btnMargin, _btnMargin, _btnMargin_btnWd,¬ _btnMargin_btnHt ) appearance button bRef, _activeBtn, 0, 0, 1,¬ "Radio 1", @r, _kControlRadioButtonProc def EmbedButton( bRef, 1 ) bRef ++ : OffsetRect( r, 0, _btnHt_btnMargin ) appearance button bRef, _activeBtn, 0, 0, 1,¬ "Radio 2", @r, _kControlRadioButtonProc def EmbedButton( bRef, 1 ) bRef ++ : OffsetRect( r, 0, _btnHt_btnMargin ) appearance button bRef, _activeBtn, 0, 0, 1,¬ "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
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:
|<img src="a/appearancebutton06.gif" alt="appearancebuttonhtm04" height="136" width="207" border="0">|
The buttons in the screen shot above were created using the following lines of code:
appearance button bRef, _activeBtn,¬ _kControlCheckBoxUncheckedValue, 0,¬ _kControlCheckBoxMixedValue,¬ "Unchecked Check Box", @r, _kControlCheckBoxProc appearance button bRef, _activeBtn,¬ _kControlCheckBoxMixedValue, 0,¬ _kControlCheckBoxMixedValue,¬ "Mixed Value Check Box", @r, _kControlCheckBoxProc appearance button bRef, _activeBtn,¬ _kControlCheckBoxCheckedValue, 0,¬ _kControlCheckBoxMixedValue,¬ "Checked Check Box", @r, _kControlCheckBoxProc
You cannot use
button bRef, state to tick and untick group buttons of type
appearance button bRef,,state-1 instead. (
button bRef,0 and
button bRef,1 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.
button 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
gFBControlLongDate and another named
gFBControlSeconds. The variable named
gFBControlSeconds 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
gFBControlLongDate is that of a
LongDateRec 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
button 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
gFBControlText (a Pascal string) are determined by the second
button function parameter. When
_FBGetControlDate is used, it is the control's date. When
_FBGetControlTime is used, it is the control's time.
|<img src="a/appearancebutton07.gif" alt="" height="283" width="442" border="0">|
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,¬ _kControlClockTimeProc appearance button bRef, _activeBtn, _kControlClockIsLive, 0, 1,,¬ @r ,_kControlClockTimeSecondsProc appearance button bRef, _activeBtn, _kControlClockNoFlags,¬ 0, 1,, @r, _kControlClockDateProc appearance button bRef, _activeBtn, _kControlClockNoFlags,¬ 0, 1,, @r, _kControlClockMonthYearProc appearance button bRef, _activeBtn, ¬ _kControlClockIsLive_kControlClockIsDisplayOnly,¬ 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
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.
|<img src="a/appearancebutton10.gif" alt="IMAGE imgs/appearancebutton.htm15.gif" height="144" width="120">|
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,¬ _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,¬ _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,¬ _kControlProgressBarProc dim b as boolean dim err as OSErr b = _true err = fn SetControlData( bRef, 0,¬ _kControlProgressBarIndeterminateTag, sizeof( boolean ), @b )
Range Selectors (Sliders and Arrows)
<img src="a/appearancebutton08.gif" alt="appearancebuttonhtm02" height="349" width="146" border="0">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 _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.
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,¬ "Bevel+_kControlBevelButtonMenuOnRight",¬ @r, _kControlBevelButtonSmallBevelProc + ¬ _kControlBevelButtonMenuOnRight
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( bRef, _FBgetBevelControlMenuHandle ) currentItem = button( bRef, _FBgetBevelControlMenuVal ) previousItem = button( bRef, _FBgetBevelControlLastMenu )
|<img src="a/appearancebutton11.gif" alt="" height="237" width="283">|
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( id&, _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 id&,, 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:"¬ ,@r, _kControlPopUpButtonProc
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( bRef, _FBgetControlMenuHandle )
You can retrieve the current pop-up menu item with:
mItem = button( bRef )
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
_"ldes" record and save that handle as a resource. The resource ID for the ldes is passed in the '
value' 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
LDEF (0). You can change the list by getting the list handle. You can set the LDEF by using the tag below (
_kControlListBoxLDEFTag) 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.
|<img src="a/appearancebutton12.gif" alt="IMAGE imgs/appearancebutton.htm18.gif" height="282" width="329">|
Creating an ldes Resource
appearance button bRef, _activeBtn, 256, 0, 1,¬ "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&( bRef ) err = fn GetControlData( cH, 0,¬ _kControlListBoxListHandleTag, ¬ sizeof( handle ), lH, bufferSize ) cellX = 0 for cellY = 0 to 9 t$ = "Item #" + mid$( str$( cellY + 1 ), 2 ) LSetCell( @t$, t$, celly, lH ) next
|<img src="a/appearancebutton09.gif" alt="" height="148" width="166" border="0">|
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.
|<img src="a/appearancebutton13.gif" alt="" height="233" width="312" border="0">|
There are many styles of tab buttons:
_kControlTabLargeProc _kControlTabSmallProc _kControlTabLargeNorthProc _kControlTabSmallNorthProc _kControlTabLargeSouthProc _kControlTabSmallSouthProc _kControlTabLargeEastProc _kControlTabSmallEastProc _kControlTabLargeWestProc _kControlTabSmallWestProc
This example uses
_kControlTabSmallProc, 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,¬ _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,¬ _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, ¬ 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,,¬ _kControlSupportsEmbedding,,,, @r,¬ _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,,,,¬ "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 xelse button -j end ifF next end if end fn on dialog fn doDialog do HandleEvents until gFBQuit
No special notes.