//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³                                                      ³
//³              Header file for windows.cc              ³
//³                                                      ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

class Window;
class Gadget;


//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Key code definitions

#define KB_PAGEUP 0x249
#define KB_PAGEDOWN 0x251
#define KB_HOME 0x247
#define KB_END 0x24f
#define KB_INS 0x252
#define KB_DEL 0x253
#define KB_LEFT 0x24b
#define KB_RIGHT 0x24d
#define KB_UP 0x248
#define KB_DOWN 0x250
#define KB_ESC 27
#define KB_RET 13
#define KB_SHIFTTAB 0x10f

// ALT key definitions

#define KB_ALTQ 0x110
#define KB_ALTW 0x111
#define KB_ALTE 0x112
#define KB_ALTR 0x113
#define KB_ALTT 0x114
#define KB_ALTY 0x115
#define KB_ALTU 0x116
#define KB_ALTI 0x117
#define KB_ALTO 0x118
#define KB_ALTP 0x119

#define KB_ALTA 0x11E
#define KB_ALTS 0x11F
#define KB_ALTD 0x120
#define KB_ALTF 0x121
#define KB_ALTG 0x122
#define KB_ALTH 0x123
#define KB_ALTJ 0x124
#define KB_ALTK 0x125
#define KB_ALTL 0x126

#define KB_ALTZ 0x12C
#define KB_ALTX 0x12D
#define KB_ALTC 0x12E
#define KB_ALTV 0x12F
#define KB_ALTB 0x130
#define KB_ALTN 0x131
#define KB_ALTM 0x132

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// flags passed when creating a window

#define W_BACKINGSTORE 1
#define W_SIMPLEBORDER 2
#define W_MOTIFBORDER 4
#define W_INCLUDETITLE 8	// include title in window's size (drawable area decreases)
#define W_INCLUDEBORDER 16 // include border in window's size (drawable area decreases)

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
#define SIMPLEBORDERSIZE 3
#define MOTIFBORDERSIZE 7
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

struct WT_CONTROL { int align; };
struct WT_COLOUR { int colour; };
struct WT_DOOMNAME { char *name; };

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
extern void ProgError(char *,...);

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Flags passed to new gadget:

#define G_TEXTHIGHLIGHT (1<<0) // Highlight the text as the cursor goes over it
#define G_BOXHIGHLIGHT  (1<<1) // Highlight the box
#define G_BOXTEXT       (1<<2) // Draw text in a box
#define G_TOGGLE        (1<<3) // Toggle-able Gadget
#define G_EXCLUSIVE     (1<<4) // if selected, all other gadgets are deselected
#define G_OVERONLY      (1<<5) // Only if the cursor is directly over it is highlighted
#define G_BACKINGSTORE  (1<<6) // Store what was underneath the gadget
#define G_HIGHLIGHTED   (1<<7) // currently highlighted?
#define G_TOGGLESTATE   (1<<8) // state of current toggle
#define G_SLIDER        (1<<9) // Slider bar
#define G_LIST          (1<<10)// List of items (specified as name - double null is end of list)
									     // Note that a second gadget (the slider) will
									     // be created automatically with an id 1 plus
									     // the id specified for this gadget
#define G_LISTSLIDER    (1<<11)// Private
#define G_STRING	       (1<<12)// String gadget (allows entry of data from keyboard)
#define G_NUMBER	       (1<<13)// In combination with G_STRING only allows numeric input
#define G_DISABLED      (1<<14)// Cannot select

#define G_HIGHLIGHTABLE (G_TEXTHIGHLIGHT|G_BOXHIGHLIGHT)
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
#define GADGETSIZEX(win,s) (win->textwidth(s)+win->textwidth("WW")+8)
#define GADGETSIZEY(win) (win->textheight()+10+2)
#define GADGETSPACING 4
#define AUTOSPACING -1
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
#define GF_HIGHLIGHT 1
#define GF_SELECTED 2
#define GF_TOGGLE 4
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
#define IF_SLIDING 1
#define IF_STRING 2
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

#define SLIDER_HEIGHT 8

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Search flags

#define GS_CURRENTITEM -2
#define GS_FROMTOP -1

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// File requester flags

#define FR_SETPATH 1	// Store the new path in the source path specified
#define FR_ALLOWDIRECTORY 2 // If a filename isn't selected it returns the directory


//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// line style flags

#define SOLID_LINE 0
#define DOTTED_LINE 1

//------------------------
// input event class

struct Input
	{
	int flags;
	int x,y;
	int buttons;
	int key;
	int kbstat;
	unsigned int time;
	int gflags;
	int gadget;
	int slider;
	int inputflags;
	char *searchstring;
	unsigned int lasttime;
	int id;
	};

//------------------------
// the Window class itself

class Window
	{
	GrContext *scr;	// Sub Context maps that onto screen
	GrContext *grc;	// Buffered Context
	GrContext store; // Used internally for storing current context
	GrContext *backstore; // What was underneath the window (if requested)

	GrTextOption Font;

	char *textline;	// current buffered line

	int DrawColor;
	int LineStyle;
	int WriteMode;
	int DrawBGColor;
	int textx,texty,tx,ty,tabx;
	int textxalign;
	int textyalign;

	int minx,miny,maxx,maxy;

	int omx,omy,ob;	// old mouse positions
	int gx,gy,gx1,gy1;			// last created gadget position and size

// flags for window:

	unsigned MAPSDIRECT:1;

// Private functions to save and restore the current context

	void Set();
	void Set(GrContext &d);
	void Unset() { GrSetContext(&store); }

// Public access code

public:

	GrContext *Drawable;		// Current Drawable
	Gadget *gadgetlist;		// List of gadgets
	Gadget *currentgadget;	// Pointer to currently highlighted gadget

// Window constructor/destructor:

	Window(int x,int y,int x1,int y1,int bg, char *title,int flags);
	~Window(void);

// Window primitives:

	void Direct();		// Switch to direct screen mode
	void Indirect();	// Switch to buffered screen mode
	void flush()		// Flush the buffered screen to the direct screen
		{
		if (!MAPSDIRECT)
			{
			GrBitBlt(scr,0,0,grc,0,0,scr->gc_xmax,scr->gc_ymax,GrWRITE);
			}
		}
	void flush(int x,int y,int x1,int y1)		// Flush the specified area to the screen
		{
		if (!MAPSDIRECT)
			{
			GrBitBlt(scr,x+minx,y+miny,grc,x+minx,y+miny,x1+minx,y1+miny,GrWRITE);
			}
		}

// Graphics primitives:

	void plot(int x,int y)
		{ Set(); GrPlot(x,y,DrawColor|WriteMode); Unset();}
	void unplot(int x,int y)
		{ Set(); GrPlot(x,y,DrawBGColor|WriteMode); Unset();}
	int pixel(int x,int y)
		{ Set(); x = GrPixel(x,y); Unset(); return x;}
	void thickline(int x,int y,int x1,int y1);
	void line(int x,int y, int x1,int y1);
	void box(int x,int y,int x1,int y1)
		{ Set(); GrBox(x,y,x1,y1,DrawColor|WriteMode); Unset();}
	void filledbox(int x,int y,int x1,int y1)
		{ Set(); GrFilledBox(x,y,x1,y1,DrawColor|WriteMode); Unset();}
	void framedbox(int x,int y,int x1,int y1,int w,GrFBoxColors *c)
		{ Set(); GrFramedBox(x,y,x1,y1,w,c); Unset();}
	void cls();
	void filledpolygon(int n,int shape[][2])
		{ Set(); GrFilledPolygon(n,shape,DrawColor|WriteMode); Unset(); }
	void polygon(int n,int shape[][2])
		{ Set(); GrPolygon(n,shape,DrawColor|WriteMode); Unset(); }
	GrContext *getimage(int x, int y, int x1, int y1)
		{ GrContext *d; d = GrCreateContext(x1-x+1,y1-y+1,NULL,NULL); GrBitBlt(d,0,0,Drawable,x,y,x1,y1,GrWRITE); return d; }
	void putimage(int x,int y,GrContext *d)
		{ GrBitBlt(Drawable,x,y,d,0,0,d->gc_xmax,d->gc_ymax,GrWRITE); }
	void freeimage(GrContext *d)
		{ GrDestroyContext(d); }
	void gtag(char *gname,int x,int y, int sx, int sy, int mode, int type);

// Graphics primitives control:

	void linestyle(int l) { LineStyle = l; }
	void writemode(int w) { WriteMode = w; }
	void FGcolor(int c) { DrawColor = c; }
	void BGcolor(int bg) { DrawBGColor = bg; }
	void setclip(int x,int y,int x1,int y1);
	void getclip(int *x,int *y,int *x1,int *y1);

// Window output control:

	int printf(char *s,...);
	int vprintf(char *s,...);

	Window& operator<<(char *str);
	Window& operator<<(unsigned char *str) { return (*this) << (char *)str;}
	Window& operator<<(const char *str) { return (*this) << (char *)str;}
	Window& operator<<(const unsigned char *str) { return (*this) << (char *)str;}
	Window& operator<<(const signed char *str) { return (*this) << (char *)str;}
	Window& operator<<(int num);
	Window& operator<<(unsigned int num);
	Window& operator<<(unsigned short num) { return (*this) << (unsigned long)num; }
	Window& operator<<(short num) { return (*this) << (long)num; }
	Window& operator<<(char c);
	Window& operator<<(WT_CONTROL a) {textxalign = (int)a.align; return *this; };
	Window& operator<<(WT_COLOUR a);
	Window& operator<<(WT_DOOMNAME *a) {char temp[9]; strncpy(temp,(char *)a,8) ; temp[9] = '\0'; return (*this) << temp; };

// Text control:

	int textwidth(char *s) { return GrStringWidth(s,strlen(s),&Font);}
	int textwidth(char *s,int n) { return GrStringWidth(s,n,&Font);}
	int textheight() { return GrCharHeight('W',&Font);}
	void textxy(int x,int y) { tabx = 0; tx = 0; textline[0] = '\0'; textx = x; texty = y; }
	int gettexty() { return texty; };
	int gettextx() { return textx; };
	void textalign(int a,int b) {textxalign = a; textyalign = b; }
	void outtext(char *s);
	void setfont(GrTextOption *f) {Font = *f;}
	GrTextOption *getfont() {return &Font;}
	void resettext() {textxy(0,0);};

// Dimension functions:

	int MaxX() { return Drawable->gc_xmax; }
	int MaxY() { return Drawable->gc_ymax; }
	int SizeX() { return Drawable->gc_xmax+1; }
	int SizeY() { return Drawable->gc_ymax+1; }

// Mouse control:

	struct Input input;

	int mouse();	// returns non-zero if there are events to be processed

// Gadget friends and control:

	void Select(int n);	// Select a gadget (or toggle it)
	void Select(int n,int i);	// Select a gadget (or toggle it) (for list gadgets)
	void Highlight(int n);		// Highlight a gadget
	void Delete(int n);	// Delete a gadget
	void DeleteAll();		// Delete all gadgets
	Gadget *Find(int n);		// Find a gadget with id n
	char *GetItem(int n,int i); // returns item i from list in gadget n
	void SetList(int n,char *s); // Set a new list to display in gadget n
	char *GetSelectedItem(int n); // returns selected item from list
	int GetSelectedItemNum(int n);	// returns selected item number from list
	void SetSelectedItem(int n,int i); // returns selected item from list
	void SetString(int n,char *s); // Set the specified G_STRING gadget's string
	char *GetString(int n);	// Get the string from the gadget n
	void SetTopItem(int n,int i);	// Set the top item in a list gadget
	int SearchList(int n,int i,char *s); // Search the list from item i

	friend Gadget;
	};


//------------------------
// Gadget class structure

class Gadget
	{
	Gadget *next;
	Gadget *prev;
	Window *window;
	GrContext *backstore;
	char *text;
	int flags;
	int id;
	int gx,gy,gx1,gy1;
	int hotkey;
	int sliderpos;
	int topitem;
	int selecteditem;
	int cursorpos;

	int FGcolor;
	int BGcolor;

	int bsize;

	GrTextOption Font;

	void DoText(int c);		// internal routine to draw the text in the gadget
	void DoBox(int onoff);	// internal routine to draw box around gadget
	void Flush()				// Flush the graphic area of this gadget
		{ window->flush(gx,gy,gx1,gy1); }
	void DrawSlider();	// Draw the slider
	void DoList();			// Draw the list of items
	void Set();				// Preserve all the window variables
	void Unset();			// Restore all the window variables

// Publically available routines and variables:
public:
	Gadget(Window *,int x,int y,int x1,int y1,char *name,int id,int flags,int c);
	~Gadget(void);
	int Onit(int x,int y);		// Cursor at x,y on the gadget?
	void Highlight();
	void Unhighlight();
	void Draw();					// Draw the gadget in full
	void Toggle();					// Toggle the gadget
	void Select();					// Select or toggle this gadget
	void Select(int);				// Select or toggle this gadget (for LIST gadgets)
	void SetTopItem(int i)		// set the top item in a list type gadget
		{ topitem = i; }
	int GetNumItems();			// get the total number of items in a list type gadget
	int GetSlider(int range)	// Calculate the slider's position from 0-range
		{return (sliderpos*range)/(gy1-gy-10-SLIDER_HEIGHT+1);}
	void SetList(char *s);		// Set a new list to display
	void SetSlider(int p,int range);		// Set slider to new position
	int GetSelectedItem()		// Get number of selected item in list
		{ return selecteditem; }
	char *GetItem(int i);		// return name of specified item in list
	char *GetSelectedItemName()	// Get name of selected item in list
		{ return GetItem(selecteditem); }
	void SetSelectedItem(int n);		// Set number of selected item
	int GetMaxWidth();			// Get the max width in pixels of the list (G_LIST)

	void Up();					// Next item up
	void Down();				// Next item down
	void PageUp();				// Next page up
	void PageDown();			// Next page down
	int Search(char *s,int i);		// Searches the list from i for best match string to s
	int OnPage(int i);		// Is gadget visable on current page?
	int Centre(int i);		// Centre page around gadget i
	int ItemsPerPage();		// Number of items per page

// Text gadget functions:

	void Ins(char c);
	void Del();
	void Left();
	void Right();
	void Home();		// these also double as list functions
	void End();
	void SetString(char *s);
	char *GetString();

// Friends:

	friend Window;
	};


// Structure for file requester

struct FRPath { char path[MAXPATH]; };


//------------------------------------------------------
// Macros for generating lists for slider gadgets

void inline sl_init(char **s)
	{
	*s = (char *)malloc(sizeof(int)+1);
	*((int *)(*s)) = sizeof(int)+1;
	(*s)[sizeof(int)] = '\0';
	}

void inline sl_add(char **s,char *n)
	{
	*s = (char *)realloc(*s,(*((int *)(*s)))+strlen(n)+1);
	strcpy(*s+(*((int *)(*s)))-1,n);
	*((int *)(*s)) += strlen(n)+1;
	(*s)[(*((int *)(*s)))-1] = '\0';
	}

void inline sl_end(char **s)
	{
	*s += sizeof(int);
	}

void inline sl_free(char **s)
	{
	free(*s-sizeof(int));
	*s = NULL;
	}

