// ******************************************************************************************* // DialogsAndAlerts.h CLASSIC EVENT MODEL // ******************************************************************************************* // // This program initially opens a small modal dialog which is automatically closed after 10 // seconds, the timeout value having been set by a call to SetDialogTimeout. The program // then: // // o Opens a window for the purposes of displaying advisory text and proving correct window // updating and activation/deactivation in the presence of alerts and dialogs. // // o Allows the user to invoke, via the Demonstration menu, modal and movable modal alerts // and dialogs, a modeless dialog and, on Mac OS X, a window-modal alert and dialog // (i.e., sheets). // // The modal alert box is created programmatically using the StandardAlert function. // // The movable modal alert is created programmatically using the StandardAlert function on Mac // OS 9 and the CreateStandardAlert function on Mac OS X. // // The modal dialog contains three checkboxes in one group box, and two pop-up menu buttons in // another group box. // // The movable modal dialog contains four radio buttons in one group box, and a clock control // and edit text item in another group box. // // The modeless dialog contains, amongst other items, an edit text item. // // The modal and movable modal alerts and dialogs use an application-defined event filter // (callback) function. // // The program utilises the following resources: // // o A 'plst' resource. // // o An 'MBAR' resource, and 'MENU' resources for Apple, File, and Demonstration pull-down // menus, and the pop-up menu buttons (preload, non-purgeable). // // o A 'WIND' resource (purgeable) (initially visible). // // o 'DLOG' resources (purgeable) (initially not visible) and associated 'DITL' resources // (purgeable), 'dlgx' resources (purgeable), and 'dftb' resources (non-purgeable, but // 'dftb' resources are automatically marked purgeable when read in). // // o 'CNTL' resources for primary group boxes, separator lines, pop-up menu buttons, a clock, // and an image well (all purgeable). // // o 'STR#' resources (purgeable) containing the message and informative text for the alerts. // // o A 'cicn' resource (purgeable) for the modeless dialog box. // // o A 'ppat' resource (purgeable), which is used to colour the content region of the // document window for update proving purposes. // // o 'hdlg' resources (purgeable) containing balloon help information for the modal and // movable modal dialog. // // o An 'hrct' resource and associated 'hwin' resource (both purgeable) containing balloon // help information for the modeless dialog. // // o A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, // doesActivateOnFGSwitch, and isHighLevelEventAware flags set. // // ******************************************************************************************* // .................................................................................. includes #include <Carbon.h> // ................................................................................... defines #define rMenubar 128 #define mAppleApplication 128 #define iAbout 1 #define mFile 129 #define iClose 4 #define iQuit 12 #define mEdit 130 #define iCut 3 #define iCopy 4 #define iPaste 5 #define iClear 6 #define mDemonstration 131 #define iModalAlert 1 #define iMovableAlert 2 #define iModalDialog 3 #define iMovableModalDialog 4 #define iModeless 5 #define iWindowModalAlert 7 #define iWindowModalDialog 8 #define mFont 132 #define rWindow 128 #define rSplash 128 #define rModalDialog 129 #define iGridSnap 4 #define iShowGrid 5 #define iShowRulers 6 #define iFont 11 #define iSound 12 #define rMovableModalDialog 130 #define iCharcoal 7 #define iOilPaint 8 #define iPencil 9 #define iChalk 10 #define iClockOne 12 #define rModelessDialog 131 #define iEditTextSearchModeless 2 #define rSheetDialog 132 #define iEditTextSheetDialog 2 #define rAlertStrings 128 #define sModalMessage 1 #define sModalInformative 2 #define sMovableMessage 3 #define sMovableInformative 4 #define rSheetStrings 132 #define sAlertSheetMessage 1 #define sAlertSheetInformative 2 #define rPixelPattern 128 #define kSearchModeless 1 #define kSheetDialog 2 #define kReturn (SInt8) 0x0D #define kEnter (SInt8) 0x03 #define kEscape (SInt8) 0x1B #define kPeriod (SInt8) 0x2E #define MAX_UINT32 0xFFFFFFFF // ....................................................................... function prototypes void main (void); void doPreliminaries (void); OSErr quitAppEventHandler (AppleEvent *,AppleEvent *,SInt32); void eventLoop (void); void doIdle (void); void doEvents (EventRecord *); void doMouseDown (EventRecord *); void doKeyDown (EventRecord *); void doUpdate (EventRecord *); void doUpdateDocument (WindowRef); void doActivate (EventRecord *); void doActivateDocument (WindowRef,Boolean); void doActivateDialogs (EventRecord *,Boolean); void doOSEvent (EventRecord *); void doAdjustMenus (void); void doMenuChoice (SInt32); void doEditMenu (MenuItemIndex); void doDemonstrationMenu (MenuItemIndex); void doExplicitlyDeactivateDocument (void); Boolean doModalAlerts (Boolean); Boolean doMovableModalAlertOnX (void); Boolean doModalDialog (void); Boolean doMovableModalDialog (void); Boolean doCreateOrShowModelessDialog (void); void doInContent (EventRecord *); void doButtonHitInSearchModeless (void); void doHideModelessDialog (WindowRef); Boolean eventFilter (DialogRef,EventRecord *,SInt16 *); void doPopupMenuChoice (ControlRef,SInt16); void doDrawMessage (WindowRef,Boolean); void doCopyPString (Str255,Str255); Boolean doSheetAlert (void); Boolean doSheetDialog (void); void doButtonHitInSheetDialog (void); void helpTagsModal (DialogRef); void helpTagsMovableModal (DialogRef); void helpTagsModeless (DialogRef); // ******************************************************************************************* // DialogsAndAlerts.c // ******************************************************************************************* // .................................................................................. includes #include "DialogsAndAlerts.h" // .......................................................................... global variables Boolean gRunningOnX = false; ModalFilterUPP gEventFilterUPP; Str255 gCurrentString; WindowRef gWindowRef; SInt32 gSleepTime; Boolean gDone; Boolean gGridSnap = kControlCheckBoxUncheckedValue; Boolean gShowGrid = kControlCheckBoxUncheckedValue; Boolean gShowRule = kControlCheckBoxUncheckedValue; SInt16 gBrushType = iCharcoal; DialogRef gModelessDialogRef = NULL; // ************************************************************************************** main void main(void) { MenuBarHandle menubarHdl; SInt32 response; MenuRef menuRef; DialogRef dialogRef; SInt16 itemHit; // ........................................................................ do preliminaries doPreliminaries(); // ............................................................... set up menu bar and menus menubarHdl = GetNewMBar(rMenubar); if(menubarHdl == NULL) ExitToShell(); SetMenuBar(menubarHdl); DrawMenuBar(); Gestalt(gestaltMenuMgrAttr,&response); if(response & gestaltMenuMgrAquaLayoutMask) { menuRef = GetMenuRef(mFile); if(menuRef != NULL) { DeleteMenuItem(menuRef,iQuit); DeleteMenuItem(menuRef,iQuit - 1); DisableMenuItem(menuRef,0); } gRunningOnX = true; } // ................... open small modal dialog and automatically dismiss it after 10 seconds dialogRef = GetNewDialog(rSplash,NULL,(WindowRef) -1); SetDialogTimeout(dialogRef,kStdOkItemIndex,10); do { ModalDialog(NULL,&itemHit); } while(itemHit != kStdOkItemIndex); DisposeDialog(dialogRef); // ............................ create universal procedure pointer for event filter function gEventFilterUPP = NewModalFilterUPP((ModalFilterProcPtr) eventFilter); // ................................................. initial advisory text for window header doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString); // ............................................................ open a window, set font size if(!(gWindowRef = GetNewCWindow(rWindow,NULL,(WindowRef)-1))) ExitToShell(); SetPortWindowPort(gWindowRef); if(!gRunningOnX) TextSize(10); // ......................................................................... enter eventLoop eventLoop(); } // *************************************************************************** doPreliminaries void doPreliminaries(void) { OSErr osError; MoreMasterPointers(192); InitCursor(); FlushEvents(everyEvent,0); osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler), 0L,false); if(osError != noErr) ExitToShell(); } // **************************************************************************** doQuitAppEvent OSErr quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon) { OSErr osError; DescType returnedType; Size actualSize; osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0, &actualSize); if(osError == errAEDescNotFound) { gDone = true; osError = noErr; } else if(osError == noErr) osError = errAEParamMissed; return osError; } // ********************************************************************************* eventLoop void eventLoop(void) { EventRecord eventStructure; Boolean gotEvent; gSleepTime = MAX_UINT32; gDone = false; while(!gDone) { gotEvent = WaitNextEvent(everyEvent,&eventStructure,gSleepTime,NULL); if(gotEvent) doEvents(&eventStructure); else { if(eventStructure.what == nullEvent) if(!gRunningOnX) doIdle(); } } } // ************************************************************************************ doIdle void doIdle(void) { if(FrontWindow() == GetDialogWindow(gModelessDialogRef)) IdleControls(GetDialogWindow(gModelessDialogRef)); } // ********************************************************************************** doEvents void doEvents(EventRecord *eventStrucPtr) { switch(eventStrucPtr->what) { case kHighLevelEvent: AEProcessAppleEvent(eventStrucPtr); break; case mouseDown: doMouseDown(eventStrucPtr); break; case keyDown: doKeyDown(eventStrucPtr); break; case autoKey: if((eventStrucPtr->modifiers & cmdKey) == 0) doKeyDown(eventStrucPtr); break; case updateEvt: doUpdate(eventStrucPtr); break; case activateEvt: doActivate(eventStrucPtr); break; case osEvt: doOSEvent(eventStrucPtr); break; } } // ******************************************************************************* doMouseDown void doMouseDown(EventRecord *eventStrucPtr) { WindowRef windowRef; WindowPartCode partCode; partCode = FindWindow(eventStrucPtr->where,&windowRef); switch(partCode) { case inMenuBar: doAdjustMenus(); doMenuChoice(MenuSelect(eventStrucPtr->where)); break; case inContent: if(windowRef != FrontWindow()) SelectWindow(windowRef); else doInContent(eventStrucPtr); break; case inDrag: DragWindow(windowRef,eventStrucPtr->where,NULL); break; case inGoAway: if(TrackGoAway(windowRef,eventStrucPtr->where)) { if(GetWindowKind(windowRef) == kDialogWindowKind) { doHideModelessDialog(windowRef); doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available", gCurrentString); } } break; } } // ********************************************************************************* doKeyDown void doKeyDown(EventRecord *eventStrucPtr) { WindowRef windowRef; SInt8 charCode; SInt32 windowRefCon; SInt16 itemHit; ControlRef controlRef; UInt32 finalTicks; DialogRef dialogRef; windowRef = FrontWindow(); charCode = eventStrucPtr->message & charCodeMask; if(!(IsDialogEvent(eventStrucPtr))) { if((eventStrucPtr->modifiers & cmdKey) != 0) { doAdjustMenus(); doMenuChoice(MenuEvent(eventStrucPtr)); } } else { windowRefCon = GetWRefCon(windowRef); if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog) { if((charCode == kReturn) || (charCode == kEnter)) { GetDialogItemAsControl(GetDialogFromWindow(windowRef),kStdOkItemIndex,&controlRef); HiliteControl(controlRef,kControlButtonPart); Delay(8,&finalTicks); HiliteControl(controlRef,kControlEntireControl); if(windowRefCon == kSearchModeless) doButtonHitInSearchModeless(); else if(windowRefCon == kSheetDialog) doButtonHitInSheetDialog(); return; } if((eventStrucPtr->modifiers & cmdKey) != 0) { if(charCode == 'X' || charCode == 'x' || charCode == 'C' || charCode == 'c' || charCode == 'V' || charCode == 'v') { HiliteMenu(mEdit); DialogSelect(eventStrucPtr,&dialogRef,&itemHit); Delay(4,&finalTicks); HiliteMenu(0); } else { doAdjustMenus(); doMenuChoice(MenuEvent(eventStrucPtr)); } return; } DialogSelect(eventStrucPtr,&dialogRef,&itemHit); } } } // ********************************************************************************** doUpdate void doUpdate(EventRecord *eventStrucPtr) { WindowRef windowRef; DialogRef dialogRef; SInt16 itemHit; if(!(IsDialogEvent(eventStrucPtr))) { windowRef = (WindowRef) eventStrucPtr->message; doUpdateDocument(windowRef); } else DialogSelect(eventStrucPtr,&dialogRef,&itemHit); } // ************************************************************************** doUpdateDocument void doUpdateDocument(WindowRef windowRef) { GrafPtr oldPort; PixPatHandle pixpatHdl; Rect portRect; BeginUpdate(windowRef); GetPort(&oldPort); SetPortWindowPort(windowRef); pixpatHdl = GetPixPat(rPixelPattern); GetWindowPortBounds(windowRef,&portRect); FillCRect(&portRect,pixpatHdl); DisposePixPat(pixpatHdl); doDrawMessage(windowRef,windowRef == FrontWindow()); SetPort(oldPort); EndUpdate(windowRef); } // ******************************************************************************** doActivate void doActivate(EventRecord *eventStrucPtr) { Boolean becomingActive; WindowRef windowRef; becomingActive = (eventStrucPtr->modifiers & activeFlag) == activeFlag; if(!(IsDialogEvent(eventStrucPtr))) { windowRef = (WindowRef) eventStrucPtr->message; doActivateDocument(windowRef,becomingActive); } else doActivateDialogs(eventStrucPtr,becomingActive); } // ************************************************************************ doActivateDocument void doActivateDocument(WindowRef windowRef,Boolean becomingActive) { if(becomingActive) doAdjustMenus(); doDrawMessage(windowRef,becomingActive); } // ****************************************************************** doActivateModelessDialog void doActivateDialogs(EventRecord *eventStrucPtr,Boolean becomingActive) { DialogRef dialogRef; SInt16 windowRefCon; SInt16 itemHit; DialogSelect(eventStrucPtr,&dialogRef,&itemHit); windowRefCon = GetWRefCon(GetDialogWindow(dialogRef)); if(becomingActive) { doAdjustMenus(); if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog) gSleepTime = GetCaretTime(); } else { if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog) gSleepTime = MAX_UINT32; } } // ********************************************************************************* doOSEvent void doOSEvent(EventRecord *eventStrucPtr) { switch((eventStrucPtr->message >> 24) & 0x000000FF) { case suspendResumeMessage: if((eventStrucPtr->message & resumeFlag) == 1) SetThemeCursor(kThemeArrowCursor); break; } } // ***************************************************************************** doAdjustMenus void doAdjustMenus(void) { WindowRef windowRef; MenuRef menuRef; SInt32 windowRefCon; windowRef = FrontWindow(); if(GetWindowKind(windowRef) == kApplicationWindowKind) { menuRef = GetMenuRef(mFile); DisableMenuItem(menuRef,iClose); menuRef = GetMenuRef(mEdit); DisableMenuItem(menuRef,0); menuRef = GetMenuRef(mDemonstration); EnableMenuItem(menuRef,iModeless); if(gRunningOnX) { if(IsWindowCollapsed(gWindowRef)) { DisableMenuItem(menuRef,iWindowModalDialog); DisableMenuItem(menuRef,iWindowModalAlert); } else { EnableMenuItem(menuRef,iWindowModalDialog); EnableMenuItem(menuRef,iWindowModalAlert); } } } else if(GetWindowKind(windowRef) == kDialogWindowKind) { windowRefCon = GetWRefCon(windowRef); if(windowRefCon == kSearchModeless) { menuRef = GetMenuRef(mFile); EnableMenuItem(menuRef,iClose); menuRef = GetMenuRef(mEdit); EnableMenuItem(menuRef,0); menuRef = GetMenuRef(mDemonstration); DisableMenuItem(menuRef,iModeless); } else if(windowRefCon == kSheetDialog) { menuRef = GetMenuRef(mFile); DisableMenuItem(menuRef,iClose); menuRef = GetMenuRef(mEdit); EnableMenuItem(menuRef,0); menuRef = GetMenuRef(mDemonstration); EnableMenuItem(menuRef,iModeless); DisableMenuItem(menuRef,iWindowModalAlert); } else { menuRef = GetMenuRef(mFile); DisableMenuItem(menuRef,iClose); menuRef = GetMenuRef(mEdit); DisableMenuItem(menuRef,0); menuRef = GetMenuRef(mDemonstration); EnableMenuItem(menuRef,iModeless); } } DrawMenuBar(); } // ****************************************************************************** doMenuChoice void doMenuChoice(SInt32 menuChoice) { MenuID menuID; MenuItemIndex menuItem; SInt16 windowRefCon; menuID = HiWord(menuChoice); menuItem = LoWord(menuChoice); if(menuID == 0) return; switch(menuID) { case mAppleApplication: if(menuItem == iAbout) SysBeep(10); break; case mFile: if(menuItem == iQuit) gDone = true; else if(menuItem == iClose) { if(GetWindowKind(FrontWindow()) == kDialogWindowKind) { windowRefCon = GetWRefCon(FrontWindow()); if(windowRefCon == kSearchModeless) doHideModelessDialog(GetDialogWindow(gModelessDialogRef)); } } break; case mEdit: doEditMenu(menuItem); break; case mDemonstration: doDemonstrationMenu(menuItem); break; } HiliteMenu(0); } // ******************************************************************************** doEditMenu void doEditMenu(MenuItemIndex menuItem) { WindowRef windowRef; SInt16 windowRefCon; DialogRef dialogRef; windowRef = FrontWindow(); if(GetWindowKind(FrontWindow()) == kDialogWindowKind) { windowRefCon = GetWRefCon(windowRef); if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog) { dialogRef = GetDialogFromWindow(windowRef); switch(menuItem) { case iCut: DialogCut(dialogRef); break; case iCopy: DialogCopy(dialogRef); break; case iPaste: DialogPaste(dialogRef); break; case iClear: DialogDelete(dialogRef); break; } } } } // *********************************************************************** doDemonstrationMenu void doDemonstrationMenu(MenuItemIndex menuItem) { switch(menuItem) { case iModalAlert: if(!doModalAlerts(false)) { SysBeep(10); ExitToShell(); } break; case iMovableAlert: if(gRunningOnX) { if(!doMovableModalAlertOnX()) { SysBeep(10); ExitToShell(); } } else if(!doModalAlerts(true)) { SysBeep(10); ExitToShell(); } break; case iModalDialog: if(!doModalDialog()) { SysBeep(10); ExitToShell(); } break; case iMovableModalDialog: if(!doMovableModalDialog()) { SysBeep(10); ExitToShell(); } break; case iModeless: if(!doCreateOrShowModelessDialog()) { SysBeep(10); ExitToShell(); } break; case iWindowModalAlert: if(!doSheetAlert()) { SysBeep(10); ExitToShell(); } break; case iWindowModalDialog: if(!doSheetDialog()) { SysBeep(10); ExitToShell(); } break; } } // ************************************************************ doExplicitlyDeactivateDocument void doExplicitlyDeactivateDocument(void) { if(FrontWindow() && (GetWindowKind(FrontWindow()) != kDialogWindowKind)) doActivateDocument(FrontWindow(),false); } // ***************************************************************************** doModalAlerts Boolean doModalAlerts(Boolean movable) { AlertStdAlertParamRec paramRec; Str255 messageText, informativeText; Str255 otherText = "\pOther"; OSErr osError; DialogItemIndex itemHit; doExplicitlyDeactivateDocument(); paramRec.movable = movable; paramRec.helpButton = true; paramRec.filterProc = gEventFilterUPP; paramRec.defaultText = (StringPtr) kAlertDefaultOKText; paramRec.cancelText = (StringPtr) kAlertDefaultCancelText; paramRec.otherText = (StringPtr) &otherText; paramRec.defaultButton = kAlertStdAlertOKButton; paramRec.cancelButton = kAlertStdAlertCancelButton; paramRec.position = kWindowDefaultPosition; if(!movable) GetIndString(messageText,rAlertStrings,sModalMessage); else GetIndString(messageText,rAlertStrings,sMovableMessage); GetIndString(informativeText,rAlertStrings,sModalInformative); osError = StandardAlert(kAlertStopAlert,messageText,informativeText,¶mRec,&itemHit); if(osError == noErr) { if(itemHit == kAlertStdAlertOKButton) doCopyPString("\pOK Button hit",gCurrentString); else if (itemHit == kAlertStdAlertCancelButton) doCopyPString("\pCancel Button hit",gCurrentString); else if (itemHit == kAlertStdAlertOtherButton) doCopyPString("\pOther Button hit",gCurrentString); else if (itemHit == kAlertStdAlertHelpButton) doCopyPString("\pHelp Button hit",gCurrentString); } return (osError == noErr); } // ******************************************************************** doMovableModalAlertOnX Boolean doMovableModalAlertOnX(void) { AlertStdCFStringAlertParamRec paramRec; Str255 messageText, informativeText; CFStringRef messageTextCF, informativeTextCF; OSErr osError; DialogRef dialogRef; DialogItemIndex itemHit; doExplicitlyDeactivateDocument(); GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne); paramRec.movable = true; paramRec.helpButton = true; paramRec.cancelButton = kAlertStdAlertCancelButton; paramRec.cancelText = CFSTR("Cancel"); paramRec.otherText = CFSTR("Other"); GetIndString(messageText,rAlertStrings,sMovableMessage); GetIndString(informativeText,rAlertStrings,sMovableInformative); messageTextCF = CFStringCreateWithPascalString(NULL,messageText, CFStringGetSystemEncoding()); informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText, CFStringGetSystemEncoding()); osError = CreateStandardAlert(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec, &dialogRef); if(osError == noErr) { osError = RunStandardAlert(dialogRef,NULL,&itemHit); if(osError == noErr) { if(itemHit == kAlertStdAlertOKButton) doCopyPString("\pOK Button hit",gCurrentString); else if (itemHit == kAlertStdAlertCancelButton) doCopyPString("\pCancel Button hit",gCurrentString); else if (itemHit == kAlertStdAlertOtherButton) doCopyPString("\pOther Button hit",gCurrentString); else if (itemHit == kAlertStdAlertHelpButton) doCopyPString("\pHelp Button hit",gCurrentString); } } if(messageTextCF != NULL) CFRelease(messageTextCF); if(informativeTextCF != NULL) CFRelease(informativeTextCF); return (osError == noErr); } // ***************************************************************************** doModalDialog Boolean doModalDialog(void) { DialogRef dialogRef; ControlRef controlRef; OSStatus osError; MenuRef menuRef; SInt16 numberOfItems, itemHit, controlValue; doExplicitlyDeactivateDocument(); if(!(dialogRef = GetNewDialog(rModalDialog,NULL,(WindowRef) -1))) return false; SetDialogDefaultItem(dialogRef,kStdOkItemIndex); SetDialogCancelItem(dialogRef,kStdCancelItemIndex); GetDialogItemAsControl(dialogRef,iGridSnap,&controlRef); SetControlValue(controlRef,gGridSnap); GetDialogItemAsControl(dialogRef,iShowGrid,&controlRef); SetControlValue(controlRef,gShowGrid); GetDialogItemAsControl(dialogRef,iShowRulers,&controlRef); SetControlValue(controlRef,gShowRule); menuRef = NewMenu(mFont,NULL); if((osError = CreateStandardFontMenu(menuRef,0,0,0,NULL)) == noErr) { GetDialogItemAsControl(dialogRef,iFont,&controlRef); SetControlMinimum(controlRef,1); numberOfItems = CountMenuItems(menuRef); SetControlMaximum(controlRef,numberOfItems); SetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuRefTag, sizeof(menuRef),&menuRef); } else return false; if(gRunningOnX) helpTagsModal(dialogRef); ShowWindow(GetDialogWindow(dialogRef)); do { ModalDialog(gEventFilterUPP,&itemHit); if(itemHit == iGridSnap || itemHit == iShowGrid || itemHit == iShowRulers) { GetDialogItemAsControl(dialogRef,itemHit,&controlRef); SetControlValue(controlRef,!GetControlValue(controlRef)); } else if(itemHit == iFont || itemHit == iSound) { GetDialogItemAsControl(dialogRef,itemHit,&controlRef); controlValue = GetControlValue(controlRef); doPopupMenuChoice(controlRef,controlValue); } } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex)); if(itemHit == kStdOkItemIndex) { GetDialogItemAsControl(dialogRef,iGridSnap,&controlRef); gGridSnap = GetControlValue(controlRef); GetDialogItemAsControl(dialogRef,iShowGrid,&controlRef); gShowGrid = GetControlValue(controlRef); GetDialogItemAsControl(dialogRef,iShowRulers,&controlRef); gShowRule = GetControlValue(controlRef); } DisposeDialog(dialogRef); doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString); return true; } // ********************************************************************** doMovableModalDialog Boolean doMovableModalDialog(void) { DialogRef dialogRef; ControlRef controlRef; SInt16 oldBrushType, itemHit, a; doExplicitlyDeactivateDocument(); if(!(dialogRef = GetNewDialog(rMovableModalDialog,NULL,(WindowRef) -1))) return false; SetDialogDefaultItem(dialogRef,kStdOkItemIndex); SetDialogCancelItem(dialogRef,kStdCancelItemIndex); SetDialogTracksCursor(dialogRef,true); GetDialogItemAsControl(dialogRef,gBrushType,&controlRef); SetControlValue(controlRef,kControlRadioButtonCheckedValue); GetDialogItemAsControl(dialogRef,iClockOne,&controlRef); SetKeyboardFocus(GetDialogWindow(dialogRef),controlRef,kControlClockPart); oldBrushType = gBrushType; if(gRunningOnX) helpTagsMovableModal(dialogRef); ShowWindow(GetDialogWindow(dialogRef)); do { ModalDialog(gEventFilterUPP,&itemHit); if(itemHit >= iCharcoal && itemHit <= iChalk) { for(a=iCharcoal;a<=iChalk;a++) { GetDialogItemAsControl(dialogRef,a,&controlRef); SetControlValue(controlRef,kControlRadioButtonUncheckedValue); } GetDialogItemAsControl(dialogRef,itemHit,&controlRef); SetControlValue(controlRef,kControlRadioButtonCheckedValue); gBrushType = itemHit; } } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex)); if(itemHit == kStdCancelItemIndex) gBrushType = oldBrushType; DisposeDialog(dialogRef); return true; } // ************************************************************** doCreateOrShowModelessDialog Boolean doCreateOrShowModelessDialog(void) { ControlRef controlRef; Str255 stringData = "\pwicked googly"; MenuRef menuRef; if(gModelessDialogRef == NULL) { if(!(gModelessDialogRef = GetNewDialog(rModelessDialog,NULL,(WindowRef) -1))) return false; SetWRefCon(GetDialogWindow(gModelessDialogRef),(SInt32) kSearchModeless); SetDialogDefaultItem(gModelessDialogRef,kStdOkItemIndex); GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef); SetDialogItemText((Handle) controlRef,stringData); SelectDialogItemText(gModelessDialogRef,iEditTextSearchModeless,0,32767); if(gRunningOnX) helpTagsModeless(gModelessDialogRef); ShowWindow(GetDialogWindow(gModelessDialogRef)); } else { ShowWindow(GetDialogWindow(gModelessDialogRef)); SelectWindow(GetDialogWindow(gModelessDialogRef)); } if(gRunningOnX) { menuRef = GetMenuRef(mFile); EnableMenuItem(menuRef,0); } return true; } // ******************************************************************************* doInContent void doInContent(EventRecord *eventStrucPtr) { WindowRef windowRef; SInt32 windowRefCon; DialogRef dialogRef; SInt16 itemHit; windowRef = FrontWindow(); if(!(IsDialogEvent(eventStrucPtr))) { // Handle clicks in document window content region here. } else { windowRefCon = GetWRefCon(windowRef); if(windowRefCon == kSearchModeless) { if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit)) if(itemHit == kStdOkItemIndex) doButtonHitInSearchModeless(); } else if(windowRefCon == kSheetDialog) { if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit)) if(itemHit == kStdOkItemIndex) doButtonHitInSheetDialog(); } } } // *************************************************************** doButtonHitInSearchModeless void doButtonHitInSearchModeless(void) { ControlRef controlRef; GrafPtr oldPort; GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef); GetDialogItemText((Handle) controlRef,gCurrentString); GetPort(&oldPort); SetPortWindowPort(gWindowRef); doDrawMessage(gWindowRef,false); SetPort(oldPort); } // ********************************************************************** doHideModelessDialog void doHideModelessDialog(WindowRef windowRef) { SInt16 windowRefCon; MenuRef menuRef; if(gRunningOnX) BringToFront(gWindowRef); HideWindow(windowRef); windowRefCon = GetWRefCon(windowRef); if(windowRefCon == kSearchModeless) gSleepTime = MAX_UINT32; if(gRunningOnX) { menuRef = GetMenuRef(mFile); DisableMenuItem(menuRef,0); } } // ******************************************************************************* eventFilter Boolean eventFilter(DialogRef dialogRef,EventRecord *eventStrucPtr,SInt16 *itemHit) { Boolean handledEvent; GrafPtr oldPort; handledEvent = false; if((eventStrucPtr->what == updateEvt) && ((WindowRef) eventStrucPtr->message != GetDialogWindow(dialogRef))) { if(!gRunningOnX) doUpdate(eventStrucPtr); } else if((eventStrucPtr->what == autoKey) && ((eventStrucPtr->modifiers & cmdKey) != 0)) { handledEvent = true; return handledEvent; } else { GetPort(&oldPort); SetPortDialogPort(dialogRef); handledEvent = StdFilterProc(dialogRef,eventStrucPtr,itemHit); SetPort(oldPort); } return handledEvent; } // ************************************************************************* doPopupMenuChoice void doPopupMenuChoice(ControlRef controlRef,SInt16 controlValue) { MenuRef menuRef; Size actualSize; Str255 itemName; GrafPtr oldPort; GetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuHandleTag, sizeof(menuRef),&menuRef,&actualSize); GetMenuItemText(menuRef,controlValue,itemName); doCopyPString(itemName,gCurrentString); GetPort(&oldPort); SetPortWindowPort(gWindowRef); doDrawMessage(gWindowRef,false); SetPort(oldPort); } // ***************************************************************************** doDrawMessage void doDrawMessage(WindowRef windowRef,Boolean inState) { Rect portRect, headerRect; CFStringRef stringRef; Rect textBoxRect; if(windowRef == gWindowRef) { SetPortWindowPort(windowRef); GetWindowPortBounds(windowRef,&portRect); SetRect(&headerRect,portRect.left - 1,portRect.bottom - 26,portRect.right + 1, portRect.bottom + 1); DrawThemePlacard(&headerRect,inState); if(inState == kThemeStateActive) TextMode(srcOr); else TextMode(grayishTextOr); stringRef = CFStringCreateWithPascalString(NULL,gCurrentString, CFStringGetSystemEncoding()); SetRect(&textBoxRect,portRect.left,portRect.bottom - 19,portRect.right, portRect.bottom - 4); DrawThemeTextBox(stringRef,kThemeSmallSystemFont,0,true,&textBoxRect,teJustCenter,NULL); if(stringRef != NULL) CFRelease(stringRef); TextMode(srcOr); } } // ***************************************************************************** doCopyPString void doCopyPString(Str255 sourceString,Str255 destinationString) { SInt16 stringLength; stringLength = sourceString[0]; BlockMove(sourceString + 1,destinationString + 1,stringLength); destinationString[0] = stringLength; } // ******************************************************************************************* // Sheets.c // ******************************************************************************************* // .................................................................................. includes #include "DialogsAndAlerts.h" // .......................................................................... global variables WindowRef gSheetDialogWindowRef = NULL; extern WindowRef gWindowRef; extern Boolean gRunningOnX; extern Str255 gCurrentString; // ****************************************************************************** doSheetAlert Boolean doSheetAlert(void) { AlertStdCFStringAlertParamRec paramRec; Str255 messageText, informativeText; CFStringRef messageTextCF, informativeTextCF; OSStatus osError; DialogRef dialogRef; MenuRef menuRef; GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne); GetIndString(messageText,rSheetStrings,sAlertSheetMessage); GetIndString(informativeText,rSheetStrings,sAlertSheetInformative); messageTextCF = CFStringCreateWithPascalString(NULL,messageText, CFStringGetSystemEncoding()); informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText, CFStringGetSystemEncoding()); osError = CreateStandardSheet(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec, GetWindowEventTarget(gWindowRef),&dialogRef); if(osError == noErr) osError = ShowSheetWindow(GetDialogWindow(dialogRef),gWindowRef); CFRelease(messageTextCF); CFRelease(informativeTextCF); menuRef = GetMenuRef(mDemonstration); if(menuRef != NULL) { DisableMenuItem(menuRef,iWindowModalDialog); DisableMenuItem(menuRef,iWindowModalAlert); } return (osError == noErr); } // ***************************************************************************** doSheetDialog Boolean doSheetDialog(void) { DialogRef dialogRef; ControlRef controlRef; Str255 stringData = "\pBradman"; OSStatus osError = noErr; MenuRef menuRef; if(!(dialogRef = GetNewDialog(rSheetDialog,NULL,(WindowRef) -1))) return false; SetWRefCon(GetDialogWindow(dialogRef),(SInt32) kSheetDialog); SetDialogDefaultItem(dialogRef,kStdOkItemIndex); GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef); SetDialogItemText((Handle) controlRef,stringData); SelectDialogItemText(dialogRef,iEditTextSheetDialog,0,32767); gSheetDialogWindowRef = GetDialogWindow(dialogRef); osError = ShowSheetWindow(gSheetDialogWindowRef,gWindowRef); menuRef = GetMenuRef(mDemonstration); if(menuRef != NULL) DisableMenuItem(menuRef,iWindowModalDialog); return (osError == noErr); } // ****************************************************************** doButtonHitInSheetDialog void doButtonHitInSheetDialog(void) { DialogRef dialogRef; ControlRef controlRef; GrafPtr oldPort; dialogRef = GetDialogFromWindow(gSheetDialogWindowRef); GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef); GetDialogItemText((Handle) controlRef,gCurrentString); HideSheetWindow(gSheetDialogWindowRef); DisposeDialog(dialogRef); gSheetDialogWindowRef = NULL; GetPort(&oldPort); SetPortWindowPort(gWindowRef); doDrawMessage(gWindowRef,true); SetPort(oldPort); } // ******************************************************************************************* // HelpTags.c // ******************************************************************************************* // .................................................................................. includes #include "DialogsAndAlerts.h" #include <string.h> // ***************************************************************************** helpTagsModal void helpTagsModal(DialogRef dialogRef) { HMHelpContentRec helpContent; SInt16 a; static SInt16 itemNumber[7] = { 1,2,3,7,8,10,11 }; ControlRef controlRef; memset(&helpContent,0,sizeof(helpContent)); HMSetTagDelay(500); HMSetHelpTagsDisplayed(true); helpContent.version = kMacHelpVersion; helpContent.tagSide = kHMOutsideTopCenterAligned; helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent; helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 129; for(a = 1;a <= 7; a++) { helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a; GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef); HMSetControlHelpContent(controlRef,&helpContent); } } // ********************************************************************** helpTagsMovableModal void helpTagsMovableModal(DialogRef dialogRef) { HMHelpContentRec helpContent; SInt16 a; static SInt16 itemNumber[9] = { 1,2,3,4,6,11,12,13,14 }; ControlRef controlRef; memset(&helpContent,0,sizeof(helpContent)); HMSetTagDelay(500); HMSetHelpTagsDisplayed(true); helpContent.version = kMacHelpVersion; helpContent.tagSide = kHMOutsideTopCenterAligned; helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent; helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 130; for(a = 1;a <= 9; a++) { helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a; GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef); HMSetControlHelpContent(controlRef,&helpContent); } } // ************************************************************************** helpTagsModeless void helpTagsModeless(DialogRef dialogRef) { HMHelpContentRec helpContent; SInt16 a; static SInt16 itemNumber[7] = { 1,2,3,4,5,6,7 }; ControlRef controlRef; memset(&helpContent,0,sizeof(helpContent)); HMSetTagDelay(500); HMSetHelpTagsDisplayed(true); helpContent.version = kMacHelpVersion; helpContent.tagSide = kHMOutsideTopCenterAligned; helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent; helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 131; for(a = 1;a <= 7; a++) { helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a; GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef); HMSetControlHelpContent(controlRef,&helpContent); } } // *******************************************************************************************
When this program is run, the user should: o Invoke alerts and dialogs by choosing items in the Demonstration menu, noting window update/activation/deactivation and menu enabling/disabling effects. o On Mac OS 8/9, choose Show Balloons from the Help menu and pass the cursor over the various items in the dialogs, noting the information in the help balloons. Also note the updating of alerts and dialogs, and of the window, behind the help balloon when the balloon closes. o On Mac OS X, pause the cursor over the various items in the dialogs, noting the information in the help tags. o Note the effects on the menus when the various alerts and dialogs are the front window. o Click anywhere outside the modal alert and modal dialog when they are the frontmost window, noting that the only response is the system alert sound. o Note that, when the movable modal alert and movable modal dialog are displayed: o The program can be sent to the background by clicking outside the alert or dialog and the document window, or by bringing another application to the foreground. o The program can be brought to the foreground again by clicking inside the alert or dialog, or the document window. o Note that, when the movable modal dialog and (on Mac OS X) the window-modal (sheet) dialog are displayed, the Edit menu and its Cut, Copy, and Paste items are enabled, given that the edit text items in these dialogs always have keyboard focus. o Note that, when the modeless dialog is displayed: o It behaves like a normal document window when the user: o Clicks outside it when it is the frontmost window. o Clicks inside it when it is not the frontmost window. o It can be hidden by clicking in the close box/button or by selecting Close from the File menu. o A modal alert, movable modal alert, modal dialog or movable modal dialog can be invoked "on top of" the modeless dialog. o The Edit menu and its Cut, Copy, Paste, and Clear items are enabled so as to support text editing in the edit text item. o Note that all alerts and dialogs respond correctly to Return and Enter key presses, and that the modal alert, modal dialog and movable modal dialog also respond correctly to escape key and Command-period presses. o Note that, when an alert or dialog is the frontmost window, the window and content region are deactivated, the latter evidenced by dimming of the text in the document window's window header. o In the modal dialog, click on the checkboxes to change their settings, noting that the new settings are remembered when the dialog is dismissed using the OK button, but not remembered when the dialog is dismissed using the Cancel button. Also, choose items in the two pop-up menus, noting that the chosen item is displayed in the document window's window header. o In the movable modal dialog, click on the radio buttons to change their settings, noting that the new setting is remembered when the dialog is dismissed using the OK button, but not remembered when the dialog is dismissed using the Cancel button. In the case of the clock control and edit text item, change the item/part with keyboard focus using the Tab key or by clicking in that item/part. In the case of the edit text item, enter text, and edit that text using the Edit menu's Cut, Copy, Paste, and Clear items and their Command-key equivalents. Note that the cursor shape changes whenever the cursor is moved over the edit text item. o In the modeless dialog and (on Mac OS X) the window-modal (sheet) dialog, enter text, and edit that text using the Edit menu's Cut, Copy, Paste, and Clear items and their Command-key equivalents. Note that, because no cursor adjustment function is included in the program, the cursor shape does not change whenever the cursor is moved over the edit text item. Also note that, when the Search button is clicked (or the Return or Enter keys are pressed) the text in the edit text item is displayed in the document window's window header. o On Mac OS X, when a window-modal (sheet) alert or dialog is showing, minimise the window into the Dock and then expand the window from the dock. In the 'DITL' resources for the modal and movable modal dialogs, note that the item numbers of the primary group box items are lower than the item numbers of the items visually contained by those group box items. This is to ensure that the group boxes do not draw over, and thus erase, the image of these contained items. In the 'dlgx' resources, note that all feature flags are set except for the kDialogFlagsHandlesMovableModal flag in 'dlgx' resources for the modal dialog and modeless dialog. Thus dialogs have a root control and embedding hierarchy. Although, for demonstration purposes, this program creates modal alerts and dialogs, it is emphasised that Aqua Human Interface Guidelines require that, on Mac OS X, applications use modal alerts and dialogs only in exceptional purposes. On Mac OS X, the vast majority of alerts and dialogs should be application-modal or window-modal. On Mac OS X, explanatory Help tags are available for the modal, movable modal, and modeless dialogs. The associated source code (in the source code file HelpTags.c) is not explained in these comments because the provision of Help tags is incidental to the demonstration. For information on creating help tags, see Chapter 25. Note that it is also possible to display help tags on Mac OS 8/9; however, it is considered by the author that their "look" is somewhat at odds with the Platinum appearance, and that help balloons remain the most appropriate option for Mac OS 8/9. The CodeWarrior project for this program adds the CarbonFrameWorksLib stub library because certain functions are used that are only available on Mac OS X. (See "Carbon and Available APIs" at Chapter 25.) Those functions (CreateStandardAlert, RunStandardAlert, GetStandardAlertDefaultParams, CreateStandardSheet, ShowSheetWindow, HideSheetWindow) are only called when the program is run on Mac OS X.
Constants are established for dialog resource IDs and for the item numbers of certain items in the item lists associated with the dialogs. rAlertStrings and rSheetStrings represent the resource IDs of 'STR#' resources holding strings for the message and informative text (label and narrative text in Mac OS 8/9 parlance) for the modal alert, movable modal alert, and window-modal (sheet) alert. The values represented by kSearchModeless and kSheetDialog will be stored as the reference constant in the window object in, respectively, the modeless dialog and window-modal (sheet) dialog objects. This enables the program to distinguish between these two dialogs. The penultimate block establishes constants representing the character codes for the Return, Enter, escape, and period keys. Finally, MAX_UINT32 is defined as the maximum possible unsigned long value. This value will be assigned to WaitNextEvent's sleep parameter at program launch.
gEventFilterUPP will be assigned a universal procedure pointer to an application-defined event filter (callback) function. gSleepTime will be assigned the value to be used as the sleep parameter in the WaitNextEvent call. (This value will be changed during program execution.) The three variables after gDone will store the current control value of the checkboxes in the modal dialog. The next variable will store the item number of the currently selected radio button in the movable modal dialog. Finally, the pointer to the dialog object for the modeless dialog is declared as a global variable.
GetNewDialog is called to create a small modal dialog. SetDialogTimeout is then called with 10 (seconds) passed in the inSecondsToWait parameter and 1 passed in the inButtonToPress parameter. (In the associated 'DITL' resource, Item 1 is the OK push button, which has been hidden.) The use of SetDialogTimeout requires that the application handle events for the dialog through the ModalDialog function, hence the ModalDialog do-while loop. This allows the Dialog Manager to simulate an item selection. After 10 seconds, the Dialog Manager simulates a user click in the (invisible) OK button, causing the do-while loop to exit. The dialog is then disposed of. (Note that pressing the Return key before the 10 seconds has elapsed will also dispose of the dialog.) The call to NewModalFilterUPP creates a universal procedure pointer for the event filter (callback) function. Note that error handling here and in other areas of this demonstration program is somewhat rudimentary. In the unlikely event that certain calls fail, ExitToShell is called to terminate the program.
The variable that will be used as WaitNextEvent's sleep parameter (gSleepTime) is initially set to the maximum unsigned long value. Note that the value assigned to gSleepTime will be changed at certain points in the program. When a NULL event is returned by WaitNextEvent, if the program is running on Mac OS 8/9, doIdle is called.
doIdle is invoked, on Mac OS 8/9 only, whenever WaitNextEvent returns a null event. If the front window is the modeless dialog, the function IdleControls is called. IdleControls calls the control definition function of those controls in the specified window which do idle-time processing. In this case, the control is an edit text control, and the call causes the control definition function to call TextEdit to blink the insertion point caret. (This call is not necessary on Mac OS X because controls on Mac OS X have built-in timers.)
doEvents switches according to the event type received. (It is important to remember at this point that events that occur when the modal dialog or movable modal dialog have been invoked are not handled by the main event loop but by the ModalDialog function.) Note that, at the autoKey case, the function doKeyDown is called only if the Command key is not down. This is to prevent the Command-key equivalents for cut, copy, and paste from repeating when the user presses and holds down those Command-key equivalents while editing text in the modeless dialog's edit text item. In this program, autoKey events generated while the Command key is down are also discarded in the event filter (callback) function eventFilter (see below). This means that the behaviour of the edit text item in the movable modal dialog will replicate that of the edit text item in the modeless dialog. (Many commercial and shareware programs (BBEdit excepted) do not discard autoKey events in these circumstances. The author considers that to be an oversight.)
doMouseDown handles mouse-down events. Mouse-downs in the content region and in the close box/button are of significance to the demonstration. If a mouse-down occurred in a close box/button, if TrackGoAway returns true, and if the window is the modeless dialog, doHideModelessDialog is called. (In this demonstration, the modeless dialog, but not the document window, has a close box/button.)
doKeyDown handles all key-down and auto-key events. First, the character code is extracted from the message field of the event structure. Then IsDialogEvent is called to determine whether the event occurred in the modeless dialog or window-modal (sheet) dialog, or in the document window. If the event occurred in a document window, and if the modifiers field of the event structure indicates that the Command key was down, the function for adjusting the menus is called, MenuEvent is called to return the long value containing the menu and menu item associated with the Command-key equivalent, and the long value is passed to doMenuChoice for further handling. If, however, the event occurred in the modeless dialog dialog or window-modal (sheet) dialog: o If the key pressed was the Return or Enter key, GetDialogItemAsControl is called to get a reference to the single push button control in the modeless dialog (item 1 in the item list). The push button is then highlighted for eight ticks (this has an effect on Mac OS 8/9 only), and then unhighlighted before a function is called to extract the text from the edit text item and display it in the document window's window header. doKeyDown then returns because it is not intended that the edit text item receive Return and Enter key presses. o If the Command key was down: o If either the X, C, or V key was pressed (that is, the user has pressed the Cut, Copy, or Paste Command-key equivalent), DialogSelect is called to further handle the event. DialogSelect uses TextEdit to cut, copy, or paste the text in the edit text item. (The calls to HiliteMenu briefly highlight the Edit menu to indicated to the user that an Edit menu Command-key equivalent has just been used. This replicates the highlighting that ModalDialog performs when Command-key presses occur in modal and movable modal dialogs with edit text items.) o If neither the X, C, nor V key was pressed, the function for adjusting the menus is called, MenuEvent is called to return the long value containing the menu and menu item associated with the Command-key equivalent, and the long value is passed to doMenuChoice for further handling. o doKeyDown returns so as to bypass the second call to DialogSelect. Thus the Command-key equivalents other than those for Cut, Copy, and Paste remain available to the user via the main event loop, while the Command-key equivalents for Cut, Copy, and Paste are trapped and passed to DialogSelect for handling. o If the Return key and the Enter key were not pressed, and if the Command key was not down, DialogSelect is called to handle the keystroke in conjunction with TextEdit, the visual result being that the character appears in the edit text item.
doUpdate performs the initial handling of update events. If the call to IsDialogEvent reveals that the event is for a window of the document kind, a function for updating the document window is called. If the event is for the modeless dialog or window-modal (sheet) dialog, DialogSelect is called to handle the event. DialogSelect calls BeginUpdate, DrawDialog, and EndUpdate to redraw the dialog's content area. To restrict the redraw to the update region, an alternative is to call BeginUpdate, UpdateDialog, and EndUpdate. (Recall here that update regions BeginUpdate and EndUpdate are irrelevant on Mac OS X.) Note that, on Mac OS X, the call to DialogSelect is really only necessary in the case of the window-modal (sheet) dialog.
doUpdateDocument simply fills the content region of the document window with a colour, using a pixel patter ('ppat') resource and a call to FillCRect for that purpose, and then calls a function which draws a window header frame and the current contents of gCurrentString.
doActivate performs initial handling of activate events. If the call to IsDialogEvent reveals that the event is for a window of the document kind, the function for activating/deactivating the document window is called, otherwise the function for activating/deactivating the modeless dialog is called.
doActivateDocument performs window activation/deactivation for the document window. If the window is becoming active, the menus are adjusted as appropriate for a document window. The call doDrawMessage draws a window header frame in the window, and the current contents of gMessageString, in either the activated or deactivated mode.
doActivateDialogs performs window activation and deactivation for the modeless dialog and window-modal (sheet) dialog. DialogSelect is called to handle the event. If the modeless or window-modal (sheet) dialog is becoming active, DialogSelect activates all controls and, on Mac OS 8/9, redraws the one-pixel-wide modeless dialog frame in the active mode. If the modeless dialog is going to the back, DialogSelect deactivates all controls and, on Mac OS 8/9, redraws the one-pixel-wide modeless dialog frame in the inactive mode. In the remaining code, if either the modeless dialog or window-modal (sheet) dialog is becoming active, the menus are adjusted and the global variable used in the sleep parameter of the WaitNextEvent function is assigned the value returned by GetCaretTime (the cursor-blinking interval set by the user in the General Controls control panel (Mac OS 8/9) and System preferences (Mac OS X)). This is necessary to ensure that null events will always be generated, and thus doIdle and IdleControls will be called (necessary on Mac OS 8/9 only), at an interval short enough to ensure insertion point caret blinking at the proper rate. If if either the modeless dialog or window-modal (sheet) dialog is being deactivated, the sleep parameter for the WaitNextEvent function is reset to the maximum unsigned long value. (Recall that changing the value in gSleepTime is irrelevant on Mac OS X because the function doIdle will not be called when the program is running on Mac OS X.)
Note that, if the program is running on Mac OS X, and a call to IsWindowCollapsed reveals that the document window has been minimised to the dock, the menu items which invoke the window-modal (sheet) alert and (sheet) dialog are disabled.
doMenuChoice handles menu choices. If the choice was the Close item in the File menu, and if the front window is the modeless dialog, a function which hides that modeless dialog is called. (In this program, because the document window does not have a close box/button, the Close item is only enabled when the modeless dialog is the front window.)
doEditMenu first determines whether the front window is the modeless dialog or window-modal (sheet) dialog (both of which have an edit text item). If so, a reference to the dialog is obtained, following which Dialog Manager functions are called to cut, copy, paste, or clear text as appropriate. The Dialog Manager, in conjunction with TextEdit, performs these operations.
doDemonstrationMenu handles choices from the Demonstration menu, switching according to the menu item passed to it. Error handling in this function is somewhat rudimentary in that the program simply terminates. Note that, when the Modal Alert item is chosen, doModalAlerts is called with false is passed in the function's parameter. Note also that, when the Movable Modal Alert item is chosen, doMovableModalAlertonX is called if the program is running on Mac OS X, otherwise doModalAlerts is called with true passed in the function's parameter. This latter reflects the fact that, on Mac OS X, the movable modal alert will be created by a function that is not available on Mac OS 8/9.
doExplicitlyDeactivateDocument is called at the beginning of those functions which create modal and movable modal alerts and dialogs. If there is at least one window of any type open, and if that front window is of the document kind, the function for activating/deactivating document windows is called to deactivate the window.
doModalAlerts creates, displays, manages, and disposes of the modal alert and, on Mac OS 8/9, the movable modal alert. The call to doExplicitlyDeactivateDocument deactivates the document window. At the next nine lines, values are assigned to the fields of a standard alert parameter structure. In sequence: the alert is to be modal or movable modal depending on the value received in the formal parameter movable; a help button is to be displayed; the event filter (callback) function used is to be the application-defined event filter (callback) function pointed to by the universal procedure pointer gEventFilterUPP; the default title for the OK push button is to be used; a Cancel push button is required, and is to have the default title for the Cancel button; an Other push button is required, and is to have the title "Other"; the default push button is to be the first push button (which will thus have the default ring drawn around it (Mac OS 8/9) or be pulsing blue (Mac OS X) and have the Return and Enter keys aliased to it); the Cancel push button is to be the second push button (which will thus have escape and Command-period key presses aliased to it); the alert is to be displayed in the alert position on the parent window screen. (With regard to the last field, the constant kWindowDefaultPosition equates to kWindowAlertPositionParentWindowScreen.) The calls to GetIndString retrieve the specified strings from the specified 'STR#' resource. These are passed in the inError and inExplanation parameters in the following call to StandardAlert. The call to StandardAlert creates and displays the alert (specifying a Stop alert in the first parameter), and handles all user interaction (by internally calling ModalDialog), including dismissing the alert when either the OK, Cancel, or Other button is hit. The item hit is returned in StandardAlert's outItemHit parameter. In a real application, the appropriate action would be taken, based on which push button was hit, following the call to StandardAlert; however, in this demonstration, the identity of the push button is simply drawn in the document window.
doMovableModalAlertOnX creates, displays, manages, and disposes of the movable modal alert when the program is run on Mac OS X. (The functions used in doMovableModalAlertOnX to create, display, and manage the alert are not available on Mac OS 8/9.) The call to doExplicitlyDeactivateDocument deactivates the document window. The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter structure with default values. (The defaults are: not movable; no Help button; no Cancel button; no Other button; alert position on parent window screen.) The next four lines modify the defaults by specifying that the alert is to be movable modal, and is to have a Help, Cancel, and Other, push button. The two calls to GetIndString retrieve the specified strings from the specified 'STR#' resource, which are then converted to CFStrings before being passed in the error and explanation fields in the following call to CreateStandardAlert. CreateStandardAlert creates the alert. The call to RunStandardAlert displays the alert and runs the alert using a ModalDialog loop. When a push button is clicked, its item number is returned in the outItemHit parameter In a real application, the appropriate action would be taken, based on which push button was hit, following the call to RunStandardAlert; however, in this demonstration, the identity of the push button is simply drawn in the document window.
doModalDialog creates, displays, manages, and disposes of the modal dialog. The call to doExplicitlyDeactivateDocument deactivates the document window. The call to GetNewDialog creates the modal dialog from the specified resource as the frontmost window. The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item and aliases the Return and Enter keys to that item. The call to SetDialogCancelItem tells the Dialog Manager which is the Cancel push button item, and aliases the escape key and Command-period key presses to that item. The next block gets handles to the three checkbox controls and sets the value of those controls to the current values contained in the global variables relating to each control. The call to NewMenu creates a new empty menu for a font menu. A reference to this menu is passed in the call to CreateStandardFontMenu, which creates a non-hierarchical font menu containing the names of all resident fonts. GetDialogItemAsControl gets a reference to the Font pop-up menu button control, facilitating the calls to SetControlMinimum, SetControlMaximum, and SetControlData. The latter sets the menu to be used by the pop-up menu button control. With the modal dialog fully prepared, it is made visible by the call to ShowWindow. The do/while loop continues to execute until ModalDialog reports that either the OK or Cancel button has been "hit". Within the loop, ModalDialog retains control until one of the enabled items has been hit. If a checkbox is hit, GetDialogItemAsControl is called to get a reference to the control and SetControlValue is called to flip that control's control value. (If it is 0, it is flipped to 1, and vice versa.) If one of the pop-up menu buttons is hit, GetDialogItemAsControl is called to get a reference to the control and GetControlValue is called to get the menu item number of the menu item chosen, following which an function is called to extract the menu item text and display it in the window header. Note that the first parameter in the ModalDialog call is a universal procedure pointer to the application-defined event filter (callback) function. When the do/while loop exits, and if the user hit the OK button, handles to each of the three checkboxes are retrieved for the purposes of retrieving the control's value and assigning it to the relevant global variable. (If the user hit the Cancel button, the global variables retain the values they contained before the dialog was created and displayed.) The dialog is then disposed of.
doMovableModalDialog creates, displays, manages, and disposes of the movable modal dialog. The call to doExplicitlyDeactivateDocument deactivates the document window. The call to GetNewDialog creates the movable modal dialog from the specified resource as the frontmost window. The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item and aliases the Return and Enter keys to that item. The call to SetDialogCancelItem tells the Dialog Manager which is the Cancel push button item and aliases the escape key and Command-period key presses to that item. The call to SetDialogTracksCursor tells the Dialog Manager to track the cursor and change it to the I-Beam cursor shape whenever it is over an edit text item. The first call to GetDialogItemAsControl gets a reference to the radio button control represented by the current value in the global variable gBrushType. The value of that control is then set to 1. The second call to GetDialogItemAsControl gets a reference to the clock control. The call to SetKeyboardFocus sets the keyboard focus to that item. Before the session of user interaction begins, the current value in the global variable gBrushType, which stores the item number of the currently selected radio button, is copied to the local variable oldBrushTupe. (This may be required later.) With the movable modal dialog fully prepared, it is made visible by the call to ShowWindow. The do/while loop continues to execute until ModalDialog reports that either the OK or Cancel button has been hit. Within the loop, ModalDialog retains control until one of the enabled items is hit. If a radio button is hit, a for loop sets the control value of all radio button controls to 0. A call to GetDialogItemAsControl then gets a reference to the radio button control that was hit. A call to SetControlValue then sets that control's value to 1, and the item number of this radio button is assigned to the global variable gBrushType. Note that the first parameter in the ModalDialog call is a universal procedure pointer to the application-defined event filter (callback) function. Note also that all user interaction relating to the clock control and edit text item is handled automatically by ModalDialog, including the movement of keyboard focus between the items. When the do/while loop exits, and if the user hit the Cancel button, the value stored in the local variable oldBrushType is assigned to gBrushType, ensuring that any change to the currently selected radio button within the do/while loop is ignored. (In a real application, a long date/time value from the clock control, and the text from the edit text item would possibly be retrieved at this point if the user hit the OK push button.)
In this program, the modeless dialog is only created once, that is, when the user first chooses Modeless Dialog from the Demonstration menu. Clicks in its close box/button, or choosing Close from the File menu while the modeless dialog is the frontmost window, will cause the dialog to be hidden, not disposed of. Accordingly, the first line determines whether the modeless dialog is already open. If it is not: the call to GetNewDialog creates the modeless dialog; the call to SetWRefCon assigns the reference constant kSearchModeless to the dialog object's window object so as to differentiate this dialog from the window-modal (sheet) dialog; a call to SetDialogDefaultItem causes the push button to be drawn with the default ring (Mac OS 8/9) or in pulsing blue (Mac OS X); a call to SetDialogItemText assigns some initial text to the edit text item; a call to SelectDialogItemText selects the text in the edit text item. (Note that, if the edit text item did not contain text, this latter call would simply display the insertion point caret, which would be made to blink by the call to IdleControls within the function doIdle (Mac OS 8/9).) If, on the other hand, the modeless dialog has already been opened, the call to ShowWindow displays the dialog and the call to SelectWindow generates the necessary activate events.
doInContent continues the content region mouse-down handling initiated by doMouseDown. doInContent is called by doMouseDown only if the mouse-down occurred in the frontmost (active) window. If the event occurred in the document window, the mouse-down event would be handled in the if section of the if/else block. (No action is required in this demonstration.) If the event occurred in the modeless dialog or the window-modal (sheet) dialog (both of which contain an edit text item), DialogSelect is called to handle the event. DialogSelect tracks enabled controls (only the push button is enabled), returning true if the mouse button is released while the cursor is still inside the control, and highlights any selection made in the edit text item. If DialogSelect returns true, and if the item hit was the OK push button, a function is called to perform the actions required in the event of a hit on that button.
doButtonHitInSearchModeless further processes, to completion, a hit on the OK (Search) button in the modeless dialog. It simply demonstrates retrieval of the text in an edit text item in a dialog. The call to GetDialogItemAsControl gets a reference to the edit text control, and the call to GetDialogItemText copies the text in the edit text control to the global variable gCurrentString. The following lines cause that text to be drawn in the window header in the document window.
doHideModelessDialog hides a modeless dialog. The call to HideWindow makes the dialog invisible. The sleep parameter for the WaitNextEvent function is reset to the maximum possible long value (relevant only on Mac OS 8/9), because insertion point caret blinking is not required while the Search dialog is hidden.
eventFilter is the application-defined event filter (callback) function which, in conjunction with ModalDialog, handles events in the modal alerts, movable modal alert on OS 8/9, modal dialog and movable modal dialog. If the program is running on Mac OS 8/9, if the event is an update event, and if that event is not for the dialog or alert in question, the application's document window updating function is called and false is returned. This response to an update event in the application's own document windows also allows ModalDialog to perform a minor switch when necessary so that background applications can update their windows as well. The call to the window updating function is not necessary on Mac OS X. If the event is an autoKey event and the Command key is down, the event is, in effect, discarded. This means that, if the user is working within the edit text item in the movable modal dialog and presses and holds the Command key equivalents for Cut, Copy or Paste, repeating cut, copy and paste actions will be defeated. That is, pressing and holding the Command key equivalent will only result in a single cut, copy, or paste action. (See also doEvents, above.) If the event is neither an update event nor an autoKey event with the Command key down, the current graphics port is saved and then set to that of the alert or dialog. The event is then passed to the standard event filter (callback) function for handling. If the standard event filter (callback) function handles the event, it will return true and, in the itemHit parameter, the number of the item that it handled. ModalDialog will then return this item number. A call to SetPort then restores the previously save graphics port. Note that the calls to GetPort and SetPort are actually redundant when this event filter (callback) function is used by all but the movable modal dialog. The calls are only necessary when SetDialogTracksCursor has been called to cause the Dialog Manager to automatically track the cursor, and the movable modal dialog is the only dialog which requires this tracking (because it contains an edit text item.)
doPopupMenuChoice, doPlaySound, doDrawMessage, and doCopyPString are incidental to the demonstration. All perform the same duties as the similarly-named functions in the demonstration program Controls1 (Chapter 7). doDrawMessage is used in this program to prove the explicit deactivation of the document window's content area when alerts and dialogs other than the modeless dialog are invoked.
gSheetDialogWindowRe will be assigned the window reference of the window-modal (sheet) dialog.
doSheetAlert creates, displays and handles a window-modal (sheet) alert. The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter structure with default values. The two calls to GetIndString retrieve the specified strings from the specified 'STR#' resource, which are then converted to CFStrings before being passed in the error and explanation fields in the following call to CreateStandardSheet, which creates the alert. The call to ShowSheetWindow displays the sheet. When the user clicks the OK button, the sheet is dismissed.
doSheetAlert creates and displays a window-modal (sheet) dialog. The call to GetNewDialog creates the dialog from the specified resource. The call to SetWRefCon assigns a value as the dialog window's reference constant. This is used elsewhere to differentiate the window-modal (sheet) dialog from the modeless dialog. The call to SetDialogDefaultItem causes the push button to be drawn with the default ring (Mac OS 8/9) or in pulsing blue (Mac OS X). The call to SetDialogItemText assigns some initial text to the edit text item and the call to SelectDialogItemText selects that text. The next line assigns a reference to the dialog's window to the global variable gSheetDialogWindowRef. This is used in the function doButtonHitInSheetDialog. The call to ShowSheetWindow displays the sheet.
doButtonHitInSearchModeless is called from doKeyDown and doInContent to further process, to completion, a hit on the OK button in the window-modal (sheet) dialog. In addition to retrieving the text in an edit text item, it hides and disposes of the dialog.