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

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

  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_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

/**@name View Management
 *
 *		A "view" is a subset of a window.
 *
 *		This is a relatively simple, but powerful concept. A view may
 *	be a control, an embedded editor, or an embedded display object.
 *	This makes constructing a window extremly easy: you would simply
 *	build up a view from smaller components.
 *
 *		Views are rectangular, and in one sense, is simply a hierarchy
 *	of rectangles in a window. Further, a window object is descendant
 *	from the view object: a window view is the rectangular area of the
 *	entire window, minus the menu bar in that window (if any).
 *
 *		Normally you would create a view using the YAAF Constructor.
 *	This would allow you to position the contents of a window, including
 *	automatic resizing of the views. Then you would specify the different
 *	controls in that window, or write your own custom views.
 */
 
//@{

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

class XGArgStream;
class XGViewFactory;
class XGView;
class XGWindow;
class XGForm;

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

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

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

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

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

/*$	XGArgStream
 *
 *		Argument stream; this is the class which manages the static
 *	data from which views are constructed. When you create a new view
 *	which has custom arguments, you would call the various Read
 *	routines to extract those arguments for your view.
 */

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

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

		void					SetLength (long length) { fLength = length; }
		void					SetBuffer (unsigned char *data) { fData = data; }

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

/*$	XGViewFactory
 *
 *		View factory class; this contains the code to search the list
 *	of views to construct the correct one. This is used internally
 *	by YAAF to create a view from a resource data stream. You can
 *	also call the create routines to handle constructing a view yourself.
 */
 
class XGViewFactory {
	public:
		/*
		 *	Public view construction
		 */
		
		static XGView			*CreateFromData(const unsigned char *, XGView *par = NULL);
		static XGView			*CreateFromResource(short, XGView *par = NULL);
		
		/*
		 *	Constructor procedure registration
		 */
		
		static void				Register(long, XGConstructorProc *);

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

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

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

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

/*$	RegisterView
 *
 *		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;
};		

/*$	XGView
 *
 *		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:
		/*
		 *	Construction/Destruction
		 */
		
								XGView(XGWindow *self);
								XGView(XGView *parent, XGArgStream &init);
								XGView(XGView *parent, XGSViewInitRecord &init);
		virtual					~XGView();
		
		enum {
			kClassID = 'view'
		};
		
		/*
		 *	Public event messages. Override these to handle this
		 *	view's behaviour.
		 */
		
		virtual void			DoDrawView(XRect);
		virtual void			DoActivate(bool);
		
		virtual bool			DoMouseDown(XPoint,short);
		virtual void			DoMouseMove(XPoint,short);
		virtual void			DoMouseUp(XPoint,short);
		virtual void			DoMouseEnter(XPoint,short);
		virtual void			DoMouseLeave();
		
		virtual void			DoSizeView(void);
		virtual void			DoMoveView(void);
		
		virtual void			DoShowHide(void);		// control support
		virtual void			DoEnable(void);
		
		/*
		 *	Focus support
		 */
		
		virtual void			SetFocus(void);
		
		/*
		 *	View display processing
		 */
		
		bool					IsVisible() const;
		void					ShowView();
		void					HideView();
		
		bool					IsEnabled() const;
		bool					IsEnabled( short id ) const;
		void					EnableView();
		void					DisableView();
		void					SetEnabled( bool beEnabled );
		void					SetEnabled( short id, bool beEnabled );
		
		bool					IsActive() const;
		
		/*$	XGView::IsTabStop
		 *
		 *		Returns 'true' if this view is a tab stop; that is,
		 *	if this view is a target when the tab stop is pressed in
		 *	a window or view.
		 */
		
		bool					IsTabStop() const		{ return fTabStop; }

		/*$	XGView::GetRefNum
		 *
		 *		Get the reference number. this is a 32-bit value associated
		 *	with this view that can be used by the application.
		 */
		
		long					GetRefNum() const		{ return fRefNum; }

		/*$	XGView::SetRefNum
		 *
		 *		Set the reference number. this is a 32-bit value associated
		 *	with this view that can be used by the application.
		 */
		
		void					SetRefNum(long x)		{ fRefNum = x; }
		
		virtual void			GetTitle(char *) const;
		virtual void			SetTitle(const char *);
		
		/*$	XGView::GetViewType
		 *
		 *		Returns the 32-bit value indicating the type of view
		 *	for this view.
		 */
		
		long					GetViewType() const		{ return fViewType; }

		/*$	XGView::GetViewID
		 *
		 *		Returns the 16-bit value indicating the ID of this
		 *	view. This view ID is used to identify this view, and as
		 *	a 'command code' for dialogs. This differs from the model
		 *	used by PowerPlant on the Macintosh, where the identifier
		 *	is separate from the view ID. As all control events are
		 *	sent to my immediate parent, there shouldn't be any
		 *	confusion between the same identifier used in different
		 *	dialogs.
		 */
		
		short					GetViewID() const		{ return fViewID; }
		
		/*$	XGView::HoldCapture
		 *
		 *		Used for handling click-hold processing for pop-up
		 *	menus. When called within the DoMouseUp routine, this
		 *	causes YAAF *not* to process the capture release operation.
		 *	This permits a single-click operation to act as if it
		 *	were a mouse-down and hold event within a single view control.
		 */

		static void				HoldCapture();
		static void				SetCapture(XGView *);
		
		/*
		 *	View hierarchy
		 */
		
		/*$	XGView::GetParent
		 *
		 *		Returns the parent of this view.
		 */
		
		XGView					*GetParent() const		{ return fParent; }

		/*$	XGView::GetChild
		 *
		 *		Returns the first child view of this view. You can
		 *	access the rest of the children views by calling the
		 *	'GetSibling' method with the child returned here.
		 */
		
		XGView					*GetChild() const		{ return fChild; }

		/*$	XGView::GetSibling
		 *
		 *		Returns the sibling of this view. Children views are
		 *	maintained in a singlularly linked list; this allows you
		 *	to traverse that linked list.
		 */
		
		XGView					*GetSibling() const		{ return fSibling; }
		
		XGWindow				*GetWindow() const;
		XGForm					*GetForm() const;
		
		XGView					*FindViewByID(short);
		const XGView			*FindViewByID(short) const;
		XGView					*FindViewByPoint(XPoint, bool recurse = true);
		const XGView			*FindViewByPoint(XPoint, bool recurse = true) const;
		
		XGView					*FindFirstView();
		XGView					*FindLastView();
		XGView					*FindBeforeView(short);
		XGView					*FindAfterView(short);
		
		XGView					*FindViewByAccel(char);
		XGView					*FindNextView();
		
		/*
		 *	View location and view manipulation
		 */
		
		/*$	XGView::GetPos 
		 *
		 *		Gets the position of this view in the parent view. This
		 *	is computed relative to the upper-left corner of the parent
		 *	view.
		 */
		
		XPoint					GetPos() const			{ return fPos; }
		
		/*$	XGView::GetSize
		 *
		 *		Get the width and height of this view.
		 */
		
		XPoint					GetSize() const			{ return fSize; }
		virtual XRect			GetContentRect() const;
		
		virtual XRect			CalcChildPos(XGView *);
		XRect					CalcAutoLocate(XRect);

		void					RecalcAutoLocation (XGView *below = NULL, XGView *beside = NULL, XRect *r = NULL);
		
		void					RePosition( int x, int y );
		void					GetAutoLocate( XRect *r,
												bool *lockleft, bool *locktop,
												bool *lockright, bool *lockbottom );
		void					SetAutoLocate( const XRect &r,
												bool lockleft, bool locktop,
												bool lockright, bool lockbottom );
		void					SetLocation(XRect);

		/*$	XGView::GlobalToView
		 *
		 *		Convert this point from window relative coordinates
		 *	to view relative coordinates.
		 */
		
		void					GlobalToView(XPoint *p) const
									{
										p->h -= fGlobalPos.h;
										p->v -= fGlobalPos.v;
									}
		/*$	XGView::GlobalToView
		 *
		 *		Convert this rectangle from window relative coordinates
		 *	to view relative coordinates.
		 */
		
		void					GlobalToView(XRect *r) const
									{
										r->left   -= fGlobalPos.h;
										r->top    -= fGlobalPos.v;
										r->right  -= fGlobalPos.h;
										r->bottom -= fGlobalPos.v;
									}
		/*$	XGView::ViewToGlobal
		 *
		 *		Convert this point from view relative coordinates
		 *	to window relative coordinates.
		 */
		
		void					ViewToGlobal(XPoint *p) const
									{
										p->h += fGlobalPos.h;
										p->v += fGlobalPos.v;
									}
		/*$	XGView::ViewToGlobal
		 *
		 *		Convert this rectangle from view relative coordinates
		 *	to window relative coordinates.
		 */
		
		void					ViewToGlobal(XRect *r) const
									{
										r->left   += fGlobalPos.h;
										r->top    += fGlobalPos.v;
										r->right  += fGlobalPos.h;
										r->bottom += fGlobalPos.v;
									}
		/*$	XGView::ViewToScreen
		 *
		 *		Convert this point from view relative coordinates
		 *	to screen relative coordinates.
		 */
		
		void					ViewToScreen(XPoint *p);

		/*$	XGView::ViewToScreen
		 *
		 *		Convert this rectangle from view relative coordinates
		 *	to screen relative coordinates.
		 */
		
		void					ViewToScreen(XRect *r);

		/*$	XGView::ScreenToView
		 *
		 *		Convert this point from screen relative coordinates
		 *	to view relative coordinates.
		 */
		
		void					ScreenToView(XPoint *p);

		/*$	XGView::ScreenToView
		 *
		 *		Convert this rectangle from screen relative coordinates
		 *	to view relative coordinates.
		 */
		
		void					ScreenToView(XRect *r);
		
		/*
		 *	Drawing Support routines
		 */
		
		void					InvalView(XRect *r = NULL);
		void					ValidView(XRect *r = NULL);
		void					UpdateView();

		/*
		 *	View scrolling support
		 */
		 
		virtual void			Scroll(long,long);
		void					ScrollView(long,long,XRect *r = NULL, Color c = 0);
		
		bool					GetScrollParams(long *, long *, long *);
		void					SetScrollLimits(long, long, long step = 12);
		void					ScrollInRange(long x, long y,
											  long w = -1, long h = -1);
		void					SetChildOffset( long x, long y );
		XPoint					GetChildOffset();
		
		/*
		 *	View management routines
		 */
		
		virtual void			ProcessDraw(XRect);
		virtual void			ProcessActivate(bool);
		XGView					*FindClick(XPoint);
		
		/*
		 *	OS Specific support
		 */

		static bool				Is72DPI();
		
		/*
		 *	Window port support
		 */
		
#if OPT_MACOS
		void					SetRootWindow(GrafPtr port)
									{
										fRootWindow = port;
									}
		GrafPtr					GetRootWindow()
									{
										return fRootWindow;
									}
#endif
		
#if OPT_WINOS
		void					SetRootWindow(HWND port)
									{
										fRootWindow = port;
									}
		HWND					GetRootWindow()
									{
										return fRootWindow;
									}
#endif
		
#if OPT_XWIN
		void					SetRootWindow(Window port)
									{
										fRootWindow = port;
									}
		Window					GetRootWindow()
									{
										return fRootWindow;
									}
#endif


	protected:
		XGDispatch				*GetParentDispatch();

		void					ClearTabStop()
									{
										fTabStop = false;
									}

	private:
		/*
		 *	Resize support
		 */
		
		void					CalcPos(void);
		void					CalcGlobalRect(void);
		
		/*
		 *	Initialization support
		 */
		
		void					IInitView(XGView *parent, XGSViewInitRecord &);
		
		/*
		 *	Basic hierarchy relationship pointers
		 */
		
		XGWindow				*fWindow;
		XGView					*fChild;
		XGView					*fSibling;
		XGView					*fParent;
		
#if OPT_MACOS
		GrafPtr					fRootWindow;
#endif

#if OPT_WINOS
		HWND					fRootWindow;
#endif

#if OPT_XWIN
		Window					fRootWindow;
#endif
		
		/*
		 *	Personal status
		 */
		
		bool					fVisible;
		bool					fEnabled;
		bool					fTabStop;
		
		/*
		 *	View specification
		 */
		
		long					fViewType;
		short					fViewID;
		long					fRefNum;

		/*
		 *	View location
		 */
		
		XPoint					fSize;				// Current size of me
		XPoint					fPos;				// Current pos in parent
		XPoint					fGlobalPos;			// Global pos in window
		XRect					fGlobalRect;		// Clipped view rectangle
		XPoint					fChildOffset;		// Offset for children to take into account scrolling
		
		/*
		 *	Auto resize structures
		 */
				
		bool					fLockLeft;
		bool					fLockTop;
		bool					fLockRight;
		bool					fLockBottom;
		
		long					fAutoLeft;
		long					fAutoTop;
		long					fAutoRight;
		long					fAutoBottom;
	
	friend class XGDraw;
};

//@}

#endif
