TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program Menus1

Goto Contents

// *******************************************************************************************
// Menus1.c                                                                CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// This program:
//
// o  Opens a window.
//
// o  Creates these pull-down menus: Apple, File, Edit, Font, Size, Special, and Window.
//
// o  Displays text in the window indicating the menu selection made by the user.
//
// The Apple menu includes an "About." menu item for the program.
//
// The second menu item in the Special menu contains a submenu.
//
// The Font and Window menus are created programmatically using the functions
// CreateStandardFontMenu and CreateStandardWindowMenu.
//
// The implementation of the Size menu is nominal only.  The current size is indicated with a
// checkmark; however, the number of sizes shown is not font-dependent and there is no "Other"
// item.
//
// Because the primary purpose of the program is to demonstrate menu creation and handling, no
// code is included to update and activate/deactivate the window or to respond to events which
// are not relevant to the demonstration. 
//
// The program is terminated by selecting Quit from the File menu, by pressing the keyboard
// equivalent for that item (Command-Q), or by clicking in the window's go-away box/close
// button.
//  
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  A 'WIND' resource (purgeable) (initially not visible).
//
// o  An 'MBAR' resource (preload, non-purgeable).
//
// o  'MENU' resources for the Apple, File, Edit, Font, Size, and Special drop-down menus
//    and the submenu (all preload, all non-purgeable).
//
// 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  iQuit            12
#define mEdit             130
#define  iUndo            1
#define  iCut             3
#define  iCopy            4
#define  iPaste           5
#define  iClear           6
#define mFont             131
#define mSize             132
#define  iTen             1
#define  iTwelve          2
#define  iEighteen        3
#define  iTwentyFour      4
#define mSpecial          133
#define  iFirstItem       1
#define  iSecondItem      2
#define mWindow           134
#define mSubmenu          135
#define mFirstFontSubMenu 136
#define  iFirstSubItem    1
#define  iSecondSubItem   2
#define rWindowResource   128
  
// .......................................................................... global variables

Boolean        gDone;
ItemCount      gFontMenuHierMenuCount;
MenuItemIndex  gCurrentFontSizeItem = 2;
MenuItemIndex  gCurrentFontMenuItem;
MenuItemIndex  gCurrentFontSubMenuItem;
MenuRef        gCurrentFontSubMenuRef = NULL;

// ....................................................................... 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  doAppleApplicationMenu (MenuItemIndex);
void  doFileMenu             (MenuItemIndex);
void  doEditMenu             (MenuItemIndex);
void  doFontMenu             (MenuID,MenuItemIndex);
void  doSizeMenu             (MenuItemIndex);
void  doSpecialMenu          (MenuItemIndex);
void  doSubMenus             (MenuItemIndex);
void  drawItemString         (Str255);

// ************************************************************************************** main

void  main(void)
{
  EventRecord eventStructure;
  WindowRef   windowRef;

  // ........................................................................ do preliminaries

  doPreliminaries();
  
  // ........................................................................... open a window
    
  if(!(windowRef = GetNewCWindow(rWindowResource,NULL,(WindowRef) -1)))
  {
    SysBeep(10);
    ExitToShell();
  }

  SetPortWindowPort(windowRef);

  // ............................................. set up menu bar and menus, then show window
  
  doGetMenus();
  ShowWindow(windowRef);

  // .............................................................................. event loop

  gDone = false;

  while(!gDone)
  {
    if(WaitNextEvent(everyEvent,&eventStructure,180,NULL))
      doEvents(&eventStructure);
  }
}

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  OSErr osError;

  MoreMasterPointers(640);
  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;
  Str255        smallSystemFontName, itemString;
  SInt16        numberOfItems,a;

  // ............................................................... get and set, and menu bar

  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);

  // ........... if running on Mac OS X, delete Quit item and preceding divider from File menu

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
      DisableMenuItem(menuRef,0);
    }
  }

  // .............................. create hirearchical Font menu, checkmark small system font

  menuRef = GetMenuRef(mFont);
  if(menuRef != NULL)
  {
    osError = CreateStandardFontMenu(menuRef,0,mFirstFontSubMenu,kHierarchicalFontMenuOption,
                                     &gFontMenuHierMenuCount);
    if(osError != noErr)
      ExitToShell();
  }
  else
    ExitToShell();

   GetFontName(kThemeSmallSystemFont,smallSystemFontName);
  numberOfItems = CountMenuItems(menuRef);
  for(a=1;a<numberOfItems + 1;a++)
  {
    GetMenuItemText(menuRef,a,itemString);
    if(EqualString(itemString,smallSystemFontName,false,false))
    {
      CheckMenuItem(menuRef,a,true);
      gCurrentFontMenuItem = a;
      break;
    }
  }

  // ............................................ create Window menu and insert into menu list

  CreateStandardWindowMenu(0,&menuRef);
  SetMenuID(menuRef,mWindow);
  InsertMenu(menuRef,0);

  // ................................................ get submenus and insert into window list

  menuRef = GetMenu(mSubmenu);
  if(menuRef != NULL)
    InsertMenu(menuRef,hierMenu);
  else
    ExitToShell();

  // ........................ set initial font size and checkmark associated item in Size menu

  doSizeMenu(gCurrentFontSizeItem);

  // ........................................................................... 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.
}

// ****************************************************************************** doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  MenuID        menuID;
  MenuItemIndex menuItem;
    
  menuID    = HiWord(menuChoice);
  menuItem  = LoWord(menuChoice);

  if(menuID == 0)
    return;

  if(menuID == mFont || ((menuID >= mFirstFontSubMenu) && 
                         (menuID <= mFirstFontSubMenu + gFontMenuHierMenuCount)))
    doFontMenu(menuID,menuItem);
  else
  {
    switch(menuID)
    {
      case mAppleApplication:
        doAppleApplicationMenu(menuItem);
        break;

      case mFile:
        doFileMenu(menuItem);
        break;

      case mEdit:
        doEditMenu(menuItem);
        break;

      case mSize:
        doSizeMenu(menuItem);
        break;

      case mSpecial:
        doSpecialMenu(menuItem);
        break;

      case mSubmenu:
        doSubMenus(menuItem);
        break;
    }
  }

  HiliteMenu(0);
}

// ******************************************************************** doAppleApplicationMenu

void  doAppleApplicationMenu(MenuItemIndex menuItem)
{
  if(menuItem == iAbout)
    drawItemString("\pAbout Menus1");
}

// ******************************************************************************** doFileMenu

void  doFileMenu(MenuItemIndex menuItem)
{
  if(menuItem  == iQuit)
    gDone = true;
}

// ******************************************************************************** doEditMenu

void  doEditMenu(MenuItemIndex menuItem)
{
  switch(menuItem)
  {
    case iUndo:
      drawItemString("\pUndo");
      break;

    case iCut:
      drawItemString("\pCut");
      break;

    case iCopy:
      drawItemString("\pCopy");
      break;

    case iPaste:
      drawItemString("\pPaste");
      break;

    case iClear:
      drawItemString("\pClear");
      break;
  }
}

// ******************************************************************************** doFontMenu

void  doFontMenu(MenuID menuID,MenuItemIndex menuItem)
{
  MenuRef      menuRef, fontMenuRef;
  OSStatus     osError;
  FMFontFamily currentFontFamilyReference;
  FMFontStyle  currentFontStyle;
  Str255       fontName, styleName, itemName;
  SInt16       a, numberOfFontMenuItems;
  
  menuRef = GetMenuRef(menuID);

  osError = GetFontFamilyFromMenuSelection(menuRef,menuItem,¤tFontFamilyReference,
                                           ¤tFontStyle);
  if(osError == noErr)
  {
    TextFont(currentFontFamilyReference);
    TextFace(currentFontStyle);

    GetFontName(currentFontFamilyReference,fontName);
    drawItemString(fontName);

    if(menuID == mFont)
    {
      CheckMenuItem(menuRef,gCurrentFontMenuItem,false);
      gCurrentFontMenuItem = menuItem;
      CheckMenuItem(menuRef,gCurrentFontMenuItem,true);

      if(gCurrentFontSubMenuRef != NULL)
        CheckMenuItem(gCurrentFontSubMenuRef,gCurrentFontSubMenuItem,false);
    }
    else
    {
      if(gCurrentFontSubMenuRef != NULL)
        CheckMenuItem(gCurrentFontSubMenuRef,gCurrentFontSubMenuItem,false);
      gCurrentFontSubMenuRef = menuRef;
      gCurrentFontSubMenuItem = menuItem;
      CheckMenuItem(gCurrentFontSubMenuRef,gCurrentFontSubMenuItem,true);

      fontMenuRef = GetMenuRef(mFont);    
      CheckMenuItem(fontMenuRef,gCurrentFontMenuItem,false);

      numberOfFontMenuItems = CountMenuItems(fontMenuRef);

      for(a=1;a<=numberOfFontMenuItems;a++)
      {
        GetMenuItemText(fontMenuRef,a,itemName);
        if(EqualString(fontName,itemName,true,true))
        {
          gCurrentFontMenuItem = a;
          break;
        }
      }

      SetItemMark(fontMenuRef,gCurrentFontMenuItem,'-');

      GetMenuItemText(menuRef,menuItem,styleName);
      DrawString("\p ");
      DrawString(styleName);
    }
  }
  else
    ExitToShell();
}

// ******************************************************************************** doSizeMenu

void  doSizeMenu(MenuItemIndex menuItem)
{  
  MenuRef sizeMenuRef;  

  switch(menuItem)
  {
    case iTen:
      TextSize(10);
      break;

    case iTwelve:
      TextSize(12);
      break;

    case iEighteen:
      TextSize(18);
      break;

    case iTwentyFour:
      TextSize(24);
      break;
  }

  sizeMenuRef = GetMenuRef(mSize);

  CheckMenuItem(sizeMenuRef,gCurrentFontSizeItem,false);
  CheckMenuItem(sizeMenuRef,menuItem,true);
  
  gCurrentFontSizeItem = menuItem;
  
  drawItemString("\pSize change");
}

// ***************************************************************************** doSpecialMenu

void  doSpecialMenu(MenuItemIndex menuItem)
{
  if(menuItem == iFirstItem)
    drawItemString("\pFirst Item");
}

// ******************************************************************************** doSubMenus

void  doSubMenus(MenuItemIndex menuItem)
{
  switch(menuItem)
  {
    case iFirstSubItem:
      drawItemString("\pSubitem 1");
      break;

    case iSecondSubItem:
      drawItemString("\pSubitem 2");
      break;
  }
}

// **************************************************************************** drawItemString

void  drawItemString(Str255 eventString)
{
  RgnHandle tempRegion;
  WindowRef windowRef;
  Rect      scrollBox;

  windowRef = FrontWindow();
  tempRegion = NewRgn();

  GetWindowPortBounds(windowRef,&scrollBox);
  
  ScrollRect(&scrollBox,0,-24,tempRegion);
  DisposeRgn(tempRegion);
  
  MoveTo(8,286);
  DrawString(eventString);
}

// *******************************************************************************************

Demonstration Program Menus1 Comments

When this program is run, the user should choose items from all menus, including the Apple
menu.  Selections should be made using the mouse and, where appropriate, the Command key
equivalents.  The user should also note the effects on the menu bar of clicking outside, then
inside, the program's window, that is, of sending the program to the background and returning
it to the foreground.

defines

Constants are established for the pull-down and submenu menu IDs and associated resource IDs,
menu item numbers and subitem numbers.

The Menu Manager function CreateStandardFontMenu will be used to create a hierarchical Font
menu and mFirstFontSubMenu establishes the ID of the first Font menu submenu to be created.

The last line establishes a constant for the resource ID of the 'WIND' resource.

Global Variables

gFontMenuHierMenuCount will be assigned a value representing the number of submenus created by
the Menu Manager function CreateStandardFontMenu.

GCurrentFontSizeItem will be assigned the menu item number of the chosen font size.

gCurrentFontMenuItem and gCurrentFontSubMenuItem will be used in the Font menu handling
function to specify which menu and submenu items are to have a checkmark added or cleared.
gCurrentFontSubMenuRef will be assigned a reference to the menu object for the currently chosen
Font menu submenu.

main

The main() function creates a window and makes its graphics port the current port, calls
doGetMenus to set up the menus, shows the window and enters the main event loop.

doPreliminaries

The large number of master pointers created by MoreMasterPointers in this program allows for
the likely creation of a large number of submenus by the Menu Manager function
CreateStandardFontMenu.

When the program is run on Mac OS X, the Quit item will be in the Application menu.  The system
informs the program of the user's choice of this item via a high-level event known as an Apple
event, more specifically, an Apple event known as the Quit Application event.  The call to
AEInstallEventHandler installs quitAppEventHandler as the handler for this high-level event.
(Apple events and Apple event handlers are explained at Chapter 10.)

quitAppEventHandler

quitAppEventHandler is the handler for the Quit Application event installed in doPreliminaries. 
Basically, it sets the global variable gDone to true, which causes the program to terminate
from the main event loop.

doGetMenus

doGetMenus sets up the menu bar and the various menus.

At the first block, GetNewMBar reads in the 'MENU' resources for each menu specified in the
'MBAR' resource and creates a menu object for each of those menus.  (Note that the error
handling here and in other areas of this program is somewhat rudimentary: the program simply
terminates.)  The call to SetMenuBar makes the newly created menu list the current list.

The call to Gestalt determines whether the application is running on Mac OS 8/9 or Mac OS X. 
If the application is running on Mac OS X, GetMenuRef is called to get a reference to the menu
object for the File menu and DeleteMenuItem is called to delete the Quit item and its preceding
divider from the menu.

The third block utilizes the relatively new Menu Manager function CreateStandardFontMenu to
create a hierarchical font menu.  A reference to the Font menu object is passed in the first
parameter.  The third parameter specifies the menu ID for the first submenu to be created.  The
fourth parameter specifies that the Font menu be created as a hierarchical menu.  The fifth
parameter receives a value representing the number of submenus created.  CreateStandardFontMenu
itself inserts these submenus into the submenu portion of the menu list.

The fourth block checkmarks the Font menu item containing the name of the small system font. 
GetFontName gets the name of the small system font and CountMenuItems counts the number of
items in the Font menu.  The for loop then walks the items in the Font menu looking for a
match.  When it finds a match, CheckMenuItem is called to checkmark the item, the global
variable which keeps track of the currently selected font is assigned the number of that item,
and the for loop is exited.

The fifth block creates the Window menu using the Window Manager function
CreateStandardWindowMenu.  The accessor function SetMenuID sets the menu's ID and InsertMenu
inserts the menu into the menu list.  (Setting the menu ID is for illustrative purposes only
because the ID is not used in this demonstration.  Since the system handles the standard Window
menu automatically, an ID is ordinarily only required for menu adjustment purposes when the
menu has been customised.)

The sixth block inserts a further single submenu (to be attached to the second item in the
Special menu) into the submenu portion of the menu list.  GetNewMBar does not read in the
resource descriptions of submenus, so the first step is to read in the 'MENU' resource with
GetMenu.  InsertMenu inserts a menu reference for this menu into the menu list at the location
specified in the second parameter to this call.  Using the constant hierMenu (-1) as the second
parameter causes the menu to be installed in the submenu portion of the menu list.

The last line causes a checkmark to be set against the Size menu item corresponding to the
initialised value of the global variable gCurrentFontSizeItem.

DrawMenuBar draws the menu bar.

Note that, in Carbon, the contents of the Apple Menu Items folder are automatically added to
the Apple menu.

doEvents

doEvents switches according to the type of low-level or Operating System event received. 
Further processing is called for in the case of mouse-down or Command key equivalents, these
being central to the matter of menu handling.

At the keyDown case, a check is made of the modifiers field of the event structure to establish
whether the Command key was also pressed at the time.  If so, menu enabling/disabling is
attended to before the call to MenuEvent establishes whether the character code is associated
with a currently enabled menu or submenu item in the menu list.  If a match is found, MenuEvent
returns a long integer containing the menu ID in the high word and the item number in the low
word, otherwise it returns 0 in the high word.  This long integer is then passed to the
function doMenuChoice.

doMouseDown

doMouseDown first establishes the window and window part in which the mouse-down event
occurred, and switches accordingly.  This demonstration program is specifically concerned with
mouse-downs in the menu bar and the content region of the window.

If the event occurred in this program's menu bar, menu enabling/disabling is attended to before
the call to MenuSelect.  MenuSelect tracks the user's actions until the mouse button is
released, at which time it returns a long integer.  If the user actually chose a menu item,
this long integer contains the menu ID in the high word and the item number in the low word,
otherwise it contains 0 in the high word.  This long integer is passed to the function 
doMenuChoice.

If the mouse-down event occurred in the content region of the window, and if the window to
which the mouse-down refers is not the front window, SelectWindow is called to effect basic
window activation/deactivation.

doAdjustMenus

doAdjustMenus is called when a mouse-down occurs in the menu bar and when examination of a
key-down event reveals that a menu item's keyboard equivalent has been pressed.  No action is
required in this simple program.

Later demonstration programs contain examples of menu adjustment functions.

doMenuChoice

doMenuChoice takes the long integer returned by the MenuSelect and MenuEvent calls, extracts
the high word (the menu ID) and the low word (the menu item number) and switches according to
the menu ID.

At the first two lines, the menu ID and the menu item number are extracted from the long
integer.  The next two lines will cause an immediate return if the high word equals 0, (meaning
that either the mouse button was released when the pointer was outside the menu box or
MenuEvent found no menu list match for the key pressed in conjunction with the Command key).

If the menu ID represents either the Font menu or one of the Font menus submenus, the menu
handling function doFontMenu is called.  Otherwise, the function switches on the menu ID so
that the appropriate individual menu handling function is called.  Note the handling of the
submenu attached to the second item in the Special menu (case mSubMenu).

The Window menu is handled automatically by the system.

MenuEvent and MenuSelect leave the menu title highlighted if an item was actually chosen. 
Accordingly, the last line unhighlights the menu title when the action associated with the
user's drop-down menu choice is complete.

doAppleApplicationMenu

doAppleApplicationMenu takes the short integer representing the menu item.  If this value
represents the first item in the Mac OS 8/9 Apple menu or Mac OS X Application menu (the
inserted "About..." item), text representing this item is drawn in the scrolling display.

If other items in the Mac OS 8/9 Apple menu are chosen, the system automatically opens the
chosen object and passes control that object.

doFileMenu

doFileMenu handles choices from the File menu when the program is run on Mac OS 8/9.  In this
demonstration, only the Quit item is enabled, all other items having been disabled in the File
menu's 'MENU' resource.  When this item is chosen, the global variable gDone is set to true,
causing termination of the program.

doEditMenu

doEditMenu switches according to the menu item number, drawing text representing the chosen
item in the window.

doFontMenu

doFontMenu first gets a reference to the Font menu object.  This, together with the menu item
number, is passed in a call to the function GetFontFamilyFromMenuSelection.  This function
returns a reference to the font family and a value representing the font style.  (A font family
reference represents a collection of fonts with the same design characteristics, e.g., Arial,
Arial Bold, Arial Italic, and Arial Bold Italic.  Font style values are, for example, 0 =
plain, 1 = bold, 2 = italic, 3 = bold italic).

The font family reference and the font style value are passed in calls to TextFont and
TextFace, which will cause subsequent text drawing to be conducted in the specified font and
style.  The call to GetFontName gets the fonts name from the font family reference and the
function drawItemString draws that name in the window.

The remaining code is mainly concerned with checkmarking the newly-chosen Font menu item and
submenu item, and unchecking the previously chosen items.

If the menu ID represents the Font menu (meaning that a menu item without an attached submenu
was chosen), the previously chosen item is unchecked, a global variable stores the item number
of the newly-chosen item preparatory to the next call to doFontmenu, and the newly chosen item
is checked.  If a submenu item has previously been chosen, and thus checked, it is unchecked.

If, on the other hand, the menuID represents one of the Font menus submenus:

o If a submenu item has previously been chosen, that item is unchecked.  A reference to the
  submenu object is assigned to a global variable, the menu item number is stored in another
  global variable preparatory to the next call to doFontmenu, and the newly chosen submenu item
  is checked.

o The next two lines uncheck the previously checked Font menu item.

o The for loop walks the Font menu looking for a match between item names and the font name
  previously extracted from the font family reference.  When a match is found, the loop exits,
  the loop variable containing the item number where the match was found.  This is stored in a
  global variable preparatory to the next call to doFontMenu, and is also passed in the call to
  CheckMenuItem to check that item.

o	The last block gets the style name from the menu object and draws that next to the font name
in the window.

doSizeMenu

doSizeMenu switches according to the menu item chosen in the Size menu, sets the text size for
all text drawing to that size, unchecks the current size item, and checks the newly chosen
item.  gCurrentSize is then set to the chosen menu item number before the function returns.

doSpecialMenu

doSpecialMenu handles a choice of the first item in the Special menu.  Since the second item is
the title of a submenu, only the first item is attended to in this function.

doSubMenus

doSubMenus switches according to the chosen item in the submenu attached to the second menu
item in the Special menu.

drawItemString

The function drawItemString is incidental to the demonstration, being called by the menu
selection handling functions to draw text in the application's window to reflect the user's
menu choices.

Demonstration Program Menus2

// *******************************************************************************************
// Menus2.c                                                                CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// This program is based on Menus1.  The basic differences between this program and Menus1 are
// as follows:
//
// o  'xmnu' resources are used to extend the 'MENU' resources for some menus.
//
// o  Extended modifier keys (Shift, Option, and Control) are used to extend the Command-key
//    equivalents for two menu items in the Style menus.
//
// o  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.
//
// o  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).
//
// o  The Font menu is non-hierarchical.  It is also WYSIWYG, meaning that each item is drawn
//    in that font.
//
// o  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.
//
// o  The submenu is attached to the second item in the Special menu programmatically rather 
//    than via the 'MENU' resource.
// 
// o  Colour icons are included in the menu items in the submenu.
//
// o  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 colour icon in the first submenu item is assigned via the 'MENU' resource.  The colour
// icon in the second item is assigned programmatically via a call to
// SetMenuItemIconHandle.
//
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  A 'WIND' resource (purgeable) (initially not visible).
//
// o  An 'MBAR' resource (preload, non-purgeable).
//
// o  'MENU' resources for the drop-down menus and submenu (all preload, all non-purgeable).
//
// o  'xmnu' resources (preload, purgeable) for the drop-down menus (except the system-managed
//     menus and the Font menu) and the submenu.
//
// o  'hmnu' resources (purgeable) providing balloon help for menus and menu items.
//
// o  Two 'cicn' resources (purgeable) for the items in the submenu.
//
// 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 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 rColourIcon       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    foreColour = { 0xFFFF,0xFFFF,0xFFFF };
  RGBColor    backColour = { 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(&backColour);
  RGBForeColor(&foreColour);

  // ............................................. 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(rColourIcon);
  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);
}

// *******************************************************************************************

Demonstration Program Menus2 Comments

When this program is run, the user should choose Show Balloons from the Help menu and make menu
choices from all menus, including the Apple menu.  Choices should be made using the mouse and,
where appropriate, the keyboard equivalents.  The user should note:

o The extended modifier keys assigned to the last two items in the Style menus.

o The Command-key equivalents assigned to the items in the Size menu.  (These are, in order,
  delete-to-the-left key, delete-to-the-right key, page-up key, and page-down key.)

o That the Font menu is WYSIWYG.

o That the marking character column has been deleted from the Special menu and the menu items
  in this menu are drawn in the Gadget font (assuming it is available).

o That the items in the submenu attached to the second item in the Special menu have colour
  icons.

o The balloon help provided for all menus and menu items.
The Menus2 demonstration program package also includes a demonstration of Apple Help, including
the methodology used to create an item in the Mac OS 8/9 Help menu.  The Apple Guide file
titled "Menus Guide", which will cause a "Menus Help" item to be created in the Mac OS 8/9 Help
menu, should be retained in the same folder as the Menus2 application.  An alias of the folder
titled "Menus Help" should be placed in the Help folder in the System Folder (Mac OS 8/9) and
in the user's Help folder (~/Library/Documentation/Help) (Mac OS X).  You will then be able to
access the help content by choosing Menus Help from the Help menu.

The help content does not provide user assistance for Menus2 programs as such.  Rather, it
provides a brief description of how to provide user assistance for your application using Apple
Help.

Because this demonstration program is based on Menus1, the following comments exclude those for
the functions that remain unchanged.

main

The calls to RGBBackColor and RGBForeColor set the window background and foreground colours to,
respectively, dark blue and white.

doGetMenus

doGetMenus sets up the menu bar and the various menus.

GetNewMBar reads in the 'MENU' resources for each menu specified in the 'MBAR' resource and
creates a menu object for each of those menus.  (Note that the error handling here and in other
areas of this program is somewhat rudimentary: the program simply terminates.)  SetMenuBar
makes the newly created menu list the current list.

The next block utilizes the Menu Manager function CreateStandardFontMenu in the creation of a
non-hierarchical Font menu.  Following the call to CreateStandardFontMenu, the process of
making the menu WYSIWYG begins.  The call to CountMenuItems returns the number of items in the
menu.  Then, for each of these items, GetMenuItemText gets the font's name, GetFNum gets the
font number associated with the font name, and SetMenuItemFontID sets the font for the menu
item.  In the following if block, the current item is checkmarked if the item name equals the
name of the small system font, and the global variable which keeps track of the currently
selected font is assigned the item number.

The next block programmatically assigns extended modifier keys to the Outline and Shadow items
in the Style (Programmatic) menu.  The SetMenuItemModifiers calls assign Shift-Option-Control
to the Outline item and Shift-Option to the Shadow item.  (The extended modifier keys for the
same two items in the Style ('xmnu') menu are assigned in the associated 'xmnu' resources.)

The next block inserts the application's single submenu into the submenu portion of the menu
list and programmatically attaches it to the Special menu's second menu item.  GetNewMBar does
not read in the resource descriptions of submenus, so the first step is to read in the 'MENU'
resource with GetMenu.  InsertMenu inserts a menu object for this menu into the menu list at
the location specified in the second parameter to this call.  (Using the constant hierMenu (-1)
as the second parameter causes the menu to be installed in the submenu portion of the menu
list.)  The call to GetMenuRef gets a reference to the Special menu, which is used in the
following call to SetMenuHierarchicalID to attach the submenu to the second item in the Special
menu.

The following rather large block programmatically assigns command IDs to all items in the Style
(Programmatic), Size, and Special menus and the submenu.  (Command IDs for the File and Style
('xmnu') menus are assigned in the associated 'xmnu' resources.  It is not possible to assign
command IDs to the items in the Font menu.)  The Command IDs are defined in the
four-character-code format, which packs four one-byte characters together in a 32-bit value. 
For example, 'plai' expressed as hexadecimal is 0x706C6169.  70 is the ASCII code for p, 6C is
the ASCII code for l, and 69 is the ASCII code for i.

The following block programmatically assigns a colour icon to the second item in the submenu. 
The call to GetCIcon creates a CIcon data structure and initializes it from data read in from
the specified 'cicn' resource.  The handle to this structure is then passed as the last
parameter in the SetMenuItemIconHandle, the third parameter specifying that the type of icon is
a colour icon.  (The colour icon for the first item in the submenu is assigned in the
associated 'xmnu' resource.)

The next block programmatically assigns command-key equivalents to the items of the Size menu. 
(Because the keys assigned are the two delete keys and the page-up and page-down keys, it is
not possible to make these assignments within the 'MENU' resource.)  Also, a substitute glyph
must be assigned, otherwise the correct glyphs will not be displayed.  The calls to SetItemCmd
assign the specified key to the menu item, and a substitute glyph is assigned via calls to
SetMenuItemGlyph.  If this is not done, the glyphs displayed will not be the correct visual
representations of the keys.  (These substitute glyphs could also have been specified in the
keyboard glyph fields for these items in the menu's 'xmnu' resource.)

In the next block, SetMenuExcludesMarkColumn is called to delete the marking character column
from the Special menu and SetMenuFont is called to set the font for the menu items in this menu
to Gadget (assuming that font is present).

In the next block, and only if the program is running on Mac OS X, HMGetHelpMenu is called to
create a Help menu, InsertMenuItem is called to insert a single item in that menu, and
SetMenuItemCommandID assigns a command ID to that item.

The next block sets checkmarks against the appropriate font, style and size menu items
according to the initialised values of the associated global variables.

The call to DrawMenuBar draws the menu bar

Note that, in Carbon, the contents of the Apple Menu Items folder are automatically added to
the Apple menu.

doMenuChoice

doMenuChoice extracts the menu ID and menu item number from the long integer returned by the
MenuSelect and MenuEvent calls.  An immediate return is made if the high word equals 0.  The
function "special cases" the Font menus, calling the function for handling choices from that
menu.  Otherwise, GetMenuItemCommandID is called.  GetMenuItemCommandID returns zero as the
function result if the call is successful, and a pointer to an integer representing the value
of the item's command ID will be returned in the third parameter.  If the call is successful,
and if a zero is not returned in the third parameter, a command ID exists for the item. 
Accordingly, the command ID is passed in a call to the function doCommand.

MenuSelect and MenuEvent leave the menu title highlighted if an item was actually chosen. 
Accordingly, the last line unhighlights the menu title when the action associated with the
user's drop-down menu choice is complete. 

doCommand

doCommand handles choices from those menus whose items have command IDs.

Note that the initial handling of all of the remaining menu items, regardless of which menu
they belong to, is attended to within the one switch in the one function.  The responses to the
user choosing the various menu items is the same as in Menus1, except that the code relating to
checkmarking the Style menu items has been added and the code for checkmarking the Size menu
items and storing the current size has been divided between this function a further handling
function (doCheckSizeMenuItem).

At the block titled Style ('xmnu') and Style (Programmatic) menu, bits in the global variable
gCurrentStyle are set or unset according to the font styles selected.  The code reflects the
fact that Bold, Italic, Underline, Outline and Shadow style selections are additive, not
mutually exclusive, and that a selection of Plain must unset all bits in gCurrentStyle.  The
code also reflects the requirement that, except in the case of the Plain item, the selection of
a checked item must cause that item to be unchecked, and vice versa.  With gCurrentStyle set,
the function doCheckStyleMenuItem is called to check/uncheck the relevant menu items as
appropriate.

Note that the handling of the two submenu items has been changed to make the items mutually
exclusive. 

The 'help' command ID case applies only when the program is run on Mac OS X.  The function
AHGoToPage is called to deliver a request to load the specified HTML file in the specified Help
book folder to the Help Viewer application.

doCheckStyleMenuItem

doCheckStyleMenuItem is called from doMenuChoice when an item in the Style menu is chosen. 
With the appropriate bit settings of gCurrentStyle attended to within doMenuChoice, a reference
to the Style menu object is obtained.  This is required for the six CheckMenuItem calls, which
check or uncheck the individual menu items according to whether the third parameter evaluates
to, respectively, true or false.

The call to TextFace sets the style for subsequent text drawing.  The last line draws some text
to prove that the desired effect was achieved.
 
AAPL
$100.91
Apple Inc.
+0.38
MSFT
$44.97
Microsoft Corpora
-0.36
GOOG
$584.63
Google Inc.
-2.23

MacTech Search:
Community Search:

Software Updates via MacUpdate

Tidy Up 3.0.15.0 - Find duplicate files...
Tidy Up is a complete duplicate finder and disk-tidiness utility. With Tidy Up you can search for duplicate files and packages by the owner application, content, type, creator, extension, time... Read more
Parallels Desktop 10.0 - Run Windows app...
Parallels Desktop is simply the world's bestselling, top-rated, and most trusted solution for running Windows applications on your Mac. With Parallels Desktop for Mac, you can seamlessly run both... Read more
Apple Final Cut Pro X 10.1.3 - Professio...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Apple Compressor 4.1.3 - Adds power and...
Compressor adds power and flexibility to Final Cut Pro X export. Customize output settings, work faster with distributed encoding, and tap into a comprehensive set of delivery features. Powerful... Read more
Chromium 36.0.1985.143 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. FreeSMUG-Free OpenSource Mac User Group build is... Read more
Macgo Blu-ray Player 2.10.6.1691 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Apple Motion 5.1.2 - Create and customiz...
Apple Motion is designed for video editors, Motion 5 lets you customize Final Cut Pro titles, transitions, and effects. Or create your own dazzling animations in 2D or 3D space, with real-time... Read more
A Better Finder Rename 9.39 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
PopChar X 6.6 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
MacUpdate Desktop 6.0.2 - Install Mac ap...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more

Latest Forum Discussions

See All

Space Colors – Tips, Tricks, Strategies,...
Hello Cadets: Want to know what we thought about this hectic space combat/roguelike? Check out our Space Colors review! Space Colors is a cool shooter/roguelike from Team Chaos. You travel from planet to planet across a huge galaxy and complete a... | Read more »
Tap Sports Baseball – Tips, Tricks, and...
Tap Sports Baseball is a pretty simple game to learn, but that doesn’t mean it’s an easy game to master, by any means. To start your batting career off well, we thought we’d give you the heads up on some handy tips and tricks. Hey Batter-Batter:... | Read more »
Tap Sports Baseball Review
Tap Sports Baseball Review By Jennifer Allen on August 20th, 2014 Our Rating: :: LET'S PLAY BALLUniversal App - Designed for iPhone and iPad Tap Sports Baseball is briefly fun but lacks some important features.   | Read more »
Frontier Heroes Review
Frontier Heroes Review By Andrew Fisher on August 20th, 2014 Our Rating: :: BLAZES NO TRAILSUniversal App - Designed for iPhone and iPad Despite awesome visuals and great music, Frontier Heroes just doesn’t quite deliver enough fun... | Read more »
Echo Prime is Now on Sale for $0.99
Echo Prime is Now on Sale for $0.99 Posted by Jessica Fisher on August 20th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Star Realms Review
Star Realms Review By Andrew Fisher on August 20th, 2014 Our Rating: :: A STAR IS BORNUniversal App - Designed for iPhone and iPad Star Realms is an excellent adaptation of an outstanding deck-builder. With great visuals and an... | Read more »
This. Is. SPRINGFIELD! War comes to The...
This. Is. SPRINGFIELD! | Read more »
One Tap RPG Review
One Tap RPG Review By Campbell Bird on August 20th, 2014 Our Rating: :: DUNGEON SLIDERUniversal App - Designed for iPhone and iPad This casual arcade game introduces some very light rpg elements into its fantasy-themed pachinko... | Read more »
Goodbye Paywall – Table Tennis Touch Eli...
Goodbye Paywall – Table Tennis Touch Eliminates In-App Purchases Posted by Jessica Fisher on August 20th, 2014 [ permalink ] | Read more »
Go to Bed – An Interview With Touchfight...
Touchfight Games is an exciting new indie studio that was co-formed between game journalist and author Nathan Meunier, artist Leonard Kenyon, and programmer Jon Kenyon. Their debut game Go To Bed will be released this fall, and with all the... | Read more »

Price Scanner via MacPrices.net

Apple now offering certified refurbished 2014...
 The Apple Store is now offering Apple Certified Refurbished 2014 MacBook Airs for up to $180 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
Best Buy’s College Student Deals: $100 off Ma...
Take an additional $100 off all MacBooks and iMacs, $50 off iPad Airs and iPad minis, at Best Buy Online with their College Students Deals Savings, valid through September 6th. Anyone with a valid .... Read more
MacBook Airs on sale for $100 off MSRP, free...
B&H Photo has three 2014 MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for Laptops... Read more
Razer Taipan Mouse For Gamers And Non-Gamers...
If you’re a serious gamer on either Mac or Windows PCs, a serious gaming mouse is a necessity for first-tier performance. However, even if like me you’re not much of a gamer, there’s still a strong... Read more
15-inch 2.2GHz MacBook Pro on sale for $1899,...
Adorama has the new 15″ 2.2GHz Retina MacBook Pro on sale for $1899 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this... Read more
Mid-Size Tablet Shootout Posted: iPad mini wi...
I ‘m curious about how many iPads Apple is actually selling these days. It’s been widely rumored and anticipated that new models with A8 SoCs, 2 GB of RAM, 8 megapixel cameras, and fingerprint... Read more
The 15 Biggest iPad Air Problems And How To A...
What’s this? Fifteen “biggest” problems with the iPad Air? Does that mean there are a lot of smaller problems as well? Say it isn’t so! My old iPad 2 has manifested no hardware problems in three... Read more
TYLT Syncable-Duo, 2-in-1 USB Cable With Appl...
TYLT has introduced the Syncable-Duo, a universal cable solution for charging and syncing data to smartphones and tablets. The Syncable-Duo eliminates the need for multiple cables by incorporating... Read more
Save up to $140 off MSRP with Apple refurbish...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
2.5GHz Mac mini on sale for $549, save $50
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more

Jobs Board

Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Solutions Consultant - Apple (United...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** Being a Business Manager at an Apple Store means you're the catalyst for businesses to discover and leverage the power, ease, and flexibility of Apple Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** At the Apple Store, you connect business professionals and entrepreneurs with the tools they need in order to put Apple solutions to work in their Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.