␡
- Introduction—Types of Menus
- Pull-Down Menus
- Hierarchical Menus
- Pop-Up Menus
- Menu Objects, Menu IDs and Item Numbers, Command IDs, and Menu Lists
- Creating Your Application's Menus
- Providing Help Balloons (Mac OS 8/9)
- Changing Menu Item Appearance
- Adding Items to a Menu
- Associating Data with Menu Items
- Handling Menu Choices
- Hiding and Showing the Menu Bar
- Accessing Menus from Alerts and Dialogs
- Main Menu Manager Constants, Data Types, and Functions
- Demonstration Program Menus1 Listing
- Demonstration Program Menus1 Comments
- Demonstration Program Menus2 Listing
- Demonstration Program Menus2 Comments
This chapter is from the book
Demonstration Program Menus2 Listing
// ******************************************************************************************* // Menus2.c CLASSIC EVENT MODEL // ******************************************************************************************* // // This program is based on Menus1. The basic differences between this program and Menus1 are // as follows: // // 'xmnu' resources are used to extend the 'MENU' resources for some menus. // // Extended modifier keys (Shift, Option, and Control) are used to extend the Command-key // equivalents for two menu items in the Style menus. // // There are two Style menus (Style ('xmnu') and Style (Programmatic). The two Style menus // are intended to demonstrate assigning extended modifier keys to a menu item (1) via an // 'xmnu' resource and (2) programmatically. // // Command IDs are assigned to all menu items except those in the system-managed menus and // the Font menu, and the associated menu handling code branches according to the command // ID of the chosen menu item (as opposed to menu ID and menu item). // // The Font menu is non-hierarchical. It is also WYSIWYG, meaning that each item is drawn // in that font. // // The delete-to-the-left, delete-to-the-right, page-up, and page-down keys are assigned as // Command-key equivalents in the Size menu, and the glyphs are adjusted where necessary. // // The submenu is attached to the second item in the Special menu programmatically rather // than via the 'MENU' resource. // // Color icons are included in the menu items in the submenu. // // Balloon help is provided, via 'hmnu' resources, for all menus. // // The extended modifier keys in the Style ('xmnu') menu are assigned via the 'xmnu' resource // for that menu. The extended modifier keys in the Style (Programmatic) menu are assigned // programmatically . // // The command IDs for items in the File, Edit, and Style ('xmnu') menus are assigned via the // 'xmnu' resources for those menus. The command IDs for the items in the Style // (Programmatic), Size, and Special menus, and the submenu, are assigned programmatically. // // The color icon in the first submenu item is assigned via the 'MENU' resource. The color // icon in the second item is assigned programmatically via a call to // SetMenuItemIconHandle. // // The program utilises the following resources: // // A 'plst' resource. // // A 'WIND' resource (purgeable) (initially not visible). // // An 'MBAR' resource (preload, non-purgeable). // // 'MENU' resources for the drop-down menus and submenu (all preload, all non-purgeable). // // 'xmnu' resources (preload, purgeable) for the drop-down menus (except the system-managed // menus and the Font menu) and the submenu. // // 'hmnu' resources (purgeable) providing balloon help for menus and menu items. // // Two 'cicn' resources (purgeable) for the items in the submenu. // // A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, // doesActivateOnFGSwitch, and isHighLevelEventAware flags set. // // ******************************************************************************************* // ...................................................................................includes #include <Carbon.h> // ....................................................................................defines #define rMenubar 128 #define mAppleApplication 128 #define mFile 129 #define iQuit 12 #define mFont 131 #define mStyleXmnu 132 #define mStyleProg 133 #define iPlain 1 #define iBold 3 #define iItalic 4 #define iOutline 6 #define iUnderline 5 #define iShadow 7 #define mSize 134 #define iTen 1 #define iTwelve 2 #define iEighteen 3 #define iTwentyFour 4 #define mSpecial 135 #define iFirst 1 #define iSecond 2 #define mSubmenu 136 #define iBat 1 #define iBowl 2 #define rWindowResource 128 #define rColorIcon 258 // ............................................................................global variables Boolean gRunningOnX = false; Boolean gDone; MenuItemIndex gCurrentFontMenuItem = 0; Style gCurrentStyle = 0; MenuItemIndex gCurrentSizeMenuItem = 2; // ........................................................................function prototypes void main (void); void doPreliminaries (void); OSErr quitAppEventHandler (AppleEvent *,AppleEvent *,SInt32); void doGetMenus (void); void doEvents (EventRecord *); void doMouseDown (EventRecord *); void doAdjustMenus (void); void doMenuChoice (SInt32); void doCommand (MenuCommand); void doFontMenu (MenuItemIndex); void doCheckStyleMenuItem (MenuID); void doCheckSizeMenuItem (MenuItemIndex); void drawItemString (Str255); // ************************************************************************************** main void main(void) { EventRecord eventStructure; WindowRef windowRef; RGBColor foreColor = { 0xFFFF,0xFFFF,0xFFFF }; RGBColor backColor = { 0x4444,0x4444,0x9999 }; Rect portRect; // ...........................................................................do preliminaries doPreliminaries(); // ...............................................................................open a window if(!(windowRef = GetNewCWindow(rWindowResource,NULL,(WindowRef) -1))) { SysBeep(10); ExitToShell(); } SetPortWindowPort(windowRef); TextSize(10); RGBBackColor(&backColor); RGBForeColor(&foreColor); // ..............................................set up menu bar and menus, then show window doGetMenus(); ShowWindow(windowRef); GetWindowPortBounds(windowRef,&portRect); EraseRect(&portRect); // ...............................................................................event loop gDone = false; while(!gDone) { if(WaitNextEvent(everyEvent,&eventStructure,180,NULL)) doEvents(&eventStructure); } } // *************************************************************************** doPreliminaries void doPreliminaries(void) { OSErr osError; MoreMasterPointers(32); 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; } // ******************************************************************************** doGetMenus void doGetMenus(void) { MenuBarHandle menubarHdl; SInt32 response; MenuRef menuRef; OSStatus osError; ItemCount hierMenuCount; SInt16 a, numberOfItems, fontNumber; Str255 fontName, smallSystemFontName; CIconHandle cicnHdl; // ......................................................................get and set menu bar menubarHdl = GetNewMBar(rMenubar); if(menubarHdl == NULL) ExitToShell(); SetMenuBar(menubarHdl); Gestalt(gestaltMenuMgrAttr,&response); if(response & gestaltMenuMgrAquaLayoutMask) { menuRef = GetMenuRef(mFile); if(menuRef != NULL) { DeleteMenuItem(menuRef,iQuit); DeleteMenuItem(menuRef,iQuit - 1); DisableMenuItem(menuRef,0); } gRunningOnX = true; } // .........................................................set up Font menu and make WYSIWYG GetFontName(kThemeSmallSystemFont,smallSystemFontName); menuRef = GetMenuRef(mFont); if(menuRef != NULL) { osError = CreateStandardFontMenu(menuRef,0,0,kNilOptions,&hierMenuCount); if(osError == noErr) { numberOfItems = CountMenuItems(menuRef); for(a=1;a<=numberOfItems;a++) { GetMenuItemText(menuRef,a,fontName); GetFNum(fontName,&fontNumber); SetMenuItemFontID(menuRef,a,fontNumber); if(EqualString(fontName,smallSystemFontName,false,false)) { CheckMenuItem(menuRef,a,true); gCurrentFontMenuItem = a; } } } else ExitToShell(); } else ExitToShell(); // .............. programmatically set the extended modifiers in Style (Programmatic) menu menuRef = GetMenuRef(mStyleProg); SetMenuItemModifiers(menuRef,iOutline,kMenuShiftModifier + kMenuOptionModifier + kMenuControlModifier); SetMenuItemModifiers(menuRef,iShadow,kMenuShiftModifier + kMenuOptionModifier); // ....... insert submenu into menu list and programmatically attach it to Special menu, item 2 menuRef = GetMenu(mSubmenu); if(menuRef != NULL) { InsertMenu(menuRef,hierMenu); menuRef = GetMenuRef(mSpecial); SetMenuItemHierarchicalID(menuRef,iSecond,mSubmenu); } else ExitToShell(); // ....... programmatically set command IDs for second Style, Size, Special menus and submenu menuRef = GetMenuRef(mStyleProg); SetMenuItemCommandID(menuRef,iPlain, 'plai'); SetMenuItemCommandID(menuRef,iBold, 'bold'); SetMenuItemCommandID(menuRef,iItalic, 'ital'); SetMenuItemCommandID(menuRef,iUnderline, 'unde'); SetMenuItemCommandID(menuRef,iOutline, 'outl'); SetMenuItemCommandID(menuRef,iShadow, 'shad'); menuRef = GetMenuRef(mSize); SetMenuItemCommandID(menuRef,iTen, 'ten '); SetMenuItemCommandID(menuRef,iTwelve, 'twel'); SetMenuItemCommandID(menuRef,iEighteen, 'eigh'); SetMenuItemCommandID(menuRef,iTwentyFour,'twen'); menuRef = GetMenuRef(mSpecial); SetMenuItemCommandID(menuRef,iFirst, 'firs'); menuRef = GetMenuRef(mSubmenu); SetMenuItemCommandID(menuRef,iBat, 'bat '); SetMenuItemCommandID(menuRef,iBowl, 'bowl'); // ........................ programmatically set the icon for the Bowl item in the submenu cicnHdl = GetCIcon(rColorIcon); SetMenuItemIconHandle(menuRef,iBowl,kMenuColorIconType,(Handle) cicnHdl); // ....... programmatically set Command-key equivalents to Size menu items and adjust glyphs menuRef = GetMenuRef(mSize); SetItemCmd(menuRef,iTen,0x08); SetMenuItemKeyGlyph(menuRef,iTen,kMenuDeleteLeftGlyph); SetItemCmd(menuRef,iTwelve,0x7f); SetMenuItemKeyGlyph(menuRef,iTwelve,kMenuDeleteRightGlyph); SetItemCmd(menuRef,iEighteen,0x0b); SetMenuItemKeyGlyph(menuRef,iEighteen,kMenuPageUpGlyph); SetItemCmd(menuRef,iTwentyFour,0x0c); SetMenuItemKeyGlyph(menuRef,iTwentyFour,kMenuPageDownGlyph); // .......... programmatically exclude the mark column and set the font in the Special menu menuRef = GetMenuRef(mSpecial); SetMenuExcludesMarkColumn(menuRef,true); GetFNum("\pGadget",&fontNumber); if(fontNumber != 0) SetMenuFont(menuRef,fontNumber,12); // ............................ if running on Mac OS X, create Help menu and insert one item if(gRunningOnX) { HMGetHelpMenu(&menuRef,NULL); InsertMenuItem(menuRef,"\pMenus Help",0); SetMenuItemCommandID(menuRef,1,'help'); } // ..................................set initial font, style, and size, and checkmark them doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); doCheckSizeMenuItem(iTen); // .....................................................................draw menu bar DrawMenuBar(); } // ********************************************************************************** doEvents void doEvents(EventRecord *eventStrucPtr) { switch(eventStrucPtr->what) { case kHighLevelEvent: AEProcessAppleEvent(eventStrucPtr); break; case mouseDown: doMouseDown(eventStrucPtr); break; case keyDown: if((eventStrucPtr->modifiers & cmdKey) != 0) { doAdjustMenus(); doMenuChoice(MenuEvent(eventStrucPtr)); } break; case updateEvt: BeginUpdate((WindowRef) eventStrucPtr->message); EndUpdate((WindowRef) eventStrucPtr->message); break; } } // ******************************************************************************* doMouseDown void doMouseDown(EventRecord *eventStrucPtr) { WindowRef windowRef; WindowPartCode partCode; SInt32 menuChoice; partCode = FindWindow(eventStrucPtr->where,&windowRef); switch(partCode) { case inMenuBar: doAdjustMenus(); menuChoice = MenuSelect(eventStrucPtr->where); doMenuChoice(menuChoice); break; case inContent: if(windowRef != FrontWindow()) SelectWindow(windowRef); break; case inDrag: DragWindow(windowRef,eventStrucPtr->where,NULL); break; case inGoAway: if(TrackGoAway(windowRef,eventStrucPtr->where)) gDone = true; break; } } // ***************************************************************************** doAdjustMenus void doAdjustMenus(void) { // Adjust menus here. Use EnableMenuCommand and DisableMenuCommand to enable/disable those // menu items with command IDs. } // ****************************************************************************** doMenuChoice void doMenuChoice(SInt32 menuChoice) { MenuID menuID; MenuItemIndex menuItem; OSErr osErr; MenuCommand commandID; menuID = HiWord(menuChoice); menuItem = LoWord(menuChoice); if(menuID == 0) return; else if(menuID == mFont) doFontMenu(menuItem); else { osErr = GetMenuItemCommandID(GetMenuRef(menuID),menuItem,&commandID); if(osErr == noErr && commandID != 0) doCommand(commandID); } HiliteMenu(0); } // ********************************************************************************* doCommand void doCommand(MenuCommand commandID) { MenuRef menuRef; switch(commandID) { // ....................................................................Apple/Application menu case 'abou': // About drawItemString("\pAbout Menus2"); break; // .............................................................................File menu case 'quit': // Quit gDone = true; break; // .............................................................................Edit menu case 'undo': // Undo drawItemString("\pUndo"); break; case 'cut ': // Cut drawItemString("\pCut"); break; case 'copy': // Copy drawItemString("\pCopy"); break; case 'past': // Paste drawItemString("\pPaste"); break; case 'clea': // Clear drawItemString("\pClear"); break; // .................................Style ('xmnu') and Style (Programmatic) menu case 'plai': // Plain gCurrentStyle = 0; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; case 'bold': // Bold if(gCurrentStyle & bold) gCurrentStyle -= bold; else gCurrentStyle |= bold; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; case 'ital': // Italics if(gCurrentStyle & italic) gCurrentStyle -= italic; else gCurrentStyle |= italic; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; case 'unde': // Underline if(gCurrentStyle & underline) gCurrentStyle -= underline; else gCurrentStyle |= underline; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; case 'outl': // Outline if(gCurrentStyle & outline) gCurrentStyle -= outline; else gCurrentStyle |= outline; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; case 'shad': // Shadow if(gCurrentStyle & shadow) gCurrentStyle -= shadow; else gCurrentStyle |= shadow; doCheckStyleMenuItem(mStyleXmnu); doCheckStyleMenuItem(mStyleProg); break; // .......................................................................Size menu case 'ten ': // 10 TextSize(10); doCheckSizeMenuItem(iTen); break; case 'twel': // 12 TextSize(12); doCheckSizeMenuItem(iTwelve); break; case 'eigh': // 18 TextSize(18); doCheckSizeMenuItem(iEighteen); break; case 'twen': // 24 TextSize(24); doCheckSizeMenuItem(iTwentyFour); break; // ....................................................................Special menu case 'firs': // First drawItemString("\pFirst Item"); break; // .....................................................................submenu case 'bat ': // Bat menuRef = GetMenuRef(mSubmenu); DisableMenuItem(menuRef,iBat); EnableMenuItem(menuRef,iBowl); drawItemString("\pBat"); break; case 'bowl': // Bowl menuRef = GetMenuRef(mSubmenu); DisableMenuItem(menuRef,iBowl); EnableMenuItem(menuRef,iBat); drawItemString("\pBowl"); break; case 'help': AHGotoPage(CFSTR("Menus Help"),CFSTR("Menus.htm"),NULL); break; } } // ******************************************************************************** doFontMenu void doFontMenu(MenuItemIndex menuItem) { MenuRef menuRef; OSStatus osError; FMFontFamily currentFontFamilyReference; FMFontStyle fontStyle; Str255 fontName; menuRef = GetMenuRef(mFont); osError = GetFontFamilyFromMenuSelection(menuRef,menuItem,¤tFontFamilyReference, &fontStyle); if(osError == noErr || osError == menuPropertyNotFoundErr) { TextFont(currentFontFamilyReference); CheckMenuItem(menuRef,gCurrentFontMenuItem,false); gCurrentFontMenuItem = menuItem; CheckMenuItem(menuRef,gCurrentFontMenuItem,true); GetMenuItemText(menuRef,menuItem,fontName); drawItemString(fontName); } else ExitToShell(); } // ********************************************************************** doCheckStyleMenuItem void doCheckStyleMenuItem(MenuID menuID) { MenuRef styleMenuRef; static Boolean stringAlreadyDrawnOnce = false; styleMenuRef = GetMenuRef(menuID); CheckMenuItem(styleMenuRef,iPlain, gCurrentStyle == 0); CheckMenuItem(styleMenuRef,iBold, gCurrentStyle & bold); CheckMenuItem(styleMenuRef,iItalic, gCurrentStyle & italic); CheckMenuItem(styleMenuRef,iUnderline,gCurrentStyle & underline); CheckMenuItem(styleMenuRef,iOutline, gCurrentStyle & outline); CheckMenuItem(styleMenuRef,iShadow, gCurrentStyle & shadow); TextFace(gCurrentStyle); if(!stringAlreadyDrawnOnce) drawItemString("\pStyle change"); stringAlreadyDrawnOnce = !stringAlreadyDrawnOnce; } // *********************************************************************** doCheckSizeMenuItem void doCheckSizeMenuItem(MenuItemIndex menuItem) { MenuRef sizeMenuRef; sizeMenuRef = GetMenuRef(mSize); CheckMenuItem(sizeMenuRef,gCurrentSizeMenuItem,false); CheckMenuItem(sizeMenuRef,menuItem,true); gCurrentSizeMenuItem = menuItem; drawItemString("\pSize change"); } // **************************************************************************** drawItemString void drawItemString(Str255 eventString) { RgnHandle tempRegion; WindowRef windowRef; Rect scrollBox; windowRef = FrontWindow(); tempRegion = NewRgn(); GetWindowPortBounds(windowRef,&scrollBox); ScrollRect(&scrollBox,0,-30,tempRegion); DisposeRgn(tempRegion); MoveTo(8,286); DrawString(eventString); } // *******************************************************************************************