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 menuŐs 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 fontŐs 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 menuŐs 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
$95.74
Apple Inc.
+0.14
MSFT
$43.02
Microsoft Corpora
-0.14
GOOG
$568.18
Google Inc.
-3.42

MacTech Search:
Community Search:

Software Updates via MacUpdate

Adobe Lightroom 5.6 - Import, develop, a...
Adobe Lightroom software helps you bring out the best in your photographs, whether you're perfecting one image, searching for ten, processing hundreds, or organizing thousands. Create incredible... Read more
OneNote 15.2 - Free digital notebook fro...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that’s too important to forget. Whether you’re at... Read more
iStat Menus 4.22 - Monitor your system r...
iStat Menus lets you monitor your system right from the menubar. Included are 8 menu extras that let you monitor every aspect of your system. Some features: CPU -- Monitor cpu usage. 7 display... Read more
Ember 1.8 - Versatile digital scrapbook....
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
OmniPlan 2.3.6 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Command-C 1.1.1 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0 - Drag-and-drop Web desi...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more

Latest Forum Discussions

See All

Dead Trigger 2 Slaughter Master Tourname...
Dead Trigger 2 Slaughter Master Tournament Set to Reward for Masterful Murdering Posted by Ellis Spice on August 1st, 2014 [ | Read more »
Soccer Physics Review
Soccer Physics Review By Andrew Fisher on August 1st, 2014 Our Rating: :: HE FLAILS, HE SCORES!!!Universal App - Designed for iPhone and iPad Soccer Physics is as entertaining as it is absurd.   | Read more »
Train Your Own Dragon in DreamWorks’ Fir...
Train Your Own Dragon in DreamWorks’ First Story App – Dreamworks Press: Dragons Posted by Jessica Fisher on August 1st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Dream Revenant Review
Dream Revenant Review By Lee Hamlet on August 1st, 2014 Our Rating: :: WATCH OUT FOR BED BUGSUniversal App - Designed for iPhone and iPad Dream Revenant takes players on a journey through a man’s subconscious. And though it’s full... | Read more »
Dawn of the Immortals Review
Dawn of the Immortals Review By Jennifer Allen on July 31st, 2014 Our Rating: :: RESPECTABLE EXPLORATIONUniversal App - Designed for iPhone and iPad Dawn of the Immortals might not re-invent the wheel, but it does tweak it a little... | Read more »
80 Days Review
80 Days Review By Jennifer Allen on July 31st, 2014 Our Rating: :: EPIC ADVENTUREUniversal App - Designed for iPhone and iPad A fantastic and fascinating re-envisioning of the classic novel by Jules Verne, 80 Days is a delightful... | Read more »
Battleheart Legacy Guide
The world of Battleheart Legacy is fun and deep; full of wizards, warriors, and witches. Here are some tips and tactics to help you get the most enjoyment out of this great game. | Read more »
Puzzle Roo Review
Puzzle Roo Review By Jennifer Allen on July 31st, 2014 Our Rating: :: PUZZLE-BASED TWISTUniversal App - Designed for iPhone and iPad A different take on the usual block dropping puzzle game, Puzzle Roo is quite pleasant.   | Read more »
Super Crossfire Re-Release Super Crossfi...
Super Crossfire Re-Release Super Crossfighter Coming Soon, Other Radiangames Titles Go 50% Off Posted by Ellis Spice on July 31st, 2014 [ | Read more »
Hexiled Review
Hexiled Review By Rob Thomas on July 31st, 2014 Our Rating: :: HEX SELLSUniversal App - Designed for iPhone and iPad In space, no one can hear you… spell? Hexiled is a neat concept for a word scramble puzzle, but it doesn’t go too... | Read more »

Price Scanner via MacPrices.net

13-inch MacBook Airs on sale for $100 off MSR...
B&H Photo has the new 2014 13″ MacBook Airs on sale $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... Read more
16GB iPad Air on sale for $399, save $100
Best Buy is offering the 16GB WiFi iPad Air for $399.99 on their online store for a limited time. Their price is $100 off MSRP. Choose free shipping or free store pickup (if available). Price is for... Read more
All Over For Tablets Or Just A Maturing, Evol...
CNN’s David Goldman weighs in on tablet sector doom and gloom, asking rhetorically: “Is this the beginning of the end for the tablet?” Answering that, he contends that hysteria and panic are... Read more
Letterspace 1.0.1 – New Free iOS Text Editor...
Bangkok, Thailand based independent developer Sittipon Simasanti has released Letterspace, a new text editor for iPhone, iPad, and iPod touch devices. Letterspace is a note taking app with an... Read more
Save up to $130 on an iPad mini with Apple re...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays available for up to $130 off the cost of new models, starting at $339. Apple’s one-year warranty is included... Read more
iPad Cannibalization Threat “Overblown”
Seeking Alpha’s Kevin Greenhalgh observes that while many commentators think Apple’s forthcoming 5.5-inch panel iPhone 6 will cannibalize iPad sales, in his estimation, these concerns are being... Read more
Primate Labs Releases July 2014 MacBook Pro P...
Primate Labs’ John Poole has posted Geekbench 3 results for most of the new MacBook Pro models that Apple released on Tuesday. Poole observes that overall performance improvements for the new MacBook... Read more
Apple Re-Releases Bugfixed MacBook Air EFI Fi...
Apple has posted a bugfixed version EFI Firmware Update 2.9 a for MacBook Air (Mid 2011) models. The update addresses an issue where systems may take longer to wake from sleep than expected, and... Read more
Save $50 on the 2.5GHz Mac mini, plus free sh...
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
Save up to $140 on an iPad Air with Apple ref...
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

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.