/*	XDraw.h
 *
 *		The drawing object. This encapsulates the common drawing operations
 *	that a program may use to draw stuff
 */

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

  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_XDRAW
#define PandaWave_XDRAW

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

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

/**@name Drawing Classes
 *
 *		These classes encapsulate the common drawing operations performed
 *	on an XGView class.
 *
 *		The idea is pretty simple: each of the platforms supported by
 *	YAAF have very different drawing models. This hides much of those
 *	differences, providing common drawing routines to handle drawing
 *	graphics into a view.
 */
 
//@{

/************************************************************************/
/*																		*/
/*	Externals															*/
/*																		*/
/************************************************************************/

#if OPT_XWIN
extern Display *_GDisplay;
extern unsigned long AllocColor(Color c);
#endif

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

class XGView;
class XGFont;
class XGBitmap;
class XGPrinter;
class XGDraw;

/************************************************************************/
/*																		*/
/*	Support Routines													*/
/*																		*/
/************************************************************************/

#if OPT_WINOS

/*	MS Windows Missing Routines */

extern void			DrawResBitmap(HDC dest, short id, long x, long y);

#endif

#if OPT_XWIN

/* X Windows routines */

extern XPoint		GetBitmapSize(short resID);
extern void			DrawXBitmap(Display *,
								Drawable, 
								GC,
								short resID, 
								long x, 
								long y);
extern void			DrawXIcon(Display *, 
							  Drawable,
							  GC,
							  short resID, 
							  long x, 
							  long y,
							  bool enable = true);

#endif

/************************************************************************/
/*																		*/
/*	Drawing Constants													*/
/*																		*/
/************************************************************************/

/*$	XGERectType
 *
 *		The rectangle type drawn by the XGDraw::Draw3DRect
 *	method.
 */

enum XGERectType {
	/// Draw a black frame around this rectangle
	KXGEFrame = 1,
	/// Draw this rectangle as a 3D inset rectangle
	KXGEInset,
	/// Draw this rectangle as a 3D "outset" rectangle
	KXGEOutset,
	/// Draw a 3D button in the "up" position. This is 2 pixels thick
	KXGEButton,
	/// Draw a 3D button in the "down" position. This is 2 pixels thick
	KXGEInButton,
	/// Draw the 3D button as a gray rectangle
	KXGEGrayFrame,
	/// Draw the 3D button as a light gray rectangle (in the background color)
	KXGEBackFrame,
	/// Fill this rectangle with the 3D color backcolor.
	KXGEBackground,
	/// White frame
	KXGEHiliteFrame
};

/*
 *	Font flags
 */

/// Select a bold faced font
#define	KXGFontBold				0x0001
/// Select an italic faced font
#define KXGFontItalic			0x0002
/// Select an underline font
#define KXGFontUnderline		0x0004
/// Select a fixed-width font if the font specified by name doesn't exist
#define KXGFontFixFont			0x0100		// fixed or variable?
/// Select a serifed font if the font specified by name doesn't exist
#define KXGFontSerifFont		0x0200		// serif or san-serif?


/************************************************************************/
/*																		*/
/*	Font Resource Format												*/
/*																		*/
/************************************************************************/

/*$	XGSFontResource
 *
 *		Font resource format. This is how a font resource is stored.
 */

struct XGSFontResource {
	short						size;
	short						fBold;
	short						fItalic;
	short						fUnderline;
	short						fFixed;
	short						fSerif;
	char						name[32];
};

/************************************************************************/
/*																		*/
/*	Drawing Support														*/
/*																		*/
/************************************************************************/

/*$	XGFont
 *
 *		Font management class. This is the class object which is used
 *	to handle font by encapsulating them.
 *
 *		To use this, normally you would first load the font using the
 *	LoadFont() routine. Then, you can make "variants" on the font by
 *	calling GetFontVariant. Once you have your font variants, you can
 *	then attach them to an XGDraw object in order to draw wth this font.
 */

class XGFont {
	public:
								XGFont();
		virtual					~XGFont();
		
		/*
		 *	Font attach/lock semantics
		 */
		
		/*$	XGFont::Attach
		 *
		 *		This increments the 'attach' count of the font. When
		 *	the font is first created, it's created with an attach count
		 *	of one.
		 */
		
		void					Attach(void)
									{
										fAttach++;
									}
		void					Detach(void);
		
		/*
		 *	Font resource management
		 */
		
		static XGFont			*LoadFont(short);
		static XGFont			*GetFontVariant(XGFont *f, short flags);
									
		/*
		 *	Font specification
		 */
		
		/*$	XGFont::GetFontFlags
		 *
		 *		Get the flags associated with this font. This returns
		 *	the 'bold', 'italic' and 'underline' settings
		 */
		
		short					GetFontFlags() const
									{
										return fFontFlags;
									}
		void					GetFontName(char *) const;

		/*$	XGFont::GetFontSize
		 *
		 *		Returns the current size of this font in points. A
		 *	'point' is 1/72th of an inch in height, and scaled upwards
		 *	or downwards into the native sizing metric of the OS.
		 */
		
		short					GetFontSize(void) const
									{
										return fFontSize;
									}

		void					SetFontFlags(short);
		void					SetFontName(const char *);
		void					SetFontSize(short);
	
		/*
		 *	Font hooks
		 */
		
#if OPT_MACOS == 1
		void					SetFont();
#endif

#if OPT_WINOS == 1
		HFONT					GetFont(HDC dc = NULL);
#endif

#if OPT_XWIN == 1
		Font					GetFont();
		XFontStruct				*GetFontStruct();
#endif

	private:
		long					fAttach;
		short					fFontResID;
		
		short					fFontFlags;
		short					fFontSize;
		char					fFontName[64];
		
		static XGPDynArray<XGFont> gFontArray;

#if OPT_MACOS == 1
		short					fFontID;
#endif

#if OPT_WINOS == 1
		HFONT					fFontHandle;
#endif

#if OPT_XWIN == 1
		XFontStruct				*fFontData;
#endif
};



class XGBitmap {
	friend class XGDraw;
	public:
					XGBitmap();
		virtual		~XGBitmap();
		
		void		FreeInternalBitmap();
		
		void		SetBitmapRGBA( const void *rgba, int width, int height, int rowbytes = 0 );
		void		SetBitmapRGB( const void *rgb, int width, int height, int rowbytes = 0 );
		void		SetBitmapAlpha( const void *alpha, int width, int height, int rowbytes = 0 );
		
		void		LoadFromPicture( int resID );
		void		LoadFromIcon( int resID );
		
		int			GetWidth();
		int			GetHeight();
	
	private:
#if OPT_MACOS
		GWorldPtr	fGWorld;
#endif
#if OPT_WINOS
		//HBITMAP 	hBitmap;
		unsigned char* bitmap_buff;
		BITMAPINFO bitmap_info;
		static unsigned char* WordAlignScanLines(const unsigned char* in_buff, int width, int height, int rowbytes);
		static void ReverseBytes(unsigned char* in_buff, int width, int height, int rowbytes);
		
		void FillBitmapInfo(BITMAPINFO* info, int width, int height, int rowbytes);
#endif
		
};

/*$	XGDraw
 *
 *		This provides a universal interface for drawing inside of a view.
 *
 *		This is a stack based object; this object is generally created
 *	on a stack. To draw, a view creates this object on the stack and
 *	then calls events into it. (By being stack based, it means that
 *	when the stack unwinds, this will be destroyed and the resources
 *	will be released.)
 *
 *		Note that YAAF does not automatically generate one of these
 *	drawing objects, even when calling your view's DoDrawView() method.
 *	Thus, you must create one of these on the stack in order to draw
 *	into a view.
 *
 *		This object encapsulates all of the common drawing operations,
 *	and translates these drawing calls into the appropriate calls for
 *	the Macintosh, Windows and X Windows.
 */

class XGDraw {
	public:
								XGDraw(XGView *v, bool lc = true);
								XGDraw(XGPrinter *p);
		virtual					~XGDraw();
		
		/*
		 *	State support
		 */
		
		/*$ XGDraw::GetDraw
		 *
		 *		Returns the current XGDraw object; this is the current
		 *	drawing environment. The XGDraw object maintains a stack
		 *	of drawing objects, in order to support nested drawing
		 */
		
		static XGDraw			*GetDraw()
									{
										return gDraw;
									}

		/*$ XGDraw::GetView
		 *
		 *		Returns the current XGView object being drawn into.
		 *	This returns the XGView object associated with the current
		 *	XGDraw object.
		 */

		static XGView			*GetView()
									{
										if (gDraw) return gDraw->fView;
										else return NULL;
									}
									
		/*
		 *	Low level drawing support
		 */
		 
		XPoint					GetResolution();
		
		void					MoveTo( long x, long y );
		void					LineTo( long x, long y );
		void					Move( long dx, long dy );
		void					Line( long dx, long dy );
		XPoint					GetPenPos(void);
		
		void					FrameOval(XRect);
		void					PaintOval(XRect);
		void					EraseOval(XRect);
		
		void					FrameArc(XRect,long,long);
		void					PaintArc(XRect,long,long);
		void					EraseArc(XRect,long,long);
		
		void					FrameRect(XRect);
		void					PaintRect(XRect);
		void					EraseRect(XRect);
		void					InvertRect(XRect);
		void					InvertFrameRect(XRect);
		void					DrawFocusRect(XRect);
		
		void					FillRect(XRect,Color);
		void					FillRect(long,long,long,long,Color);
		void					Draw3DRect(XRect,XGERectType);
		
		void					SetFont(XGFont *, bool attach = false);

		/*$ XGDraw::GetFont
		 *
		 *		Returns the current font selected into this drawing
		 *	object. This increments the 'attach' count, so you must
		 *	detach the font when done.
		 */

		XGFont					*GetFont()
									{
										fFontPtr->Attach();
										return fFontPtr;
									}
		long					GetFontAscent();
		long					GetFontDescent();
		long					GetFontHeight();
		long					GetLineHeight();
		long					StringWidth(const char *, long len = -1);
		void					DrawString(const char *, long len = -1);
		long					StringWidthA(const char *, long len = -1);
		void					DrawStringA(const char *, long len = -1);
		long					TabStringWidth(const char *,
											   unsigned long len,
											   unsigned long tabs,
											   bool password = false,
											   unsigned long startpos = 0);
		void					TabDrawString(const char *,
											  unsigned long start,
											  unsigned long len,
											  unsigned long tabs,
											  bool password = false);
		void					DrawWrap(XRect r, const char *, long len = -1);
		void					DrawWrapA(XRect r, const char *, long len = -1);
		
		void					DrawNum(const long value, short just = 0);

		void					DrawIcon(short,long x, long y, bool enable = true);
		void					DrawPicture(short, long x, long y);
		void					DrawBitmap( const XGBitmap *bmap,
											int x,
											int y,
											int width = -1,
											int height = -1 );
		
		void					ClipRect(XRect *r = NULL);

		Color					ColorFromPalette(Color);
		void					SetForeColor(Color);
		void					SetBackColor(Color);
		void					SetPenWidth(long);
		
		bool					IsColor();
		long					PixelDepth();
		
		/*$	XGDraw::GetAUnderscore
		 *
		 *		Return true if this draws an underscore with the
		 *	DrawStringA() and DrawWrapA() routines. By default this
		 *	is true on Windows and X, and false on the Macintosh.
		 */
		
		bool					GetAUnderscore()
									{
										return fAUnderscore;
									}

		/*$	XGDraw::SetAUnderscore
		 *
		 *		Set the current state of the underscore drawing
		 *	flag. This affects if underscores are drawn when the
		 *	DrawStringA() and DrawWrapA() routines are called. This
		 *	behavior should only be altered under extraordinary
		 *	circumstances.
		 */
		
		void					SetAUnderscore(bool uscore)
									{
										fAUnderscore = uscore;
									}
		
		/*
		 *	Local OS dependant state information
		 */
		
#if OPT_WINOS == 1
		HDC						GetDC() const
									{
										return fDC;
									}
#endif

#if OPT_XWIN == 1
		Display					*GetDisplay() const
									{
										return _GDisplay;
									}
		GC						GetGC() const
									{
										return fGC;
									}
		Drawable				GetDrawable() const;
#endif

#if (OPT_XWIN == 1) || (OPT_WINOS == 1)
		static void				UpdateRect(XRect *r = NULL)
									{
										gUpdate = r;
									}
#endif

#if OPT_XWIN
		static void				UpdateRegion(Region r = 0)
									{
										gRegion = r;
									}
#endif

	private:
		/*
		 *	Context management routines
		 */
		
		void					CreateContext(bool);
		void					SaveContext();
		void					RestoreContext();
		void					DestroyContext();
	
		/*
		 *	Internal globals
		 */
		
		static XGDraw			*gDraw;		// Draw stack
		XGDraw					*fLast;
		XGView					*fView;
		XGFont					*fFontPtr;	// internal font to use
		XGPrinter				*fPrinter;	// printer with my view...
		
		/*
		 *	Internal state information
		 */
		
		long					fPenWidth;
		bool					fAUnderscore;	// & draws underscore?
		
#if OPT_MACOS == 1
		PenState				fPenState;
		short					fFont;
		short					fFace;
		short					fSize;
		short					fMode;
		RGBColor				fForeColor;
		RGBColor				fBackColor;
		Fixed					fSpExtra;
		
		RgnHandle				fClip;
		XPoint					fOffset;
		GrafPtr					fPort;
		
		GDHandle				GetGDHandle();
		GDHandle				fGDCache;
#endif

#if OPT_WINOS == 1
		COLORREF				fForeColor;
		COLORREF				fBackColor;

		HGDIOBJ					fDefFont;
		HDC						fDC;
		long					fDCSave;
		static CRITICAL_SECTION	*gCritSec;
#endif

#if OPT_XWIN == 1
		GC						fGC;
		
		Color					fForeground;
		Color					fBackground;
		
		long					fXOrigin;
		long					fYOrigin;
		long					fXPen;
		long					fYPen;
#endif

#if (OPT_XWIN == 1) || (OPT_WINOS == 1)
		static XRect				*gUpdate;
#endif

#if OPT_XWIN
		static Region			gRegion;
#endif
};

//@}

#endif // PandaWave_XDRAW
