[comp.sources.mac] Hier Menu Demo Source

tedj@hpcilzb.HP.COM (Ted Johnson) (10/21/88)

[Hier Menu Demo Source]

This program demonstrates how to use hierarchical menus.  It also
demonstrates how to handle DA's, how to make your own "About..." box
(with an icon), and how to use dialog boxes.  It was written in LSC,
and includes the source code, resource file, and stripped project
file.

The use of this source code is FREE, provided it is for non-profit
purposes.  I hope it can save someone some time!

However the name "T Bear Software" and the T Bear icon are both
Copyright (C) 1988 by Ted C. Johnson, and may NOT be used without my
express written permission.

-Ted Johnson
 President, T Bear Software

[Moderator's Note:  The binary for this program has been posted to 
 comp.binaries.mac.]

---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#
#	Hier_Menu_Demo.c
#	Hier_Menu_Demo.r
#
# This archive created: Thu Oct 20 11:39:07 1988
# By:	Roger L. Long (bytebug@dhw68k.cts.com)
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Hier_Menu_Demo.c'" '(14524 characters)'
if test -f 'Hier_Menu_Demo.c'
then
	echo shar: will not over-write existing file "'Hier_Menu_Demo.c'"
else
sed 's/^X//' << \SHAR_EOF > 'Hier_Menu_Demo.c'
X/*
X*Program name: Hier Menu Demo
X*
X*Author:  Ted C. Johnson, Sun, Aug 14 1988.
X*
X*Compilation instructions:  use Lightspeed C, v.2.15.  This program DOES
X*							use a resource file.  I developed this program
X*							on a Mac SE HD20 running System/Finder 4.1/5.5.
X*
X*Summary:  This program demonstrates how to use hierarchical menus.  It 
X*		   also demonstrates how to handle DA's, how to make your own
X*		   "AboutI" box (with an icon), and how to use dialog boxes.
X*
X*		   The use of this source code is free, provided it is for 
X*		   non-profit purposes.  I hope it can save someone some time!
X*
X*		   However the name "T Bear Software" and the T Bear icon are 
X*		   both CopyRight ) 1988 by Ted C. Johnson, and may NOT be used 
X*		   without my express written permission.
X*/
X
X
X
X#include <QuickDraw.h>
X#include <WindowMgr.h>
X#include <EventMgr.h>
X#include <MenuMgr.h>
X#include <DialogMgr.h>
X#include <FontMgr.h>
X#include <DeskMgr.h>
X#include <MacTypes.h>
X#include <TextEdit.h>
X
X
X
X#define int32		long
X#define	int16		int
X#define int8		char
X
X#define NIL			0L
X
X
X
X/*Define the ID for our DLOG and DITL resource.*/
X
X#define DIALOG_MESSAGE 777
X
X
X/*
X*Define our menu IDs.  My unusual spacing is meant to give you a
X*picture of how the sub-menus relate to their parent menu.
X*/
X
X#define APPLE_ID		10
X
X#define	FILE_ID			20
X
X#define FONT_N_DA_ID	30
X#define		FONT_ID			31 /*Fonts.*/
X#define		DA_ID			32 /*DA's.*/
X
X#define	MACINTOSH_ID	40 /*128K, 512K, 512KE, Plus, SE, II*/
X#define		SE_ID			41 /*2 diskette, SE HD20*/
X
X#define NICE_CAR_ID		100	/*German, Italian, Japanese*/
X#define		GERMAN_ID		110 /*Porsche, Mercedes, BMW*/
X#define			PORSCHE_ID		111 /*911, 914, 924, 928, 930, 935, 944, 959*/
X#define			MERCEDES_ID		112 /*300, 450*/
X#define			BMW_ID			113 /*318, 320, 325, 528, 533, 633, 733*/
X#define		ITALIAN_ID		120 /*Lamborghini, Ferrari, Lotus*/
X#define		JAPANESE_ID		130 /*Honda Prelude, Acura Legend, Mazda RX-7*/
X
X
X
X/*Define our global variables.*/
X
XMenuHandle		Apple_MH;
XMenuHandle		File_MH;
XMenuHandle 		FontAndDA_MH;
XMenuHandle			Font_MH;
XMenuHandle			DA_MH;
XMenuHandle		Macintosh_MH;
XMenuHandle			SE_MH;
XMenuHandle		NiceCar_MH;
XMenuHandle			German_MH;
XMenuHandle				Porsche_MH;
XMenuHandle				Mercedes_MH;
XMenuHandle				BMW_MH;
XMenuHandle			Italian_MH;
XMenuHandle			Japanese_MH;
X
X
XEventRecord	theEvent;
XWindowPtr	theWindow, whichWindow;
Xint16		windowCode;
Xint8		theCharacter;
X
X
X
Xmain()
X{
X	InitGraf(&thePort);
X	InitFonts();
X	InitWindows();
X	InitMenus();
X	TEInit();
X	InitDialogs(0L);
X	InitCursor();
X	FlushEvents(everyEvent, 0);
X	
X	InitializeOurMenus();
X	
X	
X	do {
X	
X		EventLoop();
X		
X	} while (TRUE);
X}
X
X
X
XEventLoop()
X{
X	/*
X	*Give the DA some time.
X	*/
X	
X	SystemTask();
X	
X	/*
X	*The event loop.
X	*
X	*GetNextEvent() will return FALSE if the event is an event that the
X	*Desk Manager wants to handle itself (i.e., Desk Accessory events).
X	*Refer to I.M. I-258.
X	*/
X		
X	if (GetNextEvent(everyEvent, &theEvent) == TRUE) {
X		switch(theEvent.what) {
X				
X			case keyDown:                       /*Was a key pressed?*/
X				theCharacter = theEvent.message & charCodeMask;
X				if (theEvent.modifiers & cmdKey) { /*Check for a menu*/
X					doMenu(MenuKey(theCharacter)); /*equivalent.*/
X					HiliteMenu(0);
X				}
X				break;
X			
X			case mouseDown:
X				windowCode = FindWindow(theEvent.where, &whichWindow);
X				switch(windowCode) {
X					
X					case inMenuBar:
X					
X						/*
X						*There was a mouseDown in the menu bar.
X						*/
X						 
X						doMenu(MenuSelect(theEvent.where));
X						break;
X							
X					case inSysWindow:
X					
X						/*
X						*SystemClick() calls the Desk Manager to handle
X						*mouse_down events which occur in a desk accessory
X						*window (e.g., like in the Control Panel's window).
X						*/
X						
X						SystemClick(&theEvent, whichWindow);
X						break;
X				}
X						
X			default:
X				break;
X			}/*switch(theEvent.what)*/
X		}/*if*/
X}
X
X
X
XInitializeOurMenus()
X{
X	Apple_MH = NewMenu(APPLE_ID, "\p\024");/*Desk Accessory menu.*/
X	AppendMenu(Apple_MH, "\p^1 Software presentsI;(-");
X	AddResMenu(Apple_MH, 'DRVR');
X	InsertMenu(Apple_MH, 0);
X
X	File_MH = NewMenu(FILE_ID, "\pFile");  /*File menu.*/
X	AppendMenu(File_MH, "\pQuit/Q");
X	InsertMenu(File_MH, 0);
X	
X	
X	/*
X	*Set up our first hierarchical menu:  Fonts and DAs.
X	*
X	*Note that we can insert menus even before we define their
X	*sub-menus!!!  Octal 033 is hex 1B, which is the <ESC>
X	*character.  Octal 024 is the Apple symbol. 
X	*/
X	
X	FontAndDA_MH = NewMenu(FONT_N_DA_ID, "\pFonts and DAs");
X	AppendMenu(FontAndDA_MH, "\pFonts/\033;\024/\033");
X	InsertMenu(FontAndDA_MH, 0);
X
X		Font_MH = NewMenu(FONT_ID, "\pFonts (this title is invisible)");
X		AddResMenu(Font_MH, 'FONT');
X		InsertMenu(Font_MH, -1);
X		SetItemMark(FontAndDA_MH, 1, FONT_ID);/*Insert the Font menu beside
X											   *the 1st FontAndDA menu item.
X											   */
X
X
X
X		DA_MH = NewMenu(DA_ID, "\p\024 (this title is invisible)");/*Desk Accessory menu.*/
X		AddResMenu(DA_MH, 'DRVR');
X		InsertMenu(DA_MH, -1);
X		SetItemMark(FontAndDA_MH, 2, DA_ID);/*Insert the DA menu beside the
X											 *the 2nd FontAndDA menu item.
X											 */
X
X
X
X	/*
X	*Set up our second hierarchical menu:  Nice cars.
X	*
X	*Note that we can insert menus even before we define their
X	*sub-menus!!!
X	*/
X	
X	NiceCar_MH = NewMenu(NICE_CAR_ID, "\pNice cars");
X	AppendMenu(NiceCar_MH, "\pGerman/\033;Italian/\033;Japanese/\033");
X	InsertMenu(NiceCar_MH, 0);
X
X	
X		/*Set up and insert the German sub-menu.*/
X		
X		German_MH = NewMenu(GERMAN_ID, "\pthis title is invisible");
X		AppendMenu(German_MH, "\pPorsche/\033;Mercedes/\033;BMW/\033");
X		InsertMenu(German_MH, -1);
X		SetItemMark(NiceCar_MH, 1, GERMAN_ID);/*Insert the German menu 
X											   *beside the 1st NiceCars
X											   *menu item.
X											   */
X			
X			
X			/*Set up and insert the Porsche sub-sub-menu.*/
X			
X			Porsche_MH = NewMenu(PORSCHE_ID, "\pthis title is invisible");
X			AppendMenu(Porsche_MH, "\p911;914;924;928;930;935;944;959");
X			InsertMenu(Porsche_MH, -1);
X			SetItemMark(German_MH, 1, PORSCHE_ID);/*Insert the Porsche menu
X												   *beside the 1st German
X												   *menu item.
X												   */
X	
X	
X			/*Set up and insert the Mercedes sub-sub-menu.*/
X			
X			Mercedes_MH = NewMenu(MERCEDES_ID, "\pthis title is invisible");
X			AppendMenu(Mercedes_MH, "\p300;450");
X			InsertMenu(Mercedes_MH, -1);			
X			SetItemMark(German_MH, 2, MERCEDES_ID);/*Insert the Mercedes
X													*menu beside the 2nd
X													*German menu item.
X													*/
X			
X			
X			/*Set up and insert the BMW sub-sub-menu.*/
X			
X			BMW_MH = NewMenu(BMW_ID, "\pthis title is invisible");
X			AppendMenu(BMW_MH, "\p318;320;325;528;633;733");
X			InsertMenu(BMW_MH, -1);			
X			SetItemMark(German_MH, 3, BMW_ID);		/*Insert the BMW menu
X													 *beside the 3rd German
X													 *menu item.
X													 */
X	
X
X		/*Set up and insert the Italian sub-menu.*/
X		
X		Italian_MH = NewMenu(ITALIAN_ID, "\pthis title is invisible");
X		AppendMenu(Italian_MH, "\pLamborghini;Ferrari;Lotus");
X		InsertMenu(Italian_MH, -1);		
X		SetItemMark(NiceCar_MH, 2, ITALIAN_ID);/*Insert the Italian menu
X												*beside the 2nd NiceCar
X												*menu item.
X												*/
X		
X		
X		/*Set up and insert the Japanese sub-menu.*/
X		
X		Japanese_MH = NewMenu(JAPANESE_ID, "\pthis title is invisible");
X		AppendMenu(Japanese_MH, "\pHonda Prelude;Acura Legend;Mazda RX-7");
X		InsertMenu(Japanese_MH, -1);		
X		SetItemMark(NiceCar_MH, 3, JAPANESE_ID);/*Insert the Japanese menu
X												 *beside the 3rd NiceCar
X												 *menu item.
X												 */
X		
X		
X		
X	/*
X	*Set up our third hierarchical menu:  Macintoshes.
X	*
X	*Note that we can insert menus even before we define their
X	*sub-menus!!!
X	*/
X	
X	Macintosh_MH = NewMenu(MACINTOSH_ID, "\pMacintoshes");
X	AppendMenu(Macintosh_MH, "\p128K;512K;512KE;Plus;SE/\033;II");
X	InsertMenu(Macintosh_MH, 0);
X	
X		/*Set up and insert the SE sub-menu.*/
X		SE_MH = NewMenu(SE_ID, "\pthis title is invisible");
X		AppendMenu(SE_MH, "\pHD 20;2 diskette");
X		InsertMenu(SE_MH, -1);	
X		SetItemMark(Macintosh_MH, 5, SE_ID);/*Insert the SE menu beside the
X											 *5th Macintosh menu item.
X											 */
X
X
X	DrawMenuBar();
X}
X	
X
X
X/*
X*This is the subroutine which handles all of the menu commands.
X*/
X
XdoMenu(menuResult)
Xint32 menuResult;
X{
XGrafPtr theCurrentPort;
XStr255 theDAsName, menuItemText;
Xint16 menuID, itemNumber;
X
X	menuID = HiWord(menuResult);
X	itemNumber = LoWord(menuResult);
X	
X	switch(menuID) {
X	
X		case APPLE_ID:
X			if (itemNumber == 1) {
X				ShowAboutWindow();
X			}
X			else {
X			
X				/*
X				*Save the current grafPort, in case the DA doesn't
X				*restore it to the previous value.
X				*/
X				
X				GetPort(&theCurrentPort);
X				
X				GetItem(Apple_MH, itemNumber, &theDAsName);
X				OpenDeskAcc(&theDAsName);
X				
X				SetPort(theCurrentPort);
X			}
X			break;
X			
X		case FILE_ID:  /*The "File" menu.*/
X			switch(itemNumber) {
X				case 1:  
X					ExitToShell();
X					break;
X					
X				default:
X					break;
X			}/*switch(itemNumber)*/
X			
X			break;
X		
X		/*Handle the sub-menus for the "Font and DAs" hierarchical menu.*/
X		case FONT_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(Font_MH,  itemNumber, menuItemText); 
X					message("\pYou selected the ", menuItemText, 
X					        "\p font.");
X					break;
X			}
X			break;
X			
X		case DA_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(DA_MH,  itemNumber, menuItemText);
X					message("\pYou selected the \"", menuItemText, 
X						    "\p\" DA.");
X						
X					break;
X			}
X			break;
X			
X		/*Handle the sub-menus for the "Nice cars" hierarchical menu.*/
X		case PORSCHE_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(Porsche_MH,  itemNumber, menuItemText);
X					message("\pYou selected the ",
X							 menuItemText, 
X							 "\p Porsche.");
X					break;
X			}
X			break;
X			
X		case MERCEDES_ID:
X			switch(itemNumber) {
X				default: 
X					GetItem(Mercedes_MH,  itemNumber, menuItemText);
X					message("\pYou selected the ",
X							 menuItemText, 
X							 "\p Mercedes.");
X					break;
X			}
X			break;
X			
X		case BMW_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(BMW_MH,  itemNumber, menuItemText);
X					message("\pYou selected the ",
X							 menuItemText, 
X							 "\p BMW.");
X					break;
X			}
X			break;
X			
X		case ITALIAN_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(Italian_MH, itemNumber, menuItemText);
X					message("\pYou selected the ",
X							menuItemText, "\p.");
X					break;
X			}
X			break;
X			
X		case JAPANESE_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(Japanese_MH, itemNumber, menuItemText);
X					message("\pYou selected the ",
X							menuItemText, "\p.");
X					break;
X			}
X			break;
X			
X		/*Handle the Macintosh menu, and sub-menu.*/
X		case MACINTOSH_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(Macintosh_MH, itemNumber, menuItemText);
X					message("\pYou selected the Mac ",
X							menuItemText, "\p.");
X					break;
X			}
X			break;
X	
X		case SE_ID:
X			switch(itemNumber) {
X				default:
X					GetItem(SE_MH, itemNumber, menuItemText);
X					message("\pYou selected the Mac SE ",
X							menuItemText, "\p.");
X					break;
X			}
X			break;
X		
X		default:
X			break;
X		}/*switch(menuID)*/
X	
X	HiliteMenu(0);/*Don't forget to un-hilite the menu bar after 
X					you're done performing that menu item command.*/
X}
X		
X		
X		
X/*
X*ShowAboutWindow() puts up a window when the user selects the "About DAI" 
X*command from the apple menu.  To exit this window and return to the 
X*program, the user has to click the mouse button.		
X*/
X
XShowAboutWindow()
X{
XEventRecord	theEvent;
XGrafPtr 	DA_AboutBox_Port;
XWindowPtr	AboutWindow;
XRect		AboutRect, RectForOneLineOfText;
Xint8		*line1, *line2, *line3, *line4, *line5;
X
X	line1 = "Hier Menu Demo,";
X	line2 = "a tutorial program";
X	line3 = "by Ted C. Johnson";
X	line4 = "President of T Bear Software*";
X	line5 = "Copyright ) 1988 by Ted C. Johnson";
X	
X	GetPort(&DA_AboutBox_Port); /*Preserve the DA_About_Box port.*/
X	
X	SetRect(&AboutRect, 75, 110, 425, 230);/*Window size and position.*/
X	
X	SetRect(&RectForOneLineOfText, 5, 10, 345, 25);/*Box for first line of text.*/
X	
X	AboutWindow = NewWindow((WindowPeek)NIL, &AboutRect, "\p", TRUE,
X							altDBoxProc, (WindowPtr)-1, TRUE, 0);
X	SetPort(AboutWindow);
X	
X	/*
X	*Choose the system font (Chicago), 12 point size.
X	*/
X	
X	TextSize(12);
X
X
X	TextFont(systemFont);
X	
X	/*
X	*Draw the text.  Offset the RectForOneLineOfText box 20 pixels down and
X	*and 0 pixels the right, for each line of text.  Use different styles 
X	*of text for each line, just for the heck of it.  See I.M, page I-171.	   		 
X	*/
X	
X	TextFace(shadow);
X	TextBox(line1, strlen(line1), &RectForOneLineOfText, teJustCenter);
X	
X	OffsetRect(&RectForOneLineOfText, 0, 20);
X	TextFace(underline);
X	TextBox(line2, strlen(line2), &RectForOneLineOfText, teJustCenter);
X	
X	OffsetRect(&RectForOneLineOfText, 0, 20);
X	TextFace(italic);
X	TextBox(line3, strlen(line3), &RectForOneLineOfText, teJustCenter);
X		
X	OffsetRect(&RectForOneLineOfText, 0, 20);
X	TextFace(bold);
X	TextBox(line4, strlen(line4), &RectForOneLineOfText, teJustCenter);
X		
X	OffsetRect(&RectForOneLineOfText, 0, 20);
X	TextFace(0);
X	TextBox(line5, strlen(line5), &RectForOneLineOfText, teJustCenter);
X	
X	/*
X	*Wait for a mouse-down event.  When you get one, erase the About
X	*Window, and return to DA_AboutBox Demo window.  
X	*/
X	
X	do {
X	
X		GetNextEvent(everyEvent, &theEvent); 
X		
X	} while (theEvent.what != mouseDown);
X	
X	/*
X	*DisposeWindow() calls CloseWindow(), then releases the memory
X	*occupied by the window record.
X	*/
X	
X	DisposeWindow(AboutWindow);
X	
X	SetPort(DA_AboutBox_Port);
X}
X
X
X
X/*
X*showDialog() puts up a modal dialog box and returns the
X*number corresponding to the button pushed.		
X*/
X
Xint16 showDialog(dialogNumber, maxbutton)
Xint16 dialogNumber;
Xint16 maxbutton;
X{
XDialogPtr dialog;			/* pointer to the dialog */
XDialogRecord dialogRecord;	/* actual dialog record */
Xint16 itemHit = maxbutton + 1;
X
X	/* bring up the dialog box */
X	dialog = GetNewDialog(dialogNumber, &dialogRecord, (WindowPtr) -1);
X	ShowWindow(dialog);
X
X	while (itemHit > maxbutton)
X	{
X		ModalDialog((ProcPtr) NIL, &itemHit);
X	}
X	
X	CloseDialog(dialog); 
X	
X	return(itemHit);
X}
X
X
X
Xmessage(string1, string2, string3)
Xint8 *string1, *string2, *string3;		/* expect pascal string */
X{
X	ParamText(string1, string2, string3, "\p");
X	showDialog(DIALOG_MESSAGE, 1);
X}
X
X
X
XmessageWithInt(string, theInt)
Xint8 *string;		/* expect pascal string */
Xint16 theInt;
X{
XStr255 tempString;
X	
X	NumToString(theInt, &tempString);
X	ParamText(string, tempString, "\p", "\p");
X	showDialog(DIALOG_MESSAGE, 1);
X}
X
X
Xstrlen(s)
Xregister int8 *s;
X{
Xint8 *s0 = s;
X
X	while(*s++);
X	return(s - s0 -1);
X}
SHAR_EOF
echo shar: 6 control characters may be missing from "'Hier_Menu_Demo.c'"
if test 14524 -ne "`wc -c < 'Hier_Menu_Demo.c'`"
then
	echo shar: error transmitting "'Hier_Menu_Demo.c'" '(should have been 14524 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Hier_Menu_Demo.r'" '(852 characters)'
if test -f 'Hier_Menu_Demo.r'
then
	echo shar: will not over-write existing file "'Hier_Menu_Demo.r'"
else
sed 's/^X//' << \SHAR_EOF > 'Hier_Menu_Demo.r'
Xresource  'ICON' (257)
X{
X    0x1cff 0x3800 0x2300 0xc41f 
X    0x2000 0x0404 0x2800 0x1404 
X    0x2800 0x1404 0x3000 0x0c04 
X    0x0866 0x1000 0x0866 0x1000 
X    0x1000 0x081e 0x1000 0x0811 
X    0x103c 0x081e 0x1018 0x0811 
X    0x0891 0x101e 0x387e 0x1c00 
X    0x4400 0x221f 0x83ff 0xc210 
X    0x8001 0xc21c 0x9f82 0x2210 
X    0x9044 0x221f 0x903f 0xc200 
X    0x9000 0x0404 0x4f80 0x080a 
X    0x2070 0x340e 0x5f8f 0xc411 
X    0x4000 0x0411 0x4000 0x0400 
X    0x4000 0x041e 0x4000 0x0411 
X    0x3e00 0xf81f 0x4101 0x0414 
X    0x55ff 0x5412 0x7f01 0xfc11 
X};
X
Xresource  'DLOG' (777 , "message")
X{
X    {46, 92, 190, 394},
X    1,
X    visible,
X    goAway,
X    0x0,
X    777,
X    "this is my dialog"
X};
X
Xresource  'DITL' (777)
X{
X  {
X    {101, 120, 134, 187},
X      Button {enabled, "OK"};
X    {15, 24, 86, 295},
X      StaticText {disabled, "^0^1^2^3"}
X  }
X};
X
SHAR_EOF
if test 852 -ne "`wc -c < 'Hier_Menu_Demo.r'`"
then
	echo shar: error transmitting "'Hier_Menu_Demo.r'" '(should have been 852 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
---