/*	MacFloater.cpp
 *
 *		This is the implementation of the floating window stuff. This
 *	requires the routine 'XGRDoActivate' to be a valid subroutine which can
 *	be called to activate the window's contents, and this also requires
 *	that the 'activeEvt' of the event loop gets ignored...
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include "MacFloater.h"						/* Float library support	*/
#include <LowMem.h>							/* LMGetMBarHeight()		*/

/************************************************************************/
/*																		*/
/*	Search Routines														*/
/*																		*/
/************************************************************************/

/*	MFrontWindow
 *
 *		Find the frontmost non-floater. This searches down the linked
 *	list of windows that is maintained internaly by the Macintosh OS
 *	(the linked list kept through the WindowRecord field 'nextWindow')
 *	until I find a window which has the proper type.
 */

WindowPtr MFrontWindow(void)
{
	WindowPeek w;
	
	w = (WindowPeek)FrontWindow();
	for (;;) {
		if (w == NULL) break;
		if ((w->windowKind != KFloatingWindow) && (w->windowKind != KDialogWindow)) {
			if (w->visible) break;
		}
		w = w->nextWindow;					/* Nope, this ain't it. Go on. */
	}
	return (WindowPtr)w;
}

/*	MLastFloater
 *
 *		Get the last floater window position. This is not similar to
 *	anything in the Macintosh OS, but is very useful for figuring out
 *	where new non-floater windows go.
 */

WindowPtr MLastFloater(void)
{
	WindowPeek w;
	WindowPeek prev;
	
	prev = NULL;
	w = (WindowPeek)FrontWindow();
	while (w && ((w->windowKind == KFloatingWindow) || (w->windowKind == KDialogWindow))) {
		prev = w;
		w = w->nextWindow;
	}
	return (WindowPtr)prev;
}

/************************************************************************/
/*																		*/
/*	Selection Routines													*/
/*																		*/
/************************************************************************/

/*	MSelectWindow
 *
 *		Like select window, except for floating windows. If this is called
 *	with a floating window, it brings the floating window to the front of
 *	all of the floating windows. If called on a non-floater, this brings
 *	the non-floating window frontmost.
 */

void MSelectWindow(WindowPtr w)
{
	short isFloater;
	WindowPtr current;
	WindowPtr last;
	
	/*
	 *  Based on what kind of window this is (floating, nonfloating)
	 *	initialize some interesting variables for later
	 */
	
	if (((WindowPeek)w)->windowKind == KFloatingWindow) {
		current = FrontWindow();
		isFloater = 1;
	} else {
		isFloater = 0;
		current = MFrontWindow();
		last = MLastFloater();
	}
	
	/*
	 *  Now if we are not the current window, do the selection
	 */
	
	if (current != w) {
		if (isFloater) {
			/*
			 *  Bringing a floater forward can be done by bringing the
			 *	thing all the way to the front.
			 */
			
			BringToFront(w);
		} else {
			if (last == NULL) {
				/*
				 *  This is a standard window, but there are no floaters
				 */
				
				HiliteWindow(current,0);	/* Unhilite this window		*/
				XGRDoActivate(current,0);		/* And deactivate it		*/
				BringToFront(w);			/* Bring this one frontmost	*/
				HiliteWindow(w,1);
				XGRDoActivate(w,1);			/* ###6 Need System 6 tests.*/
			} else {
				HiliteWindow(current,0);	/* Unhilite this window		*/
				XGRDoActivate(current,0);		/* And deactivate it		*/
				SendBehind(w,last);
				
#ifdef PREVERSION7
				/*
				 *  The following two routines are only needed if this
				 *	were to run under an operating system earlier than
				 *	System 7. But as we are not going to do that, well,
				 *	these routines simply are not needed; the routine
				 *	'SendBehind' does the right thing.
				 */
				
				PaintOne((WindowPeek)w,((WindowPeek)w)->strucRgn);
				CalcVis((WindowPeek)w);
#endif

				HiliteWindow(w,1);
				XGRDoActivate(w,1);			/* ###6 Need System 6 tests.*/
			}								/* PaintOne & CalcVis		*/
		}
	}
}

/*	MDragWindow
 *
 *		Do the drag window thing
 */

void MDragWindow(WindowPtr windowToDrag, Point startPoint, const Rect *draggingBounds)
{
	Rect		dragRect;
	KeyMap		keyMap;
	GrafPtr		savePort;
	GrafPtr		windowManagerPort;
	RgnHandle	dragRegion;
	RgnHandle	windowContentRegion;
	long		dragResult;
	short		topLimit;
	short		newHorizontalWindowPosition;
	short		newVerticalWindowPosition;
	short		horizontalOffset;
	short		verticalOffset;
	Boolean		commandKeyDown = false;
	
	if (WaitMouseUp()) {
		/*
		 * Adjust the top of the dragging rectangle so that itÕs below 
		 * the menu bar
		 */
	
		topLimit = LMGetMBarHeight() + 4;
		dragRect = *draggingBounds;
		if (dragRect.top < topLimit) dragRect.top = topLimit;
	
		/* Set up the Window Manager port. */
	
		GetPort(&savePort);
		GetWMgrPort(&windowManagerPort);
		SetPort(windowManagerPort);
		SetClip(GetGrayRgn());
		
		/*
		 * Check to see if the command key is down.  If it is, donÕt bring the window to the
		 * front after the move.  Trying to do Pascal stuff in C is so much fun.  GetKeys()
		 * is a total pain to try to use properly from C, so IÕm going to hard code where the
		 * command key is in the KeyMap array.
		 */
		 
		GetKeys(keyMap);
		if (keyMap[1] & 0x8000) commandKeyDown = true;
		if ((commandKeyDown == true) || 
				(((WindowPeek)windowToDrag)->windowKind != KFloatingWindow)) {
			
			if (commandKeyDown == false)
	
		/*
		 * If there are floating windows, clip the dragging outline 
		 * to draw behind the floaters.
		 */
		 
				ClipAbove(MFrontWindow());
			else
			
		/*
		 * If the command key was down, clip the outline to draw behind any windows above
		 * the window being dragged.
		 */
		 
				ClipAbove(windowToDrag);
		}
			
		/* Create a region to drag */
	
		dragRegion = NewRgn();
		CopyRgn(((WindowPeek)windowToDrag)->strucRgn, dragRegion);
		
		/* Drag the window around */
	
		dragResult = DragGrayRgn(dragRegion, startPoint, &dragRect, &dragRect, noConstraint, nil);
	
		/* Restore the port for coordinate conversion. */
	
		SetPort(savePort);

		if (dragResult != 0) {
			horizontalOffset = dragResult & 0xFFFF;
			verticalOffset = dragResult >> 16;
	
		/* Only move it if it stayed inside the dragging box. */
	
			if (verticalOffset != -32768) {
				windowContentRegion = ((WindowPeek)windowToDrag)->contRgn;
				newHorizontalWindowPosition = (**windowContentRegion).rgnBBox.left + horizontalOffset;
				newVerticalWindowPosition = (**windowContentRegion).rgnBBox.top + verticalOffset;
				
				MoveWindow((WindowPtr) windowToDrag, newHorizontalWindowPosition, newVerticalWindowPosition, false);
				
			}
		}
	
		/* Bring the window forward if the command key wasnÕt down */
	
		if (commandKeyDown == false)
			MSelectWindow(windowToDrag);
	
		/* Get rid of the dragging region */
	
		DisposeRgn(dragRegion);
	}
}

/*	MGetWindowList
 *
 *		Get the window list top
 */

static WindowPtr MGetWindowList(void)
{
	return (*(WindowPtr *)0x09D6);
}

/*	MValidateWindowList
 *
 *		Validation of the window list's order
 */

static void MValidateWindowList(void)
{
	WindowPtr	currentWindow = MGetWindowList();
	WindowPtr	lastFloatingWindow = MLastFloater();
	WindowPtr	firstFloatingWindow = nil;
	WindowPtr	documentWindowsToMove = nil;
	WindowPtr	lastDocumentWindowAdded = nil;
	WindowPtr	previousWindow = nil;
	
	if (currentWindow) {
	
	/*
	 * First, gather up all the document windows in front of floating windows. We iterate
	 * through the window list until a floating window is encountered.
	 */
		do {
			if (((WindowPeek)currentWindow)->windowKind == KFloatingWindow) {
				firstFloatingWindow = currentWindow;
				break;
			}
			else {
				((WindowPeek)previousWindow)->nextWindow = ((WindowPeek)currentWindow)->nextWindow;

				if (documentWindowsToMove == nil)
					documentWindowsToMove = currentWindow;
				else
					((WindowPeek)lastDocumentWindowAdded)->nextWindow = (WindowPeek)currentWindow;
				lastDocumentWindowAdded = currentWindow;
				
				previousWindow = currentWindow;
				currentWindow = (WindowPtr)(((WindowPeek)currentWindow)->nextWindow);
			}
		} while (currentWindow);
		
	/* Now put them back in their place. */
	
		if (documentWindowsToMove && firstFloatingWindow) {
			((WindowPeek)lastDocumentWindowAdded)->nextWindow = ((WindowPeek)lastFloatingWindow)->nextWindow;
			((WindowPeek)lastFloatingWindow)->nextWindow = (WindowPeek)documentWindowsToMove;
			
	/*
	 * If the first window in the window list was a document window, and there are
	 * floating windows, then make the floating window the first window in the window
	 * list.
	 */
			if (documentWindowsToMove == MGetWindowList())
				(*(WindowPtr *)0x09D6) = firstFloatingWindow;
		}
	}
}

/*	MShowWindow
 *
 *		How to show this window and make it visible
 */

void MShowWindow(WindowPtr windowToShow)
{
	WindowPtr			windowBehind;
	WindowPtr			frontNonFloatingWindow;
	short				windowClass;
	Boolean				windowIsInFront = false;
	
	if (((WindowPeek)windowToShow)->visible != false) return;
		
	windowClass = ((WindowPeek)windowToShow)->windowKind;
	
	/* Handle special case of movable modal dialog. */
	
	if ((windowClass == KDialogWindow) || (windowClass == dialogKind)) {
		/* Unhilite the frontmost document window */
		windowBehind = MFrontWindow();
		if (windowBehind != NULL) {
			HiliteWindow(windowBehind,0);
			XGRDoActivate(windowBehind,0);
		}
		
		((WindowPeek)windowToShow)->hilited = true;	/* Hilite this		*/
		ShowHide((WindowPtr)windowToShow,true);		/* Show this		*/
		XGRDoActivate(windowToShow,1);					/* Activate this	*/
		return;
	}
	
	/*
	 * If the window behind the window to show is currently the frontmost document window,
	 * unhighlight it, and highlight the new front window.
	 */
	 
	if (windowClass != KFloatingWindow) {
		windowBehind = (WindowPtr)(((WindowPeek)windowToShow)->nextWindow);
		if (windowBehind == MFrontWindow()) {
			if (windowBehind != NULL) {
				HiliteWindow(windowBehind,0);
				XGRDoActivate(windowBehind,0);
			}

			/* Set the highlight state so the window appears highlighted from the start. */

			((WindowPeek)windowToShow)->hilited = true;
			windowIsInFront = true;
		}
	} else {
	
	/*
	 * A floating window is about to be shown. Make sure the windows in the 
	 * window list are all in the right place.
	 */
	
		MValidateWindowList();
			
		frontNonFloatingWindow = MFrontWindow();
		((WindowPeek)windowToShow)->hilited = true;
		windowIsInFront = true;
	}
	
	/* Show the window */
	
	ShowHide((WindowPtr) windowToShow, true);
	
	/* If this is the new frontmost document window or a floating window, send it an activate event */
	
	if (windowIsInFront) {
		XGRDoActivate(windowToShow,1);
	}
}

/*	MHideWindow
 *
 *		How to hide this window
 */

void MHideWindow(WindowPtr windowToHide)
{
	WindowPtr			frontFloater;
	WindowPtr			frontNonFloater;
	WindowPtr			lastFloater;
	WindowPtr			windowBehind;
	short				windowClass;
	
	/* DonÕt do anything if the window is already invisible. */
	
	if (((WindowPeek)windowToHide)->visible == false) return;

	/* Handle special case of movable modal dialog */
	
	windowClass = ((WindowPeek)windowToHide)->windowKind;
	if ((windowClass == KDialogWindow) || (windowClass == dialogKind)) {
		/* Hide the window */
		ShowHide(windowToHide,false);
		
		/* Hilite the frontmost document window */
		frontNonFloater = MFrontWindow();
		if (frontNonFloater != NULL) {
			HiliteWindow(frontNonFloater,1);
			XGRDoActivate(frontNonFloater,1);
		}
		return;
	}
	
	/* Get the first visible floating window, if any. */
	
	frontFloater = FrontWindow();
	if (((WindowPeek)frontFloater)->windowKind != KFloatingWindow) frontFloater = nil;
		
	/* Get the first visible document window, if any. */
	
	frontNonFloater = MFrontWindow();
	
	/* Hide the window. */
	
	ShowHide((WindowPtr) windowToHide, false);
	
	/*
	 * If the frontmost floating window is being hidden, move it behind the floating window
	 * behind it, if there is one.
	 */
	if (windowToHide == frontFloater) {
		windowBehind = (WindowPtr)(((WindowPeek)windowToHide)->nextWindow);
		
	/* Only do the rearrangement if thereÕs another floating window. */
	
		if ((windowBehind != nil) && (((WindowPeek)windowBehind)->windowKind == KFloatingWindow)) {
			((WindowPeek)windowToHide)->nextWindow = ((WindowPeek)windowBehind)->nextWindow;
			((WindowPeek)windowBehind)->nextWindow = (WindowPeek)windowToHide;
			(*(WindowPtr *)0x09D6) = windowBehind;
		}
	}
	else {
	
	/* If the frontmost document window is behind hidden, send it behind the window
	 * behind it.
	 */
		if (windowToHide == frontNonFloater) {
			windowBehind = (WindowPtr)(((WindowPeek)windowToHide)->nextWindow);
			
			if (windowBehind != nil) {
				((WindowPeek)windowToHide)->nextWindow = ((WindowPeek)windowBehind)->nextWindow;
				((WindowPeek)windowBehind)->nextWindow = (WindowPeek)windowToHide;
				
	/* Set the next link of the last floating window to point to the previously second
	 * to front document window. If there was no floating window, change the beginning
	 * of the window list.
	 */
				lastFloater = MLastFloater();
				if (lastFloater != nil)
					((WindowPeek)lastFloater)->nextWindow = (WindowPeek)windowBehind;
				else
					(*(WindowPtr *)0x09D6) = windowBehind;
				
	/* The window behind it is now the front document window.  Highlight it and send it
	 * and activate event.
	 */			
				HiliteWindow(windowBehind,1);
				XGRDoActivate(windowBehind,1);
			}
		}
	}
}

/************************************************************************/
/*																		*/
/*	Window Creation														*/
/*																		*/
/************************************************************************/

/*	MNewWindow
 *
 *		Do the same thing as the NewWindow call, but open the window
 *	right behind the floater
 */

WindowPtr MNewWindow(Ptr st, Rect *bounds, unsigned char *title, Boolean vis, short wDef, WindowPtr behind, Boolean goAway, long refCon)
{
	WindowPtr w;
	
	/* Reset the behind pointer depending on the order of this thing */

	if ((wDef >= 1984) && (wDef <= 1999)) {
		/*
		 *  If the 'wDef' parameter (the window definition) is between
		 *	1984 and 1999, this is a floating window definition function.
		 *	(This coorisponds to a 'WDEF' resource of 124--the WDEF that
		 *	Apple's floating window lives at.)
		 */
		
		if (behind == NULL) {
			behind = MLastFloater();
			if (behind == NULL) behind = (WindowPtr)-1L;
		}
	} else if ((wDef == 1) || (wDef == 5)) {
		behind = (WindowPtr)-1L;			/* always in front. */
	} else {
		if (behind == (WindowPtr)-1L) {
			behind = MLastFloater();
			if (behind == NULL) behind = (WindowPtr)-1L;
		}
	}
	
	/* Get the current front window for deactivation, and create it */
	
	w = NewWindow(st,bounds,title,false,wDef,behind,goAway,refCon);
	if (w == NULL) return NULL;
	
	/* Do the activation/deactivation if this window is visible */
	if ((wDef >= 1984) && (wDef <= 1999)) {
		((WindowPeek)w)->windowKind = KFloatingWindow;
	} else if ((wDef == 1) || (wDef == 5)) {
		((WindowPeek)w)->windowKind = KDialogWindow;
	} else {
		((WindowPeek)w)->windowKind = KNormalWindow;
	}
	if (vis) MShowWindow(w);
	return w;
}

/*	MNewCWindow
 *
 *		Do the same thing as the NewWindow call, but open the window
 *	right behind the floater
 */

WindowPtr MNewCWindow(Ptr st, Rect *bounds, unsigned char *title, Boolean vis, short wDef, WindowPtr behind, Boolean goAway, long refCon)
{
	WindowPtr w;
	
	/* Reset the behind pointer depending on the order of this thing */

	if ((wDef >= 1984) && (wDef <= 1999)) {
		/*
		 *  If the 'wDef' parameter (the window definition) is between
		 *	1984 and 1999, this is a floating window definition function.
		 *	(This coorisponds to a 'WDEF' resource of 124--the WDEF that
		 *	Apple's floating window lives at.)
		 */
		
		if (behind == NULL) {
			behind = MLastFloater();
			if (behind == NULL) behind = (WindowPtr)-1L;
		}
	} else if ((wDef == 1) || (wDef == 5)) {
		behind = (WindowPtr)-1L;			/* always in front. */
	} else {
		if (behind == (WindowPtr)-1L) {
			behind = MLastFloater();
			if (behind == NULL) behind = (WindowPtr)-1L;
		}
	}
	
	/* Get the current front window for deactivation, and create it */
	
	w = NewCWindow(st,bounds,title,false,wDef,behind,goAway,refCon);
	if (w == NULL) return NULL;
	
	/* Do the activation/deactivation if this window is visible */
	if ((wDef >= 1984) && (wDef <= 1999)) {
		((WindowPeek)w)->windowKind = KFloatingWindow;
	} else if ((wDef == 1) || (wDef == 5)) {
		((WindowPeek)w)->windowKind = KDialogWindow;
	} else {
		((WindowPeek)w)->windowKind = KNormalWindow;
	}
	if (vis) MShowWindow(w);
	return w;
}

/*	MCloseWindow
 *
 *		This handles closing the window.
 */

void MCloseWindow(WindowPtr w)
{
	if (((WindowPeek)w)->visible) MHideWindow(w);
	CloseWindow(w);
}

/************************************************************************/
/*																		*/
/*	Modeless Dialog Support												*/
/*																		*/
/************************************************************************/

/*	MIsDialogEvent
 *
 *		Is this an event for this dialog box?
 */

Boolean MIsDialogEvent(EventRecord *event)
{
	WindowPtr w;
	short where;
	
	/* Kludge for help balloons */
	IsDialogEvent(event);

	switch (event->what) {
		case mouseDown:
		case mouseUp:
			where = FindWindow(event->where,&w);
			if (where != inContent) w = NULL;
			else if (w != MFrontWindow()) w = NULL;
			break;
		case updateEvt:
		case activateEvt:
			w = (WindowPtr)(event->message);
			break;
		case keyDown:
		case autoKey:
		default:
			w = MFrontWindow();
			break;
	}
	if (w == NULL) return 0;
	if (((WindowPeek)w)->windowKind == dialogKind) return 1;
	return 0;
}

/*	MDialogSelect
 *
 *		Do the dialog select routines. This does all of the dialog
 *	processing stuff for this dialog window if it is one.
 */

Boolean MDialogSelect(EventRecord *event, DialogPtr *dlog, short *item)
{
	WindowPtr w;
	DialogPeek peek;
	short where;
	Handle h;
	Rect r;
	TEHandle text;
	char c;
	short index;
	short length;
	Point pt;
	unsigned long tmp;
	
	/*
	 *  Determine the dialog window that is being used here.
	 */
	
	switch (event->what) {
		case mouseDown:
		case mouseUp:
			where = FindWindow(event->where,&w);
			if (where != inContent) w = NULL;
			break;
		case updateEvt:
		case activateEvt:
			w = (WindowPtr)(event->message);
			break;
		default:
			w = MFrontWindow();
			break;
	}
	if (w == NULL) return 1;			/* Not my event... */
	if (((WindowPeek)w)->windowKind != dialogKind) return 1;
	
	/*
	 *  Now, actually do this event as appropriate
	 */
	
	*dlog = w;							/* The dialog I was handling.	  */
	*item = 0;							/* Default item (0)				  */
	peek = (DialogPeek)w;				/* So I can get at internal stuff */
	switch (event->what) {
	
		/*
		 *  Activate/Deactivate
		 *
		 *		This activates or deactivates the text edit field
		 *	if it is present in the dialog box.
		 */
		
		case activateEvt:
			if (peek->editField != -1) {
				SetPort(w);
				GetDialogItem(w,peek->editField + 1,&where,&h,&r);
				text = peek->textH;
				if (text && ((where & 0x7F) == 16)) {
					if (event->modifiers & activeFlag) {
						TEActivate(text);
					} else {
						TEDeactivate(text);
					}
				}
			}
			return 0;					/* Further processing not needed */
		
		/*
		 *  Update
		 *
		 *		This simply draws the contents of this thing
		 */
		
		case updateEvt:
			SetPort(w);
			BeginUpdate(w);
			UpdateDialog(w,w->visRgn);
			EndUpdate(w);
			return 0;					/* Further processing not needed */
		
		/*
		 *  Null event processing
		 *
		 *		Blink the cursor, adjust the mouse, show the balloon
		 */
		
		default:
		case nullEvent:
			SetPort(w);
			
			/*
			 *  Adjust cursor
			 */
			
			pt = event->where;
			GlobalToLocal(&pt);
			index = FindDialogItem(w,pt)+1;
			if (index != 0) {						/* Not on anything */
				GetDialogItem(w,index,&where,&h,&r);
				where &= 0x7F;
				if (where == 16) {					/* Change to ibeam */
					CursHandle c;
					
					c = GetCursor(iBeamCursor);
					HLock((Handle)c);
					SetCursor(*c);
					HUnlock((Handle)c);
					ReleaseResource((Handle)c);
				} else {
					SetCursor(&qd.arrow);
				}
			} else SetCursor(&qd.arrow);
			
			/*
			 *  Blink cursor
			 */
			
			if (peek->editField != -1) {
				GetDialogItem(w,1+peek->editField,&where,&h,&r);
				text = peek->textH;
				if (text && ((where & 0x7F) == 16)) {
					TEIdle(peek->textH);		/* Selected editable item */
				}
			}
			return 0;					/* Further processing not needed */
		
		/*
		 *	Key events
		 *
		 *		This handles keyboard events by processing the enter/
		 *	escape keys as buttons 1 and 2; otherwise, pass to the
		 *	current edit box, if any.
		 */
		
		case keyDown:
		case autoKey:
			SetPort(w);
			c = (unsigned char)(event->message & charCodeMask);
			
			/*
			 *  Enter, escape processing
			 */
			
			if ((c == 0x03) || (c == 0x0D) || (c == 0x1B)) {				
				if ((c == 0x03) || (c == 0x0D)) {
					*item = 1;
				} else {
					*item = 2;
				}
				
				GetDialogItem(w,*item,&where,&h,&r);
				HiliteControl((ControlHandle)h,kControlButtonPart);
				Delay(5,&tmp);
				HiliteControl((ControlHandle)h,0);
				return 1;				/* Further processing needed */
			}
			
			/*
			 *  Tab processing (default--bounce from edit table to edit table)
			 */
			
			if (c == 0x09) {			/* Horizontal tab key */
				if (peek->editField == -1) return 0; /* Can't deal with it. */
				if (peek->textH == NULL) return 0;	/* Can't deal with it. */
				length = *((short *)(*(peek->items))) + 1;
				index = peek->editField+2;			/* Skip this one */
				
				/*
				 *  Find the next edit item and select it
				 */
				
				while (index <= length) {
					GetDialogItem(w,index,&where,&h,&r);
					if ((0x7F & where) == 16) {		/* This is an edit item */
						SelectDialogItemText(w,index,0,32767);	/* Move edit, select me */
						*item = index;
						return ((where & 0x80) == 0) ? 1 : 0;
					}
					index++;
				}
				index = 1;							/* Wrap to beginning */
				while (index <= length) {
					GetDialogItem(w,index,&where,&h,&r);
					if ((0x7F & where) == 16) {		/* This is an edit item */
						SelectDialogItemText(w,index,0,32767);	/* Move edit, select me */
						*item = index;
						return ((where & 0x80) == 0) ? 1 : 0;
					}
					index++;
				}
				*item = 0;
				return 0;							/* Huh? Dunno... */
			}
			
			/*
			 *  Normal keyboard processing
			 */
			
			text = peek->textH;
			if (text == NULL) return 0;				/* No edit item to do */
			if (peek->editField == -1) return 0;	/* No edit item to do */
			
			*item = peek->editField+1;				/* Item ID we're doing */
			
			GetDialogItem(w,*item,&where,&h,&r);	/* What is this? */
			
			if (text && ((where & 0x7F) == 16)) {
				TEKey(c,text);						/* Do character process */
			
				return ((where & 0x80) == 0) ? 1 : 0;	/* for enable flag */
			} else return 0;						/* Huh? */
		
		/*
		 *  Mouse down:
		 *
		 *		track the controls or the edit fields as appropriate
		 */
		
		case mouseDown:
			SetPort(w);
			pt = event->where;
			GlobalToLocal(&pt);
			
			/*
			 *	Determine where the mouse went down
			 */
			
			index = FindDialogItem(w,pt)+1;
			if (index == 0) return 0;				/* Not on anything */
			GetDialogItem(w,index,&where,&h,&r);
			*item = index;
			
			/*
			 *  Handle inactive objects
			 */
			
			if (where & 0x80) {
				if (where == 0x90) {				/* Edit item here. */
				
					/*
					 *  Handle edit selection even if inactive
					 */
					
					if (peek->editField + 1 != index) {
						SelectDialogItemText(w,index,0,32767);
					}
					TEClick(pt,(event->modifiers & shiftKey) ? 1 : 0,peek->textH);
				}
				return 0;
			}
			
			/*
			 *  Process according to where I'm at
			 */
			
			switch (where) {
				default:
					return 1;						/* Just return the ID. */
				case 4:
				case 5:
				case 6:
				case 7:
					/*
					 *  Click on a standard control object
					 */
					
					if (TrackControl((ControlHandle)h,pt,(ControlActionUPP)-1)) return 1;
					return 0;						/* don't do it. */
				case 16:							/* Handle edit box */
					if (peek->editField + 1 != index) {
						SelectDialogItemText(w,index,0,32767);
					}
					TEClick(pt,(event->modifiers & shiftKey) ? 1 : 0,peek->textH);
					return 1;						/* Return where I am now.  */
			}
	}
	return 0;			/* Not one of these; can't deal with it at all... */
}

