/*
    ParaGUI - crossplatform widgetset
    Copyright (C) 2000,2001  Alexander Pipelka
 
    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 (at your option) 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
    MERCHANTABILITY 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
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
    Alexander Pipelka
    pipelka@teleweb.at
 
    Last Update:      $Author: pipelka $
    Update Date:      $Date: 2001/05/21 13:58:53 $
    Source File:      $Source: /usr/local/CVSROOT/linux/paragui/include/Attic/pgdrawobject.h,v $
    CVS/RCS Revision: $Revision: 1.1.2.12 $
    Status:           $State: Exp $
*/

#ifndef PG_DRAWOBJECT_H
#define PG_DRAWOBJECT_H

#ifdef SWIG
%include "swigcommon.h"
%module pgdrawobject
%{
#include "pgdrawobject.h"
%}
#endif

#include "paragui.h"
#include "pgsurfacecache.h"

/**
	@author Alexander Pipelka
	
	@short Base class of all objects (provides drawing functionality).
 
	Provides a graphics context and basic drawing functionality.
*/

class DECLSPEC PG_DrawObject : public PG_Rect {
public:
	
	/** */
	PG_DrawObject(const PG_Rect& rect, bool bCreateSurface);

	/** */
	virtual ~PG_DrawObject();

	// draw, update, move, ...

	/**
	Redraw the surface of the widget

	@param	update				if true PG_DrawObject::Update(true) is called after the redraw
	@return							redraw succeeded
	*/
	virtual bool Redraw(bool update = true);

	/**
	Update the widgets screen area

	@param	doBlit				if true PG_DrawObject::Blit() is called before the update
	*/
	virtual void Update(bool doBlit = true);

	/**
	Blit the surface of the object to the screen surface
	@parem	restore				restore the background before blitting if true
	*/
	virtual void Blit(bool restore = true);

	/**
	Move the object to a given screen-coordinate

	@param	x						screen x-position
	@param	y						screen y-position
	@return							move succeeded
	*/
	virtual bool MoveWindow(int x, int y);

	/**
	Resize the object

	@param	w						new width in pixels
	@param	h						new height in pixels
	@return							resize succeeded
	*/
	virtual bool SizeWindow(int w, int h);

	// set object props

	/**
	Make an object visible

	@param	visible				show / hide the object
	@return							success
	*/
	bool SetVisible(bool visible);

	/**
	Check if the object is visible
	@return							true if object is visible
	*/
	inline bool IsVisible() {
		return my_visible;
	}

	/**
	Set the transparency of the drawing object
	@param	t						transparency (0 - opaque / 255 - fully transparent)
	*/
	virtual void SetTransparency(Uint8 t);

	/**
	Get the transparency of the drawing object
	@return							transparency (0 - opaque / 255 - fully transparent)
	*/
	inline Uint8 GetTransparency() {
		return my_transparency;
	}

	/**
	Restore the background of the drawing object
	@param	rect					rectangle in screen coordinates to restore
	@return							true - background was restored successfully
	*/
	virtual bool RestoreBackground(PG_Rect* clip = NULL);

	// Drawing functions

	/**  */
	void SetPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b);
	static void SetPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b, SDL_Surface* surface);

	/**  */
	static void DrawLine(Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, SDL_Color color, Uint8 width, SDL_Surface* surface);

	/**  */
	void DrawLine(Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, SDL_Color color, Uint8 width=1);

	/**  */
	void DrawHLine(int x, int y, int w, Uint8 r, Uint8 g, Uint8 b);

	/**  */
	void DrawVLine(int x, int y, int h, Uint8 r, Uint8 g, Uint8 b);

	/**  */
	void DrawRectWH(int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b);

	/** */
	void DrawBorder(const PG_Rect& r, int size, bool up = true);

	/**
	Creates a surface filled with a gradient

	@param r		the dimensions of the surface to be created
	@param gradient	the gradient definition
	@return			a SDL_Surface pointer to the new surface

	This function creates a new surface filled with a given gradient
	*/
	static SDL_Surface* CreateGradient(const PG_Rect& r, PG_Gradient& gradient);

	/**
	Creates a surface filled with a gradient

	@param r		the dimensions of the surface to be created
	@param ul		upper/left gradient color
	@param ur		upper/right gradient color
	@param dl		lower/left gradient color
	@param dr		lower/right gradient color
	@return			a SDL_Surface pointer to the new surface

	This function creates a new surface filled with a given gradient defined by a set of colors
	*/
#ifdef SWIG
	%name(CreateGradient2) static SDL_Surface* CreateGradient(const PG_Rect& r, SDL_Color& ul, SDL_Color& ur, SDL_Color& dl, SDL_Color& dr);
#else
	static SDL_Surface* CreateGradient(const PG_Rect& r, SDL_Color& ul, SDL_Color& ur, SDL_Color& dl, SDL_Color& dr);
#endif

	/**  */
#ifdef SWIG
	%name(DrawGradient2) static void DrawGradient(SDL_Surface* surface, const PG_Rect& r, SDL_Color& ul, SDL_Color& ur, SDL_Color& dl, SDL_Color& dr);
#else
	static void DrawGradient(SDL_Surface* surface, const PG_Rect& r, SDL_Color& ul, SDL_Color& ur, SDL_Color& dl, SDL_Color& dr);
#endif

	/**  */
	static void DrawGradient(SDL_Surface* surface, const PG_Rect& r, PG_Gradient& gradient);

	/**
	Draw a 'themed' surface

	@param surface			the surface to draw on
	@param r					the rectangle of the surface to draw in
	@param gradient		pointer to a gradient structure (may be NULL)
	@param background	pointer to a background surface (may be NULL)
	@param bkmode		the mode how to fill in the background surface (BKMODE_TILE | BKMODE_STRETCH)
	@param blend				the blend-level between gradient an background
	*/
	static void DrawThemedSurface(SDL_Surface* surface, const PG_Rect& r, PG_Gradient* gradient, SDL_Surface* background, int bkmode, Uint8 blend);

	/**
	Create a 'themed' surface

	@param r					the dimensions of the surface to create
	@param gradient		pointer to a gradient structure (may be NULL)
	@param background	pointer to a background surface (may be NULL)
	@param bkmode		the mode how to fill in the background surface (BKMODE_TILE | BKMODE_STRETCH)
	@param blend				the blend-level between gradient an background
	@return 						the newly created surface
	
	The generated surface is managed by the surfacecache. Don't delete these surface with SDL_FreeSurface. Please use DeleteThemedSurface.
	*/
	static SDL_Surface* CreateThemedSurface(const PG_Rect& r, PG_Gradient* gradient, SDL_Surface* background, int bkmode, Uint8 blend);
	
	/**
	Delete a themed surface
	@param	surface		pointer to surface
	*/
	static void DeleteThemedSurface(SDL_Surface* surface);

	/**
	Render a string into a SDL_Surface
	@param	font				pointer to font definition
	@param	text				string to render
	@param	color			textcolor
	@return						pointer to SDL_Surface on success else NULL
	*/
	static SDL_Surface* RenderText(TTF_Font* font, const char* text, SDL_Color color);

	/**
	Render a textblock into a SDL_Surface
	@param rect				rectangle to render text into
	@param	font				pointer to font definition
	@param	text				string to render
	@param	color			textcolor
	@return						pointer to SDL_Surface on success else NULL
	*/
	static SDL_Surface* RenderText(const PG_Rect& rect, TTF_Font* font, const char* text, SDL_Color color, int align = PG_TA_LEFT);

	/** */
	static void GetTextSize(const char* text, int& width, int &height, TTF_Font* font);
	
	/**
	Draw a line of text onto a SDL_Surface
	@param	x					x-coordinate on the surface
	@param	y					y-coordinate on the surface
	@param	text				string to render
	@param	textfont		pointer to font definition - if NULL the default font of the object will be used
	@param	surface		destination surface - if NULL the destination will be the drawing object
	*/
	void DrawText(int x, int y, const char* text, SDL_Color c, TTF_Font* textfont = NULL);

	/**  */
#ifdef SWIG
	%name(DrawText2) void DrawText(const PG_Rect& r, const char* text, SDL_Color c, int align = PG_TA_LEFT, TTF_Font* textfont = NULL);
#else
	void DrawText(const PG_Rect& r, const char* text, SDL_Color c, int align = PG_TA_LEFT, TTF_Font* textfont = NULL);
#endif

	// clipping / intersection

	virtual void RecalcClipRect();
	
	/**
	Set the clipping rectangle for the object
	@param	x					x-position in client coordinates
	@param	y					y-position in client coordinates
	@param	w					width of the clipping rectangle
	@param	h					height of the clipping rectangle
	*/
	void SetClipRect(PG_Rect& r);

	/**
	Get the current clipping rectangle
	@return						the clipping rectangle
	*/
	PG_Rect GetClipRect();

	/**
	Check if there is a clipping rectangle assigned to the object
	@return						true / false
	*/
	inline bool IsClippingEnabled() {
		return ((my_rectClip.my_width != my_width) || (my_rectClip.my_height != my_height));
	}

	/**  */
	void GetClipRects(PG_Rect& src, PG_Rect& dst);

	/**  */
	void GetClipRects(PG_Rect& src, PG_Rect& dst, const PG_Rect& displayrect);

	/**  */
	virtual bool IsDisplayRectValid();

	/** */
	//void SetParent(PG_DrawObject* objParent);

protected:

	/**  */
	virtual void eventDraw(SDL_Surface* surface,  const PG_Rect& rect);

	/**  */
	virtual void eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst);

	/**  */
	virtual void eventSizeWindow(int w, int h);

	/**  */
	virtual void eventMoveWindow(int x, int y);

	/**
	Remove the drawing surface of an object
	This function is useful if you don't want a surface for your object. In this case
	you can use the eventBlit() handler to do drawing operations. Objects without
	a surface use less memory but drawing operations will be slower.
	*/
	void RemoveObjectSurface();

	bool my_visible;
	Uint8 my_transparency;

	SDL_Surface* my_srfObject;
	SDL_Surface* my_srfScreen;
	SDL_Surface* my_srfDrag;

	PG_Rect my_rectClip;
	PG_Point my_ptDragStart;
	SDL_Color my_colorBorder[2][2];
	
	static PG_SurfaceCache my_SurfaceCache;
	
	friend class PG_Application;

private:
	PG_DrawObject(const PG_DrawObject&);
	PG_DrawObject& operator=(const PG_DrawObject&);

	bool my_firstredraw;
	bool my_havesurface;
};

#endif // PG_DRAWOBJECT_H
