[comp.sources.mac] SimpleTools2 Source

erik@hpsadla.HP (Erik Kilk) (06/06/87)

References:


[SimpleTools2 Source]

SimpleTools is a set of C functions which greatly simplify the use of the
Macintosh Toolbox.  For example, to have one of your C functions execute
when the user selects the menu File/Quit AND install the menu, the call
would be:  menu ("File", "Quit", my_quit_function).  This sort of thing
is done for menus, windows, dialogs, text-edit, and the standard file
package with lots of little aids.

Included in this new $20 shareware distribution are:
	SimpleTools2.c		SimpleDemo.c		TinyDemo.c
	SimpleTools Doc		SimpleDemo		TinyDemo
	simple.h		SimpleDemo.project	TinyDemo.project

The code is currently maintained for the LightSpeed compiler with compile
time flags for Megamax.  It shouldn't be difficult to port to other
compilers.  The files are packed using PackIt, then textified using
BinHex, then divided into three parts for mailing.  You have to put all
the BinHex jibberish back into one large file before un-BinHexing.

[Moderator's Note:  The full distribution is being made in comp.binaries.mac.
This posting and the one that follows contains the source code for study by
interested folks without a Macintosh.]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	SimpleTools2.c
#	simple.h
sed 's/^X//' << 'SHAR_EOF' > SimpleTools2.c
X
X
X/*
X	Title	: SimpleTools2.c
X	Author	: Erik Kilk  Copyright 1985, 1987
X	Dates	: June 7, 1985, June 3, 1986, November 8, 1986
X		  November 28, 1986, April 17, 1987, April 21, 1987.
X
X	SimpleTools is a collection of routines to aid programming
X	simple "Macintosh looking" programs.  SimpleTools initializes
X	the toolbox, monitors & acts upon events, and provides generic
X	i/o routines for your application.  You initialize your program
X	by letting SimpleTools know what windows and menus you want along
X	with what functions SimpleTools should call when they are
X	selected.
X
X	The purpose of SimpleTools is to encourage you to program those
X	simple programs or to pilot larger programs which you may not
X	do due to the enormous effort required to use the Macintosh
X	toolbox.  My goal was to study Inside Macintosh once to
X	Create SimpleTools and then be able to forget most of the usages
X	of the Toolbox routines.  Instead of thumbing through hundreds of
X	pages of Inside Macintosh just to get something up and running,
X	one need only remember a dozen generic calls.
X
X	SimpleTools is very powerful, yet also very simple to use.  One
X	can get a program up and running with desk accessories, windows,
X	and menus in only a few minutes.  Advance features of SimpleTools
X	allow you to retrieve enough information from SimpleTools to call
X	any of the toolbox routines manually if need be.
X
X
X=========================================================================
X
X	You may use, study, copy, and freely distribute SimpleTools if:
X		1)  You mention "Programmed with the aid of SimpleTools
X		    (c) Erik Kilk 1986" in your About... window of all
X		    programs distributed free, share, or marketted.
X		2)  You register by sending $20 or more to:
X			Erik Kilk
X			4949 Snyder Lane, #247
X			Rohnert Park, CA  94928
X			(707) 794-2424 weekday afternoons
X		    to encourage me to maintain and improve SimpleTools.
X
X==>	For a diskette including the most recent version of SimpleTools,
X	several detailed examples of using SimpleTools, and a MacWrite file
X	describing SimpleTools and its use in more detail, send me a
X	diskette with enough stamps to mail it back to you.  Make sure you
X	have registered as stated above.
X
X	This is 128k, MFS, HFS, old ROM, new ROM, Mac+, & TMON compatible.
X	This file compiles and executes with Megamax 3.0 beta and
X	LightSpeed 2.1.  Adjust the definition in simple.h for your
X	compiler.  When porting to other compilers, pay particular
X	attention to where the Lightspeed and Megamax code is specified
X	since these places are the likely problem areas.
X
X	LIGHTSPEED NOTE:
X
X	Drag SimpleTools out of the main segment in your project window.
X	You do this by dragging it below the dotted horizontal Line in the
X	project window.
X
X	SimpleTools requires the MacTraps library and stringsasm.c or
X	strings.c.  If you load the unix library, your project will be
X	larger than needed (unless you need unix for your own program.)
X
X	MEGAMAX NOTE:
X
X	Use Megamax's convert utility to convert all Mac names to all
X	lower case.  If you send me suggestions and/or new code for
X	SimpleTools, please convert back to mixed case first.
X
X=========================================================================
X
X	SimpleTools provides the following functions for your application
X	to call.  Note that your application need not call any Toolbox
X	routines directly.  The entire C program (including the standard
X	desk accessory support):
X
X			main ()
X			{
X				simpletools ("Skel");
X				simplequits ();
X				runsimpletools ();
X			}
X
X	will execute as a Macintosh program, terminating upon the user
X	selecting Quit.  SimpleTools includes:
X
X		simpletools ()		- init Toolbox and SimpleTools
X		simplequits ()		- add Transfer & Quit menus
X		simpleevents ()		- process next Mac event
X		runsimpletools ()	- continuously process events
X
X		menu ("File","New",new) - install a menu
X		window ("My Window",..)	- install a window
X
X		run (function)		- install a periodic function
X		stop (function)		- remove a periodic function
X
X		havenewrom ()		- test for new 128k ROM
X		withwindow("My Window")	- set output to a window
X
X		stgotoxy (x, y)		- set pen to text position x, y
X		home ()			- clear window, set pen to home
X		getline (deflt, dest)	- with TE editing, get a Line
X		prompt (question, dest)	- with dialog box & TE, get a Line
X		message (string)	- with dialog box, print a string
X		getfile ("TEXT", name)	- with list, select a filename
X		putfile (orig, name)	- with list, select a filename
X
X
X	A complete Macintosh Style application (including windowing and
X	menus) is given in the following trivial example...
X
X		#include <simple.h>
X
X		char name[50];
X
X		got_beep()
X		{
X			SysBeep (10);
X		}
X
X		got_getname()
X		{
X			char newname[50];
X			*newname = 0;
X			if (prompt ("What is your name?", newname)) {
X				strcpy (name, newname);
X				withwindow ("My Window");
X				home();
X				update();
X			}
X		}
X
X		in_content(x, y)
X		int x, y;
X		{
X			MoveTo (x, y); LineTo (x, y);
X		}
X
X		update()
X		{
X			char outstring[100];
X			stgotoxy (1, 5);
X			sprintf (outstring,"Hello, %s", name);
X			#ifndef MEGAMAX
X			  CtoPstr (outstring);
X			#endif
X			DrawString (outstring);
X		}
X
X		main ()
X		{
X			simpletools ("Sample Program");
X			simplequits ();
X			menu ("Commands", "Beep", got_beep);
X			menu ("Commands", "Get Name", got_getname);
X			strcpy (name, "World");
X			window ("My Window",0,0,0,0,0L,0L,update,
X				in_content);
X			runsimpletools ();
X		}
X
X=========================================================================
X
X	ROUTINES YOUR APPLICATION MAY CALL:
X
X
X	simpleevents ()
X
X	To be called repeatedly by your program's main routine.  In
X	most SimpleTools programs, your main routine will initialize
X	and install SimpleTools followed by an loop such as:
X
X		for (;;) simpleevents();
X
X	This routine handles all window changes, menu requests, and
X	other Macintosh events.  There is also a routine called with
X	runsimpletools() which does not return.  It simply performs the
X	above loop.  Program exit is accomplished by assigning an
X	exiting routine to a menu, usually this is File/Quit.
X
X
X	simpletools (about_string)
X	char *about_string;
X
X	To be called once at the very beginning of your main routine.
X	This routine initializes all the Macintosh software managers
X	and installs the basic Apple, File, and Edit menus.  The
X	about_string is the name of the menu Item to appear first under
X	the Apple menu.
X
X
X	simplequits ()
X
X	Installs a simple File/Quit and File/Transfer menu.  You only
X	want to installs these if no application dependent processing
X	must be done when the user selects Quit or Transfer.
X
X
X	menu (name, Item, routine)
X	char 	*name;
X	char 	*Item;
X	ProcPtr	routine;
X
X	To be called when a new menu is to be installed on the menu bar
X	or when the characteristics of that menu are to be modified.
X	Name is the name of the menu to appear on the menu bar.  Item
X	is the name of the Item to appear under the menu name.  Routine
X	is the name of the routine to be executed when the stated menu/Item
X	has been selected.  The characteristics of the menu may be changed
X	by passing one of the constants itemdisable, itemenable, itemcheck,
X	or itemuncheck in place of the routine.
X
X
X	window (name, xtop, ytop, xbot, ybot, act, deact, update, content)
X	char 	*name;
X	int  	xtop, ytop;
X	int  	xbot, ybot;
X	ProcPtr	act, deact, update, content;
X
X	To be called when a new window is to be installed on the screen
X	or when the characteristics of that window are to be modified.
X	Name is the name of the window.  Xtop, ytop, xbot, and ybot are
X	the initial coordinates of the new window.  Act is the name of
X	the procedure to execute when the window becomes the top or
X	active window.  Deact is the name of the procedure to execute when
X	the window ceases being the top window and deactivates.  Update
X	is the name of the procedure called when the Macintosh needs to
X	redraw the window's contents.  Content is the name of the procedure
X	called when the mouse is pressed within the window.  The procedure
X	specified as content will be passed an x and y integer value
X	representing the local mouse coordinates.
X
X
X	withwindow (name)
X	char *name;
X
X	To be called when you want to select which window will receive
X	output and drawings.  In most cases, SimpleTools will select the
X	appropriate window before calling your specified act, deact,
X	update, or content procedures.  Use this at other times.
X
X
X	run (routine)
X	ProcPtr	routine;
X
X	To be called when you want a routine to be continuously executed
X	once each time simpleevents() is called.  Small, quickly running
X	routines should be used so as not to Delay the next event
X	processing.  Pseudo multiprocessing with each routine running in
X	its own window can be accomplished by making sure a run routine
X	uses withwindow() to direct its output to the proper window.
X
X
X	stop (routine)
X	ProcPtr routine;
X
X	To be called when you want to remove a previously run() routine
X	from the list of routines to run.  50 routines can fit into the
X	run list.
X
X
X	home ()
X
X	Clears the current window and positions the pen such that any
X	following text will appear in the upper left corner of the
X	window.
X
X
X	stgotoxy (column, row)
X	int column, row;
X
X	Positions the pen in the current window so that the next text
X	output will appear in text row and column.  This is compatible
X	with some old text only terminals.  stgotoxy (1, 1) positions the
X	pen in the upper left corner.  Any negative coordinate leaves
X	that axis of the pen where it currently is.
X
X
X	getline (default, destination)
X	char *default;
X	char *destination;
X
X	Calling this routine begins a "modal" mode where the user is
X	required to enter a Line of text.  This would be similar to
X	using scanf() on "non-Mac", text-only terminals.  This routine
X	uses the Macintoshes built in Text-Edit routines allowing the
X	user to edit his Line until <RETURN> is pressed.  The flashing
X	bar Cursor is positioned at the current pen location.  The
X	resulting string is placed into destination.  Default contains
X	the initial value to be displayed on the screen.  You may use
X	the null string "" for default.
X
X
X	prompt (question, answer)
X	char *question;
X	char *answer;
X
X	This routine places a small 3-lined Macintosh Style dialog window
X	prompting the user with question and getting the answer in a
X	boxed Text-Edit area.  Two buttons are displayed to terminate the
X	user entry.  If Cancel is clicked upon, FALSE is returned.  If
X	okay is clicked upon, TRUE is returned.  Answer must be set to
X	a default value, "" is okay.
X
X
X	message (message)
X	char *message;
X
X	This routine is similar to prompt except no textual response is
X	asked from the user.  This is like an Alert dialog.  Just like
X	prompt, TRUE or FALSE is returned depending upon which Button the
X	user presses.
X
X
X	getfile (file_type, reply)
X	char *file_type;
X	char *replay;
X
X	This routine places the standard Macintosh SFGetFile() window
X	up with a list of files of file_type.  Once the user selects a
X	file, the answer is returned in the string reply.  Also, and
X	very important for HFS, the working volume/folder is set so that
X	any subsequent open() with reply as the file name will open the
X	correct selected file.  The open() should be done before someone
X	has a chance to change the working volume.  This routine will
X	return FALSE if the user selects the CANCEL Button.
X
X
X	putfile (origname, reply)
X	char *origname;
X	char *reply;
X
X	This routine is like getfile, except the standard putfile window
X	is displayed with origname as the default name to save a file as.
X	The actual name selected by the user is returned in reply.  As
X	getfile, the working volume/folder is set properly for the next
X	open() call.
X
X=========================================================================
X
X	THE FOLLOWING IS THE FILE simple.h.  YOU SHOULD COPY THIS PORTION
X	INTO A NEW FILE NAMED simple.h SO YOU CAN #include IT INTO YOUR
X	SOURCE FILES.
X
X=========================================================================
X
X#define LIGHTSPEED	{define either LIGHTSPEED or MEGAMAX or your own}
X
X#include <stdio.h>
X
X#ifdef MEGAMAX
X  #include <menu.h>
X  #include <win.h>
X#endif
X
X#ifdef LIGHTSPEED
X  #include <MenuMgr.h>
X  #include <WindowMgr.h>
X#endif
X
X#define itemdisable	0L
X#define itemenable	1L
X#define itemcheck	2L
X#define itemuncheck	3L
X
Xextern char 		applestring[];
Xextern WindowPtr 	windowpoint();
Xextern MenuHandle 	mhand();
Xextern int 		windmenu;
Xextern int 		dogoaway;
Xextern int 		wprocid;
Xextern int		show_new_window;
Xextern int 		sizeredraw;
Xextern int		getlinecaps;
Xextern ProcPtr 		keydownproc;
Xextern ProcPtr 		autokeyproc;
Xextern void		home();
Xextern void		stnop();
X=========================================================================
X
X		Here begins SimpleTools.c
X		_________________________
X*/
X
X#include "simple.h"			/* define compiler in here	*/
X
X#ifdef MEGAMAX
X        overlay "simpletools"		/* compiler dependent		*/
X
X	#include <mem.h>
X	#include <qd.h>
X	#include <qdvars.h>
X	#include <misc.h>
X	#include <event.h>
X	#include <res.h>
X	#include <win.h>
X	#include <dialog.h>
X	#include <menu.h>
X	#include <string.h>
X	#include <stdio.h>
X	#include <pack.h>
X	#include <te.h>
X	#include <toolbox.h>
X
X	#define  ZZ	&
X#else
X	#include <MemoryMgr.h>
X	#include <Quickdraw.h>
X	#include <EventMgr.h>
X	#include <ResourceMgr.h>
X	#include <WindowMgr.h>
X	#include <TextEdit.h>
X	#include <DialogMgr.h>
X	#include <MenuMgr.h>
X	#include <strings.h>
X	#include <stdio.h>
X	#include <PackageMgr.h>
X	#include <ToolboxUtil.h>
X	#include <StdFilePkg.h>
X	#include <pascal.h>
X
X	#define  ZZ
X#endif
X
X#define TRUE (-1)		/* local definitions 			*/
X#define FALSE 0
X#define maxsruns 50		/* procedure table size			*/
X#define MESSN 30		/* array size for message dialog items	*/
X#define QUESN 40		/* array size for prompt dialog items	*/
X#define ROM85   0x28E		/* new rom stuff 			*/
X#define NEWROM  0x7FFF
X#define inzoomout 8
X#define inzoomin  7
X#define zoomproc  8
X
Xtypedef struct {			/* structure for an Item	*/
X	char		itemname[40];
X	int		itemno;		/* Item number within menu 	*/
X	int		menuId;		/* menu id			*/
X	MenuHandle	menuhand;	/* Item's menu's Handle 				*/
X	ProcPtr		menurun;	/* procedure to run 		*/
X	Ptr		next;		/* pointer to the next Item 	*/
X} itemdatum;
X
Xtypedef struct {			/* structure for a menu 	*/
X	char 		menuname[20];	/* to allow reference by name 	*/
X	int 		menuId;		/* menu id 			*/
X	MenuHandle	menuhand;	/* menu Handle to reference menu*/
X	itemdatum	**itemlist;	/* pointer to the list of items */
X	Ptr 		next;		/* pointer to the next menu 	*/
X} menudatum;
X
Xtypedef struct {			/* structure for a window 	*/
X	char		windname[80];	/* window's name and reference 	*/
X	WindowPtr	wptr;		/* window's pointer reference 	*/
X	ProcPtr	wact;			/* the activate procedure 	*/
X	ProcPtr	wdeact;			/* the deactivate procedure 	*/
X	ProcPtr	wupdate;		/* the update procedure 	*/
X	ProcPtr	wcontent;		/* the content procedure 	*/
X	Ptr		next;		/* pointer to the next window 	*/
X} winddatum;
X
X#ifdef LIGHTSPEED
X  pascal Boolean 	*TrackBox() = 0xA83B;
X  pascal void 		*ZoomWindow() = 0xA83A;
X#endif
X
XWindowPtr windowpoint();
X
X/* Local variables */
X
Xmenudatum 	**simplemenus;		/* Handle to menu data 		*/
Xchar 		accname[80];		/* desk accessory name to open 	*/
XRect 		dragrect, sizerect;	/* limits for moving windows 	*/
XRect 		swholescreen;
Xwinddatum	**simplewinds;		/* Handle to window data 	*/
Xint		firstwind;		/* if no windows have been made	*/
XProcPtr 	simpleruns[maxsruns];	/* list of procedures to run 	*/
XWindowPtr	debugw;			/* window pointer for debugging */
Xint		snewrom;
Xint		getlinecaps = FALSE;
X
X/************************************************************************/
X/* GLOBAL USER MODIFIABLE VARIABLES 					*/
X/* These are variables that you can declare extern so that you can use	*/
X/* them to change the SimpleTools defaults				*/
X/************************************************************************/
X
X/* wprocid = type of window to Create on next window() call		*/
X/* For LightSpeed C, use a lower case d and upper case P for 		*/
X/* 	DocumentProc.  Megamax conversion program does this wrong.	*/
X
Xint 		wprocid = documentProc;
X
X/* dogoaway = is the next created window to have a go-away box		*/
X
Xint 		dogoaway = TRUE;
X
X/* keydownproc = the procedure to be called when keyDown is detected	*/
X/* autokeyproc = the procedure to be called when autoKey is detected	*/
X/* BOTH OF THESE ARE PASSED THE EVENTRECORD SO THE KEY CAN BE FOUND	*/
X
XProcPtr 	keydownproc,
X  		autokeyproc; 
X
X/* applestring = a string containing the Apple for menu reference	*/
X
Xchar 		applestring[2]
X  		= {'\024', '\0'}; 
X
X/* windmenu = does the next window created get a choice under the
X              window menu (so a closed window can be brought back	*/
X          
Xint 		windmenu = TRUE;
X
X/* sizeredraw = is the window's content area erased and made
X                updateable upon being resized				*/
X            
Xint		sizeredraw = FALSE;
X
X/* show_new_window = does the created window get displayed right away
X		on the screen, if not, then it is hidden		*/
X
Xint		show_new_window = TRUE;
X
X
X/******************************************************************/
X/* Dialog lists.  These were calculated by using the new resource */
X/* editor to make a template for a dialog and then using fedit to */
X/* list the hex listing of the Item list for the dialog.	  */
X/******************************************************************/
X
Xint messd[MESSN] = {2,0,0,0x38,0xf1,0x4c,0x12d,0x402,0x4f4b,0,0,5,5,
X		0x36,0x12d,0x800,0,0,0x38,0xac,0x4c,0xe8,0x406,
X		0x4361,0x6e63,0x656c};
Xint quesd[QUESN] = {3,0,0,0x21,0xf0,0x35,0x12c,0x402,0x4f4b,0,0,8,8,
X		0x28,0xe8,0x800,0,0,0x2b,8,0x4b,0xe8,0x1000,0,0,
X		8,0xf0,0x1c,0x12c,0x406,0x4361,0x6e63,0x656c};
X
X
X/* Local procedure */
X
Xvoid stnop()				/* a no op procedure for defaults */
X{
X}
X
Xchar *ptoc(s)
Xchar *s;
X{
X	#ifndef MEGAMAX
X		return (PtoCstr(s));
X	#else
X		return (s);
X	#endif
X}
X
Xchar *ctop(s)
Xchar *s;
X{
X	#ifndef MEGAMAX
X		return (CtoPstr(s));
X	#else
X		return (s);
X	#endif
X}
X
X/* Given a menu name, find our data structure for it.  Return a Handle
X   to this structure.  This is a local procedure for SimpleTools use.
X*/
X
X/* local procedure */
X
Xmenudatum **getourmenuhandle (name)
Xchar *name;				/* name of menu bar menu */
X{
X	menudatum **here, **temp;	/* hand to menu structure*/
X	here = simplemenus;
X
X	/* find the menu name or the end of out menu list */
X	HLock (here);
X	while (strcmp(name,(**here).menuname) && (**here).next )  {
X		temp = here;
X		here = (menudatum **)(**here).next;
X		HUnlock (temp);
X		HLock (here);
X	}
X
X	/* see if we found it or just the end of the list */
X	if (!strcmp(name,(**here).menuname)) {
X		HUnlock (here);
X		return (here);
X	} else {
X		HUnlock (here);
X		return ((menudatum **)0L);
X	}
X}
X
X/* This takes a Handle to our personal Item record and either a
X   procedure name or a modifier code.  If it got a procedure name,
X   it sets it to the Item's procedure to run when the Item is chosen.
X   If it got a modifier code, it changes the state of the menu's Item
X   to checked, unchecked, enabled, or disabled.  It especially keeps
X   track of the standard Edit menu items so we can restore them after
X   a desk accessory is finished.
X*/
X
X/* Local procedure */
X
Xsetitems ( items, routine)	/* set a menu Item's routine or display */
Xitemdatum	**items;	/* if items is neg, then whole menu 	*/
XProcPtr	routine;
X{
X	int			inumber;
X	MenuHandle		mhand;
X
X	/* check to see if a procedure pointer was given to us */
X	if ( (((long)items)>0L) && (routine > (ProcPtr)0x1000L)) {
X						/* good procedure value */
X		(**items).menurun = routine;
X		return;
X	}
X
X	/* Calculate which Item number we are going to modify */
X	if ( (long)items < 0L) {		/* the whole menu 	*/
X		mhand = (MenuHandle) (0L - (long)items);
X		inumber = 0;
X	} else {				/* just one Item 	*/
X		mhand = (**items).menuhand;
X		inumber = (**items).itemno;
X	}
X
X	/* If a NULL procedure pointer, then set to a no_op routine */
X	if ( (inumber > 0) && ((**items).menurun == (ProcPtr)0L) )
X		(**items).menurun = (ProcPtr) stnop;
X
X	/* Now change the state of a menu Item */
X	switch ((int)routine) {
X		case itemdisable:
X			DisableItem(mhand,inumber); break;
X		case itemenable:
X			EnableItem(mhand, inumber); break;
X		case itemcheck:
X			CheckItem(mhand, inumber, TRUE); break;
X		case itemuncheck:
X			CheckItem(mhand, inumber, FALSE); break;
X	}
X	if (inumber == 0) DrawMenuBar();  /* if main menu was changed 	*/
X
X}
X
X/* This routine is called by the simpletools() initial routine.  It gets
X   the pointer list of menus started, loads the desk accessories into
X   the Apple menu, and loads up some standard menu entries.  The reason
X   menu File has a New entry, and none others, is because as this code
X   currently stands, a menu must have at least one Item.  And since we
X   want File before Edit, I had to make an entry.  The most commonly used
X   Item under File is Quit.  But we like quit to be at the end of the list.
X   So, since New is usually always first when it is used, that the one
X   chosen to start File.
X*/
X
X/* Local procedure */
X
Xinitsmenus(about)			/* init simpletools' menus */
Xchar *about;
X{
X	itemdatum **items;
X
X	simplemenus = (menudatum **) NewHandle ( (long)sizeof(menudatum));
X	HLock (simplemenus);
X
X	strcpy ( (**simplemenus).menuname, applestring);
X	(**simplemenus).menuId = 1;
X	(**simplemenus).next = (Ptr) 0L;
X	ctop ((**simplemenus).menuname);
X	(**simplemenus).menuhand = NewMenu (1, (**simplemenus).menuname);
X	ptoc ((**simplemenus).menuname);
X	HUnlock ((**simplemenus).menuhand);
X
X	(**simplemenus).itemlist = (itemdatum **)NewHandle (
X			(long)sizeof(itemdatum));
X	items = (itemdatum **) (**simplemenus).itemlist;
X	HLock (items);
X
X	strcpy ((**items).itemname, about);
X	(**items).itemno = 1;
X	(**items).menuId = 1;
X	(**items).menuhand = (**simplemenus).menuhand;
X	(**items).menurun = (ProcPtr) stnop;
X	(**items).next = 0L;
X	HUnlock (items);
X
X	ctop (about);
X	AppendMenu ((**simplemenus).menuhand, about);
X	ptoc (about);
X	DisableItem ((**simplemenus).menuhand, 1);
X	menu (applestring, "-", (ProcPtr) itemdisable);
X	#ifdef MEGAMAX
X	  AddResMenu ((**simplemenus).menuhand, "DRVR");
X	#else
X	  AddResMenu ((**simplemenus).menuhand, 'DRVR');
X	#endif
X	InsertMenu ((**simplemenus).menuhand, 0);
X	HUnlock (simplemenus);
X
X	menu ("File", "New", (ProcPtr)itemdisable);
X	menu ("Edit", "Undo", stnop);
X	menu ("Edit", "-", (ProcPtr)itemdisable);
X	menu ("Edit", "Cut/X", stnop);
X	menu ("Edit", "Copy/C", stnop);
X	menu ("Edit", "Paste/V", stnop);
X	menu ("Edit", "Clear", stnop);
X}
X
X/* Local procedure */
X
X#ifndef LIGHTSPEED
Xgottrans ()
X{
X  char prog[80];
X  char *argv[3];
X  if ( getfile("APPL", prog) ) {
X    argv[1] = NULL;
X    execv (prog, argv);
X  }
X}
X#endif
X
X/* Local procedure */
X
Xgotquit ()
X{
X  ExitToShell();
X}
X
X/* This routine is for the Windows menu Item.  The Windows menu is
X   set up when new windows are added.  It is used to bring forward and
X   bring into view windows that may be under other windows or have been
X   sent hiding by a click on their close box.
X*/
X
X/* Local procedure */
X
Xshowawindow(name)			/* show the named window	*/
Xchar *name;
X{
X	WindowPtr foo;
X	foo = windowpoint(name);	/* get its window pointer	*/
X	if ( foo ) {
X		ShowWindow(foo);	/* show it on the screen	*/
X		SetPort (foo);		/* set further output to it */
X		if ( foo != FrontWindow())	/* if it isn't active,	*/
X			SelectWindow (foo);	/* activate it 		*/
X	}
X}
X
X/* Local procedure */
X
Xwinddatum **wdatum(windpt)		/* return Handle to window data */
XWindowPtr windpt;
X{
X	winddatum **wind, **temp;
X
X	if (firstwind) return ((winddatum **) 0L);
X	wind = simplewinds;
X	HLock (wind);
X
X	while ( ((**wind).wptr != windpt) && (**wind).next) {
X		temp = wind;
X		wind = (winddatum **) (**wind).next;
X		HUnlock (temp);
X		HLock (wind);
X	}
X
X	if ( (**wind).wptr == windpt) {
X		HUnlock (wind);
X		return (wind);
X	} else {
X		HUnlock (wind);
X		return ((winddatum **) 0L);	/* zero if not found */
X	}
X}
X
X/* Local procedure */
X
Xrunruns(event)			/* run all the installed run procedures	*/
XEventRecord *event;		/* returns number of routines run 	*/
X{
X	int i=0;
X	WindowPtr saveport;
X	GetPort (&saveport);
X	while ( simpleruns[i] )
X		(*(simpleruns[i++])) (event);
X	SetPort (saveport);
X	return(i);
X}
X
X/* Local procedure */
X
Xstdialog( question, answer, type)  /* a general dialog displayer 	*/
Xchar *question;
Xchar *answer;
Xint  type;			/* type:  1=prompt, 2=message 		*/
X{
X	DialogPtr dialog;	/* dialog reference 			*/
X	Handle Item, items;	/* handles for the dialog items 	*/
X	Rect screen, box;	/* rectangles for dialog/items 		*/
X	int dtype, hit, canc;	/* Item type and which was hit 		*/
X	char tempanswer[255];	/* address where answer is 		*/
X
X	items = NewHandle (512L);/* get memory for items list 		*/
X	HLock (items);		/* lock it down 			*/
X	if (type == 1)
X		BlockMove (quesd, *items, (long) QUESN * 2L);
X	else
X		BlockMove (messd, *items, (long) MESSN * 2L);
X	SetRect (&screen, 103, 50, 409, 137);
X
X	/* For LIGHTSPEED, use a lower case d and upper case B and P	*/
X	/* for DBoxProc.  Megamax conversion utility does this wrong.	*/
X
X	dialog = NewDialog (0L, &screen, "", 0, dBoxProc, -1L, 0, 0L, items);
X	GetDItem (dialog, 2, &dtype, &Item, &box);
X	ctop (question);
X	SetIText (Item, question);		/* set Item#2 text 	*/
X	ptoc (question);
X	if (type == 1) {			/* set default answer	*/
X		GetDItem (dialog, 3, &dtype, &Item, &box);
X		ctop (answer);
X		SetIText (Item, answer);
X		ptoc (answer);
X		canc = 4;
X	} else
X		canc = 3;
X	ShowWindow (dialog);			/* display the dialog	*/
X	do {
X		ModalDialog (0L, &hit);		/* process the dialog	*/
X	} while ( (hit != 1) & (hit != canc) );
X	if (type == 1) {
X		GetDItem (dialog, 3, &dtype, &Item, &box);
X		HLock (Item);
X		GetIText (Item, tempanswer);	/* get Item#3 text 	*/
X		ptoc (tempanswer);
X		strcpy (answer, tempanswer);	/* make a copy of it 	*/
X		HUnlock (Item);
X	}
X	HUnlock(items);				/* unlock items memory	*/
X	HPurge(items);				/* purge it 		*/
X	DisposDialog (dialog);			/* get rid of dialog	*/
X	return ( hit==1 );			/* return true if ok	*/
X}
X
X/* Local procedures */
X
Xdocommand (which, thisevent)
Xlong which;
XEventRecord *thisevent;
X{
X	int themenu, theitem;
X	long size;
X	char *cpoint;
X	GrafPtr tempport;
X	menudatum **here, **temp;
X	itemdatum **items, **tempitems;
X	char **myreshandle;
X	Handle myhandle;
X
X	themenu = HiWord (which);
X	theitem = LoWord (which);
X	if ((themenu == 1) && (theitem != 1)) {
X
X		/* start up a desk accessory */
X		HLock (simplemenus);
X		GetItem ((**simplemenus).menuhand, theitem, accname);
X		SetResLoad (FALSE);
X		#ifdef MEGAMAX
X		  myreshandle = GetNamedResource ("DRVR", accname);
X		#else
X		  myreshandle = GetNamedResource ('DRVR', accname);
X		#endif
X		SetResLoad (TRUE);
X		size = SizeResource (myreshandle);
X		myhandle = NewHandle ( size + 3072L);
X		if (myhandle == 0L)
X			message ("Not enough memory to do that.");
X		else {
X			DisposHandle (myhandle);
X			GetPort (&tempport);
X			OpenDeskAcc(accname);
X			SetPort (tempport);
X		}
X		HUnlock (simplemenus);
X		return;
X	}
X	if (themenu ==3) {
X		/* do any system edits */
X		if (SystemEdit(theitem -1))  return;
X	}
X
X	/* now we run an installed menu procedure */
X	here = simplemenus;
X	HLock (here);
X
X	/* find out menu structure given the menu id */
X	while ( ((**here).menuId != themenu) && (**here).next) {
X		temp = here;
X		here = (menudatum **)(**here).next;
X		HUnlock (temp);
X		HLock (here);
X	}
X
X	if ((**here).menuId == themenu) {
X
X		/* now find the Item structure */
X		items = (**here).itemlist;
X		HUnlock (here);
X		HLock (items);
X
X		while ( ((**items).itemno != theitem) && (**items).next) {
X			tempitems = items;
X			items = (itemdatum **)(**items).next;
X			HUnlock (tempitems);
X			HLock (items);
X		}
X
X		/* prepare to give the Item name to the procedure */
X		cpoint = (**items).itemname;
X		if ((**items).itemno == theitem)
X		/* if we found the Item, call its procedure */
X			(*((**items).menurun))(cpoint,thisevent) ;
X		HUnlock (items);
X	}
X}
X
X/* Local procedure */
X
Xdomousedown(thisevent)		/* respond to mouse down events */
XEventRecord *thisevent;		/* passed the event record */
X{
X	WindowPtr whichwindow;
X	int code, x, y;
X	char *cpoint;
X	menudatum **omhand;
X	winddatum **thewdatum;
X	long newplace;
X	Point temp;
X	GrafPtr saveport;
X
X	code = FindWindow(ZZ(thisevent->where), &whichwindow);
X	switch (code) {
X	    case inMenuBar:
X		docommand(MenuSelect(ZZ(thisevent->where)),thisevent);
X		break;
X	    case inSysWindow:
X		SystemClick(thisevent, whichwindow); break;
X	    case inDrag:
X		DragWindow(whichwindow, ZZ(thisevent->where),
X			&dragrect); break;
X	    case inGrow:
X		newplace= GrowWindow(whichwindow, ZZ(thisevent->where),
X			&sizerect);
X		SizeWindow(whichwindow, LoWord(newplace),
X		HiWord(newplace), TRUE);
X		if (sizeredraw) {
X			GetPort (&saveport);
X			SetPort (whichwindow);
X			EraseRect (&swholescreen);
X			InvalRect (&swholescreen);
X			SetPort (saveport);
X		}
X		break;
X	    case inGoAway:
X		if ( TrackGoAway(whichwindow, ZZ(thisevent->where))) {
X			HideWindow (whichwindow);
X		}
X		break;
X	    case inzoomout:
X	    case inzoomin:
X	        #ifdef MEGAMAX
X		  if ( trackbox(whichwindow, ZZ(thisevent->where), code)) {
X			zoomwindow (whichwindow, code, 0);
X		#else
X		  if ( TrackBox(whichwindow, ZZ(thisevent->where), code)) {
X			ZoomWindow (whichwindow, code, 0);
X		#endif
X			GetPort (&saveport);
X			SetPort (whichwindow);
X			EraseRect (&swholescreen);
X			InvalRect (&swholescreen);
X			SetPort (saveport);
X		}
X		break;
X	    case inContent:
X
X		/* make the window active if it isn't yet */
X		if (whichwindow != FrontWindow()) {
X			SelectWindow(whichwindow);
X		}
X
X		/* find our window data */
X		thewdatum = wdatum (whichwindow);
X		if (thewdatum) {
X
X			/* convert the Point of click to the window's
X			   own coordinates since this will be always
X			   more useful than the global coordintates */
X			temp = thisevent->where;
X			SetPort (whichwindow);
X			GlobalToLocal (&temp);
X			#ifdef MEGAMAX
X			  x = temp.a.h;
X			  y = temp.a.v;
X			#else
X			  x = temp.h;
X			  y = temp.v;
X			#endif
X
X			/* call the window's in content routine */
X			HLock (thewdatum);
X			(*((**thewdatum).wcontent))(x, y, whichwindow,
X				thisevent);
X			HUnlock (thewdatum);
X		}
X		break;
X	}
X}
X
X
X/************************************************************************/
X/* 	GLOBAL ROUTINES INTENDED TO BE USER CALLABLE PROCEDURES		*/
X/* THE FOLLOWING PROCEDURES HAVE BEEN WRITTEN FOR THE USER'S 		*/
X/* APPLICATION TO CALL.    						*/
X/* 									*/
X/************************************************************************/
X
Xhavenewrom ()			/* returns true if new roms installed	*/
X{
X	return ((*((int *)ROM85)) == NEWROM);
X}
X
X/* Menu is usually called like:
X
X		menu ("File", "Print...", got_print)
X
X   where the first argument is the name appearing on the menubar.  The
X   2nd argument is the name appearing when the menu is pulled down.  The
X   3rd argument is USUALLY the routine to be called when the user
X   selects this particular menu.  Non-existant menus are created following
X   the last.  The menu ordering may never be changed once created.
X   Existint menus have their "routine-to-be-executed" assignment changed
X   to the new routine.  If the long values 0L, 1L, 2L, or 3L are passed
X   instead of a procedure, the menu characteristic is set as specified
X   by the constants itemdisable, itemenable, itemcheck, itemuncheck.  For
X   example:
X   		menu ("File", "Print...", itemdisable)
X
X   PROCEDURES ASSIGNED TO MENUS ARE CALLED WITH TWO ARGUMENTS.  YOU
X   DO NOT NEED TO DECLARE THESE IN YOUR PROCEDURE IF YOU DO NOT USE
X   THEM.  FOR EXAMPLE, GOT_PRINT MAY BE DECLARED AS:
X
X   		got_print()
X		char *itemname;
X		EventRecord *current_event;
X		{
X			...
X		}
X
X   Itemname is a char* pointing to the Item name.  This allows the same
X   menu procedure to be used for multiple menu/Item pairs.  Maybe your
X   Size menu just as items 9 Point, 10 Point, 12 Point, etc.  This way
X   you can specify the same procedure for each and determine what to do
X   by looking at itemname.
X
X   Current_event is a pointer to the current EventRecord that detected
X   the menu selection.  You may look at this as needed.
X*/
X
Xmenu (name, Item, routine)		/* install or change a menu	*/
Xchar *name;				/* the menu name 		*/
Xchar *Item;				/* the Item name 		*/
XProcPtr routine;			/* a procedure or modifier 	*/
X{
X	menudatum **here,**temp;	/* a roving Handle to our data 	*/
X	menudatum **ourmhandle;		/* another Handle to our data 	*/
X	itemdatum **items,**tempitems;	/* a Handle to the Item 	*/
X	int lastid, lastitem;
X
X	/* get the Handle to menu named 'name' */
X	if ((ourmhandle = getourmenuhandle (name)) == 0L) {
X
X		/* make a new menu entry by finding the end of the list */
X		here = simplemenus;
X		HLock (here);
X		while ((**here).next) {
X			temp = here;
X			here = (menudatum **)(**here).next;
X			HUnlock (temp);
X			HLock (here);
X		}
X
X		/* make a structure for our new entry */
X		lastid = (**here).menuId;
X		(**here).next = (Ptr)NewHandle ( (long)sizeof(menudatum));
X		temp = here;
X		here = (menudatum **)(**here).next;
X		HUnlock (temp);
X		HLock (here);
X
X		strcpy ( (**here).menuname, name);
X		(**here).menuId = ++lastid;
X		(**here).next = (Ptr) 0L;
X
X		/* make a new Item structure */
X		(**here).itemlist = (itemdatum **)NewHandle (
X			(long)sizeof(itemdatum));
X
X		/* make a new menu entry for the Macintosh */
X		ctop (name);
X		(**here).menuhand = NewMenu (lastid, name);
X		ptoc (name);
X		items = (**here).itemlist;
X
X		HLock (items);
X		strcpy ((**items).itemname, Item);
X		(**items).itemno = 1;
X		(**items).menuId = lastid;
X		(**items).menuhand = (**here).menuhand;
X		(**items).menurun = (ProcPtr) 0L;
X		(**items).next = 0L;
X		HUnlock (items);
X
X		/* install and display the menu */
X		ctop (Item);
X		AppendMenu ((**here).menuhand, Item);
X		ptoc (Item);
X		InsertMenu ((**here).menuhand,0);
X		HUnlock (here);
X
X		setitems (items, routine);
X		DrawMenuBar();
X		return(TRUE);
X	}
X	else {
X		HLock (ourmhandle);
X
X		if (strlen(Item) == 0) {
X		  /* then adjust main menu */
X		  setitems( 0L - (long) ((**ourmhandle).menuhand), routine);
X		  return(FALSE);
X		}
X
X		/* see if Item is in list */
X		items = (**ourmhandle).itemlist;
X		HLock (items);
X
X		while ( strcmp(Item,(**items).itemname) && (**items).next) {
X			tempitems = items;
X			items = (itemdatum **)(**items).next;
X			HUnlock (tempitems);
X			HLock (items);
X		}
X		if (strcmp(Item,(**items).itemname) ==0) {
X			setitems( items, routine);
X			return(FALSE);
X		}
X		else {
X			/* make new Item entry */
X			lastitem = (**items).itemno;
X			(**items).next =(Ptr)NewHandle((long)sizeof(itemdatum));
X			tempitems = items;
X			items = (itemdatum **)(**items).next;
X			HUnlock (tempitems);
X			HLock (items);
X
X			strcpy ((**items).itemname, Item);
X			(**items).itemno = ++lastitem;
X			(**items).menuId = (**ourmhandle).menuId;
X			(**items).menuhand = (**ourmhandle).menuhand;
X			(**items).menurun = (ProcPtr) 0L;
X			(**items).next = 0L;
X			HUnlock (items);
X
X			/* and install the Item in the menu bar */
X			ctop (Item);
X			AppendMenu ((**ourmhandle).menuhand,Item);
X			ptoc (Item);
X			HUnlock (ourmhandle);
X			setitems (items, routine);
X			return(TRUE);
X		}
X	}
X}
X
X/* Given a menu name, return the real menu Handle as used by most
X   of the Macintosh toolbox menu manager routines.
X*/
X
XMenuHandle mhand (name)			/* find MenuHandle		*/
Xchar *name;				/* given name of menu 		*/
X{
X	menudatum	**menu;
X	MenuHandle	temp;		/* a Handle to our data 	*/
X
X	menu = getourmenuhandle(name);
X	if ( menu ) {
X		HLock (menu);
X		temp = (**menu).menuhand;
X		HUnlock (menu);
X		return ( temp );	/* return menu Handle 		*/
X	} else
X		return ( (MenuHandle) 0 );
X}
X
X
X/*  Call this routine if you want these SimpleTools defined quiting	*/
X/*  procedures.  You may just install your own instead.	 The time to	*/
X/*  call this is after you have installed all your other "File" items.	*/
X/*  By calling this last, you will place Transfer and Quit on the end	*/
X/*  of the menu list.							*/
X
Xsimplequits ()
X{
X	menu ("File", "-", itemdisable);
X
X	#ifndef LIGHTSPEED
X	menu ("File", "Transfer.../T", gottrans);
X	#endif
X
X	menu ("File", "Quit/Q", gotquit);
X}
X
X/* Given a window's name, return its window pointer so that other
X   Macintosh Window Manager routines can be called for that window. */
X
XWindowPtr windowpoint(name)		/* get window pointer 		*/
Xchar *name;				/* given window's name 		*/
X{
X	winddatum **wind, **tempwind;	/* Handle to our window data 	*/
X	WindowPtr	temp;
X
X	if (firstwind) return ((WindowPtr)0);
X	wind = simplewinds;		/* look for the named window 	*/
X	HLock (wind);
X
X	while ( strcmp ((**wind).windname, name) && (**wind).next) {
X		tempwind = wind;
X		wind = (winddatum **) (**wind).next;
X		HUnlock (tempwind);
X		HLock (wind);
X	}
X	if ( strcmp ((**wind).windname, name) ==0) {
X		temp = (**wind).wptr;
X		HUnlock (wind);
X		return ( temp );	/* return pointer		*/
X	} else {
X		HUnlock (wind);
X		return ( (WindowPtr) 0);/* or zero if it wasn't found	*/
X	}
X}
X
X/* This routine installs a new window onto the screen.  It also gives
X   that window an Item in the Window menu.  This routine is also used
X   to modify a window's associated routines.  The x,y positions are the
X   top left and bottom right corners of where the window should originally
X   be placed.  The coordinates are never used when this routine is called
X   to update an already existing window.  But the spaces must be filled,
X   so you can use zeros if you want.  Once the window has been displayed in
X   its original position, the user has complete control of its size and
X   placement with the mouse.
X
X   YOU MUST ASSIGN PROCEDURES TO BE CALLED WHEN SIMPLETOOLS DETECTS THAT
X   THIS WINDOW IS BECOMMING ACTIVE, DEACTIVATING, NEEDS UPDATING, OR
X   THE MOUSE HAS BEEN PRESSED IN ITS CONTENT.  JUST LIKE THE MENU PROCEDURE,
X   THESE PROCEDURES ARE PASSED SOME ARGUMENTS.  YOU DO NOT HAVE TO
X   DECLARE THESE IF YOU DON'T WHAT TO USE THEM.  IF YOU USE THE ARGUMENTS,
X   YOU WOULD DECLAR THESE PROCEDURES AS FOLLOWS:
X
X   	my_activate (windp, event)	same as my_update
X	my_deactivate (windp, event)	same as my_update
X
X	my_update (windp, event)
X	WindowPtr 	windp;		the window being acted upon
X	EventRecord 	*event;		the current event record
X	{
X		...
X	}
X
X	my_inContent (x, y, windp, event)
X	int 		x, y;		mouse position in local coords
X	WindowPtr 	windp;		like above
X	EventRecord 	*event;		like above
X	{
X		...
X	}
X*/
X
Xwindow(name, xtop, ytop, xbot, ybot, a, d, u, c)
Xchar *name;			/* window's name 			*/
Xint xtop, ytop, xbot, ybot;	/* position if this is a new window 	*/
XProcPtr a, d, u, c;		/* activate, deactivate, update, and 	*/
X{				/*  content procedures  		*/
X	winddatum **wind, **temp;/* Handle to our window data 		*/
X	winddatum **newentry;	/* another Handle 			*/
X	Rect newplace;		/* rectable for the window's placement	*/
X
X	if (a == (ProcPtr) 0)
X		a = (ProcPtr) stnop;
X	if (d == (ProcPtr) 0)
X		d = (ProcPtr) stnop;
X	if (u == (ProcPtr) 0)
X		u = (ProcPtr) stnop;
X	if (c == (ProcPtr) 0)
X		c = (ProcPtr) stnop;
X	if ( !firstwind ) {
X
X		/* see if window is in the list */
X		wind = simplewinds;
X		HLock (wind);
X
X		while ( strcmp ((**wind).windname, name) && (**wind).next) {
X			temp = wind;
X			wind = (winddatum **) (**wind).next;
X			HUnlock (temp);
X			HLock (wind);
X		}
X		if ( strcmp ((**wind).windname, name) ==0) {
X
X			/* reset the found window's parameters */
X			(**wind).wact = (ProcPtr) a;
X			(**wind).wdeact = (ProcPtr) d;
X			(**wind).wupdate = (ProcPtr) u;
X			(**wind).wcontent = (ProcPtr) c;
X			SetPort ( (**wind).wptr);
X			HUnlock (wind);
X
X			return(FALSE);
X		}
X		HUnlock (wind);
X	}
X
X	/* make a new window entry */
X	newentry = (winddatum **)NewHandle ( (long) sizeof (winddatum));
X	if (firstwind)
X		simplewinds = newentry;
X	else
X		(**wind).next = (Ptr) newentry;
X	firstwind = 0;
X	HLock (newentry);
X
X	strcpy ((**newentry).windname, name);
X	SetRect (&newplace, xtop, ytop, xbot, ybot);
X	if (EmptyRect (&newplace))
X		SetRect (&newplace, 10, 42, 500, 330);
X	ctop (name);
X	(**newentry).wptr = NewWindow (0L, &newplace, name, show_new_window,
X		wprocid, -1L, dogoaway, newentry);
X	ptoc (name);
X	(**newentry).wact = (ProcPtr) a;
X	(**newentry).wdeact = (ProcPtr) d;
X	(**newentry).wupdate = (ProcPtr) u;
X	(**newentry).wcontent = (ProcPtr) c;
X	(**newentry).next = (Ptr) 0;
X	if (windmenu)
X		menu ("Windows", name, showawindow);
X	SetPort ( (**newentry).wptr);
X	HUnlock (newentry);
X
X	return(TRUE);
X}
X
Xwithwindow(name)			/* set output to window by name	*/
Xchar *name;				/* give it the window's name 	*/
X{					/* returns if window exists	*/
X	winddatum **wind, **temp;
X	wind = simplewinds;
X	if (firstwind) return(FALSE);	/* search for the window's name */
X
X	HLock (wind);
X	while ( strcmp ((**wind).windname, name) && (**wind).next) {
X		temp = wind;
X		wind = (winddatum **) (**wind).next;
X		HUnlock (temp);
X		HLock (wind);
X	}
X	if ( strcmp ((**wind).windname, name) ==0) {
X		SetPort ( (**wind).wptr);	/* set output to it 	*/
X		HUnlock (wind);
X		return(TRUE);
X	} else {
X		HUnlock (wind);
X		return(FALSE);
X	}
X}
X
X/* This run procedure is used to install routines to be occasionally
X   run.  The routine will be run once for each call to simpleevents()
X   which is done repeatedly by runsimpletools().
X
X   EACH ROUTINE INSERTED INTO THE RUN LIST IS RUN MULTIPLE TIMES UNTIL
X   IT IS REMOVED BY CALLING STOP.  THE ROUTINE IS CALLED WITH A SINGLE
X   ARGUMENT, A POINTER TO THE EVENT JUST RETURNED BY GETNEXTEVENT() AND
X   BEFORE SIMPLETOOLS PROCESSES IT.
X*/
X
Xrun(routine)			/* install a run procedure 	*/
XProcPtr routine;		/* give it the procedure 	*/
X{				/* return TRUE if successful 	*/
X	int i;
X	i = 0;			/* add it to the end of the list */
X	while ( simpleruns[i] != (ProcPtr) 0L) i++;
X	if (i < maxsruns) {
X		simpleruns[i] = routine;
X		simpleruns[i+1] = (ProcPtr) 0L;
X		return(TRUE);
X	} else
X		return(FALSE);
X}
X
X/* This routine removes a procedure from the list of run procedures */
X
Xstop(routine)			/* stop a procedure from running*/
XProcPtr routine;		/* give the procedure 		*/
X{				/* return TRUE if successful 	*/
X	int i = 0;
X	while ( (simpleruns[i] != routine) && simpleruns[i])  i++;
X	if (simpleruns[i]) {
X		while ( simpleruns[i] != (ProcPtr)0 ) {
X			simpleruns[i] = simpleruns[i+1];
X			i++;
X		}
X		return(TRUE);
X	} else {
X		return(FALSE);
X	}
X}
X
Xvoid home ()			/* text-based home of the pen with
X				   the window being erased.		*/
X{
X	GrafPtr	port;
X	GetPort (&port);
X	EraseRect (&(port->portRect));
X	stgotoxy (1, 1);
X}
X
Xstgotoxy (x, y)				/* goto text position x, y	*/
Xint x, y;
X{
X	Point		pt;
X	int		newx, newy;
X	FontInfo	font;
X
X	GetFontInfo (&font);
X	GetPen (&pt);
X	#ifdef MEGAMAX
X	if (x < 0)
X		newx = pt.a.h;
X	else
X		newx = font.widMax * (x);
X	if (y < 0)
X		newy = pt.a.v;
X	#else
X	if (x < 0)
X		newx = pt.h;
X	else
X		newx = font.widMax * (x);
X	if (y < 0)
X		newy = pt.v;
X	#endif
X	else
X		newy = (font.ascent + font.descent + font.leading) * (y+1);
X	MoveTo (newx, newy);
X}
X
X/* The getline procedure is to be called when you want to simply get a Line
X   of text from the user at the current pen position on the screen.  You
X   will probably preceed this with a call to stgotoxy(x,y).  You would call
X   it like:
X   		getline ("Erik", name);
X
X   where name is a character array.  This works MUCH better than scanf()
X   or gets() since it uses the Macintosh TextEdit routines to allow the
X   user to edit the Line being input.
X
X   Getline is very "modal" and no other events are handled while the
X   user is expected to enter the Line.  Getline returns ONLY when the
X   user presses <RETURN>.
X
X   Routines scheduled to run by the run() routine are called.  Make sure
X   your run routines don't strip all <RETURNS> from the event record
X   they get or getline will never stop.
X*/
X
Xgetline (dfault, destination)		/* using TE, get a Line		*/
Xchar *dfault, *destination;		/* default string, dest 	*/
X{
X	TEHandle 		hte;
X	Rect			destRect;
X	Point			pen,pt;
X	FontInfo		FInfo;
X	int			done, mask, code, in_already, nextcap;
X	GrafPtr			port, window;
X	EventRecord		event;
X	char			key;
X	CursHandle		c;
X
X	GetPort (&port);		/* Calculate Rect for TE	*/
X	if (port != FrontWindow())  SelectWindow (port);
X	GetPen (&pen);
X	GetFontInfo (&FInfo);
X	#ifdef MEGAMAX
X		SetRect (&destRect, pen.a.h, pen.a.v - FInfo.ascent,
X			1000, pen.a.v + FInfo.descent);
X	#else
X		SetRect (&destRect, pen.h - 1, pen.v - FInfo.ascent,
X			1000, pen.v + FInfo.descent);
X	#endif
X	EraseRect (&destRect);
X	hte = TENew (&destRect, &destRect);
X	TESetText (dfault, (long)strlen(dfault), hte);
X	TEActivate (hte);
X	TEUpdate (&destRect, hte);
X	mask = mDownMask + keyDownMask + autoKeyMask + mUpMask;
X	done = FALSE;
X	#ifdef MEGAMAX
X	  c = GetCursor (ibeamcursor);
X	#else
X	  c = GetCursor (iBeamCursor);
X	#endif
X	in_already = FALSE;
X	nextcap = getlinecaps;
X	do {				/* "modal" loop until <cr>	*/
X		SystemTask ();
X		TEIdle (hte);
X
X		GetNextEvent (mask, &event);
X		runruns (&event);
X		GetMouse (&pt);		/* use I beam in TE		*/
X		if (PtInRect (ZZ(pt), &destRect)) {
X		  if ( ! in_already )  {
X		     SetCursor (*c);
X		     in_already = TRUE;
X		  }
X		} else {
X		  if ( in_already ) {
X		      InitCursor ();
X		      in_already = FALSE;
X		  }
X		}
X		switch (event.what) {
X		    case mouseDown:
X			code = FindWindow (ZZ(event.where),&window);
X			if ((code == inContent) && (window == port)) {
X			   GlobalToLocal (&event.where);
X				if (PtInRect(ZZ(event.where),&destRect))
X					TEClick (ZZ(event.where), 0, hte);
X				else SysBeep (1);
X			} else SysBeep (20);
X			break;
X		    case keyDown:
X		    case autoKey:
X		        key = (char) (event.message & 0xFFL);
X			if (nextcap && (key >= 'a') && (key <= 'z'))
X				key -= ' ';
X			nextcap = FALSE;
X			if (key == ' ') nextcap = getlinecaps;
X			if (key != '\r')  TEKey (key, hte);
X			else  done = TRUE;
X			break;
X		}
X	} while (!done);
X	TEDeactivate (hte);
X
X	/* For LIGHTSPEED, use a lowercase te and upper case L in	*/
X	/* TElength.  Megamax conversion utility does this wrong too.	*/
X
X	strncpy (destination, *TEGetText(hte), (*hte)->teLength);
X	destination[(*hte)->teLength] = 0;
X
X	TEDispose (hte);
X    	InitCursor ();
X}
X
X/*  Use prompt when you want a tiny window to pop up to ask the user
X    a question.  The question is drawn and a TextEdit box is provided
X    to get the answer.  Whatever the user leaves in the answer box
X    is returned in answer.  Two buttons are also displayed:  OK and
X    CANCEL.  Prompt returns TRUE or FALSE depending on which Button was
X    pressed.
X*/
X
Xprompt ( question, answer)		/* dialog box question/answer */
Xchar *question;
Xchar *answer;
X{
X	return (stdialog (question, answer, 1));
X}
X
X/* Message is just like prompt except no answer box is displayed.  An
X   OK and CANCEL Button works just like prompt.
X*/
X
Xmessage ( message )			/* dialog box message 		*/
Xchar *message;
X{
X	return (stdialog (message, message, 2));
X}
X
X/*  This routine is a simpler whay to call the toolbox SFGetFile()
X    routine.  Simple call this like:
X
X    		getfile ("TEXT", filename)
X
X    where filename is a character array.  Replace TEXT with whatever
X    file type you desire.  The file manager's working directory is set
X    correctly so that a subsequent open() call with filename will work.
X*/
X
Xgetfile (ftype, reply)
Xchar ftype[];
Xchar reply[];
X{
X	Point where;
X	SFReply frommac;
X
X	#ifdef MEGAMAX
X	  where.a.h = 75; where.a.v = 50;
X	#else
X	  where.h = 75; where.v = 50;
X	#endif
X	if (strlen(ftype) != 4)
X	  SFGetFile (ZZ(where), NULL, NULL, -1, NULL, NULL, &frommac);
X	else
X	  SFGetFile (ZZ(where), NULL, NULL, 1, ftype, 0L, &frommac);
X	if (frommac.good) {
X	  SetVol ("", frommac.vRefNum);
X	  strcpy (reply, frommac.fName);
X	  return (TRUE);
X	}
X	else return (FALSE);
X}
X
X/* This is like getfile, but may get a new file name from the user.
X   Origname is the default you want to present to the user.
X*/
X
Xputfile (origname,reply)
Xchar *origname;
XSFReply *reply;
X{
X	Point where;
X	SFReply frommac;
X
X	#ifdef MEGAMAX
X	  where.a.h = 75; where.a.v = 50;
X	#else
X	  where.h = 75; where.v = 50;
X	#endif
X	SFPutFile (ZZ(where), "", origname, 0L, &frommac);
X	if (frommac.good) {
X	  SetVol ("", frommac.vRefNum);
X	  strcpy (reply, frommac.fName);
X	  return (TRUE);
X	}
X	return (FALSE);
X}
X
X/* This routine initializes SimpleTools and MUST be called before	*/
X/* most of the other SimpleTools routines are called.			*/
X/* The passed about string is the menu Item name to appear just under	*/
X/* the Apple menu.  This will be disabled and can be enabled using	*/
X/* a menu() call.  This routine also initializes the Macintosh 		*/
X/* for application execution and desk accessory processing.		*/
X
Xsimpletools(about)	/* to be called at the beginning of program 	*/
Xchar *about;
X{
X	#ifdef MEGAMAX
X	  maxapplzone();	/* allow maximum heap expansion 	*/
X	#else
X	  MaxApplZone();
X	#endif
X	FlushEvents (everyEvent,0);  /* ignore left over events 	*/
X	InitGraf (&thePort);	/* initialize the screen 		*/
X	InitFonts();
X	InitWindows();
X	InitMenus();
X	InitCursor();		/* make the arrow Cursor 		*/
X	TEInit();
X	InitDialogs(gotquit);
X	snewrom = havenewrom();
X
X	/* Ugh.  For LightSpeed use a lower case d in DocumentProc.	*/
X	/* Megamax conversion utility is at fault here.			*/
X
X	wprocid = documentProc;
X	if (snewrom) wprocid = zoomproc;
X	SetRect ( &sizerect, 20, 50, 250, 330);
X	simpleruns[0] = (ProcPtr) 0;  /* empty the run list 		*/
X
X	/* These are the bounds we are allowed to size a window or
X	   Move a window to.
X	*/
X
X	swholescreen = dragrect = thePort -> portRect;
X	InsetRect (&dragrect, 4, 4);
X	SetRect ( &sizerect, 20, 20, 2048, 700);
X	firstwind = 1;			/* empty window table		*/
X	keydownproc = (ProcPtr) stnop;	/* default key hit procedures 	*/
X	autokeyproc = (ProcPtr) stnop;
X	initsmenus(about);		/* install the menus 		*/
X}
X
Xsimpleevents()				/* to be called in the main loop */
X{
X	EventRecord newevent;
X	winddatum **thewdatum;
X	SystemTask();			/* Do the system D.A. etc. stuff */
X	HiliteMenu(0);
X	GetNextEvent(everyEvent, &newevent);
X	runruns(&newevent);		/* Do our run procedures 	*/
X	switch (newevent.what) {
X	    case mouseDown:
X		domousedown(&newevent); break;
X	    case keyDown:
X		if (newevent.modifiers & cmdKey)
X			docommand(MenuKey((char)(newevent.message & 0xffL)),
X				&newevent);
X		(*(keydownproc))(&newevent);
X		 break;
X	    case autoKey:
X		if (newevent.modifiers & cmdKey)
X			docommand(MenuKey((char)(newevent.message & 0xffL)),
X				&newevent);
X		(*(autokeyproc))(&newevent);
X		break;
X	    case activateEvt:
X		thewdatum = wdatum(newevent.message);
X		if (thewdatum) {
X			SetPort(newevent.message);
X			HLock (thewdatum);
X			if (newevent.modifiers & 1) {
X
X				(*((**thewdatum).wact))(newevent.message,
X					&newevent);
X			} else {
X				(*((**thewdatum).wdeact))(newevent.message,
X					&newevent);
X			}
X			HUnlock (thewdatum);
X		}
X		break;
X	    case updateEvt:
X		thewdatum = wdatum(newevent.message);
X		if (thewdatum) {
X			SetPort (newevent.message);
X			BeginUpdate (newevent.message);
X			HLock (thewdatum);
X			(*((**thewdatum).wupdate))(newevent.message,
X				&newevent);
X			HUnlock (thewdatum);
X			EndUpdate (newevent.message);
X		}
X		break;
X	}
X}
X
Xrunsimpletools ()
X{
X	for (;;) simpleevents();
X}
X
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > simple.h
X#define LIGHTSPEED	{define either LIGHTSPEED or MEGAMAX or your own}
X
X#include <stdio.h>
X
X#ifdef MEGAMAX
X  #include <menu.h>
X  #include <win.h>
X#endif
X
X#ifdef LIGHTSPEED
X  #include <MenuMgr.h>
X  #include <WindowMgr.h>
X#endif
X
X#define itemdisable	0L
X#define itemenable	1L
X#define itemcheck	2L
X#define itemuncheck	3L
X
Xextern char 		applestring[];
Xextern WindowPtr 	windowpoint();
Xextern MenuHandle 	mhand();
Xextern int 		windmenu;
Xextern int 		dogoaway;
Xextern int 		wprocid;
Xextern int		show_new_window;
Xextern int 		sizeredraw;
Xextern int		getlinecaps;
Xextern ProcPtr 		keydownproc;
Xextern ProcPtr 		autokeyproc;
Xextern void		home();
Xextern void		stnop();
SHAR_EOF
exit
---