/*	XWindow.h
 *
 *		The declaration of the XGWindow class. Note that this is a
 *	substantial rewrite of the window class from the prior version of the
 *	YAAF libraries.
 */

/*  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
 */

#ifndef PandaWave_XWINDOW
#define PandaWave_XWINDOW

#include <XConfig.h>
#include <XEvent.h>
#include <XView.h>
#include <XDynArray.h>

/************************************************************************/
/*																		*/
/*	Forwards															*/
/*																		*/
/************************************************************************/

class XGView;
class XGForm;
class XGDocument;
class XGWindow;
class XGMenuBar;

/************************************************************************/
/*																		*/
/*	Window Factory														*/
/*																		*/
/************************************************************************/

/*	XGWConstructorProc
 *
 *		This is the proc pointer template for the constructor
 */

typedef XGWindow *(XGWConstructorProc)(XGArgStream &, XGDocument *, XGForm *);

/*	XGSFactory
 *
 *		Structure used for my view factory object
 */

struct XGSWFactory {
	long				type;
	XGWConstructorProc	*proc;
};

/*	@C"XGWindowFactory"
 *	@H"XWindow.h"
 *	@I
 *
 *		Window factory class. This is used for creating a window.
 */
 
class XGWindowFactory {
	public:
		/*
		 *	Public view construction
		 */
		
		static XGWindow			*CreateFromData(const unsigned char *, XGDocument *d = NULL, XGForm *f = NULL);
		static XGWindow			*CreateFromResource(short, XGDocument *d = NULL, XGForm *f = NULL);
		
		/*
		 *	Constructor procedure registration
		 */
		
		static void				Register(long, XGWConstructorProc *);

	private:
		/*
		 *	Internal construction
		 */
		
		static XGSDynArray<XGSWFactory>	gList;
};

/*	@C"XGWindowTemplate"
 *	@H"XWindow.h"
 *	@I
 *
 *		Template declaration for registering a single view
 */

template <class T> class XGWindowTemplate {
	public:
		/*	@F"XGWindowTemplate::Register" @I
		 *
		 *		Registers the constructor method of this template with
		 *	the XGWindowFactory class so that the XGWindow derived
		 *	class specified can be constructed when the 'type' is
		 *	encountered in the 'VRes' resource
		 */
		
		static void				Register(long type)
									{
										XGWindowFactory::Register(type,Constructor);
									}
		
		/*	@F"XGWindowTemplate::Constructor" @I
		 *
		 *		The constructor method used for constructing the
		 *	XGWindow derived class.
		 */
		
		static XGWindow			*Constructor(XGArgStream &s, XGDocument *d, XGForm *f)
									{
										return new T(s,d,f);
									}
};

/*	@F"RegisterWindowID"
 *	@U"RegisterWindowID(type,class)"
 *	@H"XWindow.h"
 *	@I
 *
 *		This macro expands into the template method call to register
 *	this window class with the XGWindowFactory class. The type which
 *	this window is is the first parameter
 */

#define RegisterWindowID(x,y)	XGWindowTemplate<y>::Register(x)

/*	@F"RegisterWindow"
 *	@U"RegisterWindow(class)"
 *	@H"XWindow.h"
 *	@I
 *
 *		This macro expands into the template method call to register
 *	this window class with the XGWindowFactory class. 
 */

#define RegisterWindow(x)		XGWindowTemplate<x>::Register(x::kClassID)

/************************************************************************/
/*																		*/
/*	Window Management Attributes										*/
/*																		*/
/************************************************************************/

/*
 *	XGWindow types
 */

#define KWinDocument			0x00000000
#define KWinModal				0x00000001
#define KWinMovableModal		0x00000002
#define KWinFloating			0x00000003

#define KMaskType				0x0000000F

#define KWinPosStagger			0x00000000
#define KWinPosAlert			0x00000010
#define KWinPosCenter			0x00000020

#define KMaskPos				0x000000F0

/*
 *	XGWindow::Attributes() values
 *
 *		low word is the flags
 *		high word is the menu level
 */

#define	KAttrNoClose			0x0001		// window doesn't have close box
#define KAttrNoResize			0x0002		// window cannot be resized
#define KAttrHideOnSwitch		0x0004		// window hides on app switch
#define KAttrNoMenu				0x0008		// window has no menu bar in it
#define KAttrFloater			0x0010		// window floats above rest

/************************************************************************/
/*																		*/
/*	Initialization Structures											*/
/*																		*/
/************************************************************************/

/*	XGSWindowInitRecord
 *
 *		This is the initialization record for creating my window from
 *	scratch
 */

struct XGSWindowInitRecord {
	long						windowType;
	short						windowKind;
	short						windowID;
	bool						fVisible;

	/*
	 *	Window Size
	 */
	
	short						screenLeft;
	short						screenTop;
	short						screenRight;
	short						screenBottom;
	
	/*
	 *	Window sizing parameters
	 */
	
	short						minx;
	short						miny;
	short						maxx;
	short						maxy;
	short						initx;
	short						inity;
	short						zoomx;
	short						zoomy;
	
	/*
	 *	Window name
	 */
	
	char						windowName[256];
	
	/*
	 *	Menu to show
	 */
	
	short						menuID;
};

/************************************************************************/
/*																		*/
/*	Internal structures, globals, constants								*/
/*																		*/
/************************************************************************/

#if OPT_MACOS

/*	XGSWindowRecord								[Macintosh]
 *
 *		How I store my window record; this appends an extra four
 *	byte field to the WindowRecord object
 */

struct XGSWindowRecord {
	WindowRecord		w;
	XGWindow			*tw;
};

#endif // OPT_MACOS

#if OPT_WINOS

/*												[Windows]
 *	Globals
 */

extern "C" {
	extern HINSTANCE	_GPrevInstance;			// preveous pointer
	extern LPSTR		_GArgString;			// external parameter
	extern int			_GArgShow;
	extern HINSTANCE	_GInstance;				// instance pointer
	extern HWND			_GMainWindow;			// main window (SDI/MDI)
	extern HWND			_GMDIWindow;			// MDI container frame
	extern class XGWindow *_GWindow;			// window construction support

	extern char			_GPopClass[];			// window class name
	extern char			_GWindowClass[];		// window class name
	extern char			_GControlClass[];		// window class name
	extern char			_GDlogClass[];			// dlog class name
	extern char			_GFrameClass[];			// frame class name
	extern char			_GMainClass[];			// main window name
}

/*
 *	Window procedures
 */

extern LRESULT CALLBACK _GMainMDIWindowProc(HWND,UINT,WPARAM,LPARAM);
extern LRESULT CALLBACK _GChildWindowProc(HWND,UINT,WPARAM,LPARAM);
extern LRESULT CALLBACK _GSingleWindowProc(HWND,UINT,WPARAM,LPARAM);

#endif

/************************************************************************/
/*																		*/
/*	Class declaration													*/
/*																		*/
/************************************************************************/

/*	@C"XGPopWindow"
 *	@H"XWindow.h"
 *	@I
 *
 *		This is a wrapper for a popup window in the native OS. All this
 *	does is creates the pop-up window and destroys it; you are expected
 *	to actually talk to the view itself. Generally it is assumed this
 *	window is popped up for a very short period, such as a pop-up menu.
 */

class XGPopWindow {
	public:
		/*
		 *	Construction/Destruction (for stack-based window
		 *	construction)
		 */
		
								XGPopWindow(XGView *, Rect, XGView *);
		virtual					~XGPopWindow();
		
		/*
		 *	Pop view access
		 */
		 
		// @G"Pop view access"
		
		/*	@F"XGPopWindow::GetLocation" @I
		 *
		 *		Returns the location of this popup window
		 */
		
		Rect					GetLocation()
									{
										return fLocation;
									}
									
		/*	@F"XGPopWindow::GetView" @I
		 *
		 *		Returns the view associated with this popup window
		 */
		
		XGView					*GetView()
									{
										return fView;
									}
		
		/*	@F"XGPopWindow::GetPopCount" @I
		 *
		 *		Returns the number of popup windows outstanding
		 */
		
		static long				GetPopCount()
									{
										return gPopCount;
									}
	private:
		static long				gPopCount;
		Rect					fLocation;
		XGView					*fView;
		XGView					*fBase;
		
		/*
		 *	Support
		 */
		
		void					FixToScreen(Rect *r);
		void					CreateOSWindow(Rect r);
		void					DestroyOSWindow();

#if OPT_MACOS
		WindowRecord			fWindow;
#endif

#if OPT_WINOS
		HWND					fWindow;
#endif

#if OPT_XWIN
		Window					fWindow;
#endif
};

/*	@C"XGWindow"
 *	@D"XGFocus"
 *	@D"XGOwner"
 *	@H"XWindow.h"
 *	@I
 *
 *		The wrapper of the window for the native OS. This serves as only
 *	a wrapper for the window specific stuff
 */

class XGWindow : public XGFocus, public XGOwner {
	public:
	
		/*
		 *	Construction/Destruction
		 */
		
								XGWindow(XGArgStream &,
										 XGDocument *d = NULL,
										 XGForm *f = NULL);
								XGWindow(XGSWindowInitRecord &,
										 XGDocument *d = NULL,
										 XGForm *f = NULL);
		virtual					~XGWindow();
		
		enum {
			kClassID = 'wind'
		};
		
		virtual bool			CloseWindow();

		void					SetWindowView(XGView *v);
		
		/*
		 *	Size limits (internal or content size)
		 */
		
		virtual Point			MinWindowSize();
		virtual Point			MaxWindowSize();
		virtual Point			ZoomWindowSize();
		
		void					LimitWindowSize(Point *);

		/*
		 *	Document support (auto save on close)
		 */
		
		virtual bool			IsDirty();
		virtual bool			DoSave();

		/*
		 *	Window attributes
		 */
		
		// @G"Window Attributes"
		
		void					GetTitle(char *);
		void					SetTitle(const char *);
		
		/*	@F"XGWindow::GetWindowType" @I
		 *
		 *		Gets the window type of this window
		 */
		
		long					GetWindowType()
									{
										return fWindowType;
									}
									
		/*	@F"XGWindow::GetWindowKind" @I
		 *
		 *		Gets the kind of this window
		 */
		
		short					GetWindowKind()
									{
										return fWindowKind;
									}

		/*	@F"XGWindow::GetWindowID" @I
		 *
		 *		Gets the window ID of this window.
		 */
		
		short					GetWindowID()
									{
										return fWindowID;
									}
		unsigned short			GetWindowAttributes();
		
		/*	@F"XGWindow::GetView" @I
		 *
		 *		Gets the root level view associated with this window.
		 */
		
		XGView					*GetView()
									{
										return fView;
									}

		/*	@F"XGWindow::FindViewByID" @I
		 *
		 *		Finds the view in this window with the specified ID.
		 */

		XGView					*FindViewByID(short x)
									{
										return fView ? 
												   fView->FindViewByID(x) :
												   NULL;
									}

		/*	@F"XGWindow::FindViewByPoint" @I
		 *
		 *		Finds the view in this window that the mouse is inside.
		 */

		XGView					*FindViewByPoint(Point pt, bool recurse = true)
									{
										return fView ?
												   fView->FindViewByPoint(pt,recurse) :
												   NULL;
									}

		/*	@F"XGWindow::FindViewByAccel" @I
		 *
		 *		Finds the view by the specified accelerator key.
		 */

		XGView					*FindViewByAccel(char x)
									{
										return fView ? 
												   fView->FindViewByAccel(x) :
												   NULL;
									}
	
		/*	@F"XGWindow::GetDocument" @I
		 *
		 *		Returns the XGDocument object associated with this window.
		 */

		XGDocument				*GetDocument()
									{
										return fDocument;
									}

		/*	@F"XGWindow::GetForm" @I
		 *
		 *		Gets the XGForm object associated with this window.
		 */

		XGForm					*GetForm()
									{
										return fForm;
									}
		
		/*
		 *	Window support
		 */
		
		void					ShowWindow();
		void					HideWindow();
		bool					IsVisible(void);
		
		static XGWindow			*GetFrontWindow();
		void					SelectWindow();
		static void				GetScreenSize(Rect *);
		
		/*
		 *	Window size
		 */
		
		Point					GetContentSize() const;
		Rect					GetContentRect() const;
		
		void					SetWindowSize(Point);
		void					SetWindowPos(Point);
		void					SetWindowLocation(Rect);
		
		Point					GetWindowSize() const;
		Point					GetWindowPos() const;
		Rect					GetWindowLocation() const;
		
		static void				ContentToSize(Rect *);
		static void				ContentToSize(Point *);
		static void				SizeToContent(Rect *);
		static void				SizeToContent(Point *);
		
		/*
		 *	Dialog-like window navigation
		 */
		
		DECLAREDISPATCH
		long					Dispatch(long,long,void *);
		long					DoKey(long,void *);
		long					DoMenuKey(long,void *);
		long					DoCurMenuBar(long,void *);
		
		/*
		 *	Events I care about. (How events are sent)
		 */
		
		void					DoDraw(Rect);
		void					DoActivate(bool);
		void					DoSizeWindow();

		XGView					*DoMouseDown(Point,short);
		void					DoMouseMove(Point,short,XGView *v = NULL);
		void					DoMouseUp(Point,short,XGView *v = NULL);
		
		/*
		 *	Miscellaneous internal support
		 */
		 
#if OPT_MACOS == 1
		GrafPtr					GetGrafPtr()
									{
										return &fWindow.w.port;
									}
		static XGWindow			*GetXGWindow(GrafPtr g);
#endif

#if OPT_WINOS == 1
		HWND					GetHWND()
									{
										return fWindow;
									}
		static XGWindow			*GetXGWindow(HWND);
#endif

#if OPT_XWIN == 1
		Window					GetWindow()
									{
										return fWindow;
									}

		static XGWindow			*GetXGWindow(Window);
		static XGWindow			*GetXGWindowByParent(Window);
		
		void					SetMenuBar(XGMenuBar *);
		void					RedrawMenuBar();
		
		short					fCursorID;
		bool					fActive;
#endif	
		
	private:

		/*
		 *	Init support
		 */
		
		void					IInitWindow(XGSWindowInitRecord &);
		void					ICreateWindow(char *, Rect);
		
		/*
		 *	Tab support
		 */
		
		void					FirstTabStop();
		void					NextTabStop();
		void					PrevTabStop();

		/*
		 *	Internal structures
		 */

#if OPT_MACOS == 1
		XGSWindowRecord			fWindow;
#endif

#if OPT_WINOS == 1
		HWND					fWindow;
		HWND					fDlogParent;
#endif

#if OPT_XWIN == 1
		Window					fWindow;
		Window					fWMWindow;
		
		XGView					*fMenuBarView;
#endif
		XGWindow				*fPrev;
		XGWindow				*fNext;
		static XGWindow			*gList;
		
		XGView					*fView;
		XGDocument				*fDocument;
		XGForm					*fForm;
		
		/*
		 *	Internal window data
		 */
		
		Point					fMin;
		Point					fMax;
		Point					fZoom;

		short					fMenuBar;
		
		long					fWindowType;
		short					fWindowKind;
		short					fWindowID;

#if OPT_WINOS
	friend LRESULT CALLBACK _GMainMDIWindowProc(HWND, UINT, WPARAM, LPARAM);
	friend LRESULT CALLBACK _GChildWindowProc(HWND, UINT, WPARAM, LPARAM);
	friend LRESULT CALLBACK _GSingleWindowProc(HWND, UINT, WPARAM, LPARAM);
#endif

	friend class XGAppCore;
};


#endif // PandaWave_XWINDOW
