/*	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 is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

**********************************************************************/

#ifndef PandaWave_XWINDOW
#define PandaWave_XWINDOW

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

#if OPT_XWIN
#include <X11/Xutil.h>
#endif

/**@name Window Management
 *
 *		These classes provide basic window management.
 */

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

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

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

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

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

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

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

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

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

/*	XGWindowTemplate
 *
 *		Template declaration for registering a single view
 */

template <class T> class XGWindowTemplate {
	public:
		/*$	XGWindowTemplate::Register
		 *
		 *		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);
									}
		
		/*$	XGWindowTemplate::Constructor
		 *
		 *		The constructor method used for constructing the
		 *	XGWindow derived class.
		 */
		
		static XGWindow			*Constructor(XGArgStream &s, XGForm *f = NULL)
									{
										return new T(s,f);
									}
};

/*$	RegisterWindowID
 *
 *		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)

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

#define KWinAttributes			0x00000100
#define KWinClose				0x00000200
#define KWinResize				0x00000400
#define KWinHideOnSwitch		0x00000800
#define KWinNoMenu				0x00001000
#define KWinNoClick				0x00002000


/*
 *	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
#define KAttrNoClick			0x0020		// window select does not click

/************************************************************************/
/*																		*/
/*	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			_GToolWindow;			// Toolbar frame
	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
	extern char			_GToolClass[];			// toolbar window name
	
	extern XGView		*_GToolView;			// toolbar view (if there)
}

/*
 *	Window procedures
 */

extern LRESULT CALLBACK _GToolBarWindowProc(HWND,UINT,WPARAM,LPARAM);
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													*/
/*																		*/
/************************************************************************/

/*$	XGPopWindow
 *
 *		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 *, XRect, XGView *);
		virtual					~XGPopWindow();
		
		/*
		 *	Pop view access
		 */
		
		/*$	XGPopWindow::GetLocation
		 *
		 *		Returns the location of this popup window
		 */
		
		XRect					GetLocation()
									{
										return fLocation;
									}
									
		/*$	XGPopWindow::GetView
		 *
		 *		Returns the view associated with this popup window
		 */
		
		XGView					*GetView()
									{
										return fView;
									}
									
		/*$	XGPopWindow::GetBase
		 *
		 *		Returns the base view associated with this popup window
		 */
		
		XGView					*GetBase()
									{
										return fBase;
									}
		
		/*$	XGPopWindow::GetPopCount
		 *
		 *		Returns the number of popup windows outstanding
		 */
		
		static long				GetPopCount()
									{
										return gPopCount;
									}
									
		/*
		 *	Find the popup from the window object
		 */
		
#if OPT_MACOS
		static XGPopWindow		*GetPopWindow(WindowPtr);
#endif

#if OPT_WINOS
		static XGPopWindow		*GetPopWindow(HWND);
#endif

#if OPT_XWIN
		static XGPopWindow		*GetPopWindow(Window);
#endif

		/*
		 *	Internal routing routines to route mouse events
		 *	to the base view
		 */
		
		XGView					*ProcessMouseDown(XPoint pt, short flags);
		void					ProcessMouseMove(XPoint,short,XGView *v = NULL);
		bool					ProcessMouseUp(XPoint,short,XGView *v = NULL);

	private:
		static long				gPopCount;
		XRect					fLocation;
		XGView					*fView;
		XGView					*fBase;
		
		static XGPopWindow		*gList;
		XGPopWindow				*fNext;
		
		XPoint					ConvertToBaseView(XPoint);
		
		/*
		 *	Support
		 */
		
		void					FixToScreen(XRect *r);
		void					CreateOSWindow(XRect r);
		void					DestroyOSWindow();

#if OPT_MACOS
		WindowRecord			fWindow;
#endif

#if OPT_WINOS
		HWND					fWindow;
		static void				RegisterPopWindow(void);
		static LRESULT CALLBACK	PopWindowProc(HWND, UINT, WPARAM, LPARAM);
#endif

#if OPT_XWIN
		Window					fWindow;
#endif
};

/*$	XGWindow
 *
 *		The wrapper of the window for the native OS. This serves as only
 *	a wrapper for the window specific stuff
 */

class XGWindow : public XGView {
	public:
	
		/*
		 *	Construction/Destruction
		 */
		
								XGWindow(XGArgStream &, XGForm *);
								XGWindow(XGSWindowInitRecord &, XGForm *);
		virtual					~XGWindow();
		
		enum {
			kClassID = 'wind'
		};
		
		virtual bool			CloseWindow();
		
		/*
		 *	Size limits (internal or content size)
		 */
		
		virtual XPoint			MinWindowSize();
		virtual XPoint			MaxWindowSize();
		virtual XPoint			ZoomWindowSize();
		
		virtual void			SetMinWindowSize( XPoint p );
		virtual void			SetMaxWindowSize( XPoint p );
		virtual void			SetZoomWindowSize( XPoint p );
		
		void					LimitWindowSize(XPoint *);

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

		/*$	XGWindow::GetWindowID
		 *
		 *		Gets the window ID of this window.
		 */
		
		short					GetWindowID()
									{
										return fWindowID;
									}
		unsigned short			GetWindowAttributes();

		/*$	XGWindow::GetForm
		 *
		 *		Gets the XGForm object associated with this window.
		 */

		XGForm					*GetForm()
									{
										return fForm;
									}
		
		/*
		 *	Window support
		 */
		
		void					ShowWindow();
		void					HideWindow();
		bool					IsVisible(void);
		bool					IsMinimized(void);
		bool					IsMaximized(void);
		
		static XGWindow			*GetFrontWindow();
		void					SelectWindow();
		static void				GetScreenSize(XRect *);
		
		/*$	XGWindow::HoldCapture
		 *
		 *		If this is called while the mouse is captured by
		 *	the view's DoMouseUp() routine, the view capture is
		 *	*not* released. This is useful when implementing
		 *	functionality where the mouse is rapidly clicked in
		 *	a popup object, where the rapid click semantics is
		 *	similar to a mouse down/hold operation.
		 */

		static void				HoldCapture()
									{
										gHoldCapture = true;
									}

		/*$	XGWindow::SetCapture
		 *
		 *		When called during a DoMouseDown() event by
		 *	a view with a pointer to another view, the other
		 *	view will receive further mouse events (capturing
		 *	the mouse). Useful for implementing popup menus
		 *	and similar functionality.
		 */

		static void				SetCapture(XGView *v)
									{
										gCapture = v;
									}
									
		virtual short			GetMenuBarID();

		/*
		 *	Manage windows by it's fWindowID value. This is
		 *	sort of equivalent to the tracking of views by ID...
		 */
		
		static void				ShowWindow(short);
		static void				HideWindow(short);
		static bool				IsVisible(short);
		static bool				IsMinimized(short);
		static bool				IsMaximized(short);

		static XGWindow			*GetWindowByID(short);
		static void				SelectWindow(short);


		/*
		 *	Window size
		 */
		
		XPoint					GetContentSize() const;
		XRect					GetContentRect() const;
		
		void					SetWindowSize(XPoint);
		void					SetWindowPos(XPoint);
		void					SetWindowLocation(XRect);
		
		XPoint					GetWindowSize() const;
		XPoint					GetWindowPos() const;
		XRect					GetWindowLocation() const;
		
		static void				ContentToSize(XRect *);
		static void				ContentToSize(XPoint *);
		static void				SizeToContent(XRect *);
		static void				SizeToContent(XPoint *);
		
		/*
		 *	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)
		 */
		
		virtual void			ProcessDraw(XRect);
		virtual void			ProcessSizeWindow();
		XGView					*ProcessMouseDown(XPoint,short);
		void					ProcessMouseMove(XPoint,short,XGView *v = NULL);
		bool					ProcessMouseUp(XPoint,short,XGView *v = NULL);
		static void				ProcessMouseEnter(XPoint,short,XGView *v);
		static void				ProcessMouseLeave();
		
		/*
		 *	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	
		
	protected:
		XGDispatch				*GetParentDispatch();

	private:

		/*
		 *	Init support
		 */
		
		void					IInitWindow(XGSWindowInitRecord &);
		void					ICreateWindow(char *, XRect);
		
		/*
		 *	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;
		HWND					fCorner;
#endif

#if OPT_XWIN == 1
		Window					fWindow;
		Window					fWMWindow;
		
		Region					fUpdateRgn;
		int						fOldWidth;
		int						fOldHeight;		// screen SizeWindow events
		
		XGView					*fMenuBarView;
#endif
		XGWindow				*fPrev;
		XGWindow				*fNext;
		static XGWindow			*gList;
		
		XGForm					*fForm;
		XGView					*fFocus;
		
		static XGView			*gLastView;
#if OPT_WINOS == 1
		static HWND				gLastHWND;
#endif
		
		/*
		 *	Internal window data
		 */
		
		XPoint					fMin;
		XPoint					fMax;
		XPoint					fZoom;

		short					fMenuBar;
		
		long					fWindowType;
		short					fWindowKind;
		short					fWindowID;
		
		static bool				gHoldCapture;
		static XGView			*gCapture;

#if OPT_WINOS
	friend LRESULT CALLBACK _GToolBarWindowProc(HWND, UINT, WPARAM, LPARAM);
	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

	/*
	 *	NOTE: Rethink the following, as these classes are getting
	 *	*awfully* imbred...
	 */
	
	friend class XGWindowFactory;
	friend class XGPopWindow;
	friend class XGAppCore;
	friend class XGForm;
	friend class XGView;
	friend class XGAppMultiWindow;
	friend class XGControl;
	friend class XGDragger;
};


#endif // PandaWave_XWINDOW
