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
$112.38
Apple Inc.
-0.27
MSFT
$47.75
Microsoft Corpora
+0.23
GOOG
$510.37
Google Inc.
-0.73

MacTech Search:
Community Search:

Software Updates via MacUpdate

calibre 2.13 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Mellel 3.3.7 - 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
ScreenFlow 5.0.1 - Create screen recordi...
Save 10% with the exclusive MacUpdate coupon code: AFMacUpdate10 Buy now! ScreenFlow is powerful, easy-to-use screencasting software for the Mac. With ScreenFlow you can record the contents of your... Read more
Simon 4.0 - Monitor changes and crashes...
Simon monitors websites and alerts you of crashes and changes. Select pages to monitor, choose your alert options, and customize your settings. Simon does the rest. Keep a watchful eye on your... Read more
BBEdit 11.0.2 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
ExpanDrive 4.2.1 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
Adobe After Effects CC 2014 13.2 - Creat...
After Effects CC 2014 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous After Effects customer). After Effects CS6 is still available... Read more
Evernote 6.0.5 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
Command-C 1.1.7 - 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
Tidy Up 4.0.2 - Find duplicate files and...
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

Latest Forum Discussions

See All

BulkyPix Celebrates its 6th Anniversary...
BulkyPix Celebrates its 6th Anniversary with a Bunch of Free Games Posted by Jessica Fisher on December 19th, 2014 [ permalink ] BulkyPix has | Read more »
Indulge in Japanese cuisine in Cooking F...
Indulge in Japanese cuisine in Cooking Fever’s new sushi-themed update Posted by Simon Reed on December 19th, 2014 [ permalink ] Lithuanian developer Nordcurrent has yet again updated its restaurant simulat | Read more »
Badland Daydream Level Pack Arrives to C...
Badland Daydream Level Pack Arrives to Celebrate 20 Million Downloads Posted by Ellis Spice on December 19th, 2014 [ permalink ] | Read more »
Far Cry 4, Assassin’s Creed Unity, Desti...
Far Cry 4, Assassin’s Creed Unity, Destiny, and Beyond – AppSpy Takes a Look at AAA Companion Apps Posted by Rob Rich on December 19th, 2014 [ permalink ] These day | Read more »
A Bunch of Halfbrick Games Are Going Fre...
A Bunch of Halfbrick Games Are Going Free for the Holidays Posted by Ellis Spice on December 19th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Shift - Photo Filters Designed By You (...
Shift - Photo Filters Designed By You 1.0 Device: iOS Universal Category: Photography Price: $.99, Version: 1.0 (iTunes) Description: | Read more »
Elastic Drums (Music)
Elastic Drums 1.0 Device: iOS iPhone Category: Music Price: $3.99, Version: 1.0 (iTunes) Description: *** Introduction price 3,99$ instead of 7,99$ *** Elastic Drums is a music app with 6 channels of synthesized drum sounds, a step... | Read more »
Fireworks Simulator (Games)
Fireworks Simulator 1.0.8 Device: iOS Universal Category: Games Price: $.99, Version: 1.0.8 (iTunes) Description: *** 50% discount – For a short time only *** You can play Fireworks Simulator on these devices: - iPhone 5, 5s, 5c, 6,... | Read more »
Nicky's Gift (Games)
Nicky's Gift 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Everybody! Merry Christmas! There's 48 levels in the game. Let's go! Nicky's Gift | Read more »
The Hit List — Simply Powerful Tasks, To...
The Hit List — Simply Powerful Tasks, To-Dos, Projects, & Reminders 2.0 Device: iOS iPhone Category: Productivity Price: $9.99, Version: 2.0 (iTunes) Description: >> LAUNCH SPECIAL: The Hit List 2 for iPhone is ONLY $9.99... | Read more »

Price Scanner via MacPrices.net

It’s 1992 Again At Sony Pictures, Except For...
Techcrunch’s John Biggs interviewed a Sony Pictures Entertainment (SPE) employee, who quite understandably wished to remain anonymous, regarding post-hack conditions in SPE’s L.A office, explaining “... Read more
Holiday sales this weekend: MacBook Pros for...
 B&H Photo has new MacBook Pros on sale for up to $300 off MSRP as part of their Holiday pricing. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1699... Read more
Holiday sales this weekend: MacBook Airs for...
B&H Photo has 2014 MacBook Airs on sale for up to $120 off MSRP, for a limited time, for the Thanksgiving/Christmas Holiday shopping season. Shipping is free, and B&H charges NY sales tax... Read more
Holiday sales this weekend: iMacs for up to $...
B&H Photo has 21″ and 27″ iMacs on sale for up to $200 off MSRP including free shipping plus NY sales tax only. B&H will also include a free copy of Parallels Desktop software: - 21″ 1.4GHz... Read more
Holiday sales this weekend: Mac minis availab...
B&H Photo has new 2014 Mac minis on sale for up to $80 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 1.4GHz Mac mini: $459 $40 off MSRP - 2.6GHz Mac mini: $629 $70 off MSRP... Read more
Holiday sales this weekend: Mac Pros for up t...
B&H Photo has Mac Pros on sale for up to $500 off MSRP. Shipping is free, and B&H charges sales tax in NY only: - 3.7GHz 4-core Mac Pro: $2599, $400 off MSRP - 3.5GHz 6-core Mac Pro: $3499, $... Read more
Save up to $400 on MacBooks with Apple Certif...
The Apple Store has Apple Certified Refurbished 2014 MacBook Pros and MacBook Airs available for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
Save up to $300 on Macs, $30 on iPads with Ap...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
iOS and Android OS Targeted by Man-in-the-Mid...
Cloud services security provider Akamai Technologies, Inc. has released, through the company’s Prolexic Security Engineering & Research Team (PLXsert), a new cybersecurity threat advisory. The... Read more
KMI MIDI K-Board Great Gift for Amateur &...
The K-Board is a MIDI Nano keyboard for music creation for iPad, Android, And computers; the easiest way to make music with iPads & Android tablets, and Mac, Windows, or Linux computers. Ultra-... Read more

Jobs Board

Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*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
*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
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.