/*	XView.h
 *
 *		This contains the view port and view factory declarations
 *	related to managing views
 */

/*  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_XVIEW
#define PandaWave_XVIEW

#include <XConfig.h>
#include <XDynArray.h>
#include <XModifiers.h>
#include <XDrawData.h>
#include <XEvent.h>

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

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

class XGArgStream;
class XGViewFactory;
class XGView;
class XGOwner;
class XGWindow;
class XGDocument;
class XGForm;

/************************************************************************/
/*																		*/
/*	View Factory														*/
/*																		*/
/************************************************************************/

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

typedef XGView *(XGConstructorProc)(XGOwner *parent, XGArgStream &);

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

struct XGSFactory {
	long				type;
	XGConstructorProc	*proc;
};

/*	@C"XGArgStream"
 *	@H"XView.h"
 *	@I
 *
 *		Argument stream; this is the class which manages the static
 *	data from which views are constructed
 */

class XGArgStream {
	public:
								XGArgStream(const unsigned char *, long);

		/*
		 *	Read routines
		 */
		
		bool					ReadBoolean();
		long					ReadInteger();
		void					ReadString(char *);

	private:
		long					fLength;
		const unsigned char		*fData;
};

/*	@C"XGViewFactory"
 *	@H"XView.h"
 *	@I
 *
 *		View factory class; this contains the code to search the list
 *	of views to construct the correct one
 */
 
class XGViewFactory {
	public:
		/*
		 *	Public view construction
		 */
		
		static XGView			*CreateFromData(const unsigned char *, XGOwner *par = NULL);
		static XGView			*CreateFromResource(short, XGOwner *par = NULL);
		
		/*
		 *	Constructor procedure registration
		 */
		
		static void				Register(long, XGConstructorProc *);

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

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

template <class T> class XGViewTemplate {
	public:
		
		/*	@F"XGViewTemplate::Register" @I
		 *
		 *		Register the Constructor() method of this template
		 *	with the XGViewFactory::Register method.
		 */
		
		static void				Register(long type)
									{
										XGViewFactory::Register(type,Constructor);
									}
		
		/*	@F"XGViewTemplate::Constructor" @I
		 *
		 *		The constructor method; this creates an XGView
		 *	descendant class using the new operator.
		 */
		
		static XGView			*Constructor(XGOwner *parent, XGArgStream &s)
									{
										return new T(parent,s);
									}
};

/*	@F"RegisterViewID"
 *	@U"RegisterViewID(classType,class)"
 *	@H"XGView.h"
 *	@I
 *
 *		Macro which uses template to register with factory. This
 *	version of the macro assumes the class is a descendant of the
 *	XGView class with a constructor that takes a parent XGObject
 *	class and an XGArgStream. The creator code is provided as one
 *	of the arguments in this macro.
 */

#define RegisterViewID(x,y)		XGViewTemplate<y>::Register(x)

/*	@F"RegisterView"
 *	@U"RegisterView(class)"
 *	@H"XGView.h"
 *	@I
 *
 *		Macro which uses template to register with factory. This
 *	version of the macro assumes the class is a descendant of the
 *	XGView class with a constructor that takes a parent XGObject
 *	class and an XGArgStream, and has the class type defined as
 *	an enumeration variable of 'kClassID'.
 */

#define RegisterView(x)			XGViewTemplate<x>::Register(x::kClassID)

/************************************************************************/
/*																		*/
/*	View Definition														*/
/*																		*/
/************************************************************************/

/*	XGSViewInitRecord
 *
 *		This is the initialization record for creating one of these
 *	if it's programmatically built
 */

struct XGSViewInitRecord {
	/*
	 *	View specification
	 */
	
	long					fViewType;
	
	short					fViewID;
	long					fRefNum;
	
	bool					fLockLeft;
	bool					fLockTop;
	bool					fLockRight;
	bool					fLockBottom;
	
	short					fAutoLeft;
	short					fAutoTop;
	short					fAutoRight;
	short					fAutoBottom;

	bool					fVisible;
	bool					fEnabled;
	bool					fTabStop;
};

/*	@C"XGOwner"
 *	@H"XGView.h"
 *	@I
 *
 *		In this modern architecture, a class can be owned by either
 *	an XGView or an XGWindow. This means that the parent object
 *	needs to be either. The only property the parent needs to have
 *	in common with both is the GrafPort/Window/HWND object that
 *	contains this view.
 *
 *		This is the XGOwner object which provides that drawing context
 */

class XGOwner {
	public:
		/*
		 *	Construction
		 */
		
		// @G"Construction/Destruction"
		
		/*	@F"XGOwner::XGOwner"
		 *	@I
		 *
		 *		Construct this owner object with a NULL root window.
		 */
		
								XGOwner()
									{
										fRootWindow = NULL;
									}

		/*	@F"XGOwner::XGOwner"
		 *	@I
		 *
		 *		Construct this owner object using the root window of
		 *	the XGOwner object provided.
		 */
		
								XGOwner(XGOwner *o)
									{
										if (o) fRootWindow = o->fRootWindow;
										else fRootWindow = NULL;
									}
		
		/*	@F"XGOwner::XGOwner"
		 *	@I
		 *
		 *		Destructs this owner object.
		 */
		
		virtual					~XGOwner()
									{
									}
									
#if OPT_MACOS == 1
		/*	@F"XGOwner::GetRootWindow"
		 *	@U"window_thing XGOwner::GetRootWindow(void)"
		 *	@I
		 *
		 *		This returns a pointer to the root window that contains
		 *	this object. The 'window_thing" type is OS dependant; on the
		 *	Maintosh this is a WindowPtr. On Windows, this is an HWND.
		 *	And on X, this is a Window.
		 */
		
		WindowPtr				GetRootWindow() const
									{
										return fRootWindow;
									}
									
		/*	@F"XGOwner::SetRootWindow"
		 *	@U"void XGOwner::SetRootWindow(window_thing)"
		 *	@I
		 *
		 *		This sets the root window pointer to the window specified.
		 *	The 'window_thing" type is OS dependant; on the
		 *	Maintosh this is a WindowPtr. On Windows, this is an HWND.
		 *	And on X, this is a Window.
		 */
		
		void					SetRootWindow(WindowPtr w)
									{
										fRootWindow = w;
									}
#endif

#if OPT_WINOS == 1
		HWND					GetRootWindow() const
									{
										return fRootWindow;
									}
		void					SetRootWindow(HWND w)
									{
										fRootWindow = w;
									}
#endif

#if OPT_XWIN == 1
		Window					GetRootWindow() const
									{
										return fRootWindow;
									}
		void					SetRootWindow(Window w)
									{
										fRootWindow = w;
									}
#endif
	protected:
		/*
		 *	Properties
		 */
		
#if OPT_MACOS == 1
		WindowPtr				fRootWindow;
#endif

#if OPT_WINOS == 1
		HWND					fRootWindow;
#endif

#if OPT_XWIN == 1
		Window					fRootWindow;
#endif
};
		

/*	@C"XGView" @I
 *	@D"XGDispatch" @D"XGOwner"
 *	@H"XView.h"
 *	@I
 *
 *		This is the base class for defining a view object. This is the root
 *	of all of my drawing handling and processing.
 *
 *		This is the workhorse class; this class handles encapsulating
 *	the drawing subviews that I can draw into. How this is handled differs
 *	between the Macintosh and Windows; the essence of this, however, is
 *	that this class only specifies the boundary of the view--the
 *	drawing is mediated by the XGDraw code.
 *
 *		On all platforms this only contains the geometry of the area
 *	that the view covers. This is a departure on Windows and X Windows
 *	where separate child windows are used instead.
 */

class XGView : public XGDispatch, public XGOwner {
	public:
		/*
		 *	Construction/Destruction
		 */
		
								XGView(XGOwner *parent, XGArgStream &init);
								XGView(XGOwner *parent, XGSViewInitRecord &init);
		virtual					~XGView();
		
		enum {
			kClassID = 'view'
		};
		
		/*
		 *	Public event messages. Override these to handle this
		 *	view's behaviour.
		 */
		
		virtual void			DoDrawView(Rect);
		virtual void			DoActivate(bool);
		
		virtual bool			DoMouseDown(Point,short);
		virtual void			DoMouseMove(Point,short);
		virtual void			DoMouseUp(Point,short);
		
		virtual void			DoSizeView(void);
		virtual void			DoMoveView(void);
		
		virtual void			DoShowHide(void);		// control support
		virtual void			DoEnable(void);
		
		/*
		 *	Focus support
		 */
		
		virtual bool			SetFocus(void);
		
		/*
		 *	View display processing
		 */
		
		// @G"View status"
		
		bool					IsVisible() const;
		void					ShowView();
		void					HideView();
		
		bool					IsEnabled() const;
		void					EnableView();
		void					DisableView();
		
		bool					IsActive() const;
		
		//	@F"XGView::IsTabStop" @I Returns the tab stop status of this view
		bool					IsTabStop() const		{ return fTabStop; }
		//  @F"XGView::GetRefNum" @I Returns the application reference value
		long					GetRefNum() const		{ return fRefNum; }
		//  @F"XGView::SetRefNum" @I Sets the application reference value
		void					SetRefNum(long x)		{ fRefNum = x; }
		
		virtual void			GetTitle(char *) const;
		virtual void			SetTitle(const char *);
		
		// @F"XGView::GetViewType" @I Get the view type of this view
		long					GetViewType() const		{ return fViewType; }
		// @F"XGView::GetViewID" @I Get the view ID of this view
		short					GetViewID() const		{ return fViewID; }
		
		/*
		 *	View hierarchy
		 */
		 
		// @G"View hierarchy"
		
		// @F"XGView::GetParent" @I Get the parent of this view
		XGView					*GetParent() const		{ return fParent; }
		// @F"XGView::GetChild" @I Get the first child of this view
		XGView					*GetChild() const		{ return fChild; }
		// @F"XGView::GetSibling" @I Gets the sibling of this view
		XGView					*GetSibling() const		{ return fSibling; }
		
		XGWindow				*GetWindow() const;
		XGDocument				*GetDocument() const;
		XGForm					*GetForm() const;
		
		XGView					*FindViewByID(short);
		XGView					*FindViewByPoint(Point, bool recurse = true);
		
		XGView					*FindFirstView();
		XGView					*FindLastView();
		XGView					*FindBeforeView(short);
		XGView					*FindAfterView(short);
		
		XGView					*FindViewByAccel(char);
		XGView					*FindNextView();
		
		/*
		 *	View location and view manipulation
		 */
		 
		// @G"View location"
		
		// @F"XGView::GetPos" @I Gets the position of this view in the parent view
		Point					GetPos() const			{ return fPos; }
		// @F"XGView::GetSize" @I Gets the size of this view
		Point					GetSize() const			{ return fSize; }
		virtual Rect			GetContentRect() const;
		
		virtual Rect			CalcChildPos(XGView *);
		Rect					CalcAutoLocate(Rect);

		void					SetLocation(Rect);		
		// @F"XGView::GlobalToView" @I Converts point from global to view coordinates
		void					GlobalToView(Point *p) const
									{
										p->h -= fGlobalPos.h;
										p->v -= fGlobalPos.v;
									}
		// @F"XGView::GlobalToView" @I Converts rectangle from global to view coordinates
		void					GlobalToView(Rect *r) const
									{
										r->left   -= fGlobalPos.h;
										r->top    -= fGlobalPos.v;
										r->right  -= fGlobalPos.h;
										r->bottom -= fGlobalPos.v;
									}
		// @F"XGView::ViewToGlobal" @I Converts the point from view to global coordinates
		void					ViewToGlobal(Point *p) const
									{
										p->h += fGlobalPos.h;
										p->v += fGlobalPos.v;
									}
		// @F"XGView::ViewToGlobal" @I Converts rectangle from view to global coordinates
		void					ViewToGlobal(Rect *r) const
									{
										r->left   += fGlobalPos.h;
										r->top    += fGlobalPos.v;
										r->right  += fGlobalPos.h;
										r->bottom += fGlobalPos.v;
									}
		
		/*
		 *	Drawing Support routines
		 */
		
		void					InvalView(Rect *r = NULL);
		void					ValidView(Rect *r = NULL);
		void					UpdateView();

		/*
		 *	View scrolling support
		 */
		 
		virtual void			Scroll(long,long);
		void					ScrollView(long,long,Rect *r = NULL);
		
		
		/*
		 *	View management routines
		 */
		
		void					ProcessDraw(Rect);
		void					ProcessActivate(bool);
		XGView					*FindClick(Point);
		
		/*
		 *	OS Specific support
		 */

		static bool				Is72DPI();

	protected:
		void					ClearTabStop()
									{
										fTabStop = false;
									}

	private:
		/*
		 *	Resize support
		 */
		
		void					CalcPos(void);
		
		/*
		 *	Initialization support
		 */
		
		void					IInitView(XGOwner *parent, XGSViewInitRecord &);
		
		/*
		 *	Basic hierarchy relationship pointers
		 */
		
		XGView					*fChild;
		XGView					*fSibling;
		XGView					*fParent;
		
		/*
		 *	Personal status
		 */
		
		bool					fVisible;
		bool					fEnabled;
		bool					fTabStop;
		
		/*
		 *	View specification
		 */
		
		long					fViewType;
		short					fViewID;
		long					fRefNum;

		/*
		 *	View location
		 */
		
		Point					fSize;				// Current size of me
		Point					fPos;				// Current pos in parent
		Point					fGlobalPos;			// Global pos in window
		Rect					fGlobalRect;		// Clipped view rectangle
		
		/*
		 *	Auto resize structures
		 */
		
		bool					fLockLeft;
		bool					fLockTop;
		bool					fLockRight;
		bool					fLockBottom;
		
		short					fAutoLeft;
		short					fAutoTop;
		short					fAutoRight;
		short					fAutoBottom;
	
	friend class XGDraw;
};

#endif
