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

Fresh From the Land Down Under – The Tou...
After a two week hiatus, we are back with another episode of The TouchArcade Show. Eli is fresh off his trip to Australia, which according to him is very similar to America but more upside down. Also kangaroos all over. Other topics this week... | Read more »
TouchArcade Game of the Week: ‘Dungeon T...
I’m a little conflicted on this week’s pick. Pretty much everyone knows the legend of Dungeon Raid, the match-3 RPG hybrid that took the world by storm way back in 2011. Everyone at the time was obsessed with it, but for whatever reason the... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for July 19th, 2024. In today’s article, we finish up the week with the unusual appearance of a review. I’ve spent my time with Hot Lap Racing, and I’m ready to give my verdict. After... | Read more »
Draknek Interview: Alan Hazelden on Thin...
Ever since I played my first release from Draknek & Friends years ago, I knew I wanted to sit down with Alan Hazelden and chat about the team, puzzle games, and much more. | Read more »
The Latest ‘Marvel Snap’ OTA Update Buff...
I don’t know about all of you, my fellow Marvel Snap (Free) players, but these days when I see a balance update I find myself clenching my… teeth and bracing for the impact to my decks. They’ve been pretty spicy of late, after all. How will the... | Read more »
‘Honkai Star Rail’ Version 2.4 “Finest D...
HoYoverse just announced the Honkai Star Rail (Free) version 2.4 “Finest Duel Under the Pristine Blue" update alongside a surprising collaboration. Honkai Star Rail 2.4 follows the 2.3 “Farewell, Penacony" update. Read about that here. | Read more »
‘Vampire Survivors+’ on Apple Arcade Wil...
Earlier this month, Apple revealed that poncle’s excellent Vampire Survivors+ () would be heading to Apple Arcade as a new App Store Great. I reached out to poncle to check in on the DLC for Vampire Survivors+ because only the first two DLCs were... | Read more »
Homerun Clash 2: Legends Derby opens for...
Since launching in 2018, Homerun Clash has performed admirably for HAEGIN, racking up 12 million players all eager to prove they could be the next baseball champions. Well, the title will soon be up for grabs again, as Homerun Clash 2: Legends... | Read more »
‘Neverness to Everness’ Is a Free To Pla...
Perfect World Games and Hotta Studio (Tower of Fantasy) announced a new free to play open world RPG in the form of Neverness to Everness a few days ago (via Gematsu). Neverness to Everness has an urban setting, and the two reveal trailers for it... | Read more »
Meditative Puzzler ‘Ouros’ Coming to iOS...
Ouros is a mediative puzzle game from developer Michael Kamm that launched on PC just a couple of months back, and today it has been revealed that the title is now heading to iOS and Android devices next month. Which is good news I say because this... | Read more »

Price Scanner via MacPrices.net

Amazon is still selling 16-inch MacBook Pros...
Prime Day in July is over, but Amazon is still selling 16-inch Apple MacBook Pros for $500-$600 off MSRP. Shipping is free. These are the lowest prices available this weekend for new 16″ Apple... Read more
Walmart continues to sell clearance 13-inch M...
Walmart continues to offer clearance, but new, Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBooks... Read more
Apple is offering steep discounts, up to $600...
Apple has standard-configuration 16″ M3 Max MacBook Pros available, Certified Refurbished, starting at $2969 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free,... Read more
Save up to $480 with these 14-inch M3 Pro/M3...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
Amazon has clearance 9th-generation WiFi iPad...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Apple is offering a $50 discount on 2nd-gener...
Apple has Certified Refurbished White and Midnight HomePods available for $249, Certified Refurbished. That’s $50 off MSRP and the lowest price currently available for a full-size Apple HomePod today... Read more
The latest MacBook Pro sale at Amazon: 16-inc...
Amazon is offering instant discounts on 16″ M3 Pro and 16″ M3 Max MacBook Pros ranging up to $400 off MSRP as part of their early July 4th sale. Shipping is free. These are the lowest prices... Read more
14-inch M3 Pro MacBook Pros with 36GB of RAM...
B&H Photo has 14″ M3 Pro MacBook Pros with 36GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 Pro MacBook Pro (... Read more
14-inch M3 MacBook Pros with 16GB of RAM on s...
B&H Photo has 14″ M3 MacBook Pros with 16GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $150-$200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 MacBook Pro (... Read more
Amazon is offering $170-$200 discounts on new...
Amazon is offering a $170-$200 discount on every configuration and color of Apple’s M3-powered 15″ MacBook Airs. Prices start at $1129 for models with 8GB of RAM and 256GB of storage: – 15″ M3... Read more

Jobs Board

*Apple* Systems Engineer - Chenega Corporati...
…LLC,** a **Chenega Professional Services** ' company, is looking for a ** Apple Systems Engineer** to support the Information Technology Operations and Maintenance Read more
Solutions Engineer - *Apple* - SHI (United...
**Job Summary** An Apple Solution Engineer's primary role is tosupport SHI customers in their efforts to select, deploy, and manage Apple operating systems and Read more
*Apple* / Mac Administrator - JAMF Pro - Ame...
Amentum is seeking an ** Apple / Mac Administrator - JAMF Pro** to provide support with the Apple Ecosystem to include hardware and software to join our team and 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.