home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZAdvancedDialog.cpp -- a dialog box that can be extended with new types of items.
- * this will handle list boxes without further subclassing.
- *
- *
- * © 1997, Graham Cox
- *
- *
- *
- *************************************************************************************************/
-
- #include "ZAdvancedDialog.h"
- #include "MacZoop.h"
- #include "ZApplication.h"
- #include "ZGrafState.h"
-
- #include <LowMem.h>
-
- // note: if you don't have the extra dialog items stuff, comment out this include. The
- // code that makes use of it will be automatically compiled out.
-
- #include "ZExtraDialogItems.h"
-
- // list object for dialog items:
-
- #include "ZObjectArray.cpp"
-
- // global procedure is used in ZListDialogItem to handle searching lists for matching
- // user's keypresses to list items.
-
- static pascal short FindCellCompProc( Ptr dataA, Ptr dataB, short lenA, short lenB );
-
- ListSearchUPP gFindCellCompUPP = NewListSearchProc( FindCellCompProc );
-
- // global commander
-
- extern ZCommander* gCurHandler;
-
-
- // item objects:
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
-
- ZDialogItem::ZDialogItem( ZDialog* aDialog, short item )
- : ZCommander( aDialog )
- {
- short iType;
-
- FailNIL( aDialog );
-
- id = item;
-
- // by default, items based on ZDialogItem cannot have the keyboard focus, and
- // will behave accordingly. If you have an item that can have the keyboard focus,
- // set this member to TRUE in your constructor. See ZListDialogItem for example.
-
- canBeHandler = FALSE;
- isHandler = FALSE;
-
- // get initial info from the dialog manager item
-
- GetDialogItem( aDialog->GetMacWindow(), item, &iType, &iHand, &bounds );
-
- // convert the original dialog manager type into our more
- // "sophisticated" types.
-
- enabled = ((iType & itemDisable) == 0);
- iType &= 0x7F;
-
- switch ( iType )
- {
- case statText:
- type = typeStaticText;
- break;
- case editText:
- type = typeEditText;
- break;
- case iconItem:
- type = typeIcon;
- break;
- case picItem:
- type = typePicture;
- break;
- case ctrlItem + btnCtrl:
- type = typeButton;
- break;
- case ctrlItem + chkCtrl:
- type = typeCheckBox;
- break;
- case ctrlItem + radCtrl:
- type = typeRadioButton;
- break;
- case ctrlItem + resCtrl:
- type = typeResControl;
- break;
- case userItem:
- type = typeUserItem;
- break;
- }
- }
-
- /*--------------------------------*** DRAWBORDER ***----------------------------------*/
- /*
- draws the default outline used to indicate keyboard focus
- ----------------------------------------------------------------------------------------*/
-
- void ZDialogItem::DrawBorder( Boolean bState )
- {
- ZDialog* zd = (ZDialog*) GetBoss();
-
- // border only drawn if owning window is active
-
- if (((WindowPeek) zd->GetMacWindow())->hilited || !bState )
- {
- Rect r = bounds;
-
- InsetRect( &r, -3, -3 );
- PenSize( 2, 2 );
-
- if ( bState )
- PenMode( patOr );
- else
- PenMode( patBic );
-
- FrameRect( &r );
- PenNormal();
- }
- }
-
- /*-------------------------------*** BECOMEHANDLER ***--------------------------------*/
- /*
- this item should become the command handler, or relinquish back to its boss if false. This
- allows this item to have the keyboard focus, and draws the border accordingly.
- ----------------------------------------------------------------------------------------*/
-
- void ZDialogItem::BecomeHandler( Boolean isBecoming )
- {
- if (( isBecoming != isHandler) && canBeHandler )
- {
- ZAdvancedDialog* zd = (ZAdvancedDialog*) GetBoss();
-
- // we are becoming the handler for the owning dialog, so switch its
- // handler member to this. This is done via a couple of messages to
- // the dialog, which, as its boss, will always receive them even if
- // not explicitly told to do so.
-
- if ( isBecoming )
- SendMessage( ItemNowHandler, NULL );
- else
- SendMessage( ItemNoLongerHandler, NULL );
-
- isHandler = isBecoming;
-
- // only draw the hilite border if we're not the only item that can be the
- // handler. If this is the only one, then we're always it!
-
- if ( zd->HasMultipleFoci())
- {
- zd->Focus();
- DrawBorder( isHandler );
- }
- }
- }
-
-
- #pragma mark ============= ZListDialogItem ==============
-
- // listbox dialog item:
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
-
- ZListDialogItem::ZListDialogItem( ZDialog* aDialog, const short item )
- : ZDialogItem( aDialog, item )
- {
- theList = NULL;
- type = typeListBox;
- canBeHandler = TRUE; // list boxes can handle keyboard focus
-
- // get the key threshold. This is double the delay time
- // set by the user for "delay until repeat" in the global
- // keyboard control panel, or two seconds, whichever is shorter.
-
- fThresh = MIN( 120, LMGetKeyThresh() * 2);
- searchStr[0] = 0;
- lastKeyTime = 0;
- lastSel.h = lastSel.v = 0;
- strListID = 0;
-
- fontSize = 0;
- font = 0;
- }
-
-
- /*--------------------------------*** DESTRUCTOR ***----------------------------------*/
-
- ZListDialogItem::~ZListDialogItem()
- {
- LDispose( theList );
- }
-
- /*---------------------------------*** DRAWITEM ***-----------------------------------*/
- /*
-
- draw this dialog item. This updates the list
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::DrawItem()
- {
- ZAdvancedDialog* zd;
- ZGrafState zg;
-
- zd = (ZAdvancedDialog*) GetBoss();
-
- // if we are using a font different to the window, set that now
-
- short saveFont, saveSize;
-
- SetUpFontForList( &saveFont, &saveSize );
-
- LUpdate( zd->GetMacWindow()->visRgn, theList );
- PenNormal();
- FrameRect( &bounds );
-
- if ( fontSize != 0 &&
- font != 0 )
- {
- TextFont( saveFont );
- TextSize( saveSize );
- }
-
- // add greyscale effects if desired
-
- #ifdef _GREYSCALE_APPEARANCE
-
- FrameGrayRect( &bounds );
-
- #endif
-
- // draw a border if we are the handler and the owner can have more than
- // just this item as the keyboard focus
-
- if ( isHandler && zd->HasMultipleFoci())
- DrawBorder( TRUE );
- }
-
-
- /*---------------------------------*** CLICKITEM ***----------------------------------*/
- /*
-
- pass mouse clicks to the dialog item (the list, in this case)
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::ClickItem( const Point where, const short modifiers )
- {
- // the user clicked in this list box. If we are not already the handler, make
- // sure that we are switched in. This will give us the keyboard focus and
- // draw the hilited border if necessary
-
- Boolean dblClick;
-
- if (! isHandler && canBeHandler)
- BecomeHandler( TRUE );
-
- // if we are using a font different to the window, set that now
-
- short saveFont, saveSize;
-
- SetUpFontForList( &saveFont, &saveSize );
-
- // now pass the click on to the list manager
-
- Cell a = { 0, 0 }, b;
-
- b = a;
-
- LGetSelect( TRUE, &a, theList );
- dblClick = LClick( where, modifiers, theList );
- LGetSelect( TRUE, &b, theList );
-
- if ( fontSize != 0 &&
- font != 0 )
- {
- TextFont( saveFont );
- TextSize( saveSize );
- }
-
- // if the click resulted in a change to the selection in the list, send a message
- // to tell anyone whose listening what the new cell is. This is automatically
- // picked up by the owning dialog, which makes it very easy to respond to listbox
- // clicks and do whatever you need to with the info.
-
- if ( DeltaPoint( a, b ))
- SendMessage( newListItemSelected, &b );
-
- if ( dblClick )
- SendMessage( listItemDoubleClicked, &b );
- }
-
-
- /*-------------------------------*** BECOMEHANDLER ***--------------------------------*/
- /*
- change activation state of list according to whether this has focus or not
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::BecomeHandler( Boolean isBecoming )
- {
- inherited::BecomeHandler( isBecoming );
-
- // we don't deactivate or activate the whole list, since the appearance isn't too
- // great and is inconsistent with e.g. the Standard File Dialog. Instead we save
- // the current hilited item and save and restore that.
-
- ActivateListItem( isHandler );
- }
-
-
- /*-----------------------------------*** TYPE ***-------------------------------------*/
- /*
- when we have the keyboard focus, this will be called and we can use it to navigate
- around our list. This also selects cells according to what the user types. NOTE that
- this only works if the list is ordered alphabetically in the first place.
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::Type( const char theKey )
- {
- Cell curCell = { 0, 0 }, oldCell;
- Rect db = (*theList)->dataBounds;
-
- db.right--;
- db.bottom--;
-
- // find the currently selected cell
-
- LGetSelect( TRUE, &curCell, theList );
- oldCell = curCell;
-
- switch ( theKey )
- {
- case LEFT_ARROW_KEY: // left arrow, move left if possible
- curCell.h = MAX( db.left, curCell.h - 1 );
- break;
- case RIGHT_ARROW_KEY: // right arrow, move right if possible
- curCell.h = MIN( db.right, curCell.h + 1 );
- break;
- case UP_ARROW_KEY: // up arrow, move up if possible
- curCell.v = MAX( db.top, curCell.v - 1 );
- break;
- case DOWN_ARROW_KEY: // down arrow, move down if possible
- curCell.v = MIN( db.bottom, curCell.v + 1 );
- break;
- default:
-
- // handle letter typing to select items in list.
-
- if (( theKey >= 'a' && theKey <= 'z' ) ||
- ( theKey >= 'A' && theKey <= 'Z' ))
- {
- long theTime = TickCount();
- Cell findCell = { 0, 0 };
-
- // time to start a new string yet?
-
- if ((theTime > lastKeyTime + fThresh) || (searchStr[0] > 12))
- {
- // start a new string
-
- searchStr[0] = 0;
- }
- lastKeyTime = theTime;
-
- // add typed chars to the search string
-
- searchStr[++searchStr[0]] = theKey;
-
- // find a cell that matches this
-
- if ( LSearch( &searchStr[1], searchStr[0], gFindCellCompUPP, &findCell, theList ))
- {
- // we found one, so make it the selected cell
-
- curCell = findCell;
- }
- }
- break;
- }
-
- // turn off the old cell and hilite the new cell
-
- if ( DeltaPoint( curCell, oldCell ))
- {
- short saveFont, saveSize;
-
- SetUpFontForList( &saveFont, &saveSize );
-
- LSetSelect( FALSE, oldCell, theList );
- LSetSelect( TRUE, curCell, theList );
- LAutoScroll( theList );
-
- if ( fontSize != 0 &&
- font != 0 )
- {
- TextFont( saveFont );
- TextSize( saveSize );
- }
- // tell listeners which cell we just selected
-
- SendMessage( newListItemSelected, &curCell );
- }
-
- inherited::Type( theKey );
- }
-
-
- /*---------------------------------*** INITITEM ***-----------------------------------*/
- /*
- pass pseudo-parameters to this item for action
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::InitItem( const long param1, const long param2 )
- {
- // initialises this item from the pseudo-parameter list. The parameter list consists of
- // of up to two numbers, but only this knows what they mean! For lists, the first value
- // identifies the resource ID of a STR# resource which we use to fill the list. The second
- // is unused at present. NOTE that caller will pass 0 for missing parameters, so generally
- // this value should be avoided as having a special meaning.
-
- short numItems, i, p2;
- Cell aCell = { 0, 0 };
- Handle strListH;
- Str255 temp;
-
- // make the mac list manager structures based on the template <param1>
-
- MakeMacList( param1 );
-
- // if the template specified a string list, ignore param2. If it didn't,
- // param2 is the ID of the STR# resource to use. If everything was 0,
- // then we don't add anything to the list, and the caller must do this.
-
- if ( strListID > 0 )
- p2 = strListID;
- else
- p2 = param2;
-
- if ( p2 > 0 )
- {
- strListH = GetResource( 'STR#', p2 );
-
- if ( strListH )
- {
- // how many items in the list?
-
- numItems = **(short**) strListH;
-
- // add each string to the list
-
- LSetDrawingMode( FALSE, theList );
- aCell.v = (*theList)->dataBounds.bottom;
-
- for (i = 1; i <= numItems; i++ )
- {
- GetIndString( temp, p2, i );
-
- // append to the list
-
- aCell.v = LAddRow( 1, aCell.v + 1, theList );
- LSetCell( &temp[1], temp[0], aCell, theList );
- }
-
- // make the bounding box an exact number of cells high- this looks far neater
- // and saves the user from having to worry about tweaking the item's bounds
- // in the dialog template.
-
- short cellHeight = (*theList)->cellSize.v;
- short adjustAmount;
- Boolean hasH, hasV;
-
- hasH = ((*theList)->hScroll != NULL);
- hasV = ((*theList)->vScroll != NULL);
-
- adjustAmount = (bounds.bottom - bounds.top - (hasH? 17 : 2)) % cellHeight;
- bounds.bottom -= adjustAmount;
-
- LSize( bounds.right - bounds.left - (hasV? 17 : 2),
- bounds.bottom - bounds.top - (hasH? 17 : 2),
- theList );
-
- // turn list drawing back on and get rid of the string list
-
- LSetDrawingMode( TRUE, theList );
- ReleaseResource( strListH );
- }
- }
- }
-
-
- /*-------------------------------*** MAKEMACLIST ***----------------------------------*/
- /*
- make the list manager list. This can be built either as a 1-column list (template == 0),
- or from a list template resource which is defined in the header.
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::MakeMacList( const short listTemplateID )
- {
- // make the list manager list. By default, the list is one column wide with no
- // initial rows. It has a vertical scrollbar only, and the LDEF used is the standard
- // system one which displays strings in chicago 12. If you supply a template resource
- // the list can be built from that, giving full generality.
-
- ZDialog* zd = (ZDialog*) GetBoss();
- Rect r, dataBounds = { 0, 0, 0, 1 };
- Point cellSize = { 0, 0 };
- ListTemplateHdl ltH;
- Boolean hasV = TRUE, hasH = FALSE, hasGrow = FALSE, isVis = TRUE;
- short procID = 0;
-
- // based on the original item's bounds
-
- r = bounds;
- InsetRect( &r, 1, 1 );
-
- // obtain the template if any
-
- if ( listTemplateID != 0 )
- {
- ltH = ( ListTemplateHdl ) GetResource( kListTemplateResType, listTemplateID );
-
- if ( ltH )
- {
- // there is a template, so use that to define the list.
-
- dataBounds.right = MAX((*ltH)->columns, 1);
- dataBounds.bottom = (*ltH)->rows;
- procID = (*ltH)->procID;
- hasV = (*ltH)->hasVertScroll;
- hasH = (*ltH)->hasHorizScroll;
- hasGrow = (*ltH)->hasGrowBox;
- isVis = (*ltH)->visible;
-
- // set other data members from the template
-
- canBeHandler = (*ltH)->keyboardNav;
- fontSize = (*ltH)->fontSize;
- strListID = (*ltH)->stringsListID;
-
- GetFNum((*ltH)->fontName, &font );
-
- ReleaseResource((Handle) ltH );
- }
- }
-
- // tweak bounding box to allow for scrollbars we require
-
- if ( hasV || hasGrow )
- r.right -= 15;
-
- if ( hasH || hasGrow )
- r.bottom -= 15;
-
- // if the desired font is other than the default window font, set that
- // now so that the cell size is calculated accordingly.
-
- short saveFont, saveSize;
-
- SetUpFontForList( &saveFont, &saveSize );
-
- // make the List Manager list according to the template, or default
-
- theList = LNew( &r, &dataBounds,
- cellSize, procID,
- zd->GetMacWindow(),
- isVis, hasGrow, hasH, hasV );
-
- FailNIL( theList );
- LActivate( TRUE, theList );
- ActivateListItem( FALSE );
-
- // but back font if we changed it
-
- if ( fontSize != 0 &&
- font != 0 )
- {
- TextFont( saveFont );
- TextSize( saveSize );
- }
- }
-
- /*----------------------------*** ACTIVATELISTITEM ***--------------------------------*/
- /*
- hilite current selection. Used instead of LActivate for showing state when focussed, etc.
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::ActivateListItem( const Boolean state )
- {
- short saveFont, saveSize;
-
- SetUpFontForList( &saveFont, &saveSize );
-
- if ( state )
- LSetSelect( TRUE, lastSel, theList );
- else
- {
- lastSel.h = lastSel.v = 0;
- LGetSelect( TRUE, &lastSel, theList );
- LSetSelect( FALSE, lastSel, theList );
- }
-
- // but back font if we changed it
-
- if ( fontSize != 0 &&
- font != 0 )
- {
- TextFont( saveFont );
- TextSize( saveSize );
- }
- }
-
-
- /*---------------------------------*** ACTIVATE ***-----------------------------------*/
- /*
- owning window is becoming active/inactive. Handle hiliting accordingly.
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::Activate( const Boolean isActive )
- {
- ZAdvancedDialog* zd = (ZAdvancedDialog*) GetBoss();
-
- if ( isHandler && zd->HasMultipleFoci())
- DrawBorder( isActive );
-
- ActivateListItem( isActive );
- PenNormal();
- }
-
-
- /*-----------------------------*** SETUPFONTFORLIST ***-------------------------------*/
- /*
- if list is using font different to window, this set it up. Should be called before any
- list manager call. Returns existing font
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::SetUpFontForList( short* curFont, short* curSize )
- {
- if ( font != 0 &&
- fontSize != 0 )
- {
- ZDialog* zd = (ZDialog*) GetBoss();
-
- *curFont = zd->GetMacWindow()->txFont;
- *curSize = zd->GetMacWindow()->txSize;
-
- TextFont( font );
- TextSize( fontSize );
- }
- }
-
-
- /*-------------------------------*** APPENDSTRING ***---------------------------------*/
- /*
- appends the passed string to the list. This is a convenience function for building lists
- on the fly programmatically. This also assumes a 1-column list.
- ----------------------------------------------------------------------------------------*/
-
- void ZListDialogItem::AppendString( Str255 aString, Boolean drawIt )
- {
- Cell aCell = { 0, 0 };
-
- aCell.v = (*theList)->dataBounds.bottom;
-
- LSetDrawingMode( FALSE, theList );
-
- // append to the list
-
- aCell.v = LAddRow( 1, aCell.v + 1, theList );
- LSetCell( &aString[1], aString[0], aCell, theList );
-
- LSetDrawingMode( TRUE, theList );
-
- if ( drawIt )
- DrawItem();
- }
-
-
- #pragma mark ============ FindCellCompProc ==============
-
- /*----------------------------*** FindCellCompProc ***--------------------------------*/
- /*
- used to locate suitable cells when typing in a list box
- ----------------------------------------------------------------------------------------*/
-
- static pascal short FindCellCompProc( Ptr dataA, Ptr dataB, short lenA, short lenB )
- {
- short result = 1;
-
- if ( lenA > 0 )
- {
- if ( IUMagIDString( dataA, dataB, lenA, lenB ) == 0 )
- result = 0;
- else
- {
- if ( IUMagString( dataA, dataB, lenA, lenB ) == 1)
- result = 0;
- }
- }
-
- return result;
- }
-
- #pragma mark ============ ZAdvancedDialog ==============
-
- // the dialog:
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
- ZAdvancedDialog::ZAdvancedDialog( ZCommander* aBoss, const short dialogID )
- : ZDialog( aBoss, dialogID )
- {
- itsItems = NULL; // no special items initially
- curHandler = NULL; // interpreted to mean "this", if NULL
- focusItem = 0; // no object item has the keyboard focus
- }
-
-
- /*---------------------------------*** DESTRUCTOR ***---------------------------------*/
-
- ZAdvancedDialog::~ZAdvancedDialog()
- {
- if ( itsItems )
- {
- itsItems->DisposeAll();
- ForgetObject( itsItems );
- }
- }
-
-
- /*----------------------------------*** SETUP ***-------------------------------------*/
- /*
- set up the dialog, including special object items
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::SetUp()
- {
- inherited::SetUp();
-
- // once everything is built in the normal way, look for the magic static text items.
-
- Focus();
- BuildItemList();
-
- // if we only have a single focus, make sure it's selected by default! Otherwise we
- // rely on the inherited SetUp to select the first editable text field. You can of
- // course override this to make any desired item the initial focus.
-
- if ( ! HasMultipleFoci())
- SelectNextFocus();
- }
-
-
- /*-------------------------------*** SELECTITEM ***-----------------------------------*/
- /*
- for your convenience, you can call this to switch to a particular edit field or other
- focussable item. Called internally by SelectNextFocus. If the item can't be a focus,
- this does nothing. This will redraw hilites, etc as needed.
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::SelectItem( const short item )
- {
- ZDialogItem* di;
- short iType;
- Handle iHand;
- Rect iBox;
-
- di = GetObjectItem( item );
-
- if (di && di->CanBeHandler())
- di->BecomeHandler( TRUE );
- else
- {
- GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
-
- if (( iType & 0x7F) == editText )
- {
- focusItem = 0;
- ClickItem( item );
- }
- }
- }
-
-
- /*--------------------------------*** DEACTIVATE ***----------------------------------*/
- /*
- deactivate focussed item if needed
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::Deactivate()
- {
- if ( focusItem != 0 )
- {
- // one of our items is the focus, not a text field, so handle the hilite
- // here and return handled TRUE.
-
- ZDialogItem* di = GetObjectItem( focusItem );
-
- if ( di )
- di->Activate( FALSE );
- }
- else
- inherited::Deactivate();
- }
-
-
- /*---------------------------------*** ACTIVATE ***-----------------------------------*/
- /*
- activate focussed item if needed
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::Activate()
- {
- if ( focusItem != 0 )
- {
- // one of our items is the focus, not a text field, so handle the hilite
- // here and return handled TRUE.
-
- ZDialogItem* di = GetObjectItem( focusItem );
-
- if ( di )
- di->Activate( TRUE );
- }
- else
- inherited::Activate();
- }
-
-
- /*--------------------------------*** GETHANDLER ***----------------------------------*/
- /*
- return active item if current, or this
- ----------------------------------------------------------------------------------------*/
-
- ZCommander* ZAdvancedDialog::GetHandler()
- {
- if ( curHandler )
- return curHandler;
- else
- return this;
- }
-
-
- /*--------------------------------*** CLICKITEM ***-----------------------------------*/
- /*
- pass clicks to dialog items
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::ClickItem( const short item )
- {
- ZDialogItem* di;
-
- di = GetObjectItem( item );
-
- if ( di && di->Enabled())
- {
- EventRecord theEvent;
-
- // get the mouse and modifiers from the most recent event
-
- gApplication->GetCurrentEvent( &theEvent );
- GlobalToLocal( &theEvent.where );
-
- di->ClickItem( theEvent.where, theEvent.modifiers );
- }
- else
- {
- // if the item is an edit text field, then we may need to divert the keyboard focus
-
- short iType;
- Handle iHand;
- Rect iBox;
-
- GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
- if ((iType & 0x7F) == editText )
- ReceiveMessage( NULL, ItemNowHandler, NULL );
-
- inherited::ClickItem( item );
- }
- }
-
-
- /*-----------------------------------*** TYPE ***-------------------------------------*/
- /*
- handle keypresses. We need to do a little more than usual to handle tabbing, and passing
- keystrokes to our custom items, if need be
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::Type( const char theKey )
- {
- Boolean handled = FALSE;
-
- Focus();
-
- if ( theKey == TAB_KEY ) // tab
- handled = SelectNextFocus();
-
- if (! handled && ( curHandler == NULL ))
- inherited::Type( theKey );
- }
-
-
- /*-------------------------------*** ADJUSTCURSOR ***---------------------------------*/
- /*
- if the cursor is over an object item, call its adjust cursor method
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::AdjustCursor( const Point mouse, const short modifiers )
- {
- ZDialogItem* di;
-
- di = FindObjectItem( mouse );
-
- if (di && di->Enabled())
- di->AdjustCursor( mouse, modifiers );
- else
- inherited::AdjustCursor( mouse, modifiers );
- }
-
-
- /*-------------------------------*** DRAWUSERITEM ***---------------------------------*/
- /*
- if the item is a dialog item object, ask it to draw, otherwise call the inherited method
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::DrawUserItem( const short item )
- {
- ZDialogItem* di;
-
- di = GetObjectItem( item );
-
- if ( di )
- {
- ZGrafState zg;
-
- di->DrawItem();
- }
- else
- inherited::DrawUserItem( item );
- }
-
-
- /*------------------------*** PARSESTATTEXTPSEUDOOBJECTS ***--------------------------*/
- /*
- Extract parameters from the static text string
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::ParseStatTextPseudoObjects( Str255 sText, long* typeParam, long* param1, long* param2 )
- {
- // initially assume we won't find the magic string:
-
- *typeParam = 0;
- *param1 = 0;
- *param2 = 0;
-
- // is the string at least 6 chars long? It must consist of two dollar signs followed
- // by a four character object code. The additional parameters are optional.
-
- if ( sText[0] >= 6 )
- {
- // does it begin with two dollar signs?
-
- if (sText[1] == '$' &&
- sText[2] == '$' )
- {
- // yes, so extract the magic object code ( next 4 chars ). Note that heavyweight
- // frameworks sometimes do this sort of thing, but with the actual class name,
- // which they then pass to new_by_name, or somesuch. Though that allows greater
- // generality with less code, it is not really supported in a nice generic way
- // by all compilers, so we have opted for this simpler approach.
-
- *typeParam = *(long*) &sText[3];
-
- // any parameters? These should be comma delimited numbers
-
- char pc = 0;
- char i = 7;
- char t;
- long p;
- Str15 seg;
-
- while( i <= sText[0] )
- {
- if ( sText[i++] == ',' )
- {
- t = i;
-
- // found a comma, search forward to next comma or
- // end of string
-
- while(( sText[t] != ',' ) && ( t <= sText[0] )) t++;
-
- // extract part of string between two commas
-
- BlockMoveData( &sText[i], &seg[1], t - i );
- seg[0] = t - i;
-
- StringToNum( seg, &p );
-
- i = t;
-
- // set parameter
-
- switch (pc++)
- {
- case 0:
- *param1 = p;
- break;
- case 1:
- *param2 = p;
- break;
- }
- }
- }
- }
- }
- }
-
- /*-------------------------------*** BUILDITEMLIST ***--------------------------------*/
- /*
- builds the list of object items. This scans the dialog items looking for static text items.
- If they contain the magic strings, the items are converted to user items and a relevant
- object is created. To extend the types of objects this can make, override the
- MakeObjectItem method
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::BuildItemList()
- {
- short n = CountDITL( macWindow );
- short iType;
- long p0, p1, p2;
- Handle iHand;
- Rect iBox;
- ZDialogItem* di;
- Str255 iText;
-
- do
- {
- GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
-
- if ((iType & 0x7F) == statText)
- {
- GetDialogItemText( iHand, iText );
-
- // attempt to extract "magic" object parameters
-
- ParseStatTextPseudoObjects( iText, &p0, &p1, &p2 );
-
- // call the method to make the relevant object item from the code passed
-
- di = MakeObjectItem( p0, n );
-
- if ( di )
- {
- // if the item list hasn't been created yet, do it now
-
- if ( itsItems == NULL )
- FailNIL( itsItems = new ZDialogItemList());
-
- // convert the static text item to a user item and set up its
- // drawing proc.
-
- SetDialogItem( macWindow, n, userItem, (Handle) gUIVectorUPP, &iBox );
-
- // add it to our list of items
-
- itsItems->AppendItem( di );
-
- // now pass it any parameters we may have extracted
-
- di->InitItem( p1, p2 );
- }
- }
- }
- while( --n );
- }
-
-
- /*-----------------------------*** MAKEOBJECTITEM ***---------------------------------*/
- /*
- make an object to match the type sent from the stat text parameter. Override for
- additional types. In fact, this is the only method you need to override to extend the
- number of special objects this dialog can deal with.
- ----------------------------------------------------------------------------------------*/
-
- ZDialogItem* ZAdvancedDialog::MakeObjectItem( const long aType, const short id )
- {
- ZDialogItem* di = NULL;
-
- switch ( aType )
- {
- case 'LIST':
- di = new ZListDialogItem( this, id );
- break;
-
- #ifdef __ZEXTRADIALOGITEMS__
-
- case 'LINE':
- di = new ZLineDialogItem( this, id );
- break;
- case 'ICLB':
- di = new ZIconListBox( this, id );
- break;
- case 'TEXT':
- di = new ZScrollingTextBox( this, id );
- break;
-
- #endif
- }
-
- return di;
- }
-
-
- /*---------------------------------*** FINDITEM ***-----------------------------------*/
- /*
- find which if any of the special items contains the point
- ----------------------------------------------------------------------------------------*/
-
- ZDialogItem* ZAdvancedDialog::FindObjectItem( const Point where )
- {
- ZDialogItem* di = NULL;
- long i;
-
- if ( itsItems )
- {
- for( i = 1; i <= itsItems->CountItems(); i++ )
- {
- di = itsItems->GetObject( i );
-
- if (di && di->ContainsPoint( where ))
- break;
-
- di = NULL;
- }
- }
-
- return di;
- }
-
-
- /*----------------------------------*** GETITEM ***-----------------------------------*/
- /*
- find an object item that has the ID passed, or NULL if none do.
- ----------------------------------------------------------------------------------------*/
-
- ZDialogItem* ZAdvancedDialog::GetObjectItem( const short item )
- {
- ZDialogItem* di = NULL;
- long i;
-
- if ( itsItems )
- {
- for( i = 1; i <= itsItems->CountItems(); i++ )
- {
- di = itsItems->GetObject( i );
-
- if (di && di->GetID() == item )
- break;
-
- di = NULL;
- }
- }
-
- return di;
- }
-
-
- /*------------------------------*** RECEIVEMESSAGE ***--------------------------------*/
- /*
- manipulate command chain in response to items coming into focus, etc.
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::ReceiveMessage( ZComrade* aSender, long aMessage, void* msgData )
- {
- switch ( aMessage )
- {
- case ItemNowHandler:
- if ( aSender != curHandler )
- {
- // tell current handler to stop being the handler!
-
- if ( curHandler )
- curHandler->BecomeHandler( FALSE );
-
- curHandler = (ZDialogItem*) aSender;
-
- ClipRect( &macWindow->portRect );
- PenNormal();
- ForeColor( blackColor );
-
- if ( curHandler )
- {
- // if there is a new item handler, make sure any editable text
- // is not hilited
-
- HiliteDialogText( FALSE );
-
- focusItem = curHandler->GetID();
- ((DialogPeek) macWindow)->editField = 0;
- }
- else
- {
- focusItem = 0;
- HiliteDialogText( TRUE );
- }
- gCurHandler = GetHandler();
- }
- break;
- case ItemNoLongerHandler:
- curHandler = NULL;
- gCurHandler = GetHandler();
- break;
- default:
- inherited::ReceiveMessage( aSender, aMessage, msgData );
- break;
- }
- }
-
- /*-----------------------------*** HILITEDIALOGTEXT ***-------------------------------*/
- /*
- set up hiliting of edit text items in the dialog
- ----------------------------------------------------------------------------------------*/
-
- void ZAdvancedDialog::HiliteDialogText( Boolean state )
- {
- // turn on/off any editable text hiliting
-
- DialogPeek dp = (DialogPeek) macWindow;
-
- if ( dp->textH )
- {
- if ( state )
- TEActivate( dp->textH );
- else
- {
- TEDeactivate( dp->textH );
- TESetSelect( 32767, 32767, dp->textH );
- }
- }
- }
-
-
- /*------------------------------*** SELECTNEXTFOCUS ***-------------------------------*/
- /*
- this is a cunning routine that allows us to sneak our extra focussable items into the
- normal tabbing behaviour. Items that can have the focus are selected in turn each time
- this is called. If the item is a standard edit field, this returns FALSE. If it's one
- of ours, it returns TRUE. This boolean is passed back from the Filter function so that
- it controls whether the dialog manager helps us out or not.
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZAdvancedDialog::SelectNextFocus()
- {
- DialogPeek dp;
- short curFocus, totalItems, n, iType, i;
- ZDialogItem* di;
- Boolean found = FALSE;
- Handle iHand;
- Rect iBox;
-
- dp = (DialogPeek) macWindow;
- totalItems = CountDITL( macWindow );
-
- // what item currently has the focus?
-
- if ((focusItem == 0) && HasEditFields())
- curFocus = dp->editField + 1;
- else
- curFocus = focusItem;
-
- n = curFocus + 1;
- i = 0;
-
- // find the next item to this one eligible to have the focus. This is either an
- // edit field or an object item that returns TRUE for CanBeHandler.
-
- do
- {
- // if we got to the end, start over at item 1
-
- if ( n > totalItems )
- n = 1;
-
- // is there an object at this position?
-
- di = GetObjectItem( n );
-
- if (di && di->CanBeHandler())
- {
- // yes, and it can be the focus!!
-
- found = TRUE;
- break;
- }
- else
- {
- // no. Is there an edit text item in this position?
-
- GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
-
- if (( iType & 0x7F ) == editText )
- {
- // yes, so we'll let the Dialog Manager set the focus on this one
-
- found = TRUE;
- break;
- }
- }
-
- n++; // try the next item
- }
- while( !found && ( ++i < totalItems ));
-
- // if we found an item to be focussed, set that focus now
-
- if ( found )
- SelectItem( n );
-
- // if an object, we handled it...
-
- return ( focusItem != 0 );
- }
-
-
- /*------------------------------*** HASMULTIPLEFOCI ***-------------------------------*/
- /*
- this returns TRUE if this dialog has more than 1 item that can be the keyboard focus.
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZAdvancedDialog::HasMultipleFoci()
- {
- short iType, fCount = 0, n;
- Handle iHand;
- Rect iBox;
- ZDialogItem* di;
-
- n = CountDITL( macWindow );
-
- do
- {
- di = GetObjectItem( n );
-
- if (di && di->CanBeHandler())
- fCount++;
- else
- {
- GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
-
- if (( iType & 0x7F ) == editText )
- fCount++;
- }
- }
- while( --n );
-
- return ( fCount > 1 );
- }
-
-