/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

/*
 * Local variables:
 *   lHelpScroll = handle to the scroll bar
 *   lHelpTextEdit = TextEdit record for the help window
 *   lHelpWindow = pointer to the dialog record for the help dialog
 *
 */

static ControlHandle gHelpScroll = nil, gHelpMenu = nil;
static Rect gHelpTextRect = { 34, 9, 287, 459 };
static TEHandle gHelpTextEdit = nil;
static WindowPtr gHelpWindow = nil;
static ControlActionUPP gHelpScrollAction = nil;

extern void HandleHelpGrow(Point where)
{
	Rect limitRect = { 150, 400, 32767, 32767 }, newRect;
	long newSize;
	
	if (newSize = GrowWindow(gHelpWindow, where, &limitRect)) {
		newRect = gHelpWindow->portRect;
		newRect.right = newRect.left + (newSize & 0xffff);
		newRect.bottom = newRect.top + (newSize >> 16);
		GlobalRect(&newRect, gHelpWindow);
		SendSetWindowBounds(gHelpWindow, &newRect);
	}
}

/*
 * HandleHelpChoice(theItem)
 *
 *     Purpose: Handles menu events from the Help menu
 *      Inputs: theItem = the menu item number
 *     Returns: nothing
 *
 */
 
void HandleHelpChoice(short theItem) 
{
	if (theItem == gHelpItem) SendCreateWindow(kHelpWindowID);
}

/*
 * OpenHelp()
 *
 *     Purpose: Creates and initializes the help dialog and its various controls
 *      Inputs: theSection = the section to open up to
 *     Returns: nothing
 *
 */

OSErr OpenHelp(void)
{
	OSErr theErr = noErr;
	Point where;

	if (!gHelpFound) return errNoHelpFound;
	if (gHelpWindow) {
		if (!WindowVisible(gHelpWindow)) FWShowWindow(gHelpWindow);
		return noErr;
	}
	StartSpinning();
	if (!(gHelpWindow = AllocateWindow())) return memFullErr;
	KeepSpinning();
	PushPort();
	MySetPort(nil);
	if (gHelpWindow = FWGetNewWindow(rHelpWindow, (Ptr)gHelpWindow, (WindowPtr)-1)) {
		MySetPort((CGrafPtr)gHelpWindow);
		KeepSpinning();
		if ((gHelpTextEdit = TEStylNew(&gHelpTextRect, &gHelpTextRect)) &&
			(gHelpScroll = GetNewControl(rHelpScrollControl, gHelpWindow)) &&
			(gHelpMenu = GetNewControl(rHelpMenuControl, gHelpWindow))) {
			KeepSpinning();
			SetCtlValue(gHelpMenu, gThePrefs.helpSection);
			GetHelpText(gThePrefs.helpSection - 1);
			if (gHelpWindow) {
				if ((gThePrefs.helpBounds.top == gThePrefs.helpBounds.bottom) ||
					(DoSetWindowBounds(gHelpWindow, &gThePrefs.helpBounds) != noErr)) {
					where = CenterWindow(gHelpWindow);
					FWMoveWindow(gHelpWindow, where.h, where.v, false);
				}
				ResizeHelp(&gHelpWindow->portRect);
			}
			StopSpinning(&qd.arrow);
			PopPort();
			return noErr;
		} else gIntError = errNoHelp, theErr = memFullErr;
	} else gIntError = errNoHelp, theErr = memFullErr;
	CloseHelp();
	StopSpinning(&qd.arrow);
	PopPort();
	return theErr;
}

/*
 * CloseHelp()
 *
 *     Purpose: Creates and initializes the help dialog and its various controls
 *      Inputs: theSection = the section to open up to
 *     Returns: nothing
 *
 */

void CloseHelp(void)
{
	PushPort();
	MySetPort(nil);
	if (gHelpScroll) DisposeControl(gHelpScroll);
	gHelpScroll = nil;
	if (gHelpMenu) DisposeControl(gHelpMenu);
	gHelpMenu = nil;
	if (gHelpTextEdit) TEDispose(gHelpTextEdit);
	gHelpTextEdit = nil;
	if (gHelpWindow) {
		SaveWindowPosition(gHelpWindow, &gThePrefs.helpBounds);
		FWCloseWindow(gHelpWindow);
		DeallocateWindow(gHelpWindow);
	}
	gHelpWindow = nil;
	PopPort();
}

/*
 * GetHelpWindow()
 *
 *     Purpose: Returns a pointer to the help window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
WindowPtr GetHelpWindow(void)
{
	return gHelpWindow;
}

/*
 * HandleHelpClick(theItem)
 *
 *     Purpose: Handles events in the help dialog
 *      Inputs: theItem = the item that was clicked on
 *     Returns: nothing
 *
 */

void HandleHelpClick(Point where)
{
	ControlHandle theControl;
	short thePart, theValue;
	
	MySetPort((CGrafPtr)gHelpWindow);
	GlobalToLocal(&where);
	if (!(thePart = FindControl(where, gHelpWindow, &theControl))) return;
	if (theControl == gHelpScroll) {
		if (thePart == inThumb) {
			theValue = GetCtlValue(theControl);
			if (TrackControl(theControl, where, nil)) 
				UpdateHelpScroll(theValue, GetCtlValue(theControl));
		} else {
			if (!gHelpScrollAction)
				gHelpScrollAction = NewControlActionProc((ProcPtr)HelpScrollAction);
			TrackControl(theControl, where, gHelpScrollAction);
		}
	} else if (theControl == gHelpMenu) {
		if (TrackControl(theControl, where, (ControlActionUPP)-1)) {
			gThePrefs.helpSection = GetCtlValue(theControl);
			GetHelpText(gThePrefs.helpSection - 1);
		}
	}
}

/*
 * HandleHelpKey(theChar, theKey)
 *
 *     Purpose: Handles key down events in the help window
 *      Inputs: theChar = the ASCII representation of the character
 *				theKey = the key code of the key pressed
 *     Returns: nothing
 *
 */
 
Boolean HandleHelpKey(uchar theChar, uchar theKey) 
{
#if applec
#pragma unused(theKey)
#endif
	Boolean result = false;
	
	PushPort();
	MySetPort((CGrafPtr)gHelpWindow);
	switch (theChar) {
		case kPageUpChar:
			HelpScrollAction(gHelpScroll, inPageUp);
			result = true;
			break;
		case kPageDownChar:
			HelpScrollAction(gHelpScroll, inPageDown);
			result = true;
			break;
	}
	PopPort();
	return result;
}

/*
 * HandleHelpActivate(nowActive)
 *
 *     Purpose: Handles activate/deactivate events in the help window
 *      Inputs: nowActive = flag: true if we're now becoming the active window
 *     Returns: nothing
 *
 */
 
void HandleHelpActivate(Boolean nowActive)
{
	Rect theRect;
	
	PushPort();
	MySetPort((CGrafPtr)gHelpWindow);
	ClipRect(&gHelpWindow->portRect);
	if (gHelpScroll) {
		if (nowActive) ShowControl(gHelpScroll);
		else {
			HideControl(gHelpScroll);
			MoveTo((*gHelpScroll)->contrlRect.left, (*gHelpScroll)->contrlRect.top);
			LineTo((*gHelpScroll)->contrlRect.right, (*gHelpScroll)->contrlRect.top);
		}
	}
	theRect = gHelpWindow->portRect;
	theRect.left = theRect.right - 15;
	theRect.top = gHelpTextRect.top - 1;
	ClipRect(&theRect);
	DrawGrowIcon(gHelpWindow);
	ClipRect(&gHelpWindow->portRect);
	PopPort();
}

/*
 * GetHelpText(theSect)
 *
 *     Purpose: Fetches the desired text from its resource, copies it into the TextEdit
 *					record, and resets the scroll bar maximum
 *      Inputs: theSect = the section number we're interested in
 *     Returns: nothing
 *
 */
 
void GetHelpText(short theSect)
{
	Handle helpText, helpStyl;
	
	if (helpText = GetCompResource('ctxt', kHelpTextBase + theSect)) {
		if (helpStyl = GetCompResource('csty', kHelpTextBase + theSect)) {
			TESetSelect(0, 32767, gHelpTextEdit);
			TEDelete(gHelpTextEdit);
			HLock(helpText);
			HLock(helpStyl);
			TEScroll(0, (*gHelpTextEdit)->viewRect.top - (*gHelpTextEdit)->destRect.top, 
				gHelpTextEdit);
			TEStylInsert(*helpText, GetHandleSize(helpText), (StScrpHandle)helpStyl, 
				gHelpTextEdit);
			HUnlock(helpStyl);
			HUnlock(helpText);
			ReleaseResource(helpText);
			ReleaseResource(helpStyl);
			ResizeHelp(&gHelpWindow->portRect);
			return;
		}
	}
	MinorError(errNoHelp);
	CloseHelp();
}

/*
 * ResizeHelp(newRect)
 *
 *     Purpose: Redraws the help window
 *      Inputs: newRect = pointer to the new window rectangle
 *     Returns: nothing
 *
 */
 
void ResizeHelp(Rect *newRect)
{
	Rect itemRect = *newRect, menuRect, monRect, oldRect = gHelpWindow->portRect;
	MonitorHandle largeMon = GetBigMonitor(false);
	short theMax, theAmount = 0;
	LHHandle theLines;

	GetActiveRect(largeMon, &monRect);
	monRect.top += gTitleBarHeight;
	if (Width(newRect) > Width(&monRect)) 
		newRect->right = newRect->left + (Width(&monRect) - 2 * kWindowBorderWidth);
	if (Height(newRect) > Height(&monRect)) 
		newRect->bottom = newRect->top + (Height(&monRect) - 2 * kWindowBorderHeight);
	SizeWindow(gHelpWindow, Width(newRect), Height(newRect), false);
	OffsetRect(&itemRect, -itemRect.left, -itemRect.top);
	PushPort();
	MySetPort((CGrafPtr)gHelpWindow);
	ClipRect(&gHelpWindow->portRect);
	if (gHelpTextEdit) {
		InsetRect(&itemRect, 1, 1);
		itemRect.top += 10 + 20 + 6;
		itemRect.right -= 15;
		gHelpTextRect = (*gHelpTextEdit)->viewRect = (*gHelpTextEdit)->destRect = itemRect;
		TECalText(gHelpTextEdit);
		theLines = (*GetStylHandle(gHelpTextEdit))->lhTab;
		theMax = (*gHelpTextEdit)->nLines + 1;
		while ((theMax > 0) && (theAmount < Height(&gHelpTextRect))) {
			theMax--;
			theAmount += (*theLines)[theMax].lhHeight;
		}
	}
	if (gHelpScroll) {
		MoveControl(gHelpScroll, itemRect.right + 1, itemRect.top - 2);
		SizeControl(gHelpScroll, Width(&(*gHelpScroll)->contrlRect), Height(&itemRect) + 4 - 15);
		SetCtlMax(gHelpScroll, theMax);
		SetCtlValue(gHelpScroll, 0);
	}
	if (gHelpMenu) {
		menuRect = (*gHelpMenu)->contrlRect;
		MoveControl(gHelpMenu, (Width(&itemRect) - Width(&menuRect)) >> 1, menuRect.top);
	}
	itemRect = gHelpWindow->portRect;
	itemRect.top = gHelpTextRect.top - 2;
	if (!EqualSizeRect(&oldRect, newRect)) InvalRect(&itemRect);
	PopPort();
}

/*
 * UpdateHelp()
 *
 *     Purpose: Redraws the help window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
void UpdateHelp(void) 
{
	Rect theRect;
	
	TextFont(systemFont);
	TextSize(12);
	ClipRect(&gHelpWindow->portRect);
	PenSize(1, 1);
	InsetRect(&gHelpTextRect, -1, -1);
	PenPat(&qd.white);
	FrameRect(&gHelpTextRect);
	InsetRect(&gHelpTextRect, -1, -1);
	PenPat(&qd.black);
	FrameRect(&gHelpTextRect);
	InsetRect(&gHelpTextRect, 2, 2);
	MoveTo((*gHelpScroll)->contrlRect.left, (*gHelpScroll)->contrlRect.top);
	LineTo((*gHelpScroll)->contrlRect.right, (*gHelpScroll)->contrlRect.top);
	TEUpdate(&gHelpTextRect, gHelpTextEdit);
	UpdtControl(gHelpWindow, gHelpWindow->visRgn);
	theRect = gHelpWindow->portRect;
	theRect.left = theRect.right - 15;
	theRect.top = gHelpTextRect.top - 1;
	ClipRect(&theRect);
	DrawGrowIcon(gHelpWindow);
	ClipRect(&gHelpWindow->portRect);
}

/*
 * UpdateHelpScroll(oldValue, newValue)
 *
 *     Purpose: Updates the scroll bars to the newValue from oldValue
 *      Inputs: oldValue = the previous position of the scroll bar
 *				newValue = the new position of the scroll bar
 *     Returns: nothing
 *
 */
 
void UpdateHelpScroll(short oldValue, short newValue) 
{
	LHHandle theLines = (*GetStylHandle(gHelpTextEdit))->lhTab;
	short theAmount = 0;

	if (newValue < oldValue) {
		while (oldValue != newValue) {
			oldValue--;
			theAmount += (*theLines)[oldValue].lhHeight;
		}
	} else {
		while (oldValue != newValue) {
			theAmount -= (*theLines)[oldValue].lhHeight;
			oldValue++;
		}
	}
	if (theAmount) TEScroll(0, theAmount, gHelpTextEdit);
}

/*
 * HelpScrollAction(theControl, thePart)
 *
 *     Purpose: Called by TrackControl() to constantly update the scrolling region while
 *					the mouse button is held down
 *      Inputs: theControl = handle of the scroll bar
 *				thePart = the part that's being clicked on
 *     Returns: nothing
 *
 */
 
pascal void HelpScrollAction(ControlHandle theControl, short thePart) 
{
	short theAmount = 0, theValue, maxValue;
	LHHandle theLines;
	
	if (!thePart) return;
	theLines = (*GetStylHandle(gHelpTextEdit))->lhTab;
	theValue = GetCtlValue(theControl);
	maxValue = GetCtlMax(theControl);
	switch (thePart) {
		case inUpButton:
			if (theValue > 0) {
				theValue--;
				theAmount = (*theLines)[theValue].lhHeight;
			}
			break;
		case inDownButton:
			if (theValue < maxValue) {
				theAmount = -(*theLines)[theValue].lhHeight;
				theValue++;
			}
			break;
		case inPageUp:
			while ((theValue > 0) && 
				   (theAmount < (Height(&(*gHelpTextEdit)->viewRect) - 10))) {
				theValue--;
				theAmount += (*theLines)[theValue].lhHeight;
			}
			break;
		case inPageDown:
			while ((theValue < maxValue) && 
				   (-theAmount < (Height(&(*gHelpTextEdit)->viewRect) - 10))) {
				theAmount -= (*theLines)[theValue].lhHeight;
				theValue++;
			}
			break;
	}
	SetCtlValue(theControl, theValue);
	if (theAmount) TEScroll(0, theAmount, gHelpTextEdit);
}

/*
 * DoHelpHelp(globalPt)
 *
 *     Purpose: Pops up help for the help window; needed because things keep moving around
 *      Inputs: globalPt = point, in global coordinates, where the mouse is
 *     Returns: nothing
 *
 */
 
void DoHelpHelp(Point globalPt)
{
	Point tip = { 0, 0 }, localPt = globalPt;
	HMMessageRecord theRecord;
	short index = 0;
	Rect aRect;
	
	if (HMIsBalloon() || gInBackground) return;
	PushPort();
	MySetPort((CGrafPtr)gHelpWindow);
	GlobalToLocal(&localPt);
	if (localPt.h >= (gHelpWindow->portRect.right - 15) && 
		localPt.v >= (gHelpWindow->portRect.bottom - 15)) {
		aRect = gHelpWindow->portRect;
		aRect.top = aRect.bottom - 15;
		aRect.left = aRect.right - 15;
		tip.h = aRect.left + (Width(&aRect) >> 1);
		tip.v = aRect.top + (Height(&aRect) >> 1);
		index = 1;
	} else if (PtInRect(localPt, &(*gHelpScroll)->contrlRect)) {
		aRect = (*gHelpScroll)->contrlRect;
		tip.h = aRect.left + (Width(&aRect) >> 1);
		tip.v = aRect.top + (Height(&aRect) >> 1);
		index = 2;
	} else if (PtInRect(localPt, &(*gHelpMenu)->contrlRect)) {
		aRect = (*gHelpMenu)->contrlRect;
		tip = BotRight(aRect);
		tip.h -= 10;
		tip.v -= 10;
		index = 3;
	} else if (PtInRect(localPt, &(*gHelpTextEdit)->viewRect)) {
		aRect = (*gHelpTextEdit)->viewRect;
		tip = BotRight(aRect);
		tip.h -= 10;
		tip.v -= 10;
		index = 4;
	}
	if (index &&
		HMExtractHelpMsg(kHMRectListResType, rHelpWindow, index, kHMEnabledItem, &theRecord) == noErr) {
		LocalToGlobal(&tip);
		GlobalRect(&aRect, gHelpWindow);
		HMShowBalloon(&theRecord, tip, &aRect, nil, 0, 0, kHMRegularWindow);
	}
	PopPort();
}
