Home > Articles > Home & Office Computing > Mac OS X

  • Print
  • + Share This
This chapter is from the book

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,&currentFontFamilyReference,
   &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);
}

// *******************************************************************************************
  • + Share This
  • 🔖 Save To Your Account