/*- GADGETS.CC -------------------------------------------------------------*
 Doom Editor (Registered Version Only) Ver 0.1

 Code for generating gadgets (C++)

 Any inquiries to Colin Reed or Dylan Cuthbert via
 DYL@CIX.COMPULINK.CO.UK
*---------------------------------------------------------------------------*/
#define _GADGETS_

#include "sfc.h"

//----------------------------------------------
// prototypes
//----------------------------------------------


/*---------------------------------------------------------------------------*/

//------------------------------------------------------------
// Functions for the Gadget class:

Gadget::Gadget(Window *win,int x,int y,int x1,int y1,char *name,int i,int f,int c)
	{
	Gadget *sli;

	memset(this,sizeof(struct Gadget),0);

// Link it into the window
	next = win->gadgetlist;
	if (win->gadgetlist) win->gadgetlist->prev = this;
	prev = NULL;
	win->gadgetlist = this;

	window = win;
	flags = f;
	id = i;
	FGcolor = window->DrawColor;

	if (f&G_BOXTEXT) BGcolor = WHITE;
	else BGcolor = window->DrawBGColor;

	hotkey = c;
	sliderpos = 0;
	topitem = 0;
	selecteditem = -1;

	Font = *win->getfont();

	if (flags&(G_BOXTEXT|G_LIST|G_SLIDER)) bsize = 5;
	else bsize = 1;

	if (flags&G_STRING) cursorpos = strlen(name);

	if (x == AUTOSPACING)
		{
		x = win->gx1+GADGETSPACING;
		y += win->gy;
		if (x1) x1 += win->gx1+GADGETSPACING;
		}
	if (y == AUTOSPACING)
		{
		y = win->gy1+GADGETSPACING;
		x += win->gx;
		if (y1) y1 += win->gy1+GADGETSPACING;
		}

	if (name)
		{
		if (!(flags&G_LIST))
			{
			text = strdup(name);
			if (x1==0) x1 = x+win->textwidth(name)+win->textwidth("WW")+bsize*2-1;
			}
		else
			{
			text = name;
			if (x1==0) x1 = x+GetMaxWidth()+win->textwidth("WW")+bsize*2-1;
			}
		if (y1==0) y1 = y+win->textheight()-1+bsize*2;
		}
	else text = NULL;

// Store whatever was there before

	if (flags&G_BACKINGSTORE)
		{
		backstore = GrCreateContext(x1-x+1,y1-y+1,NULL,NULL);
		GrBitBlt(backstore,0,0,win->Drawable,x,y,x1,y1,GrWRITE);
		}

	gx = x; gy = y; gx1 = x1; gy1 = y1;

	Draw();

	if (flags&G_LIST)
		sli = new Gadget(win, gx1+2, gy, gx1+2+12 ,gy1 ,NULL ,id+1 ,G_SLIDER|G_OVERONLY|G_LISTSLIDER ,0);

	window->gx = gx;
	window->gy = gy;
	if (flags&G_LIST) window->gx1 = sli->gx1;
	else window->gx1 = gx1;
	window->gy1 = gy1;

	}

//------------------------------------------------------------
Gadget::~Gadget(void)
	{
// unlink the gadget from the list
	if (prev == NULL) window->gadgetlist = next;
	else prev->next = next;
	if (next != NULL) next->prev = prev;

// Restore whatever was there before
	if (flags&G_BACKINGSTORE)
		{
		GrBitBlt(window->Drawable,gx,gy,backstore,0,0,backstore->gc_xmax,backstore->gc_ymax,GrWRITE);
		GrDestroyContext(backstore);
		}

	if (text&&!(flags&G_LIST)) free(text);
	}

//------------------------------------------------------------
int Gadget::Onit(int x,int y)
	{
	return (x>=gx && x<=gx1 && y>=gy && y<=gy1);
	}
//------------------------------------------------------------
void Gadget::Toggle()
	{
	GrFBoxColors bdrcols = {LIGHTGRAY,BLACK,LIGHTGRAY,LIGHTGRAY,DARKGRAY};
	flags ^= G_TOGGLESTATE;

	if (flags&G_TOGGLESTATE)
		{
		if (flags&G_BOXHIGHLIGHT) DoBox(0);
		DoText(RED);
		}
	else
		{
		if (flags&G_BOXHIGHLIGHT) DoBox(1);
		DoText(FGcolor);
		}
	Flush();
	}
//------------------------------------------------------------
void Gadget::Highlight()
	{

	if (!(flags&G_HIGHLIGHTED))
		{

		Set();

		flags |= G_HIGHLIGHTED;

		if (flags&G_BOXHIGHLIGHT)
			{
			window->FGcolor(BLUE);

			window->box(gx,gy,gx1,gy1);
			}

		Unset();

		if ((flags&G_TEXTHIGHLIGHT) && (!(flags&G_TOGGLESTATE)))
			DoText(BLUE);

		Flush();

		}

	}
//------------------------------------------------------------
void Gadget::Unhighlight()
	{

	if (flags&G_HIGHLIGHTED)
		{
		Set();
		flags &= ~G_HIGHLIGHTED;

		if (flags&G_BOXHIGHLIGHT)
			{
			window->FGcolor(BLACK);
			window->box(gx,gy,gx1,gy1);
			}

		Unset();

		if ((flags&G_TEXTHIGHLIGHT) && (!(flags&G_TOGGLESTATE)))
			DoText(FGcolor);

		Flush();
		}
	}

//------------------------------------------------------------
void Gadget::Draw()
	{
	GrFBoxColors bdrcols = {DARKGRAY,WHITE,DARKGRAY,DARKGRAY,LIGHTGRAY};

// Draw text gadget

	if (text && !(flags&G_LIST))
		{

		if (flags&G_BOXTEXT)
			DoBox(1);

		DoText(FGcolor);

		}

	if (flags&G_SLIDER)
		{
		DoBox(1);
		DrawSlider();
		}

	if (flags&G_LIST)
		{
		DoBox(1);
		DoList();
		}

	if (flags&G_TOGGLESTATE)
		{
		flags &= ~G_TOGGLESTATE;
		Toggle();
		}

	if (flags&G_HIGHLIGHTED)
		{
		flags &= ~G_HIGHLIGHTED;
		Highlight();
		}

	}

//------------------------------------------------------------
void Gadget::DrawSlider()
	{
	Gadget *g;
	int n;

	Set();
	
	window->FGcolor(WHITE);
	if (sliderpos) window->filledbox(gx+bsize,gy+bsize,gx1-bsize,sliderpos+gy+bsize-1);
	window->FGcolor((flags&G_HIGHLIGHTED)?BLUE:BLACK);
	window->filledbox(gx+bsize,sliderpos+gy+bsize,gx1-bsize,sliderpos+gy+bsize+SLIDER_HEIGHT-1);

	window->FGcolor(WHITE);
	if (sliderpos+gy+bsize+SLIDER_HEIGHT<gy1-bsize) window->filledbox(gx+bsize,sliderpos+gy+bsize+SLIDER_HEIGHT,gx1-bsize,gy1-bsize);

	if (flags&G_LISTSLIDER)
		{
		if (g = window->Find(id-1))
			{
			n = g->topitem;
			g->SetTopItem(GetSlider(g->GetNumItems()-1));
			if (n != g->topitem)
				{
				Unset();
				g->Draw();
				Set();
				}
			}
		}

	Unset();
	Flush();
	}

//------------------------------------------------------------
void Gadget::Select()
	{
	Select(-1);
	}
//------------------------------------------------------------
void Gadget::Select(int selected)
	{
	Gadget *g;
	int n;

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Check for mouse clicked on string gadget
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	if (flags&G_STRING)
		{
		window->input.inputflags |= IF_STRING;
		flags |= G_HIGHLIGHTED;
		return;
		}

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Selecting a G_LIST type gadget?
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	if (flags&G_LIST)
		{
		if ((window->omx >= gx+5 && window->omx <= gx1-5 && window->omy >= gy+5 && window->omy <= gy1-5) || selected==id)
			{
			if (selected==id) n = selecteditem;
			else n = topitem + ((window->omy-gy-5)/GrCharHeight('W',nicefont));
			if (window->input.time-window->input.lasttime < 10 && selecteditem != -1)
				{
				window->input.slider = selecteditem;
				window->input.gflags |= GF_SELECTED;
				}
			else
				{
				if (flags&G_TOGGLE)
					{
					if (selecteditem == n)
						selecteditem = -1;
					else selecteditem = n;
					}
				else
					{
					if (n>=GetNumItems()) return;
					selecteditem = n;
					}
				DoList();
				window->input.lasttime = window->input.time;
				window->input.slider = selecteditem;
				}
			}
		return;
		}

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Slider gadget?
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

	if (flags&G_SLIDER)
		{
		window->input.inputflags |= IF_SLIDING;
		flags |= G_HIGHLIGHTED;
		return;
		}

//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Toggle the gadget?
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

	if (flags&G_TOGGLE)
		{
		Toggle();
		if (flags&G_TOGGLESTATE) window->input.gflags |= GF_TOGGLE;
		}
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Exclusive select? (ie. switch off all the gadgets first?)
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	if (flags&G_EXCLUSIVE)
		{
		if (!(flags&G_TOGGLESTATE))
			{
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// De-activate any existing gadgets
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
			for (g = window->gadgetlist; g; g = g->next)
				if (g->flags&G_TOGGLESTATE) g->Toggle();
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// Switch on the current one
//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
			if (!(flags&G_TOGGLESTATE)) Toggle();
			}
		}
	window->input.gflags |= GF_SELECTED;
	window->input.gadget = id;
	}
//------------------------------------------------------------
void Gadget::DoText(int c)
	{
	int cp;

	if (text&&!(flags&G_LIST))
		{
		Set();
		window->setfont(&Font);
		window->setclip(gx+bsize,gy+bsize,gx1-bsize,gy1-bsize);

		if (flags&G_STRING)
			{
			window->FGcolor(BGcolor);
			window->filledbox(gx+bsize,gy+bsize,gx1-bsize,gy1-bsize);

			cp = window->textwidth(text,cursorpos);

			window->textalign(GR_ALIGN_LEFT,GR_ALIGN_TOP);

			if (cp > gx1-gx-bsize*2-1)
				{
				window->textxy(gx1-cp-bsize-1,gy+((gy1-gy+1)-window->textheight())/2);
				cp = gx1-gx-bsize*2-1;
				}
			else window->textxy(gx+bsize,gy+((gy1-gy+1)-window->textheight())/2);
			}
		else
			{
			window->textxy(gx+(gx1-gx)/2,gy+((gy1-gy+1)-window->textheight())/2);
			window->textalign(GR_ALIGN_CENTER,GR_ALIGN_TOP);
			}

		window->BGcolor(BLACK|GrXOR);
		window->FGcolor(c);
		window->outtext(text);

		if (flags&G_STRING)
			{
			if ((flags&G_HIGHLIGHTED) || (window->currentgadget==this && window->input.inputflags==IF_STRING))
				{
				window->FGcolor((RED^BGcolor)|GrXOR);
				window->line(cp+gx+bsize,gy+((gy1-gy+1)-window->textheight())/2,cp+gx+bsize,gy+((gy1-gy+1)+window->textheight())/2);
				window->line(cp+gx+1+bsize,gy+((gy1-gy+1)-window->textheight())/2,cp+gx+1+bsize,gy+((gy1-gy+1)+window->textheight())/2);
				}
			}

		Unset();
		}
	}

//-------------------------------------------------
void Gadget::DoBox(int onoff)
	{
	GrFBoxColors bdron = {GrNOCOLOR,WHITE,DARKGRAY,BLACK,LIGHTGRAY};
	GrFBoxColors bdroff = {GrNOCOLOR,BLACK,LIGHTGRAY,WHITE,DARKGRAY};

	Set();

	window->framedbox(gx+4,gy+4,gx1-4,gy1-4,3,&((onoff)?bdron:bdroff));

	*window << ((onoff)?WT_WHITE:WT_LIGHTGRAY);
	window->filledbox(gx+4,gy+4,gx1-4,gy1-4);
	*window << WT_BLACK;
	if (onoff) window->box(gx+3,gy+3,gx1-3,gy1-3);
	else window->box(gx+4,gy+4,gx1-4,gy1-4);
	window->box(gx,gy,gx1,gy1);

	Unset();
	}

//-------------------------------------------------
void Gadget::DoList()
	{
	char *s=text;
	int n;

	if (!s) return;

	Set();
	window->setclip(gx+bsize,gy+bsize,gx1-bsize,gy1-bsize);

	window->setfont(&Font);

	window->textalign(GR_ALIGN_LEFT,GR_ALIGN_TOP);
	window->textxy(gx+bsize,gy+bsize);
	window->BGcolor(WHITE);

	n = topitem;

	while (*s && window->gettexty() < gy1)
		{
		if (n--<=0)
			{
			if (-n+topitem-1 == selecteditem) window->BGcolor(LIGHTGRAY);
			else window->BGcolor(WHITE);
			*window << WT_BLACK << s << "\n";
			}
		s += strlen(s)+1;
		}

	Unset();
	Flush();
	}

//-------------------------------------------------
int Gadget::GetNumItems()
	{
	char *s = text;
	int n=0;

	if (!(flags&G_LIST)) return 0;
	if (!s) return 0;

	while (*s)
		{
		s += strlen(s)+1;
		n++;
		}

	return n;
	}

//-------------------------------------------------
void Gadget::SetSlider(int p,int range)
	{
	sliderpos = ((gy1-gy-10-SLIDER_HEIGHT+1)*p)/range;

	DrawSlider();
	}
//-------------------------------------------------
void Gadget::SetList(char *s)
	{
	text = s;
	selecteditem=-1;
	SetTopItem(0);
	Draw();
	(window->Find(id+1))->SetSlider(0,65535);
	}

//-------------------------------------------------
char *Gadget::GetItem(int i)
	{
	char *s;

	if (flags&G_LIST)
		{
		s = text;
		while (*s)
			{
			if (!i--) return s;
			s += strlen(s)+1;
			}
		}
	return NULL;
	}

//-------------------------------------------------
void Gadget::Ins(char c)
	{
	text = (char *)realloc(text,strlen(text)+2);
	memcpy(text+cursorpos+1,text+cursorpos,strlen(text+cursorpos)+1);
	text[cursorpos] = c;
	cursorpos++;
	Draw();
	}
//-------------------------------------------------
void Gadget::Del()
	{
	if (cursorpos>0)
		{
		memcpy(text+cursorpos-1,text+cursorpos,strlen(text+cursorpos)+1);
		cursorpos--;
		Draw();
		}
	}
//-------------------------------------------------
void Gadget::Left()
	{
	if (cursorpos>0)
		{
		cursorpos--;
		Draw();
		}
	}

//-------------------------------------------------
void Gadget::Right()
	{
	if (cursorpos<strlen(text))	
		{
		cursorpos++;
		Draw();
		}
	}

//-------------------------------------------------
void Gadget::Home()
	{
	cursorpos = 0;
	Draw();
	}

//-------------------------------------------------
void Gadget::End()
	{
	cursorpos = strlen(text);
	Draw();
	}

//-------------------------------------------------
void Gadget::SetString(char *s)
	{
	if (!s) return;

	free(text);

	text = strdup(s);
	cursorpos = strlen(text);
	Draw();
	}

//-------------------------------------------------
char *Gadget::GetString()
	{
	return text;
	}


//-------------------------------------------------
// Variables used by set and unset

int _g_cx,_g_cy,_g_cx1,_g_cy1;
GrTextOption _g_t;
int _g_fg,_g_bg;
int _g_x,_g_y;
int _g_xa,_g_ya;
int _g_callcount=0;

//-------------------------------------------------
void Gadget::Set()
	{

	_g_fg = window->DrawColor;
	_g_bg = window->DrawBGColor;
	_g_x = window->gettextx();
	_g_y = window->gettexty();
	_g_xa = window->textxalign;
	_g_ya = window->textyalign;
	_g_t = *window->getfont();
	window->getclip(&_g_cx,&_g_cy,&_g_cx1,&_g_cy1);
	window->setclip(0,0,window->MaxX(),window->MaxY());

	_g_callcount++;
	}

//-------------------------------------------------
void Gadget::Unset()
	{
	if (--_g_callcount) return;
	window->BGcolor(_g_bg);
	window->FGcolor(_g_fg);
	window->textxy(_g_x,_g_y);
	window->textalign(_g_xa,_g_ya);
	window->setfont(&_g_t);
	window->setclip(_g_cx,_g_cy,_g_cx1,_g_cy1);
	}


//-------------------------------------------------
void Gadget::SetSelectedItem(int n)
	{
	selecteditem = n;
	if (!OnPage(n)) Centre(n);
	Draw();
	}

//-------------------------------------------------
void Gadget::Up()
	{
	if (selecteditem == 0) return;
	if (selecteditem-- == -1) selecteditem = GetNumItems()-1;
	SetSelectedItem(selecteditem);
	}

//-------------------------------------------------
void Gadget::Down()
	{
	if (selecteditem == GetNumItems()-1) return;
	++selecteditem;
	SetSelectedItem(selecteditem);
	}

//-------------------------------------------------
void Gadget::PageUp()
	{
	if (selecteditem-(ItemsPerPage()-1)<0) selecteditem=0;
	else selecteditem-=ItemsPerPage()-1;
	SetSelectedItem(selecteditem);
	}
//-------------------------------------------------
void Gadget::PageDown()
	{
	if (selecteditem+(ItemsPerPage()-1)>=GetNumItems()) selecteditem=GetNumItems()-1;
	else selecteditem+=ItemsPerPage()-1;
	SetSelectedItem(selecteditem);
	}
//-------------------------------------------------
int Gadget::Search(char *search,int i)
	{
	char *s;
	int n=0;

	if (i==-2) i = selecteditem;

	if (!(s = text)) return -1;

	while (*s)
		{
		if (i--<0)
			{
			if (strnicmp(search,s,strlen(search))==0) return n;
			}
		s += strlen(s)+1;
		n++;
		}
	return -1;
	}

//-------------------------------------------------
int Gadget::OnPage(int i)
	{
	return (selecteditem>=topitem)&&(selecteditem<topitem+ItemsPerPage());
	}

//-------------------------------------------------
int Gadget::Centre(int i)
	{
	topitem = selecteditem-ItemsPerPage()/2;
	if (topitem<0) topitem = 0;
	}

//-------------------------------------------------
int Gadget::ItemsPerPage()
	{
	return ((gy1-5)-(gy+5))/GrCharHeight('W',nicefont);
	}
//-------------------------------------------------
int Gadget::GetMaxWidth()
	{
	char *s=text;
	int n=0;

	if (!s) return 0;

	Set();
	window->setfont(&Font);

	while (*s!= '\0')
		{
		if (n<window->textwidth(s)) n = window->textwidth(s);
		s+=strlen(s)+1;
		}

	Unset();

	return n;
	}

