🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.mac.sources
Article #50

MakeWrite Source (part 2 of 3)

#50
From: macintosh
Date: Sat, 21 Mar 1987 19:00
2483 lines
57060 bytes
[MakeWrite Source - part 2 of 3]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	MW/MWFontOps.c
#	MW/MWGen.c
#	MW/MWIO.c
#	MW/MWMSpecOps.c
#	MW/MWMain.c
#	MW/MWMapOps.c
#	MW/MWMapWind.c
sed 's/^X//' << 'SHAR_EOF' > MW/MWFontOps.c
X# include	"MakeWrite.h"
X# define	applFont	1
X
X
X/*
X	Query user whether to replace the current font list with the
X	selected font, or just add them to the list.  Return false if
X	Cancel clicked.  If Replace clicked, then warn user that the
X	map will be destroyed (if it has been changed) and return false
X	if he declines.  Otherwise return true.
X	
X	If Replace is selected, then the map and the font list are
X	cleared as well as setting some state variables.  The map is
X	really modified by clearing it, but that was ok'd by user, so is
X	now considered clean (unmodified) - just like after New Map.
X*/
X
Xstatic Boolean ReplaceOrAdd ()
X{
Xtypedef enum	/* alert button numbers */
X{
X	cancel = 1,
X	add,
X	replace
X};
Xregister Integer	i;
X
X	i = Alert (replaceAlrtNum, nil);
X	DoUpdates ();
X
X	if (i == cancel)
X		return (false);
X
X	if (i == replace)
X	{
X		if (!DestroyWarn ())
X			return (false);
X		ClobberMap ();
X		ClearMapName ();
X		ResetFontList ();
X		mapModified = false;
X		undoOp = noUndo;
X	}
X	return (true);
X}
X
X
X/*
X	Add the names of the FONT resources in the open resource files
X	to the font list (or replace the list with those fonts).
X
X	Not all FONT resources have a name, so check it first.  This could
X	equally well be done by using only those FONT resources corresponding
X	to a point size of zero (bits 0-6 of the resource id equal to zero).
X*/
X
XResourceFonts (ask)
XBoolean	ask;
X{
XHandle			h;
Xregister Integer	i;
XInteger				fNum, nFonts;
XInteger				resId;
XResType			resType;
XStr255			resName;
X
X	if (ask)
X	{
X		if (ReplaceOrAdd () == false)
X			return;
X	}
X
X	nFonts = CountResources ('FONT');
X	SetResLoad (false);
X	for (i = 1; i <= nFonts; ++i)
X	{
X		h = GetIndResource ('FONT', i);
X		GetResInfo (h, &resId, &resType, &resName);
X		if (resName[0] != 0)	/* not all font resources have names! */
X		{
X			GetFNum (resName, &fNum);
X			if (!SetFontSpec (fNum, resName))
X				break;
X		}
X	}
X	SetResLoad (true);
X	SyncFontSpecs ();
X}
X
X
X/*
X	Add the fonts contained in the STR# whose id is  fontStrNum
X	to the font list (or replace the list with those fonts).
X*/
X
XStrFonts (ask)
XBoolean	ask;
X{
XHandle			h;
Xregister Integer	i, j, len;
XInteger				nStrings;
XStr255			s;
XLongint			fNum;
X
X	if (ask)
X	{
X		if (ReplaceOrAdd () == false)
X			return;
X	}
X
X	h = GetResource ('STR#', fontStrNum);
X	nStrings = * (Integer *) *h;
X
X	for (i = 0; i < nStrings; ++i)
X	{
X		GetIndString (s, fontStrNum, i + 1);
X		if (s[1] == '#')
X			continue;			/* comment - ignore */
X		len = s[0];
X		j = 1;
X		while (j <= len && s[j] != '/')
X			++j;
X		if (j > len)	/* error */
X		{
X			NumToString ((Longint) fontStrNum, s);
X			Message3 ("\pA font list resource (STR# ", s,
X						"\p) is messed up.");
X			break;
X		}
X		s[0] = j - 1;	/* length of numeric part */
X		StringToNum (s, &fNum);
X		s[j] = len - j;
X		if (!SetFontSpec ((Integer) fNum, &s[j]))
X			break;
X	}
X	ReleaseResource (h);
X	SyncFontSpecs ();
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWGen.c
X# include	"MWMaca.h"
X# include	"MWFileStuff.h"
X
X
X/*
X	Prototype for data of empty paragraph
X*/
X
Xtypedef struct EmptyParaData6
X{
X	Integer	pTextLen;
X	Integer	pFmtLen;
X	Format	pFormat;
X} EmptyParaData6;
X
X
XEmptyParaData6	emptyParaData =
X{
X	0,								/* text length = 0 (no text) */
X	6,								/* format data length (1 format) */
X	{ 0, 12, 0, 1}					/* format: pos 0, size 12, style */
X									/* plain, application font */
X};
X
X
XUPrintRec	uPrintRec;	/* not initialized - doesn't matter? */
X
X
XRuler	stdRuler =
X{
X	10,								/* left margin */
X	480,							/* right margin */
X	leftJust,						/* justification */
X	10,								/* number of tabs */
X	0,								/* line spacing = single */
X	10,								/* indentation of first line */
X	{ 40, 80, 120, 160, 200,		/* tab values */
X	  240, 280, 320, 360, 400 },	/* tab values */
X	{ 0, 0, 0, 0 }					/* four bytes fill */
X};
X
X
X
XGlobals6	globals =
X{
X	6,								/* MacWrite 4.5 = version 6 */
X	0,								/* main doc para count - fill in later */
X	2,								/* header para count */
X									/* (one ruler + 1 empty text para) */
X	2,								/* footer para count */
X									/* (one ruler + 1 empty text para) */
X	0,								/* title page flag */
X	0,								/* unused */
X	0,								/* scrap not displayed */
X	0,								/* footer not displayed */
X	0,								/* header not displayed */
X	0,								/* rulers displayed */
X	-1,								/* active document: -1 tells MacWrite */
X									/* to recalc display information */
X	1,								/* starting page = 1 */
X	0L,								/* free list position - fill in later */
X	8,								/* free list length */
X	8,								/* # bytes allocated for list */
X	{ 0, 0, 0, 0, 0, 0, 0,			/* unused */
X	  0, 0, 0, 0, 0, 0, 0 }			/* unused */
X};
X
X
XWindows6	windowVars =
X{
X	{ 1, 0 },						/* start of selection (para 1, char 0) */
X	{ 1, 0 },						/* end of selection (para 1, char 0) */
X	0,								/* vertical offset */
X	0,								/* first paragraph to redraw */
X	0L,								/* position of information array */
X									/* (filled in later) */
X	0,								/* length of information array */
X									/* (filled in later) */
X	0L,								/* position of line height array */
X									/* (filled in later) */
X	0,								/* length of line height array */
X									/* (filled in later) */
X	{ -14, 30 },					/* page icon position */
X	{ -14, 236 },					/* date icon position */
X	{ -14, 442 },					/* time icon position */
X	{ -1, -1, -1, -1 },				/* four bytes fill */
X	-1,								/* redraw ovals (icons) */
X	0,								/* don't redraw rulers */
X	{ -1, -1 },						/* face active when saved */
X									/* (-1 = "has never been set") */
X	-1								/* font active when saved */
X									/* (-1 = "has never been set") */
X};
X
X
XParaInfo6	rulerParaInfo;
XParaInfo6	nullTextParaInfo;
X
X
XBoolean SetParaInfo (p, height, status, dataPos, dataLen, comFormats)
Xregister ParaInfo6	*p;
XInteger			height;
XByte		status;
XLongint		dataPos;
XInteger			dataLen;
XInteger			comFormats;
X{
X
X# ifdef	debug
X	DisplayString ("\p{SetParaInfo}");
X# endif
X
X	p->paraHeight = height;
X	p->paraPos = 0;
X	p->paraHandle = nil;
X	p->paraStOff.paraOffset = dataPos;		/* this first */
X	p->paraStOff.paraStatus = status;		/* *then* this! */
X	p->paraLen = dataLen;
X	p->paraFmts = comFormats;
X
X	return (true);
X}
X
X
X/*
X	Write file prelude, using prototype structures.
X		Global variables
X		Universal print record
X		Footer document variables
X		Header document variables
X		Main document varables
X
X	Some of these will be patched in the postlude.
X
X	Also write as much of the invariant file contents as possible:
X		Footer document contents (1 ruler + 1 empty text paragraph)
X		Header document contents (1 ruler + 1 empty text paragraph)
X		Initial ruler of main document
X*/
X
XBoolean WritePrelude (f)
Xregister Integer	f;
X{
X
X	return (FileWrite (f, &globals, (Longint) sizeof (Globals6))
X		&& FileWrite (f, &uPrintRec, (Longint) sizeof (UPrintRec))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& ZeroPad (f, 6)
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X		&& FileWrite (f, &emptyParaData, (Longint) sizeof (EmptyParaData6))
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X		&& FileWrite (f, &emptyParaData, (Longint) sizeof (EmptyParaData6))
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X	);
X}
X
X
X/*
X	Write line height array, one entry for each paragraph.  First
X	para is always a ruler - write a zero word.  Other paras are
X	faked by writing information that there's one line in the para
X	of height 16 (12-point height).  MacWrite will fix when it reads
X	the file.
X
X	paraCount assumed >= 2.
X*/
X
XBoolean WriteLineHeights (f, paraCount)
XInteger		f;
XInteger	paraCount;
X{
X
X	if (!WriteInteger (f, 0))
X		return (false);
X
X	while (--paraCount > 0)
X	{
X		if (!WriteLongint (f, 0x00011010))
X			return (false);
X	}
X	
X	return (true);
X}
X
X
X/*
X	Write line height and paragraph info positions and lengths
X*/
X
XBoolean WriteArrayInfo (f, seek, piPos, piLen, lhPos, lhLen)
XInteger		f;
XLongint	seek;
XLongint	piPos;
XInteger	piLen;
XLongint	lhPos;
XInteger	lhLen;
X{
X
X	FileSeek (f, seek);
X	return (WriteLongint (f, piPos) && WriteInteger (f, piLen)
X			&& WriteLongint (f, lhPos) && WriteInteger (f, lhLen));
X}
X
X
X/*
X	Paragraph data are all written now.  The line height and paragraph
X	info arrays must now be written, as well as an empty free list.
X	Save the positions of these arrays, as they must be patched into
X	the window variables.
X
X	The paraCount and paraInfo are for the text paragraphs only.
X	When the main document paragraph count and paragraph information
X	are length are patched into the globals, increment to take
X	into account the initial ruler (written during prelude).
X*/
X
XBoolean WritePostlude (f, paraCount, paraInfo)
Xregister Integer	f;
XInteger		paraCount;
XPIAHandle	paraInfo;
X{
XLongint	fLHPos, fPIPos;		/* footer line height, para info array pos */
XLongint	hLHPos, hPIPos;		/* header line height, para info array pos */
XLongint	mLHPos, mPIPos;		/* main line height, para info array pos */
XInteger	paraInfoLen;		/* length of main para info array */
XInteger	defInfoLen;			/* length of header, footer pi array */
XInteger	defLHLen;			/* length of header, footer line height array */
XInteger	mainLHLen;			/* length of main line height array */
XLongint	freeListPos;		/* free list pos */
XBoolean	result;
X
X/*
X	Set up prototype ruler paragraph and null text paragraph
X	information array elements.  The position field must be filled
X	in on a per-window basis.
X*/
X
X	SetParaInfo (&rulerParaInfo, 0, 0, (Longint) 0x130, 34, 0);
X	SetParaInfo (&nullTextParaInfo, 16, 0, (Longint) 0x152, 10, 0);
X
X/*
X	For footer
X*/
X
X	fLHPos = FilePos (f);
X	if (!WriteLineHeights (f, 2))
X		return (false);
X
X	fPIPos = FilePos (f);
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6))
X		|| !FileWrite (f, &nullTextParaInfo, (Longint) sizeof (ParaInfo6)))
X			return (false);
X
X/*
X	For header
X*/
X
X	hLHPos = FilePos (f);
X	if (!WriteLineHeights (f, 2))
X		return (false);
X
X	rulerParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X	nullTextParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X
X	hPIPos = FilePos (f);
X
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6))
X		|| !FileWrite (f, &nullTextParaInfo, (Longint) sizeof (ParaInfo6)))
X			return (false);
X
X/*
X	For main
X*/
X
X	mLHPos = FilePos (f);
X	if (!WriteLineHeights (f, paraCount + 1))
X		return (false);
X
X	rulerParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X
X	mPIPos = FilePos (f);
X
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6)))
X		return (false);
X
X	paraInfoLen = paraCount * sizeof (ParaInfo6);
X	HLock (paraInfo);
X	result = FileWrite (f, *paraInfo, (Longint) paraInfoLen);
X	HUnlock (paraInfo);
X	if (!result)
X		return (false);
X
X/*
X	Write free list.  It's at the end of the file, so set the
X	file EOF here, too.
X*/
X
X	freeListPos = FilePos (f);
X	if (!WriteLongint (f, freeListPos + 8) || !WriteLongint (f, 0L))
X		return (false);
X
X	(void) SetEOF (f, FilePos (f));
X
X/*
X	Now patch  globals and window variables:
X		main doc para count (increment to account for ruler)
X		free list position
X		line height and para info array positions (and para info array
X		length for main document)
X*/
X
X	FileSeek (f, 2L);
X	++paraCount;
X	paraInfoLen += sizeof (ParaInfo6);
X	if (!WriteInteger (f, paraCount))
X		return (false);
X	FileSeek (f, 18L);
X	if (!WriteLongint (f, freeListPos))
X		return (false);
X
X	defInfoLen = 2 * sizeof (ParaInfo6);
X	defLHLen = 3 * sizeof (Integer);
X	mainLHLen = sizeof (Integer) + (paraCount-1) * sizeof (Longint);
X	if (!WriteArrayInfo (f, 172L, fPIPos, defInfoLen, fLHPos, defLHLen)
X		|| !WriteArrayInfo (f, 218L, hPIPos, defInfoLen, hLHPos, defLHLen)
X		|| !WriteArrayInfo (f, 264L, mPIPos, paraInfoLen, mLHPos, mainLHLen))
X			return (false);
X
X	return (true);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWIO.c
X/*
X	MakeWrite File I/O  Routines.
X*/
X
X
X# include	"MakeWrite.h"
X# include	"MWFileStuff.h"
X# include	"MWMaca.h"
X# include	<StdFilePkg.h>
X
X
Xstatic SFReply	inFile;
Xstatic SFReply	outFile;
Xstatic Str255	fName;		/* map name and volume reference number */
Xstatic Integer		vRefNum;
X
X
X/*
X	Clear the current file name, and reset the title of the map
X	window.  Obviously, the first call to this must occur
X	after the map window is initialized.
X*/
X
XClearMapName ()
X{
X	CopyString ("\pUntitled", fName);
X	SetMapName (fName);
X}
X
X
XSetMapName (name)
XStringPtr	name;
X{
XStr255	s;
X
X	CopyString ("\pMap Name:  ", s);
X	AppendString (name, s);
X	SetWTitle (mapWind, s);
X}
X
X
X/*
X	Check a ConvSpec to see that it makes sense
X*/
X
Xstatic Boolean CheckMSpec (m)
XMapSpec	*m;
X{
XInteger		errCnt = 0;
X
X	if (FontIndex (m->font) < 0)
X	{
X		ErrWindMsge ("\pUnknown font number: ", m->font);
X		++errCnt;
X	}
X	if (SizeIndex ((Integer) m->size) < 0)
X	{
X		ErrWindMsge ("\pUnknown size: ", (Integer) m->size);
X		++errCnt;
X	}
X
X	return (errCnt == 0);
X}
X
X
X/*
X	Read paragraph style variables
X*/
X
Xstatic Boolean ReadParaStyle (f, version)
XInteger		f;
XInteger		version;
X{
X	if (version == 1)
X	{
X		InitParaStyle ();		/* use defaults */
X		return (true);
X	}
X	return (FileRead (f, &paraStyle, (Longint) sizeof (ParaStyle))
X			&& ReadString (f, paraMark)
X			&& ReadString (f, pageMark)
X			&& ReadString (f, periodStr)
X			&& ReadString (f, quoteStr));
X}
X
X
X/*
X	Read one map specification from a file.  First read the MapSpec
X	structure, being careful not to clobber the mark string handle.
X	Then read the string that gets put into the handle (first the
X	length byte, then the rest of the string).
X*/
X
Xstatic Boolean ReadMSpec (f, m)
Xregister Integer		f;
Xregister MapSpec	*m;
X{
XStringHandle	hStr;
XBoolean			ok;
X
X	hStr = m->mark;	/* save since clobbered by next read */
X	ok = FileRead (f, m, (Longint) sizeof (MapSpec));
X	m->mark = hStr;
X	if (ok)
X	{
X		HLock (hStr);
X		ok = ReadString (f, *hStr);
X		HUnlock (hStr);
X	}
X	return (ok);
X}
X
X
X/*
X	Read map specifications from a file.  Duplicate or illegal
X	specifications are not added.
X
X	Assumes file is open and all mappings already cleared (for Open) or
X	not (for Append).  If setParaInfo is true (Open), paragraph style
X	info is set.  If it's false (Append), it's not set.
X
X	Does not set undo variables or map-changed variables.
X*/
X
Xstatic ReadMap (f, setParaInfo)
XInteger		f;
XBoolean	setParaInfo;
X{
XMapSpec	mSpec;
XInteger		badCnt = 0;
XInteger	ver;
XInteger	i, nLines;
XStr255	str;
XBoolean	ok;
X
X	InitMSpec (&mSpec);
X	ErrWindInit (inFile.fName);
X	if (!ReadInteger (f, &ver))
X	{
X		Message1 ("\pCan't read map file.");
X	}
X	else if (ver != mapVersion && ver != 1)
X	{
X		NumToString ((Longint) ver, str);
X		Message2 ("\pUnknown map file version:  ", str);
X	}
X	else if (ReadInteger (f, &nLines))
X	{
X		ok = true;
X		for (i = 0; i < nLines; ++i)
X		{
X			ok = false;
X			if (!ReadMSpec (f, &mSpec))
X				break;
X			ok = true;
X	
X/*
X	Need to check legality here, since the file may have been
X	created using the fonts from a font list other than the current
X	one.
X*/
X	
X			if (CheckMSpec (&mSpec) == false)
X			{
X				++badCnt;
X				continue;			/* its bad - don't use it */
X			}
X	
X			if (StatMSpec (&mSpec))
X			{
X				++badCnt;
X				continue;			/* already exists - don't use dups */
X			}
X	
X			if (InsertMapping (&mSpec, mapList->nLines) == false)
X				break;
X		}
X		if (ok && setParaInfo)
X			(void) ReadParaStyle (f, ver);
X	}
X
X	TermMSpec (&mSpec);
X
X	(void) FSClose (f);
X	ScrollToLine (mapList, 0);		/* force scroll to top */
X	SelectMapping (noLine);			/* but leave unselected */
X
X	if (badCnt)
X	{
X		NumToString ((Longint) badCnt, str);
X		Message2 (str, "\p illegal or duplicate specifications were found and ignored");
X	}
X}
X
X
X/*
X	Open a map.  Clobber the current map first, set the map name
X	afterward.
X*/
X
XBoolean OpenMap ()
X{
XInteger		f;
X
X	if (GetInputFile ("\pOpen", mwType, &inFile)
X		&& OpenInputFile (&inFile, &f))
X	{
X		ClobberMap ();
X		ReadMap (f, true);
X		CopyString (inFile.fName, fName);
X		vRefNum = inFile.vRefNum;
X		SetMapName (fName);
X		return (true);
X	}
X	return (false);
X}
X
X
X/*
X	Add a map to the current map.  Doesn't set map name afterward.
X*/
X
XBoolean AddMap ()
X{
XInteger		f;
X
X	if (GetInputFile ("\pAdd", mwType, &inFile)
X		&& OpenInputFile (&inFile, &f))
X	{
X		ReadMap (f, false);
X		return (true);
X	}
X	return (false);
X}
X
X
X/*
X	Save map to file.  askForName is true if should ask for name,
X	otherwise use current name.  If name is "Untitled", ask for a name
X	anyway.  Sets the current name if it wasn't already set.
X
X	The file is deleted if not written properly.
X*/
X
XBoolean SaveMap (askForName)
XBoolean	askForName;
X{
XInteger				f;
Xregister Integer	i;
XOSErr			result;
XLongint			pos;
XBoolean			ok = false;
XStringHandle	hStr;
X
X	if (GetOutputFile (askForName, fName, vRefNum, &outFile) == false)
X		return (false);
X	if (OpenOutputFile (&outFile, mwCreator, mwType, &f) == false)
X		return (false);
X
X	if (WriteInteger (f, (Integer) mapVersion)
X		&& WriteInteger (f, (Integer) mapList->nLines))
X	{
X		ok = true;
X		for (i = 0; i < mapList->nLines; ++i)
X		{
X			ok = FileWrite (f, &mapSpec[i], (Longint) sizeof (MapSpec));
X			if (!ok)
X				break;
X			hStr = mapSpec[i].mark;
X			HLock (hStr);
X			ok = WriteString (f, *hStr);
X			HUnlock (hStr);
X			if (!ok)
X				break;
X		}
X		if (ok)
X		{
X			ok = FileWrite (f, &paraStyle, (Longint) sizeof (ParaStyle))
X				&& WriteString (f, paraMark)
X				&& WriteString (f, pageMark)
X				&& WriteString (f, periodStr)
X				&& WriteString (f, quoteStr);
X		}
X	}
X
X	(void) GetFPos (f, &pos);
X	(void) SetEOF (f, pos);
X	(void) FSClose (f);
X	(void) FlushVol (f, outFile.vRefNum);
X
X	if (!ok)
X	{
X		Message1 ("\pCould not write map");
X		(void) FSDelete (outFile.fName, outFile.vRefNum);
X		return (false);
X	}
X
X	CopyString (outFile.fName, fName);		/* set map name */
X	vRefNum = outFile.vRefNum;
X	SetMapName (fName);
X	return (true);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMSpecOps.c
X# include	"MWMapInfo.h"
X
X
X/*
X	Initialize a MapSpec by allocating a mark string for it.
X*/
X
XInitMSpec (mSpec)
XMapSpec	*mSpec;
X{
X	mSpec->mark = (StringHandle) NewHandle ((Size) maxMarkLen + 1);
X}
X
X
X/*
X	Terminate a MapSpec by tossing its mark string.  The procedure
X	name is somewhat of a misnomer since it doesn't actually dispose
X	of the MapSpec itself.
X*/
X
XTermMSpec (mSpec)
XMapSpec	*mSpec;
X{
X	DisposHandle (mSpec->mark);
X}
X
X
X/*
X	Copy one init'ed MapSpec to another.  The most difficult part
X	is making sure the mark string gets copied correctly.
X*/
X
XCopyMSpec (srcMSpec, dstMSpec)
Xregister MapSpec	*srcMSpec, *dstMSpec;
X{
Xregister StringHandle	srcStr, dstStr;
X
X	dstStr = dstMSpec->mark;		/* save, since next line clobbers it */
X	*dstMSpec = *srcMSpec;
X	dstMSpec->mark = dstStr;		/* fix this field and copy the handle */
X	srcStr = srcMSpec->mark;
X	HLock (srcStr);
X	HLock (dstStr);
X	CopyString (*srcStr, *dstStr);
X	HUnlock (srcStr);
X	HUnlock (dstStr);
X	/*SetHandleSize (dstStr, (Size) 0);
X	HandAndHand (srcMSpec->mark, dstStr);*/
X}
X
X
X/*
X	Zero the contents of an init'ed MapSpec.
X*/
X
X
XClearMSpec (mSpec)
Xregister MapSpec	*mSpec;
X{
X	mSpec->font = sameFont;
X	mSpec->size = sameSize;
X	mSpec->style = sameStyle;
X	(*mSpec->mark)[0] = 0;
X	mSpec->selStart = 0;
X	mSpec->selEnd = 0;
X}
X
X
X/*
X	Compare two markers for equality.
X*/
X
XCompareMark (s1, s2)
XStringHandle	s1, s2;
X{
XInteger		result;
X
X	HLock (s1);
X	HLock (s2);
X	result = CompareString (*s1, *s2);
X	HUnlock (s1);
X	HUnlock (s2);
X	return (result);
X}
X
X
X/*
X	Compare two map specifications.
X	Return:
X		0		m1 = m2
X		< 0		m1 < m2
X		> 0		m1 > m2
X
X	Mark sorts before font, which sorts before size, which sorts
X	before style.
X
X	For all of font, size and style, the "same" selection is greater,
X	so that generic selections sort to the end of the list.  Font
X	comparisons are otherwise based on the name of the font, rather
X	than its number.   A string compare is avoided by keeping the
X	fonts in alphabetic order in the font information structures.
X
X	Note that the style comparison does not use the manifest constants
X	defined for each style value, and so would break if style coding
X	changed!
X*/
X
XCompareMSpec (m1, m2)
Xregister MapSpec	*m1, *m2;
X{
Xregister Integer	i;
Xregister Integer	s1, s2;
X
X	if ((i = CompareMark (m1->mark, m2->mark)) != 0)
X		return (i);
X
X	if (m1->font != m2->font)
X	{
X		if (m1->font == sameFont)
X			return (1);
X		if (m2->font == sameFont)
X			return (-1);
X		return (FontIndex (m1->font) - FontIndex (m2->font));
X	}
X
X	if ((i = m1->size - m2->size) != 0)
X	{
X		if (m1->size == sameSize)
X			return (1);
X		if (m2->size == sameSize)
X			return (-1);
X		return (i);
X	}
X
X	s1 = m1->style;
X	s2 = m2->style;
X	if (s1 - s2 != 0)
X	{
X		if (s1 == sameStyle)
X			return (1);
X		if (s2 == sameStyle)
X			return (-1);
X		for (i = 0; i < 7; ++i)
X		{
X			if (s1 == 0)
X			{
X				if (s2 != 0)
X					return (-1);
X			}
X			else if (s2 == 0)
X			{
X				return (1);
X			}
X			else if (s1 & 1)
X			{
X				if (!(s2 & 1))
X					return (-1);
X			}
X			else if (s2 & 1)
X				return (1);
X			s1 >>= 1;
X			s2 >>= 1;
X		}
X	}
X	return (0);			/* equal */
X}
X
X
X/*
X	Convert map specs to map text.  Do this by converting input specs
X	and output specs.
X*/
X
XMSpecToMStr (mSpec, mStr)
Xregister MapSpec	*mSpec;
Xregister MapStr		*mStr;
X{
X	HLock (mSpec->mark);
X	CopyString (*mSpec->mark, mStr->markStr);
X	HUnlock (mSpec->mark);
X	FontToStr (mSpec->font, mStr->fontStr);
X	SizeToStr (mSpec->size, mStr->sizeStr);
X	StyleToStr (mSpec->style, mStr->styleStr);
X}
X
X
X/*
X	Convert font number to font name.  The font *must* be legal.
X*/
X
XFontToStr (font, str)
Xregister Integer		font;
Xregister StringPtr	str;
X{
X	FontName (FontIndex (font), str);
X}
X
X
X/*
X	Convert size value to string.
X*/
X
XSizeToStr (size, str)
Xregister Integer		size;
Xregister StringPtr	str;
X{
X	if (size == sameSize)		/* no size specified, use default */
X		CopyString ("\pSame", str);
X	else
X		NumToString ((Longint) size, str);
X}
X
X
X/*
X	Convert style value to string. If the style has only one attribute
X	bit set, use the attribute name, otherwise use abbreviated form with
X	one letter for each attribute.
X*/
X
Xstatic StringPtr	styleStr[7] =
X{
X	(StringPtr) "\pBold",
X	(StringPtr) "\pItalic",
X	(StringPtr) "\pUnder",
X	(StringPtr) "\pOutline",
X	(StringPtr) "\pShadow",
X	(StringPtr) "\pHigh",
X	(StringPtr) "\pLow"
X};
X
X
XStyleToStr (style, str)
Xregister Integer		style;
Xregister StringPtr	str;
X{
Xregister Integer	i, style2;
X
X	if (style == sameStyle)		/* no style specified, use default */
X		CopyString ("\pSame", str);
X	else if (style == 0)			/* no bits set = plain text */
X		CopyString ("\pPlain", str);
X	else
X	{
X		style2 = style;
X		for (i = 0; i < 7; ++i)
X		{
X			if ((style2 & 1))
X			{
X				if (style2 != 1)
X					break;			/* more than 1 bit set */
X				CopyString (styleStr[i], str);
X				return;
X			}
X			style2 >>= 1;
X		}
X		i = 0;
X		if (style & styleBold)
X			str[++i] = 'B';
X		if (style & styleItalic)
X			str[++i] = 'I';
X		if (style & styleUnder)
X			str[++i] = 'U';
X		if (style & styleOutline)
X			str[++i] = 'O';
X		if (style & styleShadow)
X			str[++i] = 'S';
X		if (style & styleSuper)
X			str[++i] = 'H';
X		if (style & styleSub)
X			str[++i] = 'L';
X		str[0] = i;
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMain.c
X# include	"MakeWrite.h"
X
X
X/*
X	Offsets of each field in the map and font lists.  There is one
X	extra value, which is actually the offset of the right edge of
X	the last field.  These offsets are relative to the text area.
X*/
X
X
X# define	mapFields	4		/* number of fields in mapping */
X
X
Xstatic Integer		mapOffsets[mapFields + 1] =
X{
X	0,
X	100,
X	217,
X	257,
X	313
X};
X
X
Xstatic LineList	mapStruct =
X{
X	nil,						/* port - filled in later        */
X	nil,						/* control - filled in later     */
X	{ 150, 124, 246, 436 },		/* text display rect, t, l, b, r */
X	0,							/* max lines (set by InitList)   */
X	6,							/* max visible lines             */
X	0,							/* top visible line              */
X	16,							/* line height                   */
X	0,							/* number of lines               */
X	noLine,						/* current line                  */
X	false,						/* no hiliting                   */
X	mapFields,					/* number of fields/line         */
X	mapOffsets,					/* field offsets                 */
X	nil							/* line array (set by InitList)  */
X};
X
X
X
XWindowPtr	mapWind;
X
XListPtr		mapList = &mapStruct;
XMapSpec		mapSpec[maxMappings];
X
XBoolean		mapModified = false;
X
XInteger			undoOp = noUndo;
XInteger			undoVal;
XInteger			undoPos;
XInteger			undoFieldType;
XMapSpec		undoMSpec;
XBoolean		undoCPMarker;
X
XBoolean		havePasteMSpec = false;	/* for setting Paste menu item */
X
XBoolean		cpMarker = false;	/* whether cut/paste applies to marker */
X
X
X/*
X	Paragraph style control
X
X	Default is "every line a paragraph", ignore command-only lines
X*/
X
XParaStyle	paraStyle;
X
XStr255	paraMark;	/* paragraph marker string */
XStr255	pageMark;	/* page break marker string */
XStr255	periodStr;	/* sentence "periods" (terminators) */
XStr255	quoteStr;	/* quotes to ignore after periods */
X
X# ifdef	debug
XBoolean	debugOut = false;	/* controls debugging output during format */
X# endif
X
X
Xmain ()
X{
X	SkelInit ();
X	InitParaStyle ();
X	SetupMenus ();
X	MapSetup ();
X	SkelMain ();
X	SkelClobber ();
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMapOps.c
X# include	"MakeWrite.h"
X
X
X/*
X	Check whether a MapSpec already exists in the map
X*/
X
XBoolean StatMSpec (mSpec)
XMapSpec	*mSpec;
X{
Xregister Integer	i;
X
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		if (CompareMSpec (mSpec, &mapSpec[i]) == 0)
X			return (true);
X	}
X	return (false);
X}
X
X
X
X/*
X	Insert the text of all the fields for the given map list line.
X
X	This routines relies implicitly on the ordering of fields
X	within a map line.
X*/
X
Xstatic SetMapFields (hLine, mStr)
Xregister LineHandle	hLine;
Xregister MapStr		*mStr;
X{
Xregister FieldHandle	hField;
X
X	hField = hLine;
X	SetFieldStr (hField, mStr->markStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->fontStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->sizeStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->styleStr);
X}
X
X
X/*
X	Select a mapping
X*/
X
XSelectMapping (lineNo)
Xregister Integer	lineNo;
X{
X	SelectLine (mapList, lineNo);
X	if (lineNo != noLine)
X		ScrollToLine (mapList, lineNo);
X	SetSelectors (lineNo);
X}
X
X
X/*
X	Insert a new mapping, making it mapping n.  This takes care
X	of both the specification array, and the list of text representations
X	of the mappings.
X
X	Note that there's no explicit count of mappings.  Use the count
X	in the LineList corresponding to the mapping array is used.
X*/
X
XBoolean InsertMapping (mSpec, n)
XMapSpec	*mSpec;
XInteger		n;
X{
XMapStr				mStr;
Xregister LineHandle	hLine;
Xregister Integer		i, nLines;
XStr255				s;
X
X	if (mapList->nLines < mapList->maxLines)
X	{
X
X/*
X	Convert mapping specification into string form and put the strings
X	into a new line to be inserted into the line list.
X
X	Then make room for the new mapping in spec array and insert it.
X*/
X
X		nLines = mapList->nLines;		/* save; InsertLine changes it */
X		MSpecToMStr (mSpec, &mStr);		/* convert specs to strings */
X		hLine = NewLine (mapList->nFields);
X		SetMapFields (hLine, &mStr);
X		if (InsertLine (mapList, hLine, n) == false)
X		{
X			DisposeLine (hLine);
X		}
X		else
X		{
X/*
X	Move specs around to make room, then add the new one
X	in the empty slot.
X*/
X			for (i = nLines; i > n; --i)
X			{
X				CopyMSpec (&mapSpec[i-1], &mapSpec[i]);
X			}
X			CopyMSpec (mSpec, &mapSpec[n]);
X			/*mapSpec[n].selStart = 0;
X			mapSpec[n].selEnd = 32767;*/
X			SelectMapping (n);
X			/*SetCPMarker (true);*/
X			return (true);
X		}
X	}
X	NumToString ((Longint) mapList->maxLines, s);
X	Message3 ("\pMap is full (", s, "\p lines).  Can't add anything to it.");
X	return (false);
X}
X
X
X/*
X	Add a new, blank, mapping to the end of the list.
X	This should be different - the handle should be copied in InsertMapping.
X*/
X
XNewMapping ()
X{
XMapSpec	mSpec;
X
X	InitMSpec (&mSpec);
X	ClearMSpec (&mSpec);
X	(void) InsertMapping (&mSpec, mapList->nLines);
X	TermMSpec (&mSpec);
X}
X
X
X/*
X	Duplicate the currently selected mapping and add right after the
X	selection.
X*/
X
XDupMapping (n)
X{
X	(void) InsertMapping (&mapSpec[n], n+1);
X}
X
X
X/*
X	Replace the currently selected mapping with the given one.
X	(It's assumed that there *is* one selected.)
X*/
X
XPasteMapping (mSpec, n)
XMapSpec	*mSpec;
XInteger		n;
X{
XMapStr			mStr;
Xregister Integer	curLine;
X
X	curLine = mapList->curLine;
X	CopyMSpec (mSpec, &mapSpec[curLine]);
X	MSpecToMStr (mSpec, &mStr);
X	SetMapFields (ListLine (mapList, curLine), &mStr);
X	DrawLine (mapList, curLine);
X	SetSelectors (curLine);				/* set selection controls */
X}
X
X
X/*
X	Clobber the n'th mapping.
X*/
X
XDeleteMapping (n)
Xregister Integer	n;
X{
Xregister Integer	i;
X
X	for (i = n; i < mapList->nLines; ++i)
X	{
X		CopyMSpec (&mapSpec[i+1], &mapSpec[i]);		/* copy specs */
X	}
X	DeleteLine (mapList, n);
X	SelectMapping (noLine);
X	ScrollToLine (mapList, n);
X}
X
X
X/*
X	Clobber entire map.
X*/
X
XClobberMap ()
X{
X	SelectMapping (noLine);
X	ResetList (mapList);
X	InitParaStyle ();
X}
X
X
X
X/*
X	Sort the map specifications on the input format values.  Make
X	sure to keep track of the current spec and redraw the text 
X	and controls properly when done.
X*/
X
XSortMap ()
X{
Xregister Integer		i, j, curLine;
Xregister LineHandle	tmpLine;
XMapSpec				tmpSpec;
X
X	InitMSpec (&tmpSpec);
X	curLine = mapList->curLine;
X	for (i = 0; i < mapList->nLines - 1; ++i)
X	{
X		for (j = i; j < mapList->nLines; ++j)
X		{
X			if (CompareMSpec (&mapSpec[i], &mapSpec[j]) > 0)
X			{
X				CopyMSpec (&mapSpec[i], &tmpSpec);
X				CopyMSpec (&mapSpec[j], &mapSpec[i]);
X				CopyMSpec (&tmpSpec, &mapSpec[j]);
X				tmpLine = ListLine (mapList, i);
X				ListLine (mapList, i) = ListLine (mapList, j);
X				ListLine (mapList, j) = tmpLine;
X				if (curLine == i)
X					curLine = j;
X				else if (curLine == j)
X					curLine = i;
X			}
X		}
X	}
X	DrawListText (mapList);
X	SelectMapping (curLine);
X	TermMSpec (&tmpSpec);
X}
X
X
X/*
X	Eliminate duplicates in the map.  The loops must explicitly
X	test mapList->nLines, not a variable set equal to that before
X	the loops, since DeleteMapping causes mapList->nLines to change.
X*/
X
XSquishMap ()
X{
Xregister Integer	i, j;
X
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		j = i + 1;
X		while (j < mapList->nLines)
X		{
X			if (CompareMSpec (&mapSpec[i], &mapSpec[j]) == 0)
X				DeleteMapping (j);
X			else
X				++j;
X		}
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMapWind.c
X# include	<TextEdit.h>
X# include	"MakeWrite.h"
X
X
X# define	tab			'\t'
X# define	shiftKey	0x0200
X# define	applFont	1
X
X
X/*
X	Local data for creating controls
X*/
X
X
X/*
X	maxSize = number of point-size selection radio buttons
X	maxStyle = number of style selection check boxes
X	maxCP = number of edit menu cut/paste indicator controls
X	maxCtrl = sum of above three
X	maxFonts = maximum number of fonts allowed in scrollable list
X*/
X
X# define	maxSize		7
X# define	maxStyle	9
X# define	maxCP		2
X# define	maxCtrl		(maxSize+maxStyle+maxCP)
X# define	maxFonts	102
X
X
Xtypedef enum	/* control types, by function */
X{
X	sizeType,	/* size radio button */
X	styleType,	/* style check box */
X	cpType		/* edit menu check box */
X};
X
X
Xtypedef struct CtrlInfo
X{
X	Str255	cTitle;		/* initial control title */
X	Integer		ch, cv;		/* location of upper left corner */
X} CtrlInfo;
X
X
Xstatic CtrlInfo	ctrlInfo[maxCtrl] =
X{
X	{ "\pSame",				181,	20 },
X	{ "\p9",				172,	40 },
X	{ "\p10",				172,	60 },
X	{ "\p12",				172,	80 },
X	{ "\p14",				217,	40 },
X	{ "\p18",				217,	60 },
X	{ "\p24",				217,	80 },
X	{ "\pSame",				312,	20 },
X	{ "\pPlain",			265,	40 },
X	{ "\pBold",				265,	60 },
X	{ "\pItalic",			265,	80 },
X	{ "\pUnderline",		265,	100 },
X	{ "\pOutline",			355,	40 },
X	{ "\pShadow",			355,	60 },
X	{ "\pSuperscript",		355,	80 },
X	{ "\pSubscript",		355,	100 },
X	{ "\pMarker",			9,		210 },
X	{ "\pMap Lines",		9,		230 }
X};
X
X
Xstatic ControlHandle	sizeCtrl[maxSize];
Xstatic ControlHandle	styleCtrl[maxStyle];
Xstatic ControlHandle	cpCtrl[maxCP];
X
X
X
X/*
X	Standard MacWrite point sizes, plus the "same size" selection.
X	The order of these corresponds to the size radio buttons.
X*/
X
Xstatic Integer		sizeInfo[maxSize] = { sameSize, 9, 10, 12, 14, 18, 24 };
X
X
X/*
X	Masks for manipulating style selections.  The order of these
X	corresponds to the style check boxes.
X*/
X
X
Xstatic Integer		styleMask[maxStyle] =
X{
X	sameStyle,
X	0,				/* plain; special-cased */
X	styleBold,
X	styleItalic,
X	styleUnder,
X	styleOutline,
X	styleShadow,
X	styleSuper,
X	styleSub
X};
X
X
X/*
X	Standard font specifications
X*/
X
X
Xtypedef struct
X{
X	Integer				fontNum;
X	StringHandle	fontName;
X} FontSpec;
X
X
Xstatic FontSpec	fontSpecs[maxFonts];
Xstatic Integer		nFontSpecs;
X
X
Xstatic Integer		fontOffsets[2] = { 0, 137 };
X
X
Xstatic LineList	fontStruct =
X{
X	nil,						/* port - filled in later        */
X	nil,						/* control - filled in later     */
X	{ 20, 5, 116, 141 },		/* text display rect, t, l, b, r */
X	0,							/* max lines                     */
X	6,							/* max visible lines             */
X	0,							/* top visible line              */
X	16,							/* line height                   */
X	0,							/* number of lines               */
X	noLine,						/* current line                  */
X	false,						/* no hiliting                   */
X	1,							/* number of fields/line         */
X	fontOffsets,				/* field offsets                 */
X	nil							/* line array                    */
X};
X
X
Xstatic ListPtr	fontList = &fontStruct;
X
Xstatic MapSpec	*curMSpec;
Xstatic Integer		curMSpecNo;
X
Xstatic TEHandle	markTE;
X
X
X/* ---------------------------------------------------------------- */
X/*					General Control Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X
X/*
X	Set a control value, but only when it changes, to avoid
X	unnecessary redrawing (ugly, since gobs of them are usually
X	changed together).
X
X	Use for check boxes and radio buttons only, not scroll bars!
X*/
X
Xstatic SetControl (ctrl, value)
XControlHandle	ctrl;
XBoolean			value;
X{
X	if (GetCtlValue (ctrl) != value)
X		SetCtlValue (ctrl, value);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Font List Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Add a font to the spec list.  Return false if there's overrun.
X*/
X
XBoolean SetFontSpec (fNum, fName)
XInteger			fNum;
XStringPtr	fName;
X{
Xregister StringHandle	h;
XStr255					s;
Xregister Integer			i, result;
X
X	for (i = 0; i < nFontSpecs; ++i)	/* see if already there */
X	{
X		h = fontSpecs[i].fontName;
X		HLock (h);
X		result = CompareString (*h, fName);
X		HUnlock (h);
X		if (result == 0)		/* font name's a duplicate */
X			return (true);		/* but that's ok */
X	}
X
X	if (nFontSpecs >= fontList->maxLines)	/* will list be too full? */
X	{
X		NumToString ((Longint) maxFonts - 2, s);
X		Message3 ("\pSorry, I am such a brain-damaged program that I only allow ",
X					s, "\p fonts!");
X		return (false);
X	}
X
X	h = (StringHandle) NewHandle ((Longint) (fName[0] + 1));
X	HLock (h);
X	CopyString (fName, *h);
X	HUnlock (h);
X	fontSpecs[nFontSpecs].fontName = h;
X	fontSpecs[nFontSpecs++].fontNum = fNum;
X	return (true);
X}
X
X
X/*
X	Set up to construct a new font list.  Note that the other
X	selector controls must have been initialized by this point.
X*/
X
XResetFontList ()
X{
Xregister Integer	i;
X
X	for (i = 0; i < fontList->nLines; ++i)
X		DisposHandle (fontSpecs[i].fontName);
X	nFontSpecs = 0;
X	ResetList (fontList);
X	SetFontSpec (sameFont, "\pSame");
X	SetFontSpec (applFont, "\pApplication");
X}
X
X
X/*
X	Sync information in fontSpec to fontList by constructing the LineList
X	elements.
X*/
X
XSyncFontSpecs ()
X{
Xregister Integer		i, j;
XInteger					tmp;
Xregister FontSpec	*f1, *f2;
XStringHandle		h1, h2;
XLineHandle			hField;
X
X/*
X	Sort font names, except for "Same" and "Application", which
X	stay at the front of the list.
X*/
X
X	for (i = 2; i < nFontSpecs - 1; ++i)
X	{
X		for (j = i + 1; j < nFontSpecs; ++j)
X		{
X			f1 = &fontSpecs[i];
X			f2 = &fontSpecs[j];
X			h1 = f1->fontName;
X			h2 = f2->fontName;
X			HLock (h1);
X			HLock (h2);
X			if (CompareString (*h1, *h2) > 0)
X			{
X				f1->fontName = h2;
X				f2->fontName = h1;
X				tmp = f1->fontNum;
X				f1->fontNum = f2->fontNum;
X				f2->fontNum = tmp;
X			}
X			HUnlock (h1);
X			HUnlock (h2);
X		}
X	}
X
X/*
X	Add names to fontList
X*/
X
X	ResetList (fontList);
X	for (i = 0; i < nFontSpecs; ++i)
X	{
X		h1 = fontSpecs[i].fontName;
X		HLock (h1);
X		hField = NewLine (1);
X		SetFieldStr (hField, *h1);
X		HUnlock (h1);
X		(void) InsertLine (fontList, hField, i);
X	}
X	SelectLine (fontList, 0);
X	ScrollToLine (fontList, 0);		/* force scroll to top */
X}
X
X
X/*
X	Given a font number, find its index in the stdFontSpecs
X	array.  Return -1 if it's not there.
X*/
X
XFontIndex (fontNum)
XInteger		fontNum;
X{
Xregister Integer		i;
X
X	for (i = 0; i < fontList->nLines; ++i)
X	{
X		if (fontNum == fontSpecs[i].fontNum)
X			return (i);
X	}
X	return (-1);
X}
X
X
X/*
X	Return a font name corresponding to the given index
X*/
X
XFontName (fontIndex, str)
XInteger			fontIndex;
XStringPtr	str;
X{
XStringHandle	hStr;
X
X	hStr = fontSpecs[fontIndex].fontName;
X	HLock (hStr);
X	CopyString (*hStr, str);
X	HUnlock (hStr);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Size Control Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Given a point size, find its index in the sizeInfo
X	array.  (Return -1 if it's not there.)
X*/
X
XSizeIndex (size)
XInteger		size;
X{
Xregister Integer		i;
X
X	for (i = 0; i < maxSize; ++i)
X	{
X		if (size == sizeInfo[i])
X			return (i);
X	}
X	return (-1);
X}
X
X
Xstatic SetSizeCtrls ()
X{
Xregister Integer		i;
X
X	for (i = 0; i < maxSize; ++i)
X		SetControl (sizeCtrl[i], sizeInfo[i] == curMSpec->size);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Style Control Operations					*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Set the style controls based on the current value of theStyle.
X
X	The sameStyle bit and the attributes bits cause the corresponding
X	boxes to be checked if they are set.  If the style is zero, it's
X	plain.
X*/
X
Xstatic SetStyleCtrls ()
X{
Xregister Integer		i;
Xregister Boolean	same;
Xregister Integer		theStyle;
X
X	theStyle = curMSpec->style;
X	same = ((theStyle & sameStyle) != 0);
X	SetControl (styleCtrl[0], same);
X
X	if (same)
X	{
X		for (i = 1; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X	}
X	else if (theStyle == 0)					/* plain */
X	{
X		SetControl (styleCtrl[1], true);
X		for (i = 2; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X	}
X	else									/* not plain */
X	{
X		SetControl (styleCtrl[1], false);
X		for (i = 2; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], (theStyle & styleMask[i]) != 0);
X	}
X}
X
X
X/*
X	Determine style value.  The argument is an index into the control
X	array not a style value itself.  Style controls interact in
X	wretched complexity.
X
X	If same is toggled on, all the other style boxes are toggled off.
X	If it's toggled off, plain is toggled on.
X
X	If plain is toggled on, all the other style boxes are toggled off.
X	If it's toggled off, same is toggled on.
X
X	The other style boxes correspond to style attributes.  If any of
X	them are toggled on, then same and plain are toggle off if
X	they were on.  If all the attributes are toggled off, plain is
X	toggled on.  Superscript and subscript are mutually exclusive,
X	so that if one of them is toggled on, the other is toggled off.
X*/
X
Xstatic NewStyleValue (i)
Xregister Integer	i;
X{
Xregister Integer	curValue;
Xregister Integer	theStyle;
X
X	curValue = GetCtlValue (styleCtrl[i]);	/* current value - new value */
X											/* will be opposite */
X	theStyle = curMSpec->style;
X
X	if (i == 0)			/* "same" box clicked */
X	{
X		if (curValue)	/*  currently same, turn off (implies plain) */
X			theStyle = 0;
X		else
X			theStyle = styleMask[0];	/* currently off, turn on */
X	}
X	else if (i == 1)	/* plain box clicked */
X	{
X		if (curValue)	/*  currently plain, turn off (implies same) */
X			theStyle = styleMask[0];
X		else
X			theStyle = 0;	/* currently off, turn on */
X	}
X	else
X	{
X	/*
X		Flip box value.
X		Can't have superscript and subscript at the same time.
X	*/
X		if (curValue)	/* currently on, turn off */
X			theStyle &= ~styleMask[i];
X		else			/* currently off, turn on (turn same off) */
X		{
X			theStyle |= styleMask[i];
X			theStyle &= ~styleMask[0];
X		}
X
X		if (i == 7)	/* superscript.  if turning on, turn off sub */
X		{
X			if (curValue == 0)
X				theStyle &= ~styleMask[8];
X		}
X		if (i == 8)	/* subscript.  if turning on, turn off super */
X		{
X			if (curValue == 0)
X				theStyle &= ~styleMask[7];
X		}
X	}
X	return (theStyle);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*				Edit Menu Cut/Paste Control Operations				*/
X/* ---------------------------------------------------------------- */
X
X
Xstatic SetCPCtrls ()
X{
X	SetControl (cpCtrl[0], cpMarker);
X	SetControl (cpCtrl[1], !cpMarker);
X}
X
X
XSetCPMarker (useMarker)
XBoolean	useMarker;
X{
X	cpMarker = useMarker;
X	SetCPCtrls ();
X}
X
X
XBlankCPCtrls ()
X{
X	SetControl (cpCtrl[0], false);
X	SetControl (cpCtrl[1], false);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*							Marker Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Sync the marker edit text to a mapSpec
X*/
X
XMSpecToMark (m)
XMapSpec	*m;
X{
XStringHandle	s;
XRect			r;
X
X	s = m->mark;
X	HLock (s);
X	TESetSelect (0L, 32767L, markTE);
X	TEDelete (markTE);
X	TEInsert (*s + 1, (Longint) (*s)[0], markTE);	/* replace text */
X	HUnlock (s);
X	TESetSelect ((Longint) m->selStart, (Longint) m->selEnd, markTE);
X}
X
X
X/*
X	Sync current mapSpec to the marker edit text
X*/
X
Xstatic MarkToMSpec ()
X{
XStringHandle	hStr;
XHandle			h;
XInteger				len;
X
X	curMSpec->selStart = (**markTE).selStart;
X	curMSpec->selEnd = (**markTE).selEnd;
X	h = TEGetText (markTE);
X	len = (**markTE).teLength;
X	if (len > maxMarkLen)
X		len = maxMarkLen;		/* truncate length if necessary */
X	hStr = curMSpec->mark;
X	HLock (h);
X	HLock (hStr);
X	BlockMove (*h, *hStr + 1, (Longint) len);
X	(*hStr)[0] = len;
X	HUnlock (h);
X	PasteField (mapList, mapList->curLine, markField, *hStr);
X	HUnlock (hStr);
X}
X
X
Xtypedef enum		/* relevant Edit menu item numbers */
X{
X	cut = 3,
X	copy,
X	paste,
X	clear
X};
X
X
XMarkerUndoSetup ()
X{
X	CopyMSpec (curMSpec, &undoMSpec);
X	undoOp = undoMarkerOp;
X	undoPos = mapList->curLine;
X	undoCPMarker = cpMarker;
X}
X
X
XBoolean EditMarker (item)
XInteger		item;
X{
X	if (!cpMarker)
X		return (false);
X
X	switch (item)
X	{
X	
X	case cut:
X		MarkerUndoSetup ();
X		TECut (markTE);
X		(void) ZeroScrap ();
X		(void) TEToScrap ();
X		break;
X	
X	case copy:
X		TECopy (markTE);
X		(void) ZeroScrap ();
X		(void) TEToScrap ();
X		break;
X	
X	case paste:
X		if (curMSpec == nil)	/* ignore if no line selected */
X			return (false);
X		MarkerUndoSetup ();
X		(void) TEFromScrap ();
X		TEPaste (markTE);
X		break;
X	
X	case clear:
X		MarkerUndoSetup ();
X		(void) TEDelete (markTE);
X		break;
X	
X	default:
X		return (false);	/* all others handled by general */
X						/* edit menu handler */
X
X	}
X
X	MarkToMSpec (curMSpec);	/* sync map with change in mark */
X	if (item != copy)
X		mapModified = true;
X	FixMenus ();
X	return (true);
X}
X
X
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Set a field in the currently selected line.  Don't call this if
X	no line is selected, or if the field already has the same value.
X*/
X
XSetMapFieldValue (fieldType, value)
XInteger		fieldType;
XInteger		value;
X{
XStr255		s;
X
X	switch (fieldType)
X	{
X
X	case fontField:
X		undoVal = curMSpec->font;
X		FontToStr (value, s);
X		curMSpec->font = value;
X		SelectLine (fontList, FontIndex (value));
X		break;
X
X	case sizeField:
X		undoVal = curMSpec->size;
X		SizeToStr (value, s);
X		curMSpec->size = value;
X		SetSizeCtrls ();
X		break;
X
X	case styleField:
X		undoVal = curMSpec->style;
X		StyleToStr (value, s);
X		curMSpec->style = value;
X		SetStyleCtrls ();
X		break;
X	}
X
X	PasteField (mapList, mapList->curLine, fieldType, s);
X	mapModified = true;
X	undoOp = undoFieldChg;
X	undoFieldType = fieldType;
X}
X
X
X/*
X	Set the selection controls and font list to reflect currently
X	selected conversion specification.  Also sets current MapSpec
X	pointer.
X*/
X
XSetSelectors (lineNo)
XInteger		lineNo;
X{
Xregister Integer	i;
X
X	if (lineNo == noLine)				/* no map line selected */
X	{
X
X		curMSpec = nil;
X		curMSpecNo = noLine;
X
X		ListActivate (fontList, false);
X	
X		for (i = 0; i < maxSize; ++i)
X			SetControl (sizeCtrl[i], false);
X	
X		for (i = 0; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X
X		TESetSelect (0L, 32767L, markTE);
X		TEDelete (markTE);
X		TEDeactivate (markTE);
X
X		return;
X	}
X
X	curMSpec = &mapSpec[curMSpecNo = lineNo];
X
X	SelectLine (fontList, FontIndex (curMSpec->font));
X	ListActivate (fontList, true);
X	ScrollToLine (fontList, fontList->curLine);
X	SetSizeCtrls ();
X	SetStyleCtrls ();
X	MSpecToMark (curMSpec);
X	TEActivate (markTE);
X	/*SetCPCtrls ();*/
X}
X
X
X/*
X	Map window mouse handler.
X
X	First test the scroll bars, and return if one was hit; they
X	require no further action.
X
X	Then check for hit in map list.  If a new line was selected, set
X	the selectors to the values, and disable undo.
X
X	Then, if a line is currently selected, check the selection controls.
X	If one is hit, change the values in the current line and reset the
X	controls properly - but only if the current values *change*.
X*/
X
Xstatic Mouse (pt, t, mods)
XPoint	pt;
XLongint	t;
XInteger		mods;
X{
XControlHandle	ctrl;
XInteger				index;
XInteger				type;
XLongint			refCon;
XInteger				newVal;
XBoolean			newIO;
XInteger				curLine;
XRect			r;
X
X	if (ListTestScroll (mapList, pt) || ListTestScroll (fontList, pt))
X		return;
X
X	curLine = mapList->curLine;				/* current line */
X	if (ListTestText (mapList, pt))
X	{
X		if (curLine != mapList->curLine)	/* different now? */
X		{
X			undoOp = noUndo;
X			if ((curLine = mapList->curLine) != noLine)
X			{
X				mapSpec[curLine].selStart = 0;
X				mapSpec[curLine].selEnd = 32767;
X			}
X			/*SetCPMarker (true);*/
X			SetSelectors (curLine);
X			FixMenus ();
X		}
X		return;
X	}
X
X	if (curMSpec == nil)
X		return;				/* no current line - controls irrelevant */
X
X	if (ListTestText (fontList, pt))
X	{
X		if (fontList->curLine == noLine)
X			SelectLine (fontList, fontList->nLines - 1);
X		newVal = fontSpecs[fontList->curLine].fontNum;	
X		if (curMSpec->font != newVal)
X		{
X			SetMapFieldValue (fontField, newVal);
X			FixMenus ();
X		}
X		return;
X	}
X
X/*
X	Check the edittext box
X*/
X
X	r = (**markTE).viewRect;
X	InsetRect (&r, -3, -3);
X	if (PtInRect (pt, &r))
X	{
X		undoOp = noUndo;
X		SetCPMarker (true);
X		TEClick (pt, (mods & shiftKey) != 0, markTE);
X		curMSpec->selStart = (**markTE).selStart;
X		curMSpec->selEnd = (**markTE).selEnd;
X		FixMenus ();
X		return;
X	}
X
X
X/*
X	Don't need to check control type returned from FindControl - at
X	this point, it can't be anything but inCheckBox.  The control type
X	and index is coded in the reference constant (see MakeControl).
X*/
X
X	if (FindControl (pt, mapWind, &ctrl))
X	{
X		if (TrackControl (ctrl, pt, nil) == inCheckBox)
X		{
X			refCon = GetCRefCon (ctrl);
X			index = refCon & 0x00ff;
X			type = (refCon & 0xff00) >> 8;
X
X			switch (type)
X			{
X
X			case sizeType:
X				newVal = sizeInfo[index];
X				if (newVal != curMSpec->size)
X					SetMapFieldValue (sizeField, newVal);
X				break;
X
X			case styleType:
X				newVal = NewStyleValue (index);
X				if (newVal != curMSpec->style)
X					SetMapFieldValue (styleField, newVal);
X				break;
X
X			case cpType:
X				SetCPMarker (index == 0);
X				undoOp = noUndo;
X				break;
X
X			}
X
X			FixMenus ();
X		}
X		return;
X	}
X}
X
X
X/*
X	Process key click in window for mark string.  On the first key
X	after any other operation, save the current mark string state
X	for undo.  And on every key click, save the selection range.  This
X	is so the range can be saved properly if the window is inactivated
X	and later activated, or if another line is selected and then this
X	line is reselected.
X*/
X
Xstatic Key (c, mods)
Xchar	c;
XInteger		mods;
X{
XHandle			h;
XStringHandle	s;
XInteger				len;
X
X	if (curMSpec == nil)
X		return;
X
X	switch (c)
X	{
X	
X	case tab:
X	case enter:
X	case cr:
X		undoOp = noUndo;
X		if (mods & shiftKey)
X		{
X			if (--curMSpecNo < 0)
X				curMSpecNo = mapList->nLines - 1;
X		}
X		else
X		{
X			if (++curMSpecNo >= mapList->nLines)
X				curMSpecNo = 0;
X		}
X		SelectMapping (curMSpecNo);
X		break;
X
X	default:
X		if (undoOp != undoTyping)	/* first char typed */
X		{
X			MarkerUndoSetup ();
X			undoOp = undoTyping;
X		}
X
X		TEKey (c, markTE);
X		MarkToMSpec (curMSpec);
X		SetCPMarker (true);
X		mapModified = true;
X		FixMenus ();
X
X	}
X}
X
X
Xstatic Update (resized)
XBoolean	resized;
X{
Xregister Integer	i;
XRect	r;
X
X	MoveTo (65, 14);
X	DrawString ("\pFont");
X	MoveTo (180, 14);
X	DrawString ("\pPoint Size");
X	MoveTo (322, 14);
X	DrawString ("\pStyle");
X	MoveTo (30, 145);
X	DrawString ("\pMarker");
X	MoveTo (4, 190);
X	DrawString ("\pCut & Paste Ops");
X	MoveTo (4, 206);
X	DrawString ("\pAffect:");
X	MoveTo (212, 143);
X	DrawString ("\pFormat Specifications");
X	DrawControls (mapWind);
X	r = (**markTE).viewRect;
X	EraseRect (&r);
X	TEUpdate (&r, markTE);
X	InsetRect (&r, -3, -3);
X	FrameRect (&r);
X	DrawListFrame (fontList);
X	DrawListFrame (mapList);
X	DrawListText (fontList);
X	DrawListText (mapList);
X}
X
X
X/*
X	When the window is activated, do appropriate map list and font list
X	line and scroll bar hiliting, and set size and style controls to
X	current values.
X
X	When the window is deactivated, all hiliting is turned off, the
X	scroll bars are unhilited and the size and style controls go blank.
X
X	Note that SetSelectrs takes care of setting font list line and scroll
X	bar hiliting; it doesn't have to be done here.  It also activates
X	or deactivates the text field properly.
X*/
X
Xstatic Activate (active)
XBoolean	active;
X{
X	if (active)
X	{
X		DoUpdates ();
X		ListActivate (mapList, true);
X		SetSelectors (mapList->curLine);
X	}
X	else
X	{
X		SetSelectors (noLine);
X		ListActivate (mapList, false);
X	}
X	FixMenus ();
X}
X
X
Xstatic Clobber ()
X{
X	HideWindow (mapWind);
X	TEDispose (markTE);
X	/*DisposeList (mapList);
X	DisposeList (fontList);*/
X	DisposeWindow (mapWind);
X}
X
X
Xstatic Idle ()
X{
X	TEIdle (markTE);
X}
X
X
X/*
X	Create controls.  These are created in the same order as the specs
X	in the ctrlInfo array.
X*/
X
Xstatic ControlHandle MakeControl (proc, type, index)
XInteger				proc;
XInteger				type;
XInteger				index;
X{
Xstatic Integer			i = 0;	/* used to step through ctrlInfo array */
Xregister CtrlInfo	*cInfo;
XRect				r;
XStringPtr			title;
Xregister Integer		h, v;
XControlHandle		ctrl;
X
X	cInfo = &ctrlInfo[i++];
X	title = cInfo->cTitle;
X	h = cInfo->ch;
X	v = cInfo->cv;
X	SetRect (&r, h, v, h + StringWidth (title) + 20, v + 20);
X	ctrl = NewControl (mapWind,
X						&r,
X						title,
X						true,
X						0, 0, 1,
X						proc,
X						(Longint) (type << 8 | index));
X	return (ctrl);
X}
X
X
XMapSetup ()
X{
Xregister Integer	i;
XRect			r;
X
X	SetRect (&r, 24, 60, 480, 311);
X	mapWind = NewWindow (nil, &r, "\p", false, noGrowDocProc,
X							-1L, false, 0L);
X	SkelWindow (mapWind,
X				Mouse,
X				Key,
X				Update,
X				Activate,
X				nil,
X				Clobber,
X				Idle,
X				true);
X
X	TextFont (0);			/* do this so StringWidth calculations */
X	TextSize (0);			/* for controls will be accurate */
X
X	for (i = 0; i < maxSize; ++i)
X		sizeCtrl[i] = MakeControl (radioButProc, sizeType, i);
X
X	for (i = 0; i < maxStyle; ++i)
X		styleCtrl[i] = MakeControl (checkBoxProc, styleType, i);
X
X	for (i = 0; i < maxCP; ++i)
X		cpCtrl[i] = MakeControl (radioButProc, cpType, i);
X
X	SetRect (&r, 7, 152, 107, 168);
X	markTE = TENew (&r, &r);
X	(void) ZeroScrap ();
X
X	InitList (fontList, maxFonts);		/* initialize empty list */
X	InitList (mapList, maxMappings);
X	for (i = 0; i < maxMappings; ++i)
X		InitMSpec (&mapSpec[i]);
X
X/*
X	Add default set of fonts:  ImageWriter fonts and LaserWriter fonts.
X	Reset the list and add the two sets without asking whether to add to
X	or replace the current list, since there's not really any current
X	list.
X*/
X
X	ResetFontList ();
X	StrFonts (false);
X
X	ClearMapName ();
X	ShowWindow (mapWind);
X}
SHAR_EOF
exit
--- end of part 2 ---
Technical Details
Message-ID: <2457@felix.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!water!watnot!watmath!clyde!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!pyramid!oliveb!felix!macintosh
References: <2455@felix.UUCP>

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!utgpu!water!watnot!watmath!clyde!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!pyramid!oliveb!felix!macintosh
From: macintosh@felix.UUCP
Newsgroups: mod.mac.sources
Subject: MakeWrite Source (part 2 of 3)
Message-ID: <2457@felix.UUCP>
Date: Sat, 21-Mar-87 14:00:06 EST
Article-I.D.: felix.2457
Posted: Sat Mar 21 14:00:06 1987
Date-Received: Mon, 23-Mar-87 00:30:57 EST
References: <2455@felix.UUCP>
Sender: root@felix.UUCP
Reply-To: dubois@uwmacc.UUCP (Paul DuBois)
Organization: UWisconsin-Madison Academic Comp Center
Lines: 2483
Approved: bytebug@felix.UUCP (Roger L. Long)