/*

MemoCards 1.3
ŠUmberto Salsi <salsi@dsnet.it>
15 December 1995

Dev. system: THINK C 4.0

External modules: QFile.c

*/

#include "ControlMgr.h"
#include "DeskMgr.h"
/* #include "DeviceMgr.h" */
#include "DialogMgr.h"
#include "EventMgr.h"
#include "FileMgr.h"
/* #include "HFS.h" */
/* #include "IntlPkg.h" */
/* #include "ListMgr.h" */
#include "MacTypes.h"
#include "MemoryMgr.h"
#include "MenuMgr.h"
#include "OSUtil.h"
/* #include "PackageMgr.h" */
#include "Quickdraw.h"
#include "ResourceMgr.h"
#include "ScrapMgr.h"
/* #include "SegmentLdr.h" */
#include "StdFilePkg.h"
#include "TextEdit.h"
#include "ToolboxUtil.h"
#include "WindowMgr.h"
/* #include "asm.h" */
/* #include "pascal.h" */

#include <stdlib.h>

#include "QFile.c"

#define applSignature 'psit'
#define dataType 'DATA'
#define dataVer 3  /* 1->2: more colors added (see later) */
                   /* 2->3: win. size, font style */
#define prefsFile "\pMemoCards Prefs"
#define prefsType 'pref'
#define prefsVer 4  /* 2->3: the n. of colors go from 4 to 12 */
                    /* 3->4: from normalWidth to normalColorB */
	
#define defAutoSaveOnQuit false
#define defAutoSaveOnSuspend false
#define defUseShadowColors false
#define defNormalWidth 99
#define defNormalHeight 99
#define defNormalColor 0
#define defNormalFont 3
#define defNormalFace 0
#define defNormalSize 9
#define defNormalColorR 0
#define defNormalColorG 0
#define defNormalColorB 0

#define untitled "\pUntitled"
	
#define ETX 3
#define BAK 8
#define HT 9
#define CR 13
#define ESC 27
	
/* Cards windows: */
#define glueBand 8  /* simulated title bar height */
#define textLeftMargin 2
#define textRightMargin 3
#define textTopMargin 2
#define textBottomMargin 0
#define maxColors 12
	
/* Dialog box resource ID numbers: */

#define aboutID 1000

#define preferencesID 128
	#define yellowID 6
	
#define saveChangesID 2000	/* save changes to "xyz"? */
	#define saveButton 1
	#define dischargeButton 2
	#define cancelButton 3

#define alertID 1001	/* alert box */
	#define stopAlert 1
	#define noteAlert 2
	#define cautionAlert 3

#define throwAwayID 3000  /* "throw away card" alert box */
	#define iCancel 1
	#define iThrowAway 2

#define captureDefaultID 4000 /* ok=1, cancel=2 */
	
/* Menų ID numbers: */
	
#define appleM 128
	#define aboutCmd 1

#define fileM 129
	#define newCmd 1
	#define openCmd 2
	#define closeCmd 3
		
	#define saveCmd 5
	#define saveAsCmd 6
		
	#define quitCmd 8
	
#define editM 130
	#define undoCmd 1
		
	#define cutCmd 3
	#define copyCmd 4
	#define pasteCmd 5
	#define clearCmd 6
	#define selectAllCmd 7
	
#define cardM 131
	#define newCardCmd 1
	#define reorderCmd 2
	#define reorderCompactCmd 3
	#define zoomCmd 4
	#define lockCmd 5
	#define followingCmd 6
	#define previousCmd 7
		
	#define preferencesCmd 9
	#define captureDefaultCmd 10
		
	#define yellowCmd 12

#define textM 132
	#define fontM 140
	#define sizeM 141
	#define faceM 142
	#define colorCmd 4


typedef struct Card {
	struct Card * link;
	struct Card * updLink; /* this field used only by PROC. Reorder() */
	WindowPtr window;
	int color;  /* 0,1,2,3 = yellow,red,green,blue */
	BOOLEAN locked;
	enum{ undefZoom, userZoom, stdZoom } zoomState;
	Rect zoomBox;
	TEHandle text;
	BOOLEAN undoAvailable;
	int undoPos;
	char *undoText;
	StScrpHandle undoStyle;
} Card;


#define nameSize 32

typedef struct {
	char name[nameSize];
	int vRefNum;
	BOOLEAN modified;
	Card * cards;
} Doc;


typedef struct {
	unsigned int red, green, blue;
} RGBColor;

BOOLEAN  quitProgram;
Doc *  doc;
int  normalWidth,
	normalHeight,
	normalColor,
	normalFont,
	normalFace,
	normalSize,
	normalColorR,
	normalColorG,
	normalColorB;
int  offsetPosition;  /* posizione sfalsata delle nuove finestre */
Cursor  iBeam;

BOOLEAN  autoSaveOnQuit, autoSaveOnSuspend, useShadowColors;
RGBColor  colors[maxColors];
RGBColor  black1, white1;   /* 'black' e 'white' non li posso ridefinire: perche'? *****/


char **memoryReserve;
BOOLEAN memoryLow = false;

/******
#define MEM ReportMemUsage()

unsigned long A7Min = 0xFFFFFFFF;

void  ReportMemUsage()
{
	unsigned long l;
	
	asm{
		move.l A7, l
	}
	if( l < A7Min )  A7Min = l;
}
*****/


long  StackPtr()
{
	long l;
	
	asm{
		move.l A7, l
	}
	return  l;
}


void  SetColor(RGBColor * rgb,  int r, int g, int b)
{
	rgb->red = (r << 8) + r;
	rgb->green = (g << 8) + g;
	rgb->blue = (b << 8) + g;
}


/* Preferences: */

BOOLEAN  ReadFlag()
{
	int f;
	
	f = 0;
	QFRead(1, &f);
	if( f )
		return  true;
	else
		return  false;
}


void  WriteFlag(BOOLEAN  f)
{
	int b;
	
	if( f )
		b = 0xFFFF;
	else
		b = 0;
	QFWrite(1, &b);
}


void  LoadPreferences()
{
	int version, i;
	BOOLEAN  colorsGood;

	QFOpenRead(0, prefsFile);
	QFReadInt(&version);
	QFRead(sizeof(colors), &colors);
	autoSaveOnQuit    = ReadFlag();
	autoSaveOnSuspend = ReadFlag();
	useShadowColors   = ReadFlag();
	colorsGood = ( (QFError() == noErr) && (version == 3) );
	QFReadInt(&normalWidth);
	QFReadInt(&normalHeight);
	QFReadInt(&normalColor);
	QFReadInt(&normalFont);
	QFReadInt(&normalFace);
	QFReadInt(&normalSize);
	QFReadInt(&normalColorR);
	QFReadInt(&normalColorG);
	QFReadInt(&normalColorB);
	QFClose();
	if( (QFError() != noErr) || (version != prefsVer) ){
		/* something goes wrong: use def. values: */
		if( !colorsGood ){
			SetColor(&colors[0], 255, 255, 107);  /* yellow */
			SetColor(&colors[1], 255,  67,  72);  /* red    */
			SetColor(&colors[2], 158, 255, 160);  /* green  */
			SetColor(&colors[3], 164, 166, 255);  /* blue   */
			for(i = 4; i < maxColors; i++ )
				SetColor(&colors[i], 204, 204, 204);
			autoSaveOnQuit = defAutoSaveOnQuit;
			autoSaveOnSuspend = defAutoSaveOnSuspend;
			useShadowColors = defUseShadowColors;
		}
		normalWidth  = defNormalWidth;
		normalHeight = defNormalHeight;
		normalColor  = defNormalColor;
		normalFont   = defNormalFont;
		normalFace   = defNormalFace;
		normalSize   = defNormalSize;
		normalColorR = defNormalColorR;
		normalColorG = defNormalColorG;
		normalColorB = defNormalColorB;
	}
}


void  SavePreferences()
{
	QFOpenWrite(0, prefsFile, applSignature, prefsType);
	QFWriteInt(prefsVer);
	QFWrite(sizeof(colors), &colors);
	WriteFlag(autoSaveOnQuit);
	WriteFlag(autoSaveOnSuspend);
	WriteFlag(useShadowColors);
	QFWriteInt(normalWidth);
	QFWriteInt(normalHeight);
	QFWriteInt(normalColor);
	QFWriteInt(normalFont);
	QFWriteInt(normalFace);
	QFWriteInt(normalSize);
	QFWriteInt(normalColorR);
	QFWriteInt(normalColorG);
	QFWriteInt(normalColorB);
	QFClose();
}


/* PROCEDUREs di utilitā generale: */

int  Min(a, b)
{
	if( a <= b )
		return  a;
	else
		return  b;
}


int  Max(a, b)
{
	if( a >= b )
		return  a;
	else
		return  b;
}


/* Alert box: */

void  Message(int type,  char *diagnosis, char *cure)
{
	int item;

	SetCursor(&arrow);
	ParamText(diagnosis, cure, "\p", "\p");
	switch (type ){
	case stopAlert:     item = StopAlert(alertID, NULL);  break;
	case noteAlert:     item = NoteAlert(alertID, NULL);  break;
	case cautionAlert:  item = CautionAlert(alertID, NULL);  break;
	}
}


void  ErrorMsg(char * msg,  long code)
{
	char s[15];

	NumToString(code, s);
	Message(stopAlert, msg, s);
}


void  MemoryFullMsg()
{
	Message(noteAlert, "\pMemory is full!",
			"\pPlease, quit this program, then assign more memory to it.");
}


BOOLEAN  LockedMsg(Card *card)
{
	if( card->locked )
		Message(stopAlert, "\pThis card is locked.",
			"\pUnlock this card selecting `Lock|Unlock' from the menu `Card'.");
	return  card->locked;
}


BOOLEAN MultipleDocsDisallowedMsg()
{
	if(  doc != NULL  ){
		Message(stopAlert, "\pA document already exist.",
			"\pMultiple documents treatment has been disabled in this version of the program.");
		return  true;
	} else
		return  false;
}


/* Windows maintenance: */

void  SetCloseBox(Card *card, Rect *closeBox)
{
	SetRect(closeBox, 1, 1, glueBand+1, glueBand-1);
}


void  SetZoomBox(Card *card, Rect *zoomBox)
{
	int w;
	
	w = card->window->portRect.right;
	SetRect(zoomBox, w-glueBand-1, 1, w-1, glueBand-1);
}


void  SetGrowBox(Card *card, Rect *growBox)
{
	int w, h;

	w = card->window->portRect.right;
	h = card->window->portRect.bottom;
	SetRect(growBox, w - textRightMargin, h - 2*textRightMargin, w, h);
}

void  SetBarBox(Card *card, Rect *barBox)
{
	*barBox = card->window->portRect;
	barBox->bottom = glueBand;
}


void  SetInContentBox(Card *card, Rect *inContentBox)
{
	*inContentBox = card->window->portRect;
	inContentBox->top = glueBand;
}


void  SetViewBox(Card *card, Rect *viewBox)
{
	SetInContentBox(card, viewBox);
	viewBox->left   += textLeftMargin;
	viewBox->top    += textTopMargin;
	viewBox->right  -= textRightMargin;
	viewBox->bottom -= textBottomMargin;
}


void  GetCardPos(Card * card,  Point * where)
{
	SetPort(card->window);
	SetPt(where, 0, 0);
	LocalToGlobal(where);
}


void  SetCardPos(Card *  card,  int h, int v)
{
	MoveWindow(card->window, h, v, false);
}


void  SetCardSize(Card *card, int w, int h)
{
	Rect view;
	
	if( (card->window->portRect.right == w) && (card->window->portRect.bottom == h) )  return;
	SizeWindow(card->window, w, h, true);
	SetViewBox(card, &view);
	(*card->text)->destRect.left = view.left;
	(*card->text)->destRect.right = view.right;
	(*card->text)->destRect.bottom = 32767;
	(*card->text)->viewRect = view;
	TECalText(card->text);
	SetPort(card->window);
	InvalRect(&card->window->portRect);
}


void  GetCardPosAndSize(Card *card, Rect *state)
{
	Point  pos;
	
	GetCardPos(card, &pos);
	state->left = pos.h;
	state->top  = pos.v;
	state->right = card->window->portRect.right;
	state->bottom = card->window->portRect.bottom;
}


void  SetCardPosAndSize(Card *card, Rect *state)
{
	ShowHide(card->window, false);
	TESetSelect(0, 0, card->text);
	SetCardPos(card, state->left, state->top);
	SetCardSize(card, state->right, state->bottom);
	ShowHide(card->window, true);
}


int  iabs(int i)
{
	return  (i < 0)? -i:i;
}


int  LimitStep(int inc, int maxStep)
{
	if( inc > maxStep )  return  maxStep;
	else if( inc < -maxStep )  return  -maxStep;
	else  return  inc;
}


void  ZoomEffect(WindowPtr  win, Rect *fromState, Rect *toState)
#define step (20)
#define stepMin (3)
#define dt (1L)
{
	Rect a, b;
	RgnHandle origVisRgn;
	Rect visRect, r, oldR;
	long targetTime;
	int dh, dv, dLeft, dTop, dRight, dBottom;
	
	SetPort(win);
	a = *fromState;
	b = *toState;
	a.right += a.left;
	a.bottom += a.top;
	b.right += b.left;
	b.bottom += b.top;
	UnionRect(&a, &b, &visRect);
	InsetRect(&visRect, -1, -1);
	if( !SectRect(&visRect, &screenBits.bounds, &visRect) )  return;
	a.right  -= a.left;
	a.bottom -= a.top;
	b.left   -= a.left;
	b.right  -= a.left;
	b.top    -= a.top;
	b.bottom -= a.top;
	visRect.left   -= a.left;
	visRect.right  -= a.left;
	visRect.top    -= a.top;
	visRect.bottom -= a.top;
	a.left = 0;
	a.top = 0;
	InsetRect(&a, -1, -1);
	InsetRect(&b, -1, -1);
	origVisRgn = win->visRgn;
	win->visRgn = NewRgn();
	RectRgn(win->visRgn, &visRect);
	/* SetRect(&r, -32768, -32768, 32767, 32767);  ClipRect(&r); */
	PenPat(gray);
	PenMode(patXor);
	oldR = a;
	FrameRect(&oldR);
	targetTime = TickCount() + dt;
	dh = iabs(b.left - a.left);
	dv = iabs(b.top - a.top);
	if( dh > dv ){
		dLeft = step;
		dTop = Max((int) (step * (long) dv / dh), stepMin);
	} else if( dv > dh ){
		dLeft = Max((int) (step * (long) dh / dv), stepMin);
		dTop = step;
	} else {
		dLeft = step;
		dTop = step;
	}
	dh = iabs(b.right - a.right);
	dv = iabs(b.bottom - a.bottom);
	if( dh > dv ){
		dRight = step;
		dBottom = Max((int) (step * (long) dv / dh), stepMin);
	} else if( dv > dh ){
		dRight = Max((int) (step * (long) dh / dv), stepMin);
		dBottom = step;
	} else {
		dRight = step;
		dBottom = step;
	}
	do{
		r.left   = oldR.left   + LimitStep(b.left   - oldR.left  , dLeft);
		r.top    = oldR.top    + LimitStep(b.top    - oldR.top   , dTop);
		r.right  = oldR.right  + LimitStep(b.right  - oldR.right , dRight);
		r.bottom = oldR.bottom + LimitStep(b.bottom - oldR.bottom, dBottom);
		do{ }while( TickCount() < targetTime );
		if( EqualRect(&r, &b) ){
			FrameRect(&oldR);
			DisposeRgn(win->visRgn);
			win->visRgn = origVisRgn;
			PenNormal();
			return;
		}
		FrameRect(&r);
		FrameRect(&oldR);
		oldR = r;
		targetTime = TickCount() + dt;
	}while( true );
}


void  DoZoom(Card *card)
{
	Rect state;
	
	if( card->zoomState == undefZoom )  return;
	GetCardPosAndSize(card, &state);
	ZoomEffect(card->window, &state, &card->zoomBox);
	SetCardPosAndSize(card, &card->zoomBox);
	card->zoomBox = state;
	if( card->zoomState == stdZoom)
		card->zoomState = userZoom;
	else
		card->zoomState = stdZoom;
	doc->modified = true;
}


Card *  WindowToCard(WindowPtr window)
{
	Card *card;
	
	if( (window == NULL) || (doc == NULL) )  return  NULL;
	card = doc->cards;
	while( card != NULL ){
		if( card->window == window)  return  card;
		card = card->link;
	}
	return  NULL;
}


Card *  FrontCard()
{
	return  WindowToCard(FrontWindow());
}


int  Compare(Card * aCard, Card * bCard)
{
/* Points ordering criteria: top to bottom, left to right. */
	Point  a, b;

	GetCardPos(aCard, &a);
	GetCardPos(bCard, &b);
	if( a.h < b.h )
		return  -1;
	else if( a.h == b.h )
		if( a.v < b.v )
			return  -1;
		else if( a.v == b.v )
			/* return  0; */
			if( aCard < bCard) /* resolve the case of superimposed cards */
				return  -1;
			else
				return  +1;
		else
			return  +1;
	else
		return  +1;
}


Card *  GetFirst()
{
/* return the first card of the doc according the ordering criteria of "\pCompare".
   if doc has not cards, return NULL.
*/
	Card *temp, *first;

	first = doc->cards;
	if( first == NULL)  return  NULL;
	temp = first->link;
	while( temp != NULL ){
		if( Compare(temp, first) < 0)  first = temp;
		temp = temp->link;
	}
	return  first;
}


Card *  GetLast()
{
/* return the last card of the doc according the ordering criteria of "\pCompare".
   if( doc has not cards, return NULL.
*/
	Card *temp, *last;

	last = doc->cards;
	if( last == NULL)  return  NULL;
	temp = last->link;
	while( temp != NULL ){
		if( Compare(last, temp) <= 0)  last = temp;
		temp = temp->link;
	}
	return  last;
}


Card *  GetSucc(Card * card)
{
/* return the successive card according the ordering criteria of "\pCompare".
   if( there is not a succ. card, return NULL.
*/
	Card *temp, *succ;

	succ = NULL;
	temp = doc->cards;
	while( temp != NULL ){
		if( (temp != card )
		&& (Compare(card, temp) < 0)
		&& ((succ == NULL) || (Compare(temp, succ) < 0)) )
			succ = temp;
		temp = temp->link;
	}
	return  succ;
}


Card *  GetPrec(Card * card)
{
/* return the precedent card according the ordering criteria of "\pCompare".
   if( there is not a succ. card, return NULL.
*/
	Card *temp, *prec;

	prec = NULL;
	temp = doc->cards;
	while( temp != NULL ){
		if( (temp != card )
		&& (Compare(temp, card) < 0)
		&& ((prec == NULL) || (Compare(prec, temp) < 0)) )
			prec = temp;
		temp = temp->link;
	}
	return  prec;
}


void  Reorder()
{
	Card *first, *card;

	first = GetFirst();
	if( first == NULL)  return;
	/* Recalculate the ordered list of cards first->updLink->updLink->..: */
	card = first;
	do {
		card->updLink = GetSucc(card);
		card = card->updLink;
	}while( card != NULL);
	/* Update doc with the ordered list of cards: */
	doc->cards = first;
	card = first;
	do {
		card->link = card->updLink;
		card = card->updLink;
	}while( card != NULL);
}


/* Window drawing procs: */

void  MakeDarker(RGBColor * c)
{
	c->red   = (c->red   / 2);
	c->green = (c->green / 2);
	c->blue  = (c->blue  / 2);
}


void  MakeLighter(RGBColor * c)
{
	c->red   = c->red   + (0xFFFF - c->red  ) / 2;
	c->green = c->green + (0xFFFF - c->green) / 2;
	c->blue  = c->blue  + (0xFFFF - c->blue ) / 2;
}


void  Draw3DFrameRect(Rect * r,  RGBColor * color,  BOOLEAN embossed)
{
	RGBColor darker, lighter;

	darker = *color;
	MakeDarker(&darker);
	lighter = *color;
	MakeLighter(&lighter);
	if( embossed )
		if( useShadowColors )
			RGBForeColor(&darker);
		else
			PenPat(black);
	else
		if( useShadowColors )
			RGBForeColor(&lighter);
		else
			PenPat(white);
	MoveTo(r->left, r->bottom-1);
	LineTo(r->left, r->top);
	LineTo(r->right-1, r->top);
	if( embossed )
		if( useShadowColors )
			RGBForeColor(&lighter);
		else
			PenPat(white);
	else
		if( useShadowColors )
			RGBForeColor(&darker);
		else
			PenPat(black);
	LineTo(r->right-1, r->bottom-1);
	LineTo(r->left+1, r->bottom-1);
	PenPat(black);
	RGBForeColor(&black1);
}


void  DrawWindowFrame(Card * card)
{
	BOOLEAN  active, locked;
	RGBColor  color;
	Rect  bar, closeBox, zoomBox, incontentBox, growBox;

	SetPort(card->window);
	active = ((WindowPeek)(card->window))->hilited;
	locked = card->locked;
	color = colors[card->color];
	SetBarBox      (card, &bar);
	SetCloseBox    (card, &closeBox);
	SetInContentBox(card, &incontentBox);
	SetGrowBox     (card, &growBox);
	SetZoomBox     (card, &zoomBox);
	RGBBackColor(&color);
	EraseRect(&bar);
	EraseRect(&growBox);
	RGBBackColor(&white1);
	RGBForeColor(&black1);
	if( active ){
		if( useShadowColors )
			Draw3DFrameRect(&bar, &color, locked);
		else
			FillRect(&bar, black);
		if( locked ){
			/* --- */
		} else {
			Draw3DFrameRect(&closeBox, &color, false);
			if( useShadowColors )
				Draw3DFrameRect(&growBox, &color, true);
			else
				FillRect(&growBox, black);
			if( card->zoomState != undefZoom ){
				Draw3DFrameRect(&zoomBox, &color, false);
				zoomBox.right = (zoomBox.right + zoomBox.left) / 2 + 1;
				zoomBox.bottom = (zoomBox.bottom + zoomBox.top) / 2 + 1;
				zoomBox.left++;
				zoomBox.top++;
				Draw3DFrameRect(&zoomBox, &color, true);
			}
		}
	}
	RGBBackColor(&color);
	RGBForeColor(&black1);
}


void  UpdateWindow(WindowPtr  window)
{
	Card * card;

	card = WindowToCard(window);
	if( card == NULL )  return;
	BeginUpdate(window);
	SetPort(window);
	RGBBackColor(&colors[card->color]);
	EraseRect(&card->window->portRect);  /* necessario per TE! (cfr I-387) */
	DrawWindowFrame(card);
	TEUpdate(&( (*(card->text))->viewRect ), card->text);
	EndUpdate(window);
}


void  Activate(WindowPtr window,  BOOLEAN active)
{
	Card * card;

	card = WindowToCard(window);
	if( card == NULL )  return;
	SetPort(window);
	DrawWindowFrame(card);
	if( active )
		TEActivate(card->text);
	else
		TEDeactivate(card->text);
}

	
void  DragCard(Card * card,  Point where)
{
	Rect state;

	GetCardPosAndSize(card, &state);
	DragWindow(card->window, where, &screenBits.bounds);
	switch( card->zoomState ){
	case undefZoom:  break;
	case stdZoom:
		card->zoomBox = state;
		card->zoomState = userZoom;
		break;
	case userZoom:  break;
	}
	doc->modified = true;
}


long  MyGrowWindow(WindowPtr  w, Point orig, Rect *minMax)
{
	Rect  frame, newVisBox, oldFrame;
	RgnHandle  origVisRgn, newVisRgn;
	Point  old, new, pos, a, b;
	
	long targetTime;
	BOOLEAN  changed;
	Card *card;
	
	SetPort(w);
	oldFrame = w->portRect;
	frame = w->portRect;
	InsetRect(&frame, -1, -1);
	origVisRgn = w->visRgn;
	newVisRgn = NewRgn();
	SetPt(&pos, 0, 0);
	LocalToGlobal(&pos);
	SetPt(&a, Max(pos.h-1, 0), Max(pos.v-1, 0));
	SetPt(&b, screenBits.bounds.right, screenBits.bounds.bottom);
	GlobalToLocal(&a);
	GlobalToLocal(&b);
	SetRect(&newVisBox, a.h, a.v, b.h, b.v);
	RectRgn(newVisRgn, &newVisBox);
	w->visRgn = newVisRgn;
	PenPat(gray);
	PenMode(patXor);
	FrameRect(&frame);
	old = orig;
	
	changed = false;
	card = WindowToCard(w);
	
	do{
		GetMouse(&new);
		if( (new.h != old.h) || (new.v != old.v) ){
			changed = true;
			targetTime = TickCount() + 15;
			FrameRect(&frame);
			frame.right  = oldFrame.right + new.h - orig.h + 1;
			frame.bottom = oldFrame.bottom + new.v - orig.v + 1;
			frame.right  = Max(frame.right, minMax->left+1);
			frame.right  = Min(frame.right, minMax->right+1);
			frame.bottom = Max(frame.bottom, minMax->top+1);
			frame.bottom = Min(frame.bottom, minMax->bottom+1);
			FrameRect(&frame);
			old = new;
		}
		if( changed && (TickCount() > targetTime) ){
			FrameRect(&frame);
			PenNormal();
			w->visRgn = origVisRgn;
			SetCardSize(card, frame.right-1, frame.bottom-1);
			UpdateWindow(w);
			w->visRgn = newVisRgn;
			PenPat(gray);
			PenMode(patXor);
			FrameRect(&frame);
			changed = false;
		}
	}while( StillDown() );
	FrameRect(&frame);
	DisposeRgn(newVisRgn);
	w->visRgn = origVisRgn;
	PenNormal();
	InsetRect(&frame, 1, 1);
	if( EqualRect(&frame, &oldFrame) )
		return  0L;
	else
		return  65536L*frame.bottom + frame.right;
}


void  GrowCard(Card *card, Point where)
/* 'where' must be in local coord. */
{
	Rect  minMax;
	long  newSize;
	Rect state;
	
	SetRect(&minMax, 4*glueBand, 2*glueBand, 2000, 2000);
	GetCardPosAndSize(card, &state);
	newSize = MyGrowWindow(card->window, where, &minMax);
	if( newSize != 0 ){
		SetCardSize(card, LoWord(newSize), HiWord(newSize));
		switch( card->zoomState ){
		case undefZoom:  break;
		case stdZoom:  card->zoomBox = state;  card->zoomState = userZoom;  break;
		case userZoom:  break;
		}
		doc->modified = true;
	}
}


/* Comandi del menų MELA: */

void  DrawDefaultButton(DialogPtr dialog,  int itemNo)
{
	int  itemType;
	Handle  item;
	Rect  box;

	SetPort(dialog);
	GetDItem(dialog, itemNo, &itemType, &item, &box);
	InsetRect(&box, -4, -4);
	PenSize(3, 3);
	FrameRoundRect(&box, 16, 16);
	PenNormal();
}


void  PressButton(DialogPtr dialog,  int itemNo)
{
	int  itemType;
	Handle  item;
	Rect  box;
	long  targetTime;

	GetDItem(dialog, itemNo, &itemType, &item, &box);
	HiliteControl((ControlHandle) item, inButton);
	targetTime = TickCount() + 10L;
	do { }while( TickCount() < targetTime);
	HiliteControl((ControlHandle) item, 0);
}


void  AboutCmd()
{
	DialogPtr  theDialog;
	int  itemHit;

	SetCursor(&arrow);
	theDialog = GetNewDialog(aboutID, NULL, -1);
	DrawDefaultButton(theDialog, 1);
	ModalDialog(NULL, &itemHit);
	DisposDialog(theDialog);
}


/* Comandi del menų File: */

Doc *  NewDoc()
{
	Doc *doc;
	
	doc = (Doc *) NewPtr(sizeof(Doc));
	if( doc == NULL)  return  NULL;
	AssignPStr(doc->name, untitled);
	doc->vRefNum = 0;
	doc->modified = false;
	doc->cards = NULL;
	return  doc;
}


Card *  NewCard()
{
#define topMargin 25  /* menu bar height + 5 points */
#define leftMargin 15
#define offset (4*glueBand)
#define offsetCycle 4

	Card * card;
	Rect  r;
	TextStyle  theStyle;
	
	card = (Card *) NewPtr(sizeof(Card));
	if( card == NULL )  return  NULL;
	
	/* set card->window: */
	SetRect(&r, 0, 0, 100, 100);
	card->window = (WindowPtr) NewCWindow(NULL, &r, "\p", false, plainDBox, -1, false, 0);
	if( card->window == NULL ){
		DisposPtr(card);
		return  NULL;
	}

	card->color = normalColor;
	card->locked = false;
	
	/* set card zoom state: */
	card->zoomState = undefZoom;
	SetRect(&card->zoomBox, 0, 0, 0, 0);
	
	/* set card->text: */
	SetPort(card->window);
	TextFont(normalFont);
	TextSize(normalSize);
	TextFace(normalFace);
	SetViewBox(card, &r);
	card->text = TEStylNew(&r, &r);
	if( card->text == NULL ){
		DisposeWindow(card->window);
		DisposPtr(card);
		return  NULL;
	}
	TEAutoView(true, card->text);
	theStyle.tsFont = normalFont;
	theStyle.tsFace = normalFace;
	theStyle.tsSize = normalSize;
	theStyle.tsColor.red = normalColorR;
	theStyle.tsColor.green = normalColorG;
	theStyle.tsColor.blue = normalColorB;
	/* TESetSelect(0, 32767, card->text); *****/
	TESetStyle(doAll, &theStyle, false, card->text);
	/* TESetSelect(0, 0, card->text); *****/
	
	/* set position and size: */
	SetCardPos(card, leftMargin + offsetPosition, topMargin + offsetPosition);
	SetCardSize(card, normalWidth, normalHeight);
	offsetPosition = (offsetPosition + offset) % (offset * offsetCycle);
	
	/* set undo: */
	card->undoAvailable = false;
	card->undoPos   = 0;
	card->undoText  = NULL;
	card->undoStyle = NULL;
	
	card->link = doc->cards;
	doc->cards = card;
	return  card;
}


void  DisposeUndoData(Card *card)
{
	if( !card->undoAvailable )  return;
	card->undoAvailable = false;
	DisposPtr(card->undoText);
	DisposHandle(card->undoStyle);
}


void  DisposeCard(Card *card)
{
	Card *prec;
	
	if( doc->cards == card )
		doc->cards = card->link;
	else {
		prec = doc->cards;
		while( prec->link != card)
			prec = prec->link;
		prec->link = card->link;
	}
	TEDispose(card->text);
	DisposeWindow(card->window);
	DisposeUndoData(card);
	DisposPtr(card);
}


void  DisposeDoc()
{
	while( doc->cards != NULL )
		DisposeCard(doc->cards);
	DisposPtr(doc);
	doc = NULL;
}


/* Comandi del menų File: */

void  NewCmd()
{
	Card * card;
	
	if( MultipleDocsDisallowedMsg() )  return;
	doc = NewDoc();
	if( doc == NULL ){
		MemoryFullMsg();
		return;
	}
	card = NewCard();
	if( card == NULL ){
		DisposeDoc();
		MemoryFullMsg();
		return;
	}
	ShowWindow(card->window);
}


BOOLEAN  CheckFileError()
{
	if( QFError() != noErr ){
		QFClose();
		ErrorMsg("\pError in file operation.", QFError());
		return  true;
	} else
		return  false;
}


BOOLEAN  ReadCard(Card *card, int version)
{
	Point where;
	int textLen, width, height, i;
	char *text;
	long styleLen;
	StScrpHandle style;
	TextStyle  theStyle;

	QFRead(sizeof(Point), &where);
	if( (version == 1) || (version == 2) ){
		width = defNormalWidth;
		height = defNormalHeight;
	} else {
		QFRead(sizeof(width), &width);
		QFRead(sizeof(height), &height);
	}
	QFReadInt(&card->color);
	card->locked = ReadFlag();
	if( version == dataVer ){
		QFReadInt(&i);
		card->zoomState = i;
		QFRead(sizeof card->zoomBox, &card->zoomBox);
	}
	QFReadInt(&textLen);
	if( CheckFileError() )  return  false;
	SetCardPos(card, where.h, where.v);
	SetCardSize(card, width, height);
	text = NewPtr(textLen);
	if( text == NULL ){
		MemoryFullMsg();
		return  false;
	}
	QFRead(textLen, text);
	if( CheckFileError() )  return  false;
	if( (version == 1) || (version == 2) ){
		theStyle.tsFont = defNormalFont;
		theStyle.tsSize = defNormalSize;
		theStyle.tsFace = defNormalFace;
		theStyle.tsColor.red = defNormalColorR;
		theStyle.tsColor.green = defNormalColorG;
		theStyle.tsColor.blue = defNormalColorB;
		TESetStyle(doAll, &theStyle, false, card->text);
		TEInsert(text, textLen, card->text);
	} else {
		QFRead(sizeof styleLen, &styleLen);
		if( CheckFileError() ){
			DisposPtr(text);
			return false;
		}
		style = (StScrpHandle) NewHandle(styleLen);
		if( style == NULL ){
			DisposPtr(text);
			MemoryFullMsg();
			return false;
		}
		QFRead(styleLen, *style);
		if( CheckFileError() ){
			DisposPtr(text);
			DisposHandle(style);
			return false;
		}
		TEStylInsert(text, textLen, style, card->text);
		DisposHandle(style);
	}
	TESetSelect(0, 0, card->text);
	DisposPtr(text);
	return  true;
}


void  OpenDoc(int vRefNum,  char * fName)
{
	Card * card;
	int  version, n, i;

	QFOpenRead(vRefNum, fName);
	if( CheckFileError())  return;
	doc = NewDoc();
	if( doc == NULL ){
		QFClose();
		MemoryFullMsg();
		return;
	}
	if( fName[0] >= nameSize)     /* ? ********/
		fName[0] = nameSize - 1;
	AssignPStr(doc->name, fName);
	doc->vRefNum = vRefNum;
	
	QFReadInt(&version);
	if( CheckFileError() ){
		DisposeDoc();
		return;
	}
	if( (version != dataVer) && (version != 2) && (version != 1) ){
		QFClose();
		DisposeDoc();
		Message(stopAlert, "\pCan't read this version of the data file.",
			"\pUse an update version of the program.");
		return;
	}
	QFReadInt(&n);
	if( CheckFileError() ){
		DisposeDoc();
		return;
	}
	for (i = 1; i <= n; i++ ){
		card = NewCard();
		if( card == NULL ){
			QFClose();
			MemoryFullMsg();
			return;
		}
		if( !ReadCard(card, version) ){
			QFClose();
			DisposeCard(card);
			return;
		}
		ShowWindow(card->window);
	}
	
	QFClose();
}


void  OpenCmd()
{
	int  folder;
	char  name[nameSize];
	
	if( MultipleDocsDisallowedMsg() )  return;
	SetCursor(&arrow);
	if( QFSelectInputFile(dataType, &folder, name) )
		OpenDoc(folder, name);
}


void  SaveCard(Card *card)
{
	Point where;
	int textLen;
	StScrpHandle style;
	long styleLen;
	int origSelStart, origSelEnd;
	
	GetCardPos(card, &where);
	QFWrite(sizeof(where), &where);
	QFWriteInt(card->window->portRect.right);
	QFWriteInt(card->window->portRect.bottom);
	QFWriteInt(card->color);
	WriteFlag(card->locked);
	QFWriteInt(card->zoomState);
	QFWrite(sizeof card->zoomBox, &card->zoomBox);
	textLen = (*(card->text))->teLength;
	QFWriteInt(textLen);
	QFWrite(textLen, *((*(card->text))->hText));
	origSelStart = (*card->text)->selStart;
	origSelEnd   = (*card->text)->selEnd;
	TESetSelect(0, 32767, card->text);
	style = GetStylScrap(card->text);
	TESetSelect(origSelStart, origSelEnd, card->text);
	styleLen = GetHandleSize(style);
	QFWrite(sizeof styleLen, &styleLen);
	QFWrite(styleLen, *style);
	DisposHandle(style);
}


void  Save()
{
	Card * card;
	int  n, i;

	if( !doc->modified )  return;
	QFOpenWrite(doc->vRefNum, doc->name, applSignature, dataType);
	
	QFWriteInt(dataVer);
	n = 0;
	Reorder();
	card = doc->cards;
	while( card != NULL ){
		n++;
		card = card->link;
	}
	QFWriteInt(n);
	card = doc->cards;
	for (i = 1; i <= n; i++ ){
		SaveCard(card);
		card = card->link;
	}
	QFClose();
	if( QFError() == noErr )
		doc->modified = false;
	else
		ErrorMsg("\pError writing the file.", QFError());
}


void  SaveAsCmd()
{
	Point  where;
	SFReply  reply;

	if( doc == NULL )  return;
	SetCursor(&arrow);
	if( QFSelectOutputFile(&doc->vRefNum, doc->name) ){ /* pericolo lungh. doc->name! *****/
		doc->modified = true;
		Save();
	}
}


void  SaveCmd()
{
	if( doc == NULL )  return;
	if( !doc->modified )  return;
	if( EqPStr(doc->name, untitled) )
		SaveAsCmd(doc);
	else
		Save(doc);
}


void  CloseCmd()
{
	if( doc == NULL )  return;
	if( doc->modified ){
		ParamText(doc->name, "\p", "\p", "\p");
		SetCursor(&arrow);
		switch( CautionAlert(saveChangesID, NULL)  ){
		case saveButton:		SaveCmd();  break;
		case dischargeButton:	doc->modified = false;  break;
		case cancelButton:		return;  break;
		}
	}
	if( !doc->modified )  DisposeDoc();
}


void  QuitCmd()
{
	if(  doc != NULL  ){
		if( autoSaveOnQuit && !EqPStr(doc->name, untitled)  ){
			SaveCmd();
			if( doc->modified )  /* saving failed cause Cancel or file error */
				return;
		}
		CloseCmd();
	}
	quitProgram = (doc == NULL);
}


/* Comandi del menų Edit: */

void  SaveSelectionForUndo(Card *card)
{
	int selStart, selEnd, i;
	char *text;

	selStart = (*card->text)->selStart;
	selEnd   = (*card->text)->selEnd;
	if( selStart == selEnd )  return;
	DisposeUndoData(card);
	card->undoPos = selStart;
	card->undoText = NewPtr(selEnd - selStart);
	if( card->undoText == NULL )  return;  /*****/
	text = *(*card->text)->hText;
	BlockMove(&(text[selStart]), card->undoText, selEnd - selStart);
	card->undoStyle = GetStylScrap(card->text);  /* NULL? ****/
	card->undoAvailable = true;
}


void  UndoCmd()
{
	Card * card;
	int textLen;

	card = FrontCard();
	if( (card == NULL) || !card->undoAvailable || card->locked )  return;
	textLen = GetPtrSize(card->undoText);
	TESetSelect(card->undoPos, card->undoPos, card->text);
	TEStylInsert(card->undoText, textLen, card->undoStyle, card->text);
	TESetSelect(card->undoPos, card->undoPos + textLen, card->text);
	DisposeUndoData(card);
	doc->modified = true;
}


void  CutCmd()
{
	Card * card;

	card = FrontCard();
	if( (card == NULL)
	|| ( (*(card->text))->selStart == (*(card->text))->selEnd)
	|| LockedMsg(card) ){
		return;
	}
	SaveSelectionForUndo(card);
	TECut(card->text);
	doc->modified = true;
}


void  CopyCmd()
{
	Card * card;

	card = FrontCard();
	if( (card == NULL) || ((*(card->text))->selStart == (*(card->text))->selEnd) ){
		return;
	}
	TECopy(card->text);
}


void  PasteCmd()
{
	Card * card;
	int selStart, selEnd, origLen;

	card = FrontCard();
	if( (card == NULL) || LockedMsg(card))  return;
	selStart = (*card->text)->selStart;
	selEnd   = (*card->text)->selEnd;
	origLen  = (*card->text)->teLength;
	if( selStart == selEnd ){
		TEStylPaste(card->text);
		if( card->undoAvailable && (card->undoPos > selStart) )
			card->undoPos += (*card->text)->teLength - origLen;
	} else {
		SaveSelectionForUndo(card);
		TEStylPaste(card->text);
	}
	doc->modified = true;
}


void  ClearCmd()
{
	Card * card;

	card = FrontCard();
	if( (card == NULL) || ((*(card->text))->selStart == (*(card->text))->selEnd) || LockedMsg(card) ){
		return;
	}
	SaveSelectionForUndo(card);
	TEDelete(card->text);
	doc->modified = true;
}


void  SelectAllCmd()
{
	Card * card;

	card = FrontCard();
	if( card == NULL)  return;
	TESetSelect(0, 32767, card->text);
}



/* Comandi del menų Card: */

void  NewCardCmd()
{
	Card *card;

	if( doc == NULL )  return;
	card = NewCard();
	if( card == NULL ){
		MemoryFullMsg();
		return;
	}
	ShowWindow(card->window);
}


void  ReorderCmd(BOOLEAN  compact)
{
	Card * card;
	int  hStep, vStep;
	Point  where, topLeft, botRight;
	WindowPtr  lastWin;
	WindowPeek  wPeek;
	Rect oldZoom, newZoom;

	if( doc == NULL )  return;
	Reorder();
	hStep = normalWidth + 1;
	if( compact )
		vStep = normalHeight / 2;
	else
		vStep = normalHeight + 1;
	topLeft = topLeft(screenBits.bounds);
	botRight = botRight(screenBits.bounds);
	topLeft.v += 20;
	where = topLeft;
	if( compact && (FrontCard() != NULL) ){
		card = FrontCard();
		HiliteWindow(card->window, FALSE);
		Activate(card->window, false);
	}
	card = doc->cards;
	lastWin = NULL;
	while( card != NULL ){
		if( card->locked )
			card->zoomState = undefZoom;
		else {
			SetRect(&newZoom, where.h, where.v, normalWidth, normalHeight);
			GetCardPosAndSize(card, &oldZoom);
			if( !EqualRect(&newZoom, &oldZoom) ){
				ZoomEffect(card->window, &oldZoom, &newZoom);
				SetCardPosAndSize(card, &newZoom);
				switch( card->zoomState ){
				case undefZoom:
					card->zoomBox = oldZoom;
					card->zoomState = stdZoom;
					DrawWindowFrame(card);
					break;
				case stdZoom:    break;
				case userZoom:
					card->zoomBox = oldZoom;
					card->zoomState = stdZoom;
					break;
				}
			}
			if( compact ){
				lastWin = card->window;
				BringToFront(lastWin);
			}
			where.v += vStep;
			if( where.v + vStep > botRight.v ){
				where.v = topLeft.v;
				where.h += hStep;
				if( where.h + hStep > botRight.h)  where = topLeft;
			}
		}
		card = card->link;
	}
	if( compact && (lastWin != NULL) ){
		HiliteWindow(lastWin, TRUE);
		Activate(lastWin, true);
	}
	doc->modified = true;
}


void  ZoomCmd()
{
	Card *card;
	
	card = FrontCard();
	if( card == NULL )  return;
	DoZoom(card);
}


void  LockCmd()
{
	Card *card;

	card = FrontCard();
	if( card == NULL)  return;
	card->locked = !card->locked;
	SetPort(card->window);
	DrawWindowFrame(card);
	doc->modified = true;
}


void  FollowingCmd()
{
	Card *curr, *succ;

	curr = FrontCard();
	if( curr == NULL )  return;
	succ = GetSucc(curr);
	if( succ == NULL )  succ = GetFirst();
	if( succ != NULL )  SelectWindow(succ->window);
}


void  PreviousCmd()
{
	Card *curr, *prec;

	curr = FrontCard();
	if( curr == NULL )  return;
	prec = GetPrec(curr);
	if( prec == NULL )  prec = GetLast();
	if( prec != NULL )  SelectWindow(prec->window);
}


void  ColorCmd(int color)
{
	Card *card;

	card = FrontCard();
	if( (card == NULL) || (card->color == color) || LockedMsg(card) )
		return;
	card->color = color;
	SetPort(card->window);
	InvalRect(&card->window->portRect);
	doc->modified = true;
}


void  InvalidateAll()
{
	Card *card;

	card = doc->cards;
	while( card != NULL ){
		SetPort(card->window);
		InvalRect(&card->window->portRect);
		card = card->link;
	}
}


pascal BOOLEAN  PreferencesDlgFilter(DialogPtr dialog,  EventRecord * event,
	int * itemHit)
#define FALSE  0
#define TRUE 0xFFFF
{
	int  i, itemType;
	Handle  item;
	Rect  box;
	Point  where;
	BOOLEAN  checked;
	long targetTime;

	switch (event->what ){
	
	case keyDown:
		switch ((int) (event->message & charCodeMask) ){
		
		case CR:
		case ETX:
			PressButton(dialog, 1);
			*itemHit = 1;
			return  TRUE;
		
		case ESC:
			PressButton(dialog, 2);
			*itemHit = 2;
			return  TRUE;
			
		default:  return  FALSE;
		}
		
	case mouseDown:
		SetPort(dialog);
		where = event->where;
		GlobalToLocal(&where);
		for (i = 0; i < maxColors; i++ ){
			GetDItem(dialog, yellowID + i, &itemType, &item, &box);
			InsetRect(&box, 1, 1);
			checked = false;
			if( PtInRect(where, &box) ){
				do {
					GetMouse(&where);
					if( PtInRect(where, &box) != checked ){
						checked = !checked;
						Draw3DFrameRect(&box, &colors[i], checked);
						if( checked )  targetTime = TickCount() + 10L;
					}
				}while( StillDown());
				if( checked ){
					do{ }while( TickCount() < targetTime );
					Draw3DFrameRect(&box, &colors[i], false);
					*itemHit = yellowID + i;
					return  TRUE;
				} else {
					*itemHit = -111;
					return  TRUE;
				}
			}
		}
		return  FALSE;
	
	case updateEvt:
		if( (WindowPtr)(event->message) == dialog ){
			*itemHit = -1;  /* "-1" mean "updateEvt": what a trick! */
			return  TRUE;
		} else {
			UpdateWindow((WindowPtr)(event->message));
			return  FALSE;
		}
	
	default:
		return  FALSE;
	}
}


BOOLEAN  Equal(RGBColor * a, RGBColor * b)
{
	return  (a->red == b->red) && (a->green == b->green) && (a->blue == b->blue);
}


void  PreferencesCmd()
{
	DialogPtr  dialog;
	EventRecord  event;
	int  itemHit, itemType, i;
	Handle  item, autoSaveOnQuitControl, autoSaveOnSuspendControl, useShadowColorsControl;
	Rect  box;
	Point  where;
	BOOLEAN  modified;
	RGBColor  outColor;
	BOOLEAN  newAutoSaveOnQuit, newAutoSaveOnSuspend, newUseShadowColors;
	RGBColor  newColors[maxColors];
	
	SetCursor(&arrow);
	dialog = GetNewDialog(preferencesID, NULL, -1);
	/* Set local prefs (to be copyed in global prefs on "OK"): */
	for (i = 0; i <= maxColors-1; i++ )
		newColors[i] = colors[i];
	newAutoSaveOnQuit    = autoSaveOnQuit;
	newAutoSaveOnSuspend = autoSaveOnSuspend;
	newUseShadowColors   = useShadowColors;
	GetDItem(dialog, 3, &itemType, &autoSaveOnQuitControl,    &box);
	GetDItem(dialog, 4, &itemType, &autoSaveOnSuspendControl, &box);
	GetDItem(dialog, 5, &itemType, &useShadowColorsControl,   &box);
	SetCtlValue(autoSaveOnQuitControl,    (newAutoSaveOnQuit   )? 1:0);
	SetCtlValue(autoSaveOnSuspendControl, (newAutoSaveOnSuspend)? 1:0);
	SetCtlValue(useShadowColorsControl,   (newUseShadowColors  )? 1:0);
	do {
		ModalDialog((ProcPtr)PreferencesDlgFilter, &itemHit);
		switch (itemHit ){
		
		case -1: 
			BeginUpdate(dialog);
			SetPort(dialog);		
			DrawDialog(dialog);
			DrawDefaultButton(dialog, 1);
			for (i = 0; i < maxColors; i++ ){
				GetDItem(dialog, yellowID + i, &itemType, &item, &box);
				FrameRect(&box);
				InsetRect(&box, 1, 1);
				Draw3DFrameRect(&box, &colors[i], false);
				InsetRect(&box, 1, 1);
				RGBForeColor(&newColors[i]);
				PaintRect(&box);
				RGBForeColor(&black1);
			}
			EndUpdate(dialog);
			break;
				
		case 1:  /* OK */
			modified = (newAutoSaveOnQuit != autoSaveOnQuit)
				|| (newAutoSaveOnSuspend != autoSaveOnSuspend)
				|| (newUseShadowColors != useShadowColors);
			autoSaveOnQuit = newAutoSaveOnQuit;
			autoSaveOnSuspend = newAutoSaveOnSuspend;
			useShadowColors = newUseShadowColors;
			for (i = 0; i < maxColors; i++ ){
				if( !Equal(&colors[i], &newColors[i]) ){
					colors[i] = newColors[i];
					modified = true;
				}
			}
			if( modified ){
				SavePreferences();
				InvalidateAll();
			}
			DisposDialog(dialog);
			return;
			break;
			
		case 2:  /* Cancel */
			DisposDialog(dialog);
			return;
			break;
		
		case 3:
			newAutoSaveOnQuit = !newAutoSaveOnQuit;
			SetCtlValue((ControlHandle) autoSaveOnQuitControl, newAutoSaveOnQuit & 1);
			break;
		
		case 4:
			newAutoSaveOnSuspend = !newAutoSaveOnSuspend;
			SetCtlValue((ControlHandle) autoSaveOnSuspendControl, newAutoSaveOnSuspend & 1);
			break;
			
		case 5:
			newUseShadowColors = !newUseShadowColors;
			SetCtlValue((ControlHandle) useShadowColorsControl, newUseShadowColors & 1);
			break;
		
		default:
			if( (itemHit >= yellowID) && (itemHit < yellowID + maxColors) ) {
				SetPt(&where, 0, 0);
				if( GetColor(where, "\pBackground Color:", &newColors[itemHit-yellowID], &outColor) ){
					newColors[itemHit-yellowID] = outColor;
					SetPort(dialog);
					InvalRect(&dialog->portRect);
				}
			}
			break;
				
		}
	}while( true);
}


void  CaptureDefaultCmd()
{
	Card *card;
	TextStyle theStyle;
	int a, b;
	DialogPtr dialog;
	int  itemHit;

	card = FrontCard();
	if( card == NULL )  return;
	SetCursor(&arrow);
	dialog = GetNewDialog(captureDefaultID, NULL, -1);
	DrawDefaultButton(dialog, 1);
	ModalDialog(NULL, &itemHit);
	DisposDialog(dialog);
	if( itemHit != 1 )  return;
	normalWidth = card->window->portRect.right;
	normalHeight = card->window->portRect.bottom;
	normalColor = card->color;
	TEGetStyle(0, &theStyle, &a, &b, card->text);
	normalFont = theStyle.tsFont;
	normalFace = theStyle.tsFace;
	normalSize = theStyle.tsSize;
	normalColorR = theStyle.tsColor.red;
	normalColorG = theStyle.tsColor.green;
	normalColorB = theStyle.tsColor.blue;
	SavePreferences();
}


/* Menu: */

void  SetupMenus()
{
	MenuHandle  m;

	m = NewMenu(appleM, "\p\024");
	AppendMenu(m, "\pAbout MemoCards...;(-");
	AddResMenu(m, 'DRVR');
	InsertMenu(m, 0);
	
	m = NewMenu(fileM, "\pFile");
	AppendMenu(m, "\pNew;Open.../O;Close;(-;Save/S;Save As...;(-;Quit/Q");
	InsertMenu(m, 0);

	m = NewMenu(editM, "\pEdit");
	AppendMenu(m, "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All/A");
	InsertMenu(m, 0);
	
	m = NewMenu(cardM, "\pCard");
	AppendMenu(m, "\pNew/N;Reorder/R;Reorder Compact/E;Zoom/H;Lock|Unlock/L");
	AppendMenu(m, "\pFollowing [TAB];Previous [SHIFT+TAB];(-;Preferences...;Capture Default...;(-");
	AppendMenu(m, "\pYellow/1;Red/2;Green/3;Blue/4");
	AppendMenu(m, "\p5/5;6/6;7/7;8/8;9/9;10/0;11/-;12/=");
	InsertMenu(m, 0);
	
	m = NewMenu(fontM, "\p");
	AddResMenu(m, 'FONT');
	InsertMenu(m, -1);
	
	m = NewMenu(sizeM, "\p");
	AppendMenu(m, "\p7;9;10;12;14;18;24;36;48;72");
	InsertMenu(m, -1);
	
	m = NewMenu(faceM, "\p");
	AppendMenu(m, "\pPlain Text/T;<BBold/B;<IItalic/I;<UUnderline/U");
	AppendMenu(m, "\p<OOutline;<SShadow;Condensed/J;Extended/K");
	InsertMenu(m, -1);
	SetItemStyle(m, 7, condense);
	SetItemStyle(m, 8, extend);
	
	m = NewMenu(textM, "\pText");
	AppendMenu(m, "\pFont/\033!\214;Size/\033!\215;Face/\033!\216;Color...");  /*****/
	InsertMenu(m, 0);
	
	DrawMenuBar();
}


int  RetrieveItemNo(MenuHandle m, char *iName)
{
	int i, n;
	char s[256];
	
	n = CountMItems(m);
	for( i = 1; i <= n; i++ ){
		GetItem(m, i, s);
		if( EqPStr(s, iName) )  return  i;
	}
	return  0;
}


void  UncheckAllItems(MenuHandle m)
{
	int i, n;
	
	n = CountMItems(m);
	for( i = 1; i <= n; i++ )  CheckItem(m, i, false);
}


void  Item(MenuHandle m, int item, BOOLEAN enabled)
{
	if( enabled )
		EnableItem(m, item);
	else
		DisableItem(m, item);
}


void  AdjustMenu()
{
	MenuHandle m;
	Card *card;
	int i;
	TextStyle ts;
	int a, b;
	int iNo;
	char iName[256];
	BOOLEAN selectionAvailable;

	card = FrontCard();
	
	/* Menu "File": */
	m = GetMHandle(fileM);
	Item(m, newCmd   , doc == NULL);
	Item(m, openCmd  , doc == NULL);
	Item(m, closeCmd , doc != NULL);
	Item(m, saveCmd  , (doc != NULL) && (doc->modified) );
	Item(m, saveAsCmd, doc != NULL);
	
	/* Menu "Edit": */
	m = GetMHandle(editM);
	selectionAvailable = (card != NULL) && ((*card->text)->selStart != (*card->text)->selEnd);
	Item(m, undoCmd , (card != NULL) && (card->undoAvailable) );
	Item(m, cutCmd  , selectionAvailable && !card->locked);
	Item(m, copyCmd , selectionAvailable);
	Item(m, pasteCmd, (card != NULL) && !card->locked);  /* se lo scrap e' vuoto? ******/
	Item(m, clearCmd, selectionAvailable && !card->locked);
	Item(m, selectAllCmd, card != NULL);
	
	/* Menu "Card": */
	m = GetMHandle(cardM);
	Item(m, newCardCmd  , doc != NULL);
	Item(m, reorderCmd  , card != NULL);
	Item(m, reorderCompactCmd, card != NULL);
	Item(m, zoomCmd     , (card != NULL) && (card->zoomState != undefZoom) && !card->locked );
	Item(m, lockCmd     , card != NULL);
	Item(m, followingCmd, card != NULL);
	Item(m, previousCmd , card != NULL);
	Item(m, captureDefaultCmd, card != NULL);
	for( i = 0; i < maxColors; i++ ){
		if( (card == NULL) || (card->locked) )
			DisableItem(m, yellowCmd + i);
		else
			EnableItem(m, yellowCmd + i);
	}
	
	/* Menu "Text": */
	m = GetMHandle(textM);
	if( (card == NULL) || (card->locked) ){
		DisableItem(m, 1);
		DisableItem(m, 2);
		DisableItem(m, 3);
		DisableItem(m, 4);
	} else {
		EnableItem(m, 1);
		EnableItem(m, 2);
		EnableItem(m, 3);
		EnableItem(m, 4);
		TEGetStyle((*card->text)->selStart, &ts, &a, &b, card->text);
		/* Menu "Font": */
		m = GetMHandle(fontM);
		UncheckAllItems(m);
		GetFontName(ts.tsFont, iName);
		iNo = RetrieveItemNo(m, iName);
		if( iNo > 0 )  CheckItem(m, iNo, true);
		/* Menu "Size": */
		m = GetMHandle(sizeM);
		UncheckAllItems(m);
		NumToString(ts.tsSize, iName);
		iNo = RetrieveItemNo(m, iName);
		if( iNo > 0 )  CheckItem(m, iNo, true);
		/* Menu "Face": */
		m = GetMHandle(faceM);
		CheckItem(m, 1, ts.tsFace == 0);
		CheckItem(m, 2, (ts.tsFace & bold     ) != 0);
		CheckItem(m, 3, (ts.tsFace & italic   ) != 0);
		CheckItem(m, 4, (ts.tsFace & underline) != 0);
		CheckItem(m, 5, (ts.tsFace & outline  ) != 0);
		CheckItem(m, 6, (ts.tsFace & shadow   ) != 0);
		CheckItem(m, 7, (ts.tsFace & condense ) != 0);
		CheckItem(m, 8, (ts.tsFace & extend   ) != 0);
	}
}


void  OpenMenuAcc(int item)
{
	MenuHandle  m;
	Str255  name;
	short  n;
	
	m = GetMHandle(appleM);
	GetItem(m, item, name);
	n = OpenDeskAcc(name);
}


void  SetFont(int item)
{
	Card *card;
	TextStyle  theStyle;
	int a, b;
	int fontNum;
	Str255 fontName;
	
	card = FrontCard();
	if( (card == NULL) || LockedMsg(card) )  return;
	if( item < 1 )  return;
	GetItem(GetMHandle(fontM), item, &fontName);
	GetFNum(&fontName, &fontNum);
	theStyle.tsFont = fontNum;
	TESetStyle(doFont, &theStyle, true, card->text);
	doc->modified = true;
}


void  SetSize(int size)
{
	Card *card;
	TextStyle  theStyle;
	
	card = FrontCard();
	if( (card == NULL) || LockedMsg(card) )  return;
	theStyle.tsSize = size;
	TESetStyle(doSize, &theStyle, true, card->text);
	doc->modified = true;
}


void  SetFace(int face)
{
	Card *card;
	TextStyle  theStyle;
	int a, b, mode;
	
	card = FrontCard();
	if( (card == NULL) || LockedMsg(card) )  return;
	theStyle.tsFace = face;
	if( face == 0 )
		mode = doFace;
	else
		mode = doToggle + doFace;
	TESetStyle(mode, &theStyle, true, card->text);
	doc->modified = true;
}


void  SetTextColor()
{
	Card *card;
	Point where;
	TextStyle theStyle;
	int a, b;

	card = FrontCard();
	if( (card == NULL) || LockedMsg(card) )  return;
	TEGetStyle((*card->text)->selStart, &theStyle, &a, &b, card->text);
	SetPt(&where, 0, 0);
	if( GetColor(where, "\pText Color:", &theStyle.tsColor, &theStyle.tsColor) ){
		TESetStyle(doColor, &theStyle, true, card->text);
		doc->modified = true;
	}
}


void  DoCommand(long  mResult)
{
	int  theMenu, theCmd;

	theMenu = HiWord(mResult);
	theCmd = LoWord(mResult);
	switch (theMenu ){
	
	case appleM:
		if( theCmd == 1 )
			AboutCmd();
		else
			OpenMenuAcc(theCmd);
		break;
	
	case fileM:
		switch (theCmd ){
		
		case newCmd:	NewCmd();  break;
		case openCmd:	OpenCmd();  break;
		case closeCmd:	CloseCmd();  break;
		
		case saveCmd:	SaveCmd();  break;
		case saveAsCmd:	SaveAsCmd();  break;
		
		case quitCmd:	QuitCmd();  break;
		
		}
		break;
	
	case editM:
		switch (theCmd ){
		
		case undoCmd:  UndoCmd();  break;
		
		case cutCmd:  CutCmd();  break;
		case copyCmd:  CopyCmd();  break;
		case pasteCmd:  PasteCmd();  break;
		case clearCmd:  ClearCmd();  break;
		case selectAllCmd:  SelectAllCmd();  break;

		}
		break;
	
	case cardM:
		switch (theCmd ){
		
		case newCardCmd:   NewCardCmd();  break;
		case reorderCmd:   ReorderCmd(false);  break;
		case reorderCompactCmd: ReorderCmd(true);  break;
		case zoomCmd:      ZoomCmd();  break;
		case lockCmd:      LockCmd();  break;
		case followingCmd: FollowingCmd();  break;
		case previousCmd:  PreviousCmd();  break;
		
		case preferencesCmd:  PreferencesCmd();  break;
		case captureDefaultCmd:  CaptureDefaultCmd();  break;
		
		default:  if( theCmd >= yellowCmd )  ColorCmd(theCmd - yellowCmd);
		
		}
		break;
	
	case fontM:  SetFont(theCmd);  break;
	
	case sizeM:
		switch( theCmd ){
		case 1:  SetSize(7);  break;
		case 2:  SetSize(9);  break;
		case 3:  SetSize(10);  break;
		case 4:  SetSize(12);  break;
		case 5:  SetSize(14);  break;
		case 6:  SetSize(18);  break;
		case 7:  SetSize(24);  break;
		case 8:  SetSize(36);  break;
		case 9:  SetSize(48);  break;
		case 10:  SetSize(72);  break;
		}
		break;
	
	case faceM:
		switch( theCmd ){
		case 1:  SetFace(0);       break;
		case 2:  SetFace(bold);    break;
		case 3:  SetFace(italic);  break;
		case 4:  SetFace(underline);  break;
		case 5:  SetFace(outline);  break;
		case 6:  SetFace(shadow);  break;
		case 7:  SetFace(condense);  break;
		case 8:  SetFace(extend);  break;
		}
		break;
	
	case textM:
		switch( theCmd ){
		case 4: SetTextColor();  break;
		}
		break;
	
	}
	HiliteMenu(0);
}


/* Gestione azioni dell'utente sulla inContent area della window: */


BOOLEAN  TrackInButton(Card * card, Rect *button)
{
	BOOLEAN  checked;
	Point  where;
	long targetTime;

	SetPort(card->window);
	RGBBackColor(&white1);
	checked = false;
	do {
		GetMouse(&where);
		if( PtInRect(where, button) != checked ){
			checked = !checked;
			Draw3DFrameRect(button, &colors[card->color], checked);
			if( checked )  targetTime = TickCount() + 10L;
		}
	}while( StillDown());
	if( checked ){
		do{ }while( TickCount() < targetTime );
		Draw3DFrameRect(button, &colors[card->color], false);
	}
	RGBBackColor(&colors[card->color]);
	return  checked;
}


Card *throwAwayCard;
long throwAwayTargetTime;
BOOLEAN throwAwayChecked;


void  Flash()
{
	WindowPtr origGrapPort;
	Rect closeBox;
	
	origGrapPort = thePort;
	SetPort(throwAwayCard->window);
	SetCloseBox(throwAwayCard, &closeBox);
	Draw3DFrameRect(&closeBox, &colors[throwAwayCard->color], throwAwayChecked);
	SetPort(origGrapPort);
}


pascal BOOLEAN  ThrowAwayAlertFilter(DialogPtr dialog,  EventRecord * event,
	int * iHit)
{
	if( TickCount() > throwAwayTargetTime ){
		Flash();
		throwAwayChecked = !throwAwayChecked;
		throwAwayTargetTime = TickCount() + 20;
	}
	if( (event->what == keyDown) ){
		switch( (int) (event->message & charCodeMask) ){
		case CR:
		case ETX:
			PressButton(dialog, 1);
			*iHit = 1;
			return  0xFFFF;
		}
	}
	return  0;
}


BOOLEAN  ThrowAwayAlert(Card *card)
{
	int iHit;
	
	if( (*(card->text))->teLength == 0 )  /****/
		return  true;
	else {
		throwAwayCard = card;
		throwAwayTargetTime = 0L;
		throwAwayChecked = false;
		iHit = CautionAlert(throwAwayID, ThrowAwayAlertFilter);
		if( throwAwayChecked )  Flash();
		return (iHit == iThrowAway);
	}
}


BOOLEAN  InCloseBox(Point where, Card *card)
{
	Rect  closeBox;
	
	SetCloseBox(card, &closeBox);
	return  PtInRect(where, &closeBox)
		&& TrackInButton(card, &closeBox)
		&& ThrowAwayAlert(card);
}


BOOLEAN  InZoomBox(Point where, Card *card)
{
	Rect zoomBox;
	
	SetZoomBox(card, &zoomBox);
	return  PtInRect(where, &zoomBox) && TrackInButton(card, &zoomBox);
}


BOOLEAN  PtInGrowBox(Point  where, Card *card)
{
	Rect  growBox;
	
	SetGrowBox(card, &growBox);
	return  PtInRect(where, &growBox);
}


void  HandleInContentMouseDown(EventRecord * event,  WindowPtr window)
{
	Card *card;

	card = WindowToCard(window);
	if( card == NULL )  return;
	if( (cmdKey & event->modifiers) != 0 ){
		DragCard(card, event->where);
	} else if( window == FrontWindow() ){
		SetPort(window);
		GlobalToLocal(&event->where);
		if( (!card->locked) && InCloseBox(event->where, card) ){
			doc->modified = true;
			DisposeCard(card);
		} else if( (!card->locked)
			&& (card->zoomState != undefZoom)
			&& InZoomBox(event->where, card) ){
			DoZoom(card);
		} else if( event->where.v < glueBand ){
			LocalToGlobal(&event->where);
			DragCard(card, event->where);
		} else if( !card->locked && PtInGrowBox(event->where, card) ){
			GrowCard(card, event->where);
		} else if( PtInRect(event->where, &(*(card->text))->viewRect) )
			TEClick(event->where, (shiftKey & event->modifiers) != 0, card->text);
	} else
		SelectWindow(window);
}


void  HandleMouseDown(EventRecord * event)
{
	int  thePart;
	WindowPtr  window;

	thePart = FindWindow(event->where, &window);
	switch (thePart ){
	
	case inSysWindow:  SystemClick(event, window);  break;
	
	case inMenuBar:
		AdjustMenu();
		DoCommand(MenuSelect(event->where));
		break;
		
	case inContent:  HandleInContentMouseDown(event, window);  break;

	}
}


void  HandleOSEvt(EventRecord *event)
#define osEvt 15
#define suspendResumeMessage (0x01000000)
#define resumeFlag (0x00000001)
{
	if( (event->message & 0xFF000000) == suspendResumeMessage )
		if( (event->message & resumeFlag) == 0 ){
			/* suspend */
			if( autoSaveOnSuspend && (doc != NULL) && doc->modified
			&& !EqPStr(doc->name, untitled))  Save();
		} else {
			/* resume */
		}
}


/* PROCEDURE per l'interfaccia al Finder: */
/* NOTA: col System 7 sarebbe pių corretto usare gli high level events. */

void  OpenSelectedFiles()
{
	int  message, count, i;
	AppFile  theFile;

	CountAppFiles(&message, &count);
	if( count == 0 )
		NewCmd();
	else {
		for (i = 1; i <= count; i++ ){
			GetAppFiles(i, &theFile);
			if( theFile.fType == dataType ){
				if( MultipleDocsDisallowedMsg() )  /* confusing message? */
					return;
				else {
					OpenDoc(theFile.vRefNum, (char*)theFile.fName);
					ClrAppFiles(i);
				}
			} else {
				/* this file type is not readable *****/
			}
		}
	}
}


void  IdleTasks()
{
	Card *card;

	card = FrontCard();
	if( card != NULL )  TEIdle(card->text);
}


void  UpdateTextArea(Card *card)
{
	TECalText(card->text);
	SetPort(card->window);
	EraseRect(&(*card->text)->viewRect);
	TEUpdate(&(*card->text)->viewRect, card->text);
}


void  DoHome(Card *card)
{
	(*card->text)->destRect.top = (*card->text)->viewRect.top;
	UpdateTextArea(card);
}


void  DoEnd(Card *card)
{
	Rect view, dest;
	int endV;
	
	view = (*card->text)->viewRect;
	dest = (*card->text)->destRect;
	endV = HiWord(TEGetPoint(32767, card->text));
	dest.top -= endV - (view.top + view.bottom) / 2;
	if( dest.top > view.top )  return;
	(*card->text)->destRect = dest;
	UpdateTextArea(card);
}


void  DoPageUp(Card *card)
{
	Rect view, dest;
	
	view = (*card->text)->viewRect;
	dest = (*card->text)->destRect;
	dest.top += view.bottom - view.top;
	if( dest.top > view.top )  dest.top = view.top;
	(*card->text)->destRect = dest;
	UpdateTextArea(card);
}


void  DoPageDw(Card *card)
{
	Rect view, dest;
	
	view = (*card->text)->viewRect;
	dest = (*card->text)->destRect;
	dest.top -= view.bottom - view.top;
	if( HiWord(TEGetPoint(32767, card->text)) < (view.top + view.bottom) / 2 )  return;
	(*card->text)->destRect = dest;
	UpdateTextArea(card);
}


void  InsertChar(int c)
{
	Card *card;
	int selStart, selEnd, origLen;

	card = FrontCard();
	if( card == NULL )  return;
	switch( c ){
	
	case  1:  DoHome(card);  break;
	case  4:  DoEnd(card);  break;
	case 11:  DoPageUp(card);  break;
	case 12:  DoPageDw(card);  break;
	
	case 28:
	case 29:
	case 30:
	case 31:  TEKey(c, card->text);  break;
	
	default:  
		if( LockedMsg(card) )  return;
		ObscureCursor();
		selStart = (*card->text)->selStart;
		selEnd   = (*card->text)->selEnd;
		origLen  = (*card->text)->teLength;
		if( selStart == selEnd ){
			TEKey(c, card->text);
			if( card->undoAvailable && (card->undoPos > selStart) )
				card->undoPos += (*card->text)->teLength - origLen;
		} else {
			SaveSelectionForUndo(card);
			TEKey(c, card->text);
		}
		doc->modified = true;
	}
}


void  MaintainCursor()
{
	Card *card;
	Point  where;

	card = FrontCard();
	if( card == NULL )
		SetCursor(&arrow);
	else {
		SetPort(card->window);
		GetMouse(&where);
		if( PtInRect(where, &((*(card->text))->viewRect)))
			SetCursor(&iBeam);
		else
			SetCursor(&arrow);
	}
}


ToolboxInit()
{
	MaxApplZone();
	InitGraf(&thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(NULL);
	InitCursor();
}


void  DoEvent(EventRecord *event)
{
	int c;
	
	switch (event->what ){
	
	case updateEvt:  UpdateWindow((WindowPtr) event->message);  break;
	
	case activateEvt:  Activate((WindowPtr) event->message, (activeFlag & event->modifiers) != 0);  break;
	
	case mouseDown:  HandleMouseDown(event);  break;
	
	case keyDown:
	case autoKey:
		c = (int) (event->message & charCodeMask);
		if( (cmdKey & event->modifiers) != 0 ){
			if( event->what != autoKey ){
				AdjustMenu();
				DoCommand(MenuKey(c));
			}
		} else if( c == HT ){
			if( (shiftKey & event->modifiers) != 0 )
				PreviousCmd();
			else
				FollowingCmd();
		} else
			InsertChar(c);
		break;
		
	case osEvt:  HandleOSEvt(event);  break;
	
	}
}


pascal long  MyGrowZone(Size cbNeeded)
{
	Card *card;
	long saved;
	
	saved = 0;
	card = (doc == NULL)? NULL : doc->cards;
	while( card != NULL ){
		if( card->undoAvailable ){
			saved += GetPtrSize(card->undoText) + GetHandleSize(card->undoStyle);
			DisposeUndoData(card);
		}
		card = card->link;
	}
	if( (saved == 0) && (memoryReserve != NULL) ){
		saved += GetPtrSize(memoryReserve);
		DisposHandle(memoryReserve);
		memoryReserve = NULL;
	}
	memoryLow = true;
	return  saved;
}


main()
{
	EventRecord  event;
	CursHandle  iBeamH;
	
	/* Initialization: */
	ToolboxInit();
	doc = NULL;
	
	SetGrowZone(MyGrowZone);
	SetApplLimit(StackPtr() - 10 * 1024);
	MoreMasters();
	MoreMasters();
	memoryReserve = NewHandle(10*1024);
	
	offsetPosition = 0;
	iBeamH = GetCursor(1);
	iBeam = **iBeamH;
	DisposHandle(iBeamH);
	SetColor(&black1, 0, 0, 0);
	SetColor(&white1, 255, 255, 255);
	SetupMenus();
	LoadPreferences();
	
	/* Finder interface: */
	OpenSelectedFiles();
	
	/* Event loop: */
	quitProgram = false;
	do {
		SystemTask();
		IdleTasks();
		MaintainCursor();
		if( memoryLow ){
			Message(cautionAlert, "\pDANGER! Memory is too low.",
				"\pMay be some operation can't be completed. For your safety, save the document!");
			memoryLow = false;
		}
		if( GetNextEvent(everyEvent, &event) )  DoEvent(&event);
	}while( !quitProgram );
}
