TweetFollow Us on Twitter

MACINTOSH C

Demonstration Programs

Go to Contents

Menus1

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Menus1.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 
// This program:
//
// „  Opens a window.
//
// „  Creates these pull-down menus: Apple, File, Edit, Font, Style, Size, and Special.
//
//    The Apple menu includes an "About..." menu item for the program.
//
//    The second menu item in the Special menu contains a submenu.
//
//    A "Help" menu item for the program is appended to the Help menu.
//
// „  Displays text in the window indicating the menu selection made by the user.
//
// 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.
//
// To facilitate a comparison with the fully theme-compliant menus in the 
// demonstration program Menus2, no measures are taken in this program to cause the menu
// bar and menus to use the new menu bar and menu definition functions when system-wide
// Appearance is selected off in the Mac OS 8.0 and 8.1 Appearance control panel.  The 
// menu bar and menus will only use the new definition functions when system-wide 
// Appearance is selected on in the Mac OS 8.0 and 8.1 Appearance control panel.
//
// 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. 
//  
// The program utilises the following resources:
//
// „  A 'WIND' resource (purgeable) (initially not visible).
//
// „  An 'MBAR' resource (preload, non-purgeable).
//
// „  'MENU' resources for the drop-down and hierarchical menus (all preload, all 
//    non-purgeable).
//
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include <Appearance.h>
#include <Balloons.h>
#include <Devices.h>
#include <Fonts.h>
#include <Sound.h>
#include <ToolUtils.h>

// .............................................................................. defines

#define mApple           128
#define  iAbout          1
#define mFile            129
#define  iQuit           11
#define mEdit            130
#define  iUndo           1
#define  iCut            3
#define  iCopy           4
#define  iPaste          5
#define  iClear          6
#define mFont            131
#define mStyle           132
#define  iPlain          1
#define  iBold           3
#define  iItalic         4
#define  iUnderline      5
#define  iOutline        6
#define  iShadow         7
#define mSize            133
#define  iTen            1
#define  iTwelve         2
#define  iEighteen       3
#define  iTwentyFour     4
#define mSpecial         134
#define  iFirstItem      1
#define  iSecondItem     2
#define mSubmenu         135
#define  iFirstSubItem   1
#define  iSecondSubItem  2
#define rWindowResource  128
  
// ..................................................................... global variables

Boolean  gDone;
SInt16   gCurrentFont  = 1;
Style    gCurrentStyle = 0;
SInt16   gCurrentSize  = 2;

// .................................................................. function prototypes

void    main              (void);
void    doInitManagers    (void);
void    doGetMenus        (void);
void    doEvents          (EventRecord *);
void    doMouseDown       (EventRecord *);
void    doAdjustMenus     (void);
void    doMenuChoice      (SInt32);
void    doAppleMenu       (SInt16);
void    doFileMenu        (SInt16);
void    doEditMenu        (SInt16);
void    doFontMenu        (SInt16);
void    doStyleMenu       (SInt16);
void    doSizeMenu        (SInt16);
void    doSpecialMenu     (SInt16);
void    doSubMenus        (SInt16);
void    doHelpMenu        (SInt16);
void    drawItemString    (Str255);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  EventRecord  eventStructure;
  WindowPtr    windowPtr;

  // ................................................................ initialise managers

  doInitManagers();
  
  // ...................................................................... open a window
    
  if(!(windowPtr = GetNewCWindow(rWindowResource,NULL,(WindowPtr) -1)))
  {
    SysBeep(10);
    ExitToShell();
  }

  SetPort(windowPtr);

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

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

  gDone = false;

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

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);

  InitCursor();  
  FlushEvents(everyEvent,0);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doGetMenus

void  doGetMenus(void)
{
  Handle        menubarHdl;
  MenuHandle    menuHdl;
  OSErr         osErr;
  
  menubarHdl = GetNewMBar(128);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  menuHdl = GetMenuHandle(mApple);
  if(menuHdl != NULL)
    AppendResMenu(menuHdl,'DRVR');
  else
    ExitToShell();

  menuHdl = GetMenuHandle(mFont);
  if(menuHdl != NULL)
    AppendResMenu(menuHdl,'FONT');
  else
    ExitToShell();

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

  osErr = HMGetHelpMenuHandle(&menuHdl);
  if(osErr == noErr)
    AppendMenu(menuHdl,"\pMenus1 Help");
  else
    ExitToShell();

  doFontMenu(gCurrentFont);
  doStyleMenu(gCurrentStyle);
  doSizeMenu(gCurrentSize);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt8  charCode;

  switch(eventStrucPtr->what)
  {
    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        doAdjustMenus();
        doMenuChoice(MenuEvent(eventStrucPtr));
      }
      break;

    case updateEvt:
      BeginUpdate((WindowPtr)eventStrucPtr->message);
      EndUpdate((WindowPtr)eventStrucPtr->message);
      break;

    case osEvt:
      HiliteMenu(0);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    partCode;
  SInt32    menuChoice;

  partCode = FindWindow(eventStrucPtr->where,&windowPtr);
  
  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      menuChoice = MenuSelect(eventStrucPtr->where);
      doMenuChoice(menuChoice);
      break;

    case inContent:
      if(windowPtr != FrontWindow())
        SelectWindow(windowPtr);
      break;

    case inDrag:
      DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
      break;

    case inGoAway:
      if(TrackGoAway(windowPtr,eventStrucPtr->where))
        gDone = true;
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus

void  doAdjustMenus(void)
{
  // Adjust menus here.
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  SInt16    menuID, menuItem;
    
  menuID   = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mApple:
      doAppleMenu(menuItem);
      break;

    case mFile:
      doFileMenu(menuItem);
      break;
      
    case mEdit:
      doEditMenu(menuItem);
      break;

    case mFont:
      doFontMenu(menuItem);
      break;

    case mStyle:
      doStyleMenu(menuItem);
      break;

    case mSize:
      doSizeMenu(menuItem);
      break;

    case mSpecial:
      doSpecialMenu(menuItem);
      break;

    case mSubmenu:
      doSubMenus(menuItem);
      break;

    case kHMHelpMenuID:
      doHelpMenu(menuItem);
      break;
  }

  HiliteMenu(0);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAppleMenu

void  doAppleMenu(SInt16 menuItem)
{
  Str255  itemName;
  SInt16  daDriverRefNum;
  
  if(menuItem == iAbout)
    drawItemString("\pAbout Menus1.");
  else
  {
    GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
    daDriverRefNum = OpenDeskAcc(itemName);
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFileMenu

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

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEditMenu

void  doEditMenu(SInt16 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(SInt16 menuItem)
{
  MenuHandle  fontMenuHdl;
  Str255      fontName;
  SInt16      fontNumber;

  fontMenuHdl = GetMenuHandle(mFont);

  CheckMenuItem(fontMenuHdl,gCurrentFont,false);
  CheckMenuItem(fontMenuHdl,menuItem,true);

  gCurrentFont = menuItem;

  GetMenuItemText(fontMenuHdl,menuItem,fontName);
  GetFNum(fontName,&fontNumber);
  TextFont(fontNumber);

  drawItemString(fontName);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doStyleMenu

void  doStyleMenu(SInt16 menuItem)
{
  MenuHandle  styleMenuHdl;
  
  switch(menuItem)
  {
    case iPlain:
      gCurrentStyle = 0;
      break;

    case iBold:
      if(gCurrentStyle & bold)
        gCurrentStyle -= bold;
      else
        gCurrentStyle |= bold;
      break;

    case iItalic:
      if(gCurrentStyle & italic)
        gCurrentStyle -= italic;
      else
        gCurrentStyle |= italic;
      break;

    case iUnderline:
      if(gCurrentStyle & underline)
        gCurrentStyle -= underline;
      else
        gCurrentStyle |= underline;
      break;

    case iOutline:
      if(gCurrentStyle & outline)
        gCurrentStyle -= outline;
      else
        gCurrentStyle |= outline;
      break;

    case iShadow:
      if(gCurrentStyle & shadow)
        gCurrentStyle -= shadow;
      else
        gCurrentStyle |= shadow;
      break;
  }

  styleMenuHdl = GetMenuHandle(mStyle);

  CheckMenuItem(styleMenuHdl,iPlain,     gCurrentStyle == 0);
  CheckMenuItem(styleMenuHdl,iBold,      gCurrentStyle & bold);
  CheckMenuItem(styleMenuHdl,iItalic,    gCurrentStyle & italic);
  CheckMenuItem(styleMenuHdl,iUnderline, gCurrentStyle & underline);
  CheckMenuItem(styleMenuHdl,iOutline,   gCurrentStyle & outline);
  CheckMenuItem(styleMenuHdl,iShadow,    gCurrentStyle & shadow);
  
  TextFace(gCurrentStyle);

  drawItemString("\pStyle change");
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSizeMenu

void  doSizeMenu(SInt16 menuItem)
{  
  MenuHandle  sizeMenuHdl;  

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

    case iTwelve:
      TextSize(12);
      break;

    case iEighteen:
      TextSize(18);
      break;

    case iTwentyFour:
      TextSize(24);
      break;
  }

  sizeMenuHdl = GetMenuHandle(mSize);

  CheckMenuItem(sizeMenuHdl,gCurrentSize,false);
  CheckMenuItem(sizeMenuHdl,menuItem,true);
  
  gCurrentSize = menuItem;
  
  drawItemString("\pSize change");
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSpecialMenu

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

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSubMenus

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

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

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doHelpMenu

void  doHelpMenu(SInt16 menuItem)
{
  MenuHandle  helpMenuHdl;
  SInt16      origHelpItems, numItems;

  HMGetHelpMenuHandle(&helpMenuHdl);

  numItems = CountMenuItems(helpMenuHdl);
  origHelpItems = numItems - 1;

  if(menuItem > origHelpItems)
    drawItemString("\pMenus1 Help");
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× drawItemString

void  drawItemString(Str255 eventString)
{
  RgnHandle  tempRegion;
  WindowPtr  windowPtr;
  Rect       scrollBox;

  windowPtr = FrontWindow();
  tempRegion = NewRgn();

  scrollBox = windowPtr->portRect;
  
  ScrollRect(&scrollBox,0,-24,tempRegion);
  DisposeRgn(tempRegion);
  
  MoveTo(8,286);
  DrawString(eventString);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

Menus2

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Menus2.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 
// This program is based on Menus1 and, amongst other things, demonstrates:
//
// „  How to achieve theme-compliant menus and menu bars.
//
// „  The additional menus-related features introduced with Mac OS 8 and the Appearance 
//    Manager and, later, Mac OS 8.5.
//
// The basic differences between this program and Menus1 are as follows:
//
// „  A call to RegisterAppearanceClient is used early in main() to cause the new menu
//    bar definition function (resource ID 63) to be used regardless of whether 
//    system-wide Appearance is  selected on or off in the Mac OS 8.0 and 8.1 Appearance
//    control panel.  Also, the new menu definition function (resource ID 63) is 
//    specified in the 'MENU'  resource for all menus, meaning that that that definition
//    function will be used  regardless of whether system-wide Appearance is selected on
//    or off in the Mac OS 8.0 and 8.1 Appearance  control panel. 
//
// „  'xmnu' resources are used to extend the 'MENU' resources for all non-system
//    managed menus and the Font menu.
//
// „  Extended modifier keys (Shift, Option, and Control) are used to extend the
//    Command-key equivalents for two menu items in the Style menus.
//
// „  There are two Style menus (Style ('xmnu') and Style (Programmatic).  The two Style
//    menus are intended to demonstrate an anomaly in the first version of the 
//    theme-compliant menu definition function (resource ID 63) in the case where
//    extended modifier keys are assigned to a menu  item via an 'xmnu' resource as 
//    opposed to being assigned programmatically.  (Note that this only applies to Mac
//    OS 8.0 and 8.1.  This problem was fixed in Mac OS 8.5.)
//
// „  Command IDs are assigned to all menu items except those in the system-managed
//    menus and the Font menu, and the associated menu handling code branches according
//    to the command ID of the chosen menu item (as opposed to menu ID and menu item).
//
// „  The Font menu is WYSIWYG, meaning that each item is drawn in that font.
//
// „  The delete-to-the-left, delete-to-the-right, page-up, and page-down keys are
//    assigned as Command-key equivalents in the Size menu, and the glyphs are adjusted
//    where necessary.
//
// „  If Mac OS 8.5 is present, the mark column is eliminated from the Special menu and
//    the font for the menu is set to the Gadget font (if it is present).
//
// „  The submenu is attached to the second item in the Special menu programmatically 
//    rather than via the 'MENU' resource.
// 
// „  Colour icons are included in the menu items in the submenu.
//
// „  Balloon help is provided, via 'hmnu' resources, for all menus.
//
// „  A Menus2 Help item is not programmatically appended to the Help Menu.  Instead, an
//    Apple Guide file, which is included in the application folder, causes the system
//    to install a Menus Help item in the Help menu.  (Note:  This works only when the
//    application is run on Mac OS 8.6 and later.)
//
// 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 via calls to SetMenuItemModifiers.  
//
// 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:
//
// „  A 'WIND' resource (purgeable) (initially not visible).
//
// „  An 'MBAR' resource (preload, non-purgeable).
//
// „  'MENU' resources for the drop-down menus and submenu (all preload, all non-
//    purgeable).
//
// „  'xmnu' resources (preload, purgeable) for the drop-down menus (except the 
//    system-managed menus and the Font menu) and the submenu.
//
// „  'hmnu' resources (purgeable) providing balloon help for menus and menu items.
//
// „  Two 'cicn' resources (purgeable) for the items in the submenu.
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include <Appearance.h>
#include <Devices.h>
#include <Fonts.h>
#include <Gestalt.h>
#include <Sound.h>
#include <ToolUtils.h>

// .............................................................................. defines

#define mApple            128
#define  iAbout           1
#define mFile             129
#define  idQuit           'quit'
#define mEdit             130
#define  idUndo           'undo'
#define  idCut            'cut '
#define  idCopy           'copy'
#define  idPaste          'past'
#define  idClear          'clea'
#define mFont             131
#define mStyle_xmnu       132
#define  idPlain_xmnu     'plax'
#define  idBold_xmnu      'bolx'
#define  idItalic_xmnu    'itax'
#define  idUnderline_xmnu 'undx'
#define  idOutline_xmnu   'outx'
#define  idShadow_xmnu    'shax'
#define mStyle_prog       133
#define  iPlain           1
#define  iBold            3
#define  iItalic          4
#define  iOutline         6
#define  iUnderline       5
#define  iShadow          7
#define  idPlain_prog     'plap'
#define  idBold_prog      'bolp'
#define  idItalic_prog    'itap'
#define  idUnderline_prog 'undp'
#define  idOutline_prog   'outp'
#define  idShadow_prog    'shap'
#define mSize             134
#define  iTen             1
#define  iTwelve          2
#define  iEighteen        3
#define  iTwentyFour      4
#define  idTen            'ten '
#define  idTwelve         'twel'
#define  idEighteen       'eigh'
#define  idTwentyFour     'twen'
#define mSpecial          135
#define  iFirst           1
#define  iSecond          2
#define  idFirst          'firs'
#define mSubmenu          136
#define  iBat             1
#define  iBowl            2
#define  idBat            'bat '
#define  idBowl           'bowl'
#define rWindowResource   128
#define rColourIcon       258

// ..................................................................... global variables

Boolean gMacOS_85_present;
Boolean gDone;
SInt16  gCurrentFont =  1;
Style   gCurrentStyle =  0;
SInt16  gCurrentSize =  2;

// .................................................................. function prototypes

void    main                    (void);
void    doInitManagers          (void);
void    doGetMenus              (void);
void    doEvents                (EventRecord *);
void    doMouseDown             (EventRecord *);
void    doAdjustMenus           (void);
void    doMenuChoice            (SInt32);
void    doAppleMenu             (SInt16);
void    doFontMenu              (SInt16);
void    doCheckStyleMenuItem    (SInt16);
void    doCheckSizeMenuItem     (SInt16,SInt16);
void    drawItemString          (Str255);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  SInt32      response;
  EventRecord eventStructure;
  WindowPtr   windowPtr;
  RGBColor    foreColour = { 0xFFFF,0xFFFF,0xFFFF };
  RGBColor    backColour = { 0x4444,0x4444,0x9999 };

  // ................................................................ initialise managers

  doInitManagers();
  
  // ....... cause the theme-compliant menu bar definition function to be called directly
  
  RegisterAppearanceClient();

  // ............................................ check if Mac OS 8.5 or later is present

  Gestalt(gestaltSystemVersion,&response);
  if(response >= 0x00000850)
    gMacOS_85_present = true;
  else
    gMacOS_85_present = false;

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

  SetPort(windowPtr);
  TextFace(bold);
  RGBBackColor(&backColour);
  RGBForeColor(&foreColour);

  // ........................................ set up menu bar and menus, then show window
  
  doGetMenus();
  ShowWindow(windowPtr);
  EraseRect(&windowPtr->portRect);

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

  gDone = false;

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

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);

  InitCursor();  
  FlushEvents(everyEvent,0);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doGetMenus

void  doGetMenus(void)
{
  Handle      menubarHdl;
  MenuHandle  menuHdl;
  SInt16      a, numberOfItems, fontNumber;
  Str255      fontName;
  CIconHandle cicnHdl;
  
  // .............................................................. get and draw menu bar  

  menubarHdl = GetNewMBar(128);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  // .................................................................. set up Apple menu

  menuHdl = GetMenuHandle(mApple);
  if(menuHdl != NULL)
    AppendResMenu(menuHdl,'DRVR');
  else
    ExitToShell();

  // .................................................. set up Font menu and make WYSIWYG

  menuHdl = GetMenuHandle(mFont);
  if(menuHdl != NULL)
  {
    AppendResMenu(menuHdl,'FONT');

    numberOfItems = CountMenuItems(menuHdl);
    for(a=1;a<=numberOfItems;a++)
    {
      GetMenuItemText(menuHdl,a,fontName);
      GetFNum(fontName,&fontNumber);
      SetMenuItemFontID(menuHdl,a,fontNumber);
    }
  }    
  else
    ExitToShell();

  // ........... programmatically set the extended modifiers in Style (Programmatic) menu
    
  menuHdl = GetMenuHandle(mStyle_prog);
  SetMenuItemModifiers(menuHdl,iOutline,kMenuShiftModifier + kMenuOptionModifier
                       + kMenuControlModifier);
  SetMenuItemModifiers(menuHdl,iShadow,kMenuShiftModifier + kMenuOptionModifier);

  //Źinsert submenu into menu list and programmatically attach it to Special menu, item 2 

  menuHdl = GetMenu(mSubmenu);
  if(menuHdl != NULL)
  {
    InsertMenu(menuHdl,hierMenu);
    menuHdl = GetMenuHandle(mSpecial);
    SetMenuItemHierarchicalID(menuHdl,iSecond,mSubmenu);
  }
  else
    ExitToShell();

  // . programmatically set command IDs for second Style, Size, Special menus and submenu

  menuHdl = GetMenuHandle(mStyle_prog);
  SetMenuItemCommandID(menuHdl,iPlain,      idPlain_prog);
  SetMenuItemCommandID(menuHdl,iBold,        idBold_prog);
  SetMenuItemCommandID(menuHdl,iItalic,      idItalic_prog);
  SetMenuItemCommandID(menuHdl,iUnderline,  idUnderline_prog);
  SetMenuItemCommandID(menuHdl,iOutline,    idOutline_prog);
  SetMenuItemCommandID(menuHdl,iShadow,      idShadow_prog);

  menuHdl = GetMenuHandle(mSize);
  SetMenuItemCommandID(menuHdl,iTen,        idTen);
  SetMenuItemCommandID(menuHdl,iTwelve,      idTwelve);
  SetMenuItemCommandID(menuHdl,iEighteen,    idEighteen);
  SetMenuItemCommandID(menuHdl,iTwentyFour,  idTwentyFour);

  menuHdl = GetMenuHandle(mSpecial);
  SetMenuItemCommandID(menuHdl,iFirst,      idFirst);

  menuHdl = GetMenuHandle(mSubmenu);
  SetMenuItemCommandID(menuHdl,iBat,        idBat);
  SetMenuItemCommandID(menuHdl,iBowl,        idBowl);
  
  // ..................... programmatically set the icon for the Bowl item in the submenu

  cicnHdl = GetCIcon(rColourIcon);
  SetMenuItemIconHandle(menuHdl,iBowl,kMenuColorIconType,(Handle) cicnHdl);

  // .. programmatically set Command-key equivalents to Size menu items and adjust glyphs

  menuHdl = GetMenuHandle(mSize);
  SetItemCmd(menuHdl,iTen,0x08);
  SetMenuItemKeyGlyph(menuHdl,iTen,0x17);
  SetItemCmd(menuHdl,iTwelve,0x7f);
  SetMenuItemKeyGlyph(menuHdl,iTwelve,0x0A);
  SetItemCmd(menuHdl,iEighteen,0x0b);
  SetItemCmd(menuHdl,iTwentyFour,0x0c);

  // ...... programmatically exclude the mark column and set the font in the Special menu

#if TARGET_CPU_PPC
  if(gMacOS_85_present)
  {
    menuHdl = GetMenuHandle(mSpecial);
    SetMenuExcludesMarkColumn(menuHdl,true);
    
    GetFNum("\pGadget",&fontNumber);
    if(fontNumber != 0)
      SetMenuFont(menuHdl,fontNumber,12);
    
  }  
#endif

  // .............................. set initial font, style, and size, and checkmark them

  doFontMenu(gCurrentFont);
  doCheckStyleMenuItem(mStyle_xmnu);
  doCheckStyleMenuItem(mStyle_prog);
  doCheckSizeMenuItem(mSize,iTen);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt8  charCode;

  switch(eventStrucPtr->what)
  {
    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        doAdjustMenus();
        doMenuChoice(MenuEvent(eventStrucPtr));
      }
      break;

    case updateEvt:
      BeginUpdate((WindowPtr)eventStrucPtr->message);
      EndUpdate((WindowPtr)eventStrucPtr->message);
      break;

    case osEvt:
      HiliteMenu(0);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    partCode;
  SInt32    menuChoice;

  partCode = FindWindow(eventStrucPtr->where,&windowPtr);
  
  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      menuChoice = MenuSelect(eventStrucPtr->where);
      doMenuChoice(menuChoice);
      break;

    case inContent:
      if(windowPtr != FrontWindow())
        SelectWindow(windowPtr);
      break;

    case inDrag:
      DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
      break;

    case inGoAway:
      if(TrackGoAway(windowPtr,eventStrucPtr->where))
        gDone = true;
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus

void  doAdjustMenus(void)
{
  // Adjust menus here.
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  SInt16      menuID, menuItem;
  OSErr       osErr;
  UInt32      commandID;
  MenuHandle  menuHdl;
      
  menuID   = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;
  
  if(menuID == mApple)
    doAppleMenu(menuItem);
  else if(menuID == mFont)
    doFontMenu(menuItem);
  else
  {
    osErr = GetMenuItemCommandID(GetMenuHandle(menuID),menuItem,&commandID);
    if(osErr || commandID != 0)
    {
      switch(commandID)
      {
        // .................................................................... File menu

        case 'quit':
          gDone = true;
          break;
      
        // .................................................................... Edit menu

        case 'undo':
          drawItemString("\pUndo");
          break;

        case 'cut ':
          drawItemString("\pCut");
          break;

        case 'copy':
          drawItemString("\pCopy");
          break;

        case 'past':
          drawItemString("\pPaste");
          break;

        case 'clea':
          drawItemString("\pClear");
          break;

        // ................................. Style ('xmnu') and Style (Programmatic) menu

        case 'plax':
        case 'plap':
          gCurrentStyle = 0;
          doCheckStyleMenuItem(menuID);
          break;

        case 'bolx':
        case 'bolp':
          if(gCurrentStyle & bold)
            gCurrentStyle -= bold;
          else
            gCurrentStyle |= bold;
          doCheckStyleMenuItem(menuID);
          break;

        case 'itax':
        case 'itap':
          if(gCurrentStyle & italic)
            gCurrentStyle -= italic;
          else
          gCurrentStyle |= italic;
          doCheckStyleMenuItem(menuID);
          break;

        case 'undx':
        case 'undp':
          if(gCurrentStyle & underline)
            gCurrentStyle -= underline;
          else
            gCurrentStyle |= underline;
          doCheckStyleMenuItem(menuID);
          break;

        case 'outx':
        case 'outp':
          if(gCurrentStyle & outline)
            gCurrentStyle -= outline;
          else
            gCurrentStyle |= outline;
          doCheckStyleMenuItem(menuID);
          break;

        case 'shax':
        case 'shap':
          if(gCurrentStyle & shadow)
            gCurrentStyle -= shadow;
          else
            gCurrentStyle |= shadow;
          doCheckStyleMenuItem(menuID);
          break;

        // .................................................................... Size menu

        case 'ten ':
          TextSize(10);
          doCheckSizeMenuItem(menuID,menuItem);
          break;

        case 'twel':
          TextSize(12);
          doCheckSizeMenuItem(menuID,menuItem);
          break;

        case 'eigh':
          TextSize(18);
          doCheckSizeMenuItem(menuID,menuItem);
          break;

        case 'twen':
          TextSize(24);
          doCheckSizeMenuItem(menuID,menuItem);
          break;
        
        // ................................................................. Special menu
  
        case 'firs':
          drawItemString("\pFirst Item");
          break;

        // ...................................................................... submenu

        case 'bat ':
          menuHdl = GetMenuHandle(mSubmenu);
          DisableItem(menuHdl,iBat);
          EnableItem(menuHdl,iBowl);
          drawItemString("\pBat");
          break;

        case 'bowl':
          menuHdl = GetMenuHandle(mSubmenu);
          DisableItem(menuHdl,iBowl);
          EnableItem(menuHdl,iBat);
          drawItemString("\pBowl");
          break;
      }
    }
  }

  HiliteMenu(0);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAppleMenu

void  doAppleMenu(SInt16 menuItem)
{
  Str255  itemName;
  SInt16  daDriverRefNum;
  
  if(menuItem == iAbout)
    drawItemString("\pAbout Menus2.");
  else
  {
    GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
    daDriverRefNum = OpenDeskAcc(itemName);
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFontMenu

void  doFontMenu(SInt16 menuItem)
{
  MenuHandle  fontMenuHdl;
  Str255      fontName;
  SInt16      fontNumber;
  
  fontMenuHdl = GetMenuHandle(mFont);
  
  CheckMenuItem(fontMenuHdl,gCurrentFont,false);
  CheckMenuItem(fontMenuHdl,menuItem,true);

  gCurrentFont = menuItem;  
      
  GetMenuItemText(fontMenuHdl,menuItem,fontName);
  GetFNum(fontName,&fontNumber);
  TextFont(fontNumber);

  drawItemString(fontName);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCheckStyleMenuItem

void  doCheckStyleMenuItem(SInt16 menuID)
{
  MenuHandle  styleMenuHdl;

  styleMenuHdl = GetMenuHandle(menuID);

  CheckMenuItem(styleMenuHdl,iPlain,    gCurrentStyle == 0);
  CheckMenuItem(styleMenuHdl,iBold,      gCurrentStyle & bold);
  CheckMenuItem(styleMenuHdl,iItalic,    gCurrentStyle & italic);
  CheckMenuItem(styleMenuHdl,iUnderline,gCurrentStyle & underline);
  CheckMenuItem(styleMenuHdl,iOutline,  gCurrentStyle & outline);
  CheckMenuItem(styleMenuHdl,iShadow,    gCurrentStyle & shadow);
  
  TextFace(gCurrentStyle);

  drawItemString("\pStyle change");
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCheckSizeMenuItem

void  doCheckSizeMenuItem(SInt16 menuID,SInt16 menuItem)
{  
  MenuHandle  sizeMenuHdl;  

  sizeMenuHdl = GetMenuHandle(menuID);

  CheckMenuItem(sizeMenuHdl,gCurrentSize,false);
  CheckMenuItem(sizeMenuHdl,menuItem,true);
  
  gCurrentSize = menuItem;
  
  drawItemString("\pSize change");
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× drawItemString

void  drawItemString(Str255 eventString)
{
  RgnHandle tempRegion;
  WindowPtr windowPtr;
  Rect      scrollBox;
  
  windowPtr = FrontWindow();
  tempRegion = NewRgn();

  scrollBox = windowPtr->portRect;
    
  ScrollRect(&scrollBox,0,-30,tempRegion);
  DisposeRgn(tempRegion);
  
  MoveTo(8,286);
  DrawString(eventString);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

Demonstration Program Comments

Menus1

When this program is run, the user should make menu selections from all menus, including
the Apple menu and the Help 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.

#define

Constants are established for the pull-down and hierarchical menu IDs and resources, menu
item numbers and subitem numbers.  The last line establishes a constant for the resource
ID of the 'WIND' resource.

Global Variables

The global variable gDone relates to the main event loop.  When set to true, the loop
will exit and the program will terminate.  The remaining three global variables will hold
the current choices, in terms of item numbers, from the Font, Style and Size menus.

main

The main() function initialises the system software managers, creates a window and makes
its graphics port the current port, calls the application-defined function which sets up
the menus, shows the window and enters 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 record 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 and DrawMenuBar draws the menu bar.

The next block adds the contents of the Apple Menu Items folder to the Apple menu.  The
use of 'DRVR' as the second parameter to the AppendResMenu call is automatically
interpreted to mean that the Apple menu is being created, so that all items in the Apple
Menu Items folder are added rather than resources of type 'DRVR'.

The third block adds the names of all resident fonts to the Font menu.  Using 'FONT' in
the second parameter in the call to AppendResMenu causes all such resources to be
searched out and their names added to the specified menu.

The fourth block inserts the application's single submenu 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
record 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 next block appends a menu item with the name "Menus Help" to the Help menu.

The last three lines cause checkmarks to be set against the appropriate font, style and
size menu items according to the initialised values of the associated global
variables.

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.

In the case of key-down and auto-key events, the character code is first extracted from
the event record's message field.  A check is then made of the modifiers field 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.

The call to HiliteMenu at the osEvt case unhighlights the Apple menu title when the user
brings the demonstration program to the foreground, having previously sent it to the
background by choosing an Apple Menu Items folder item from the Apple menu.

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.

The inDrag case responds to a mouse-down in the drag bar.

The inGoAway case responds to a mouse-down in the go-away box, setting gDone to true and
thus terminating the program if the cursor is still within the go-away box when the mouse
button is released.

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 taken in this simple program because only one window, whose content never
changes, is ever open.

(Later demonstration programs contain examples of menu adjustment functions which cater
for specific circumstances.  For example, the menu adjustment function in the
demonstration program at Chapter 8 - Dialogs and Alerts accommodates the situation where
the front window could be either a document window or a modeless dialog box.)

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).
 
Within the switch on the menu ID, the appropriate application-defined individual menu
handling function are called.  Note the handling of the hierarchical menu (case
mSubMenu).  Note also that, at the last case, the kHMHelpMenuID constant (-16490) is
returned in the high word if the user chooses an appended item from the Help menu.

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

doAppleMenu

doAppleMenu takes the short integer representing the menu item.  If this value represents
the first item in the Apple menu (the inserted "About..." item), text representing this
item is drawn in the scrolling display.

If the value passed to the doAppleMenu function represents other items in the Apple menu,
the call to GetMenuItemText gets the string representing the item's name.  This string
(which excludes metacharacters) is used as the parameter in the OpenDeskAcc call. 
OpenDeskAcc opens the chosen object and passes control that object.

doFileMenu

doFileMenu handles choices from the File menu.  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 handle to the Font menu structure required by the following
CheckMenuItem calls.  The CheckMenuItem calls uncheck the current font menu item and
check the menu item passed to the doFontMenu function.  This latter menu item number is
then assigned to the gCurrentFont global variable.

The call to GetMenuItemText extracts the string representing the item's name.  This
string is passed as the first parameter in the call to GetFNum, which gets the font
number associated with the name.  This number is then used in the call to TextFont, which
will cause subsequent text drawing to be conducted in the specified font.  The last line
draws the name of the font in that font.

doStyleMenu

doStyleMenu switches according to the menu item chosen in the Style menu.  Within the
switch, 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 the appropriate bit settings of gCurrentStyle attended to, a handle to the Style
menu record is then obtained.  This is required for the six CheckMenuItem, which check or
uncheck the individual menu items according to whether the third argument 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.

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 selected 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 subitem in the hierarchical menu represented
by the second menu item in the Special menu.

doHelpMenu

doHelpMenu handles the choice of the "Menus Help" item added by this program to the
system-managed Help Menu.  This code reflects the fact that Apple reserves the right to
add items to the Help menu in future versions of the system software.

HMGetHelpMenuHandle gets a handle to the Help menu record.  The call to CountMenuItems
returns the number of items in the Help menu.  Since we know that we have added one item
to this menu, the next line will establish the original number of help items.  If the
value passed to the doHelpMenu function is greater than this number, it must therefore
represent the item number of our "Menus Help" item, in which case some text is drawn in
the window to register the fact.

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.

Menus2

This demonstration program includes a demonstration of Apple Help, including
the methodology used to create an item in the Help menu.  The Apple Guide file titled
"Menus  Guide", which will cause a "Menus Help" item to be created in the Help menu, 
should be retained in the same folder as the Menus2 application.  The folder titled 
"Menus Help" should be moved to the Help folder in the System Folder.  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 the Menus2 programs as such.  
Rather, it provides a brief description of how to provide user assistance for your 
application using Apple Help.

Note that Apple Help is only available on Mac OS 8.6 and later.
When this program is run, the user should choose Show Balloons from the Help menu and
make menu selections from all menus, including the Apple menu and the Help menu. 
Selections should be made using the mouse and, where appropriate, the keyboard
equivalents.  The user should also note:

*   That, if the program is being run under Mac OS 8.0 or 8.1, the appearance of the
    menu bar and menus remains the same regardless of whether system-wide appearance
    is selected on or off in the Mac OS 8.0 and 8.1 Appearance control panel.

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

*   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.)

*   That the Font menu is WYSIWYG.

*   That, if the program is compiled and run under Mac OS 8.5, 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).*   That the items in the 
    submenu attached to the second item in the Special menu 
    have colour icons.

*   That, if the program is being run under Mac OS 8.0 or 8.1, there is an anomaly in
    the way the new MDEF draws Style menus.  In the Style ('xmnu') menu, in which the
    extended modifier keys for the last two menu items are assigned via the 'xmnu'
    resource, the item text is severely truncated and an ellipsis is added.  In the
    Style (Programmatic) menu, in which the extended modifier keys are assigned
    programmatically, this truncation of the item text does not occur.  (This problem
    was fixed in Mac OS 8.5.)

*   The balloon help provided for all menus and menu items.

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

#define

The #defines now establish constants for command IDs for menu items.  Command IDs are of
type UInt32.  To enhance source code readability, these are defined in the
four-character-code format, which packs four one-byte characters together in a 32-bit
value.

main

The call to RegisterAppearanceClient means that the new theme-compliant menu
bar
definition function (resource ID 63) will be used regardless of whether system-wide
Appearance is selected on or off in the Mac OS 8.0 and 8.1  Appearance control panel.

Next, the function Gestalt is used to determine whether Mac OS 8.5 or later is present.
If so, the global variable gMacOS_85_present is set to true.  (In the function 
doGetMenus, this global variable will determine whether two functions introduced with
Mac OS 8.5 get called.)

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 structure 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 and
DrawMenuBar draws the menu bar.

The next block adds the contents of the Apple Menu Items folder to the Apple menu.  The
use of 'DRVR' as the second parameter to the AppendResMenu call is automatically
interpreted to mean that the Apple menu is being created, so that all items in the Apple
Menu Items folder are added rather than resources of type 'DRVR'.

The next block adds the names of all resident fonts to the Font menu and makes the menu
WYSIWYG.  The call to AppendResMenu causes all 'FONT' resources to be searched out and
their names added to the specified menu.  The process of making the menu WYSIWYG then
begins.  The call to CountMenuItems returns the number of items in the menu.  Then, for
each of these items, GetMenuItemText gets the text (the font's name), GetFNum gets the
font number associated with the font name, and SetMenuItemFontID sets the font for the
menu item.

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 structure 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 GetMenuHandle gets the
handle 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 this application's items in the system-managed menus
(Apple and Help), nor is it possible to assign command IDs to the items in the Font
menu.)

The following small 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 second 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 in the case of the two delete keys, otherwise the
correct glyphs will not be displayed.  The calls to SetItemCmd assign the specified key
to the menu item.  In the case of the first two calls, a substitute glyph is assigned via
calls to SetMenuItemGlyph.  If this is not done, the glyphs displayed will not be visual
representations of the delete keys.  (These substitute glyphs could also have been
specified in the keyboard glyph fields for these items in the menu's 'xmnu' resource.)

The next block is applicable only to the PowerPC target, and only executes if Mac OS 8.5
or later is present.  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).

The block beginning with the call to HMGetHelpMenuHandle appends a menu item with the
name "Menus Help" to the Help menu.

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

doMenuChoice

doMenuChoice takes the long integer returned by the MenuSelect and MenuEvent calls,
extracts the menu ID, the menu item number, and the command ID (if any) and switches
according to the menu ID (if no Command ID is present) or the command ID (if present).

Prior to the switch, the menu ID and the menu item number are extracted from the long
integer.  An immediate return is made 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 the Apple, Font, or Help menus, the relevant
application-defined functions are called to further handle the menu item choice. 
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 program switches according to the command ID.

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 for checkmarking the Style menu items and changing the current style, and
for checkmarking the Size menu items and storing the current size, has been divided
between this function and two further-handling functions (doCheckStyleMenuItem and
doCheckSizeMenuItem).

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

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

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasnā€™t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, donā€™t remind me I could currently buy him this month Iā€™m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly ā€œborrowedā€ many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »

Price Scanner via MacPrices.net

13-inch M2 MacBook Airs in stock today at App...
Apple has 13ā€³ M2 MacBook Airs available for only $849 today in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Appleā€™s one-year warranty is included,... Read more
New today at Apple: Series 9 Watches availabl...
Apple is now offering Certified Refurbished Apple Watch Series 9 models on their online store for up to $80 off MSRP, starting at $339. Each Watch includes Appleā€™s standard one-year warranty, a new... Read more
The latest Apple iPhone deals from wireless c...
Weā€™ve updated our iPhone Price Tracker with the latest carrier deals on Appleā€™s iPhone 15 family of smartphones as well as previous models including the iPhone 14, 13, 12, 11, and SE. Use our price... Read more
Boost Mobile will sell you an iPhone 11 for $...
Boost Mobile, an MVNO using AT&T and T-Mobileā€™s networks, is offering an iPhone 11 for $149.99 when purchased with their $40 Unlimited service plan (12GB of premium data). No trade-in is required... Read more
Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobileā€™s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13ā€³ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Appleā€™s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16ā€³ and 14ā€³ MacBook Pros along with 13ā€³ and 15ā€³ MacBook... Read more
Every model of Appleā€™s 13-inch M3 MacBook Air...
Best Buy has Apple 13ā€³ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13ā€³ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9ā€³ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more

Jobs Board

DMR Technician - *Apple* /iOS Systems - Haml...
ā€¦relevant point-of-need technology self-help aids are available as appropriate. ** Apple Systems Administration** **:** Develops solutions for supporting, deploying, Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.