/*
 * $Source: $
 * $Revision: $
 * $Date: $
 * $State: $
 * $Author: $
 *
 *
 * $Log: $
 * Revision 3.1  3/10/92 wade
 * Added Baylor's changes
 * #documentRec.h stuff, cleaned up windowKind stuff
 * added gif window routines, e.g. resize
 */
 /*  
 *	Copyright (c) 1991 by the Massachusetts Institute of Technology,
 *	For copying and distribution information, see the file
 *	"mit-copyright.h".
 *
 *  windowMgr.c  - WADE 8/23/89
 *		The idea is that this file contains general window functions for drawing,
 *		resizing and creating.  We are not a that goal yet.
 *
 *	window_init
 *	DoZoomWindow
 *	DoCloseWindow
 *	IsAppWindow
 *	IsDAWindow
 *	DrawWindow
 *	DoGrowWindow
 *	ResizeWindow
 *	wind_next_window
 *
 */
 
#include <Limits.h>
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <OSUtils.h>
#include <Traps.h>
#include <SysEqu.h>
#include <resources.h>
#include <stdio.h>
#include <script.h>
#include <String.h>
#include "pips.h"
#include "prototype.h"
#include "mit-copyright.h"
#include "documentRec.h"

extern	WindowPtr	gTextWindow;
extern	WindowPtr	gListWindow;
extern	WindowPtr	gMsgDialog;
extern	Boolean		gInBackground;

/*     
 *
 * 	wind_list_init:
 * 	
 *	This routine creates the window object and initializes the global variable 
 *	gListWindow.  This window object will be used for the list display.
 *	Window attributes are set, ie. window title, font size, style.
 *
 */
#pragma segment Initialize
wind_list_init()
{
		
	GrafPtr		myPort;
	char		window_startup[6];
	Handle		tempHandle;
	WStateData	*zoomRecord;
	WindowPtr	window;
	
	window = GetNewWindow( LIST_WINDOW_ID, NIL_POINTER,  (WindowPtr) -1 );
	gListWindow = window;  /* eventually we will not need gListWindow */
	pref_get_string(WINDOW_STARTUP, window_startup);
		
	if (window == NULL)
		BigBadError(NO_RESOURCE);
		
	/* true means to use the last window placement settings */
	if (strcmp("true",window_startup) || (!wind_check_bounds(window))) {
		/* will the previous window settings fit on the screen */
		/* use the default location and size */
		MoveWindow(window,DEFAULT_MENU_LEFT,DEFAULT_MENU_TOP,false);	
		SizeWindow(window,DEFAULT_MENU_RIGHT,DEFAULT_MENU_BOTTOM,false);
	}
		
	/* ShowWindow( gListWindow ); */
	SetPort ( window );
		
	/* Set font, text size and style */
	TextFont ( monaco );
	TextFace ( 0 ); /* plain text */
	TextSize ( TEXT_FONT_SIZE ); 
	
	GetPort( &myPort );
	
	/* now, setup the max zoom window size */
	tempHandle = ((WindowPeek) window)->dataHandle;
	zoomRecord = (WStateData*)*tempHandle;
	zoomRecord -> stdState.right = zoomRecord -> stdState.left + 503; /* 1 + 484 + 16 */

	(((WindowPeek) window) -> windowKind) = list;
	
	list_Init(window);					/* create list handle object */
	
	/* change color, this might be a good preference 
	myPort -> bkColor = cyanColor; */
} /* wind_list_init */
	
/*     
 *
 *  DoZoomWindow:
 *
 *  Called when a mouseClick occurs in the zoom box of an active window.
 *	Everything has to get re-drawn here, so we don't mind that
 *	ResizeWindow invalidates the whole portRect. 
 *
 */
#pragma segment Window
void DoZoomWindow(window,part)
	WindowPtr	window;
	short		part;
{
	
	SetPort(window);
	ZoomWindow(window, part, window == FrontWindow());
	
	if (wind_type(window) == list) {
		list_Size(window);
		InvalRect( &window -> portRect );	/* force a new screen to be drawn */
	}
	else if (wind_type(window) == text) {
		EraseRect(&window->portRect);
		ResizeWindow(window);
	}
#ifdef GIFSTUFF
	else if (wind_type(window) == gif) {
	/*	EraseRect(&window->portRect); */
		ResizeWindow(window);
	}
#endif
#ifdef DEBUGSTR
	else {
		DEBUGSTR("\pUnknown windowKind in DoZoomWindow");
	}
#endif
	
} /*  DoZoomWindow */
	
/*     
 *
 * 	DoCloseWindow:
 * 
 *	Close a window. This handles desk accessory and application windows. 
 *
 */
#pragma segment Window
Boolean DoCloseWindow(window,action)
	WindowPtr	window;
	int		action;
{
	TEHandle	te;
	Point		top_left, bot_right;
	Rect		**h_Rect;
	int			error;
	GrafPtr		oldPort;
	char		window_startup[NODE_LENGTH];
	Handle		select_node;
	
	extern short 	gNumDocuments;
	
	if ( IsDAWindow(window) )
		CloseDeskAcc(((WindowPeek) window)->windowKind);
		
	else 
		if ( IsAppWindow(window) ) {
			switch( wind_type(window) ) {
				case text:
				
					if (action == hide_window ) {
						HideWindow(window);
						wind_set_cursor(0);  
					}
					else {
						te = ((DocumentPeek) window)->docTE;
						if ( te != nil )
							TEDispose(te);	
						gNumDocuments -= 1;
						
						GetPort( &oldPort );
						SetPort(window);
						
						pref_get_string(WINDOW_STARTUP, window_startup);
						if (!strcmp("true",window_startup)) {
	
							/* save current settings of the list window */
							h_Rect = (Rect**) GetResource('WIND',DOC_WINDOW);
							if (h_Rect != nil) {
								SetPt(&top_left,window->portRect.left,window->portRect.top);
								SetPt(&bot_right,window->portRect.right,window->portRect.bottom);
								LocalToGlobal(&top_left);
								LocalToGlobal(&bot_right);
								(**h_Rect).top = top_left.v;
								(**h_Rect).left = top_left.h;
								(**h_Rect).bottom = bot_right.v;
								(**h_Rect).right = bot_right.h;
								ChangedResource((Handle)h_Rect); 
								error = ResError();
								if (error != noErr)
									BigBadError(NO_RESOURCE);
								
								WriteResource((Handle)h_Rect);
								error = ResError();
								if (error != noErr) 
									BigBadError(NO_RESOURCE);
							}
						}
						DisposeWindow(window);
						gTextWindow = NULL;
						SetPort(oldPort);
					}
			
					break;
				case list:
				
					if (action == hide_window)
						HideWindow(window);
					else {
						GetPort( &oldPort );
						SetPort(window);
						
						pref_get_string(WINDOW_STARTUP, window_startup);
						if (!strcmp("true",window_startup)) {
	
							/* save current settings of the list window */
							h_Rect = (Rect**) GetResource('WIND',LIST_WINDOW_ID);
							if (h_Rect != nil) {
								SetPt(&top_left,window->portRect.left,window->portRect.top);
								SetPt(&bot_right,window->portRect.right,window->portRect.bottom);
								LocalToGlobal(&top_left);
								LocalToGlobal(&bot_right);
								(**h_Rect).top = top_left.v;
								(**h_Rect).left = top_left.h;
								(**h_Rect).bottom = bot_right.v;
								(**h_Rect).right = bot_right.h;
								ChangedResource((Handle)h_Rect); 
								error = ResError();
								if (error != noErr)
									BigBadError(NO_RESOURCE);
						
								WriteResource((Handle)h_Rect);
								error = ResError();
								if (error != noErr) 
									BigBadError(NO_RESOURCE);
							}
						}
						
						DisposeWindow(window);
						gListWindow = NULL;
						SetPort(oldPort);
					}
			
					break;
				case gif:
					GIF_CloseWindow(window);
					break;
				case getinfo:
				
					(long)select_node = GetWRefCon(window);
					DisposHandle(select_node);

					DisposDialog(window);
			
					break;
					
				default:
#ifdef DEBUGSTR
					DEBUGSTR("\pUnknown windowKind in DoCloseWindow, disposing");
#endif
					DisposeWindow(window);
					break;
			
			}
			
			return true;
		}
	
} /*DoCloseWindow*/

	
/*     
 *
 *  IsAppWindow:
 *
 * 	Check to see if a window belongs to the application. If the window pointer
 *	passed was NIL, then it could not be an application window. WindowKinds
 *	that are negative belong to the system and windowKinds less than userKind
 * 	are reserved by Apple except for windowKinds equal to dialogKind, which
 *	mean it is a dialog. 
 *
 */
#pragma segment Window
Boolean IsAppWindow(window)
	WindowPtr	window;
{
	short		windowKind;
	
	if ( window == nil )
		return false;
	else {	/* application windows have windowKinds >= userKind (8) or dialogKind (2) */
		windowKind = ((WindowPeek) window)->windowKind;
		return (windowKind >= userKind) || (windowKind == dialogKind);
	}
} /*IsAppWindow*/

/*     
 *
 * 	IsDAWindow: 
 *
 *	Check to see if a window belongs to a desk accessory.
 * 
 *
 */
#pragma segment Window
Boolean IsDAWindow(window)
	WindowPtr	window;
{
	if ( window == nil )
		return false;
	else	/* DA windows have negative windowKinds */
		return ((WindowPeek) window)->windowKind < 0;
} /*IsDAWindow*/

/*     
 *
 * 	DrawWindow:
 * 
 *	Draw the contents of either the list or text window.
 */
#pragma segment Window
void DrawWindow(window)
	WindowPtr	window;
{
	GrafPtr			oldPort;
	
	GetPort( &oldPort );
	SetPort(window);
	
	if (wind_type(window) == list) {
		EraseRect(&window->portRect);
		list_Draw(window);
	}
	else if ( wind_type(window) == text ) {
		EraseRgn(window->visRgn);
		DrawControls(window);
		TEUpdate(&window->portRect, ((DocumentPeek) window)->docTE);
		
	}
#ifdef GIFSTUFF
	else if ( wind_type(window) == gif ) {
		GIF_Draw((DocumentPeek)window);
		DrawControls(window);
	}
#endif
#ifdef DEBUGSTR
	else {
		DEBUGSTR("\pUnknown windowKind in DrawWindow");
	}
#endif
	
	DrawGrowIcon(window);
	SetPort( oldPort );
} /*DrawWindow*/

/*     
 *
 * 	DoGrowWindow: 
 *
 *	Called when a mouseDown occurs in the grow box of an active window. In
 *	order to eliminate any 'flicker', we want to invalidate only what is
 *	necessary. Since ResizeWindow invalidates the whole portRect, we save
 *	the old TE viewRect, intersect it with the new TE viewRect, and
 *	remove the result from the update region. However, we must make sure
 *	that any old update region that might have been around gets put back. 
 *
 */
#pragma segment Window
void DoGrowWindow(window,event)
	WindowPtr	window;
	EventRecord	*event;
{
	long		growResult;
	Rect		tempRect;
	RgnHandle	tempRgn;
	DocumentPeek doc;
		
	tempRect = qd.screenBits.bounds;	/* set up limiting values */
	tempRect.left = MINDOCDIM;
	tempRect.top = MINDOCDIM;
	
	switch( wind_type(window) ) {
		case list:
			tempRect.right = 503; /* max dimension */
			break;
			
		case text:
			tempRect.right = 503; /* max dimension */
			break;
			
		case gif:
			// reset .right and .bottom if they need it
			GIF_GetSizeRect(window, &tempRect);
			break;
			
		case getinfo:	/* No window type (dialog) */
			return;
			break;
			
		default:
#ifdef DEBUGSTR
			DEBUGSTR("\pUnknown windowKind in DoGrowWindow");
#endif
			break;
	}
	
	growResult = GrowWindow(window, event->where, &tempRect);
	
	/* see if it really changed size */
	if ( growResult != 0 ) { 
		switch( wind_type(window) ) {
			case list:
				SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
				list_Size(window);
				InvalRect( &window -> portRect );		
				break; 
				
			case text:
				doc = (DocumentPeek) window;
				tempRect = (*doc->docTE)->viewRect;	/* save old text box */
				tempRgn = NewRgn();
				GetLocalUpdateRgn(window, tempRgn);	/* get localized update region */
				SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
				ResizeWindow(window);
				/* calculate & validate the region that hasnÕt changed so it wonÕt get redrawn */
				SectRect(&tempRect, &(*doc->docTE)->viewRect, &tempRect);
				ValidRect(&tempRect);			/* take it out of update */
				InvalRgn(tempRgn);			/* put back any prior update */
				DisposeRgn(tempRgn);
				break;
				
			case gif:
				doc = (DocumentPeek) window;
				SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
				ResizeWindow(window);
				break;
				
			default:
#ifdef DEBUGSTR
				DEBUGSTR("\pUnknown windowKind in DoGrowWindow");
#endif
				break;
		}
		
	}
} /* DoGrowWindow */

/*     
 *
 * 	ResizeWindow:
 *
 * 	Called when the window has been resized to fix up the controls and content.
 *
 */
#pragma segment Window
void ResizeWindow(window)
	WindowPtr	window;
{
	/* let's get out of here if window is not a text window */
	if (wind_type(window) == text) {
		AdjustScrollbars(window, true);
		AdjustTE(window);
		InvalRect(&window->portRect);
	}
	else if (wind_type(window) == list) {
		return;
	}
#ifdef GIFSTUFF
	else if (wind_type(window) == gif) {
		AdjustGIFScrollbars(window, true);
		InvalRect(&window->portRect);
	}
#endif
#ifdef DEBUGSTR
	else {
		DEBUGSTR("\pUnknown windowKind in ResizeWindow");
	}
#endif
} /* ResizeWindow */

#pragma segment Window
void
wind_set_cursor( type )
int	type;
{
	switch (type) {
		case 0:
			SetCursor(&qd.arrow);
			break;
		default:
			SetCursor(*GetCursor(type));
			break;
	}
	
}  /* wind_set_cursor */

/*     
 *
 * 	wind_visible:
 * 	
 *	This routine returns a true boolean if the window is visible.  It may be hidden if the window
 *	was closed by the user. 
 *
 */
#pragma segment Window
Boolean
wind_visible(window)
WindowPtr	window;
{		
	return(((WindowPeek) window)->visible);
	
} /* wind_visible */


/*     
 *
 * 	wind_next_window:
 * 	
 *	
 */
#pragma segment Window
WindowPeek
wind_next_window(window)
WindowPtr	window;
{				
	WindowPeek	next_window;
	
	next_window = ((WindowPeek) window) -> nextWindow;
	
	if ( (WindowPtr)next_window == gMsgDialog ) 
	    return (next_window->nextWindow);
	else
		return ( next_window);
}

/*     
 *
 * wind_windows_data:
 * 
 *
 */
#pragma segment Window
typedef struct {
	WindowPtr	window;
	short		section;
} wlist;

Boolean
wind_windows_data(mode,index,wind_list)
int   		mode;
short		index;
wlist		*wind_list;
{
	static wlist	window_list[MAX_OPEN_DOCUMENTS];
	enum{store,retrieve};
	
	switch(mode) {
		case store:
			if (index > MAX_OPEN_DOCUMENTS)
				return false;
			window_list[index].window = wind_list -> window;
			window_list[index].section = wind_list ->  section;
			break;
		case retrieve:
			if (index > MAX_OPEN_DOCUMENTS)
				return false;
			wind_list -> window = window_list[index].window;
			wind_list -> section = window_list[index].section;
			break;
	}
	
	return true;
}

/*     
 *
 * 	wind_type:
 * 	
 *	return type (list or text) of window.
 */
#pragma segment Window
int
wind_type(window)
WindowPtr	window;
{				

	return (((WindowPeek) window) -> windowKind);
}

/*     
 *
 * 	wind_set_type:
 * 	
 *	set the window class
 */
#pragma segment Window
void
wind_set_type(window,class)
WindowPtr	window;
int		class;
{
	((WindowPeek) window) -> windowKind = class;
}

/*     
 *
 * 	wind_find_window:
 * 	
 *	return windowPtr for the first occurance of the window_type in the window list.
 */
#pragma segment Window
WindowPtr
wind_find_window(window_type)
int	window_type;
{	
	WindowPtr	next_window;
	
	next_window = *((WindowPtr *) WindowList);
	while(next_window != nil && IsAppWindow(next_window)) {
		if (((WindowPeek) next_window) -> windowKind == window_type)
			return next_window;
		(WindowPeek)next_window = wind_next_window(next_window);
	}
	
	return NULL;
}

/*     
 *
 * 	wind_check_bounds:
 * 	
 *	determine if window is within the screen bounds.
 *  This is needed if window settings are saved and the
 *  screen display has changed.
 */

#pragma segment Window
Boolean 
wind_check_bounds(window)
WindowPtr	window;        
{
	Point top_left, top_right;
	Rect title_rect;
	GrafPtr	myPort;
	Boolean itfits;
        
	GetPort( &myPort );
	
	SetPort(window);
        
	SetPt(&top_left,window->portRect.left,window->portRect.top);
	LocalToGlobal(&top_left);
	
	SetPt(&top_right,window->portRect.right,window->portRect.top);
	LocalToGlobal(&top_right);
        
	SetRect(&title_rect,top_left.h + 4,top_left.v,
					top_right.h - 4,top_left.v + 15);
                        
	if(!RectInRgn(&title_rect,GetGrayRgn()))
		itfits = false;
	else
		itfits = true;
                
	SetPort(myPort);
	
	return(itfits);
}


/*
 * Adjust Cursor - set the cursor to something appropriate depending on window
 *	type.  TextAdjustCursor handles the text-window-specific parts.  This function
 *	is in the Main segment because it is called from there every time through the
 *	main event loop.
 */
#pragma segment Main
void AdjustCursor(Point mouse, RgnHandle region)
{
	WindowPtr	window;
	RgnHandle	arrowRgn;

	window = FrontWindow();	// we only adjust the cursor when we are in front
	if ( (gInBackground) || (! IsAppWindow(window)) ) {
		return;
	}
	
	switch( wind_type(window) ) {
		case text:
			TextAdjustCursor(mouse,region);
			break;
			
		case list:
		case gif:
		case getinfo:
			/* reset the cursor region (to wide open) for WaitNextEvent */
			arrowRgn = NewRgn();
			SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
			CopyRgn(arrowRgn, region);
			DisposeRgn(arrowRgn);

			SetCursor(&qd.arrow);
			break;
			
		default:
#ifdef DEBUGSTR
			DEBUGSTR("\pUnknown windowKind in AdjustCursor");
#endif
			break;
	}
}