#ifndef INCL_GADGET_H
#define INCL_GADGET_H

/*-----------------------------------------------------------------------
 * Xclasses header file
 * 
 * Copyright (C) 1998 Jürgen Schmitz
 *
 * 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *-----------------------------------------------------------------------
 */

#include <Xclasses/types.h>
#include <Xclasses/Xcolors.h>
#include <Xclasses/callable.h>

// ===============================================================
// Flags and values
// required for programming Xclasses programs
// ---------------------------------------------------------------

// Fonts - used for .Font(int)
#define FONT_GADGET		1
#define FONT_GROUP		2
#define FONT_FIXED		3
#define FONT_SMALL		4
#define FONT_BIG		5
#define FONT_MENU		6


class gadget : public Xcolors
{
	friend class Ddraw;
	friend class pgadget;
	friend class group;
	friend class pgroup;

	class pgadget *p;    

protected:

// ===============================================================
// fields mostly for programmers of Xclasses gadgets
// ---------------------------------------------------------------

				// limits, set by GSetLimits() call, 
				// don't change later, if not called you may ignore it!
	int	setlimit;	// dummy for your help, set to !=0 if GSetLimits() was called
	int	minwidth;	// nolimit: 0
	int	minheight;	// nolimit: 0
	int	maxwidth;	// nolimit: 0xffffff
	int	maxheight;	// nolimit: 0xffffff
	int	before_x;	// if you have text left of gadget body set pixel length here, later read this before drawing, it may have changed to make all gadget look the same
	int minxaspect;	// noaspect x: 0
	int minyaspect;	// noaspect y: 0
	int maxxaspect;
	int maxyaspect;

    // following fields are READONLY!
    unsigned long	white;
    unsigned long	black;
    int				weight;
    int     		x;
    int     		y;
    int     		width;
    int     		height;
    Window  		win;
    Window  		parent;
    GC      		gc;
    int				locked;
    gadget			*wasfor; // NULL: for me
    unsigned int    state;  // ==0 - released, !=0 - pressed
    unsigned int	active; // ==0 - not active, see GA_... flags

public:				

// ===============================================================
// fields & functions for Xclasses gadget programmers
// ---------------------------------------------------------------
	unsigned int	specialflags;

					// special class identifyer - returns a 
					// private id string, required by group
	virtual char *Class(void);

					// functions that should be overloaded by 
					// every child gadget
    virtual void GExpose(XEvent *event); // event may be NULL if call not caused by an event: (un)lock, )
    virtual void GActionPress(int mx,int my,int rx,int ry,unsigned int state,int button,int reason);
    virtual void GActionRelease(int mx,int my,int rx,int ry,unsigned int state,int button,int reason);
    virtual int  GMouseMove(int mx,int my,int rx,int ry,unsigned int state,int button);

    virtual int  GActivate(XEvent *event,int why);
    virtual int  GSelected(XEvent *event,int why,int wasabove);

	virtual void GSetLimits(void);

	virtual int  GClipHandler(int why,char *data,int size);
	virtual int  GKeyHandler(XEvent *,KeySym,char *);

					// functions for gadgets
    void SendEventTo(class gadget *to);
	int DefaultKeyHandler(XEvent *event);
	void ClipTo(char *data,int size);
	void ClipRequest(void);

					// methods to call BEFORE gadget::CreateGadget(),
					// best in overloaded CreateGadget()
    void Background(unsigned long gbackcolor); 
    unsigned long Background(void);
	void CopyFont(gadget *);
	void CopyFont(gadget &g) { CopyFont(&g); };
	void SetKeyHandler(int);
	int  GetKeyHandler(void);

					// methods to call AFTER or BEFORE 
					// gadget::CreateGadget()
    void MCursor(int);
	void Mode(int);				// obsolete!
    void Mode(unsigned int);
	void SetEvents(unsigned int);

					// methods to call AFTER
					// gadget::CreateGadget()
	int GrabPointer(Bool owner_events,unsigned int event_mask,int pointer_mode=GrabModeAsync,int keyboard_mode=GrabModeAsync,Window confine_to=None,Cursor cursor=None);
	void UngrabPointer(void);

	KeySym LookupKeysym(XEvent *event);
	int LookupString(XEvent *event,char *buffer_return,int buffer_size,KeySym &keysym,int &status);

					// methods to return protected & private members
					// most likely for gadget programmers
	int 		gg_minwidth(void);
	int 		gg_maxwidth(void);	
	int 		gg_minheight(void);
	int 		gg_maxheight(void);	
	Window 		gg_win(void);
	GC			gg_gc(void);	
	int			gg_width(void);
	int			gg_height(void);
	int			gg_weight(void);
	XFontStruct	*gg_font(void);
	void		gg_font(XFontStruct*);
	int			gg_before_x(void);
	int 		gg_minxaspect(void);
	int 		gg_minyaspect(void);
	int 		gg_maxxaspect(void);
	int 		gg_maxyaspect(void);
 	int			gg_active(void);
	int			gg_locked(void);
	unsigned int			gg_mode(void);

	void 		CallCallback(void);

public:

// ===============================================================
// really public things
// ---------------------------------------------------------------
	void		*userdata;

    gadget();
    gadget(gadget &g);	// DON'T use copy contructor!
    virtual ~gadget();

// ===============================================================
// following have to be called BEFORE calling Creare()
// ---------------------------------------------------------------

						// layout functions, don't call after Create() !
    virtual void Dimensions(Window gparent,int gx,int gy,int gheight,int gwidth);
				    	// Dimensions must not be used if you use
				    	// this object in groups

    void Weight(int);	// set weigth of object in group

						// mostly already set by gadget itself
						// but you may change it BEFORE Create() call
	int Font(char *name); // 0 for error
	int Font(int deffont);
						  // if error is returned old font is used

						// Callback and/or ID settings
						// better don't use ID and callbacks with
						// the same object - it works but will be
						// removed later if all code is clean
	void ID(int gid);
	void Callback(void gfunc(class gadget*,int));
	void Callback(callable *c,void (callable::*)(gadget *,int));	// use this for callable objects!
	void Callback(void *c,void gfunc(class gadget*,int));
	void Callback(void *c,...);		// for Callback(c,gfunc)

	void ID(void gfunc(class gadget*,int));					// obsolete!
	void ID(void *c,void gfunc(class gadget*,int));			// obsolete!
	void ID(void gfunc(class gadget*,int),int gid);			// obsolete!
	void ID(void *c,void gfunc(class gadget*,int),int gid);	// obsolete!
	int ID(void);

						// set some features
	void HelpText(char *);
	void ContextPopup(class popup *);
	void ContextPopup(class popup &po) { ContextPopup(&po); };
	void ApplyKey(char key,int qualifier=0);
	void ApplyXKey(int xkey,int qualifier=0);

						// message system, this is called by
						// class message
	void MessageHandler(class message *m);
// ===============================================================
// main create and destroy functions, should be overloaded 
// but then must be called by the child function! (ignore this
// commend if you only write programs with Xclasses)
// ---------------------------------------------------------------
    virtual int Create(void); // 0 for error
    virtual void Free(void);  

// ===============================================================
// some useful functions to manipulate the gadget
// ---------------------------------------------------------------
    void ActivateKey(void);   // activate gadget for to receive keys
    void DeactivateKey(void); // deactivate (e.g. the active gadget could do this)


// overload if required, but must then call these functions
    virtual void Resize(int newwidth,int newheight);
    virtual void Move(int newx,int newy);
    virtual void ResizeD(int dwidth,int dheight) { Resize(width+dwidth,height+dheight); };
    virtual void MoveD(int dx,int dy) { Move(x+dx,y+dy); };
    virtual void Lock(void);
    virtual void Unlock(void);
    virtual void Block(int);
    virtual void Unblock(int);

// class independent functions, currently private!
	void IgnoreExcept(Window);
	void IgnoreNothing(void);

// ===============================================================
// main event handler, class independent, never overload
// ---------------------------------------------------------------
    static int HandleEvent(XEvent *event);	// 0 - unused, -1 - used, >0 - ID

// ===============================================================
// easier frontend for main event handler - but with appwindow
// it's much more easier!
// ---------------------------------------------------------------
    static int NextEvent(XEvent *event); 	// warten, unbenutzte Events in event wenn !=NULL
								  			// 0 - Event, >0 - ID
    static int UpdateEvent(XEvent *event);	// wenn Events bearbeiten, unbenutzte in event wenn !=NULL
											// 0 - Event, -1 - No Event, >0 - ID
    static int TickEvent(XEvent *event);	// warten, unbenutze Events in event wenn !=NULL, Timeout nach 1/10 Sek
											// 0 - Event, -1 - Tick, >0 - ID

	static int DoubleClick(void);
	static gadget *LastSelected(void);

// ===============================================================
// select() fd callbacks - class independent
// ---------------------------------------------------------------
	static void AddReadFD(int fd,void *c,...);
	static void AddReadFD(int fd,callable *c,void (callable::*)(int));
	static void AddWriteFD(int fd,void *c,...);
	static void AddWriteFD(int fd,callable *c,void (callable::*)(int));
	static void AddExceptFD(int fd,void *c,...);
	static void AddExceptFD(int fd,callable *c,void (callable::*)(int));
	static void RemoveFD(int fd);

// ===============================================================
// tick callbacks - class independent
// ---------------------------------------------------------------
	static void AddTicker(int mode,int delay,void (*f)(void));
	static void AddTicker(int mode,int delay,callable *c,void (callable::*)(void));
	static void RemoveTicker(void (*f)(void));
	static void RemoveTicker(callable *c,void (callable::*)(void));
};


// ===============================================================
// Flags and values for programming Xclasses gadgets:
// ---------------------------------------------------------------

// ===============================================================
// some modes, may be binarary added (OR) - used for .Mode(int)
// ---------------------------------------------------------------
#define GM_BUTTON1    	0x00000001		// send button 1 (default)
#define GM_BUTTON2    	0x00000002		// send button 2
#define GM_BUTTON3    	0x00000004		// send button 3
#define GM_BUTTON4    	0x00000008		// send button 4
#define GM_BUTTON5    	0x00000010		// send button 5
#define GM_MOUSEMOVE  	0x00000020		// send mouse move while button pressed
#define GM_ABOVE      	0x00000040		// send if mouse already above gadget
#define GM_KEY        	0x00000080		// send keyboard event (event will call GActivate(), if TRUE returned GSelected() )
#define GM_ALLMOVES		0x00000100		// send mouse move also if not active (but events must be set by gadget, e.g. with PointerGrap!)
#define GM_MINIMALMOVE	0x00000200		// only last mousemove
#define GM_LOCKATONCE	0x80000000		// allow gadget locking if mouse above gadget in GM_ABOVE mode, no GSelected() is called!!
#define GM_ONEEXPOSE	0x40000000		// only send expose if count==0
#define GM_ACTIVETICK	0x20000000		// send ticks every 1/10 sec if gadget is active
#define GM_NORMALTICK	0x10000000		// send ticks if gadget isn't active
#define GM_KEYTICK		0x08000000		// send ticks if gadget is key active
#define GM_OWNERGRAB	0x04000000		// set OwnerGrabButtonMask flag
#define GM_ALLEVENTS	0x02000000		// allow sending of all window events
#define GM_CUTPASTE		0x01000000		// cut & paste for this gadget

// ===============================================================
// active modes, binarary added
// ---------------------------------------------------------------
#define GA_NOTACTIVE  	0x00000000		// not active
#define GA_BUTTONPRESS	0x00000001		// activated by mouse button
#define GA_ABOVE      	0x00000002		// mouse was above gadget (with GM_ABOVE)
#define GA_KEY        	0x00000004		// activated by key press (with GM_KEY)
#define GA_TICK			0x00000008		// tick (with GM_ACTIVETICK or GM_NORMALTICK)
#define GA_EVENT		0x00000010		// other event
#define GA_DCLICK		0x00000020		// double click

// ===============================================================
// GClipHandler() reasons:
// ---------------------------------------------------------------
#define CH_DESELECT		0x00000001		// gadget cut&paste deselected
#define CH_REQUEST		0x00000002		// cut&paste result

// ===============================================================
// GActionPress()/GActionRelease() reasons (may be logically added):
// ---------------------------------------------------------------
#define GB_BUTTON		0x00000001		// mouse button
#define GB_ABOVE		0x00000002		// enter/leave gadget
#define GB_KEY			0x00000004		// key (de)active

// ===============================================================
// GActivate() return values
// ---------------------------------------------------------------
#define GAR_MESSAGE		0x00000001		// state changed, send messages
#define GAR_ACTIVE		0x00000002		// gadget is active

// ===============================================================
// GSelected()/GMouseMove() return values
// ---------------------------------------------------------------
#define GSR_MESSAGE		0x00000001		// state changed, send message
#define GSR_SELECTION	0x00000002		// selected, inform program

// ===============================================================
// GClipHandler() return values
// ---------------------------------------------------------------
#define GCH_MESSAGE		0x00000001		// state changed, send message

// ===============================================================
// DefaultKeyHandler() return codes
// ---------------------------------------------------------------
#define DKH_NOKEYEVENT	-2
#define DKH_INTERNAL	-1
#define DKH_NOTHING		0
#define DKH_SELECT		1
#define DKH_DEACTIVATED	2

// ===============================================================
// Specialflags
// ---------------------------------------------------------------
#define SPF_NOKEYBORDER	0x00000001		// this tells Ddraw to ignore any request of the class for keyborder

// ===============================================================
// KeyHandler modes
// ---------------------------------------------------------------
#define KHM_NONE			0
#define KHM_ACTIVATE		1				// default
#define KHM_SELECT			2
#define KHM_SENDTO			3
#define KHM_HANDLER			4				// call GKeyHandler
#define KHM_HANDLERSELECT	5				// call GKeyHandler & call gadget callback/ID

// ===============================================================
// Ticker modes
// ---------------------------------------------------------------

#define TM_ONCE 			0				// call ticker once, remove from list
#define TM_REGULARLY		1				// call every delay ticks

// ===============================================================
// casts
// ---------------------------------------------------------------

#define CALLBACK void (callable::*)(gadget *,int)
#define FDHANDLER void (callable::*)(int)

#endif
