TGC Codebase Backup



Dark GDK Windows GUI by Gallanteer

22nd Oct 2011 12:26
Summary

Need a virtual windows GUI to run within DarkGDK? Look no further!



Description

Need a windows type GUI? Look no further!

Below are three scripts. The Source code section shows the Demo program, the Header File and class file for the dbGUI class.

It implements a Window, in input box (single line), a listbox, a checkbox and a button type. It tries to mimic many Windows look and feel standards, although it would want something that behaves excatly the same....use a proper Window!

Have Fun!



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    ---------------------------------------------------------------------------
Demo Program
---------------------------------------------------------------------------

// Dark GDK - The Game Creators - www.thegamecreators.com

// the wizard has created a very simple project that uses Dark GDK
// it contains the basic code for a GDK application


// whenever using Dark GDK you must ensure you include the header file
#include "DarkGDK.h"
#include "dbGUI.h"

// the main entry point for the application is this function
void DarkGDK ( void )
{
	// turn on sync rate and set maximum rate to 60 fps
	dbSyncOn   ( );
	dbSyncRate ( 60 );

	// Demo 3d stuff just for a bit of extra depth
	// the box
	dbMakeObjectBox(1,10,10,10);
	dbColorObject(1,dbRGB(250,250,50));
	dbSetShadowShadingOn(1);
	// the "floor"
	dbMakeObjectPlain(2,200,200);
	dbColorObject(2,dbRGB(50,100,50));
	dbRotateObject(2,-90,0,0);
	dbPositionObject(2,0,-20,0);
	dbSetShadowShadingOn(2);
	// the lights
	dbPositionLight(0,0,500,0);
	dbSetAmbientLight(10);
	dbSetLightRange(0,7000);
	// the camera
	dbPositionCamera(0,25,-30);
	dbRotateCamera(45,0,0);
	// some variables for cube animation
	float xrot = 0.000f;
	float yrot = 0.000f;
	float zrot = 0.000f;
	char buffer[256];
	bool popup_shown = false;


	////////////// The Gui stuff /////////////////////////
	// instantiate the class
	dbGUI *gui = new dbGUI();
	// create the pop-up window
	gui->CreateGuiWindow(1,360,350,"Game Maintenance",1);
	// Add some Labels
	gui->AddLabelToWindow(1,10,38,"Input Box 1","Tahoma",16,dbRGB(255,255,0));
	gui->AddLabelToWindow(1,10,68,"Input Box 2","Tahoma",16,dbRGB(255,255,0));
	gui->AddLabelToWindow(1,135,98,"Listbox","Tahoma",16,dbRGB(255,255,0));
	gui->AddLabelToWindow(1,10,290,"Create new items in Listbox?","Tahoma",16,dbRGB(255,255,0));
	// Add some text input boxes
	gui->AddInputToWindow(2,1,150,35,200,20,15,"Tahoma",16,dbRGB(10,10,40));
	gui->AddInputToWindow(3,1,150,65,200,20,15,"Tahoma",16,dbRGB(10,10,40));
	// add the listbox
	gui->AddListboxToWindow(4,1,10,120,325,8,15,"Tahoma",16);
	// Populate the listbox
	for(int cnt=0; cnt < 50; cnt++){
		sprintf(buffer,"Game type %d",cnt);
		gui->AddItemToListbox(4,buffer,dbRGB(10,10,40));
	}
	gui->AddItemToListbox(4,"Last Item!",dbRGB(200,10,40));
	// Add the checkbox
	gui->AddCheckboxToWindow(5,1,210,290,16,16,false);
	// Add the finished button
	gui->AddButtonToWindow(6,1,270,320,80,20,"Ready!","Tahoma",16,dbRGB(255,255,255),20);

	char *input1 = "";
	char *input2 = "";
	char *input3 = "";

	// our main loop
	while ( LoopGDK ( ) )
	{
		
		xrot=dbWrapValue(xrot+0.100f);
		yrot=dbWrapValue(yrot+0.150f);
		zrot=dbWrapValue(zrot+0.200f);
		dbRotateObject(1,xrot,yrot,zrot);
		
		int result = 0;

		if(popup_shown){
			int mousex = dbMouseX();
			int mousey = dbMouseY();
			int mouseclick = dbMouseClick();
			result = gui->MessageHandler(mousex,mousey,mouseclick);
			if(result==6){
				gui->ShowWindow(1,120,105,false,200);
				input1 = strdup(gui->GetInputText(2));
				input2 = strdup(gui->GetInputText(3));
				int itemno = gui->GetListboxSelection(4);
				if(itemno >=0){
					input3 = strdup(gui->GetListboxItem(4,itemno));
					gui->SetInputText(2,input3,false);
				}
				if(gui->GetCheckbox(5)){
					gui->ClearListbox(4);
					for(int cnt=0; cnt < 10; cnt++){
						sprintf(buffer,"Different type %d",cnt);
						gui->AddItemToListbox(4,buffer,dbRGB(10,10,40));
					}
					gui->SetCheckbox(5,false);
				}
				popup_shown=false;
			}
		} else {
			dbSetTextSize(24);
			dbText(180,350,"Press SPACEBAR for Popup Box");
			dbSetTextSize(18);
			dbText(5,400,input1);
			dbText(5,425,input2);
			dbText(5,450,input3);
			if(dbSpaceKey()==1){
				popup_shown=true;
				//Show the window
				gui->ShowWindow(1,120,90,true,200);
			}
		}

		dbInk(dbRGB(255,255,255),dbRGB(255,255,255));
		dbSetTextFont("Tahoma");
		dbSetTextSize(16);
		sprintf(buffer,"Frames per second: %d",dbScreenFPS());
		dbText(5,5,buffer);
		if(result>0){
			sprintf(buffer,"Message from Window #%d",result);
			dbText(5,25,buffer);
		}
		// update the screen
		dbSync ( );
	}

	// return back to windows
	return;
}


-------------------------------------------------------------------------------------
Header
-------------------------------------------------------------------------------------
#ifndef DBGUICLASS
#define DBGUICLASS

#include "DarkGDK.h"

class dbGUI {
public:
	dbGUI(int winR=100, int winG=100, int winB=200, int edgeR=200, int edgeG=200, int edgeB=100,int resourceStart=800);
	~dbGUI();
	void CreateGuiWindow(int window, int width, int height, char *banner, int priority=0);
	void AddLabelToWindow(int window, int x, int y, char *buffer, char *font, int fontsize,int color);
	void AddWhiteBoxToWindow(int window, int x, int y, int width, int height);
	void AddInputToWindow(int window, int parentwin, int x, int y, int width, int height, int maxchars, char *font, int fontsize, int textcolor);
	void SetInputText(int window, char *buffer, bool cursor);
	void AddListboxToWindow(int window, int parentwin, int x, int y, int width, int displayrows, int maxchars, char *font, int fontsize);
	void AddItemToListbox(int window,char *buffer, int textcolor);
	void ClearListbox(int window);
	void ResetListbox(int window);
	char *GetListboxItem(int window, int item);
	void AddButtonToWindow(int window, int parentwin, int x, int y, int width, int height, char *buffer, char *font, int fontsize,int textcolor, int textx);
	void AddCheckboxToWindow(int window, int parentwin, int x, int y, int width, int height, bool checked);
	void ShowWindow(int window, int x, int y, bool show=true, int translucent=255);
	void DeleteWindow(int window);
	int  OverWindow(int x, int y);
	int  MessageHandler(int mousex, int mousey, int mouseclick);	
	bool GetCheckbox(int window);
	void SetCheckbox(int window, bool checked);
	char *GetInputText(int window);
	int GetListboxSelection(int window);
	void SetListboxSelection(int window, int selection, bool movetopage);

	// Need to add - reset Listbox, add tickbox, refresh tickbox
private:
	int guiWinStart;
	int winColorR, winColorG, winColorB;
	int edgeColorR, edgeColorG, edgeColorB;
	int GUIFocus;
	int GUILastFocus;

	static const int listMaxItems = 200;

	struct GUIWINDOW {
		int sprite;
		char type;
		int maxchars;
		char buffer[40];
		int x,y,width,height,textcolor;
		char font[25];
		int fontsize;
		bool created;
		char **listitem;
		int *itemcolor;
		int maxitems;
		int topitem;
		int displayrows;
		int rowselected;
		bool vscrollbar;
		int scrollbary;
		int scrollboxh;
		bool but1, but2, but3;
		int textoffset;
	} guiWindow[50];

	void RefreshInput(int window);
	void PrepareInput(int sprite, int window);
	int  KeyboardInput(int window);
	void RefreshListbox(int window);
	void RefreshCheckbox(int window);
	int  ListboxInput(int window,int mousex, int mousey);
	void ListboxInputScrollbar(int window, int mousex, int mousey);
	void DrawButton(int sprite, int x, int y, int width, int height, char *buffer, int facecolor, bool pressed, int textcolor = 0, bool raised=true, char *font="Tahoma", int fontsize=16, int textx=2);
	void RefreshButton(int window);
	void ResetButton(int sprite);
};

#endif

-------------------------------------------------------------------------------------
dbGUI.cpp class
--------------------------------------------------------------------------------------
#include "dbGUI.h"



dbGUI::dbGUI(int winR, int winG, int winB, int edgeR, int edgeG, int edgeB, int resourceStart){
	// Instantiate the GUI class
	guiWinStart = resourceStart;
	winColorR = winR;
	winColorG = winG;
	winColorB = winB;
	edgeColorR = edgeR;
	edgeColorG = edgeG;
	edgeColorB = edgeB;

	GUIFocus = 0;
	GUILastFocus = 0;

	for(int cnt=0; cnt < 50; cnt++){
		guiWindow[cnt].created = false;
	}
}

dbGUI::~dbGUI(){
}


void dbGUI::CreateGuiWindow(int window, int width, int height, char *banner, int priority){
	// Create a parent Window to place your window controls in
	if(dbSpriteExist(window+guiWinStart)==1) return;
	guiWindow[window].sprite = window + guiWinStart;
	guiWindow[window].type = 'W';
	guiWindow[window].maxchars = 0;
	guiWindow[window].width = width;
	guiWindow[window].height = height;
	guiWindow[window].created = true;
	window = window + guiWinStart;

	// create bitmap
	dbCreateBitmap(window,width,height);
	dbSetCurrentBitmap(window);
	// Draw it
	dbInk(dbRGB(winColorR,winColorG,winColorB),dbRGB(0,0,0));
	dbBox(0,0,width,height);
	dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
	dbLine(0,0,width-1,0);
	dbLine(width-1,0,width-1,height-1);
	dbLine(width-1,height-1,0,height-1);
	dbLine(0,height-1,0,0);
	int banlen = strlen(banner);
	if(banlen>0){
		dbInk(dbRGB(winColorR-50,winColorG-50,winColorB-50),dbRGB(0,0,0));
		dbBox(1,1,width-2,25);
		dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
		dbLine(0,25,width,25);
		dbInk(dbRGB(255,255,255),dbRGB(10,10,10));
		dbSetTextFont("Tahoma");
		dbSetTextSize(20);
		int banpos = (width-(banlen*10))/2;
		dbSetCursor(banpos,2);
		dbSetTextToBold();
		dbPrint(banner);

	}
	// convert to sprite
	dbGetImage(window,0,0,width,height,1);
	dbSprite(window,0,0,window);
	dbSetSpritePriority(window,priority);
	dbHideSprite(window);
	dbSetCurrentBitmap(0);
}

void dbGUI::AddLabelToWindow(int window, int x, int y, char *buffer, char *font, int fontsize, int color){
	// Draw a text label on the window
	int sprite = window + guiWinStart;
	if(dbSpriteExist(sprite)!=1) return;
	dbSetCurrentBitmap(sprite);
	dbInk(color,color);
	dbSetTextFont(font);
	dbSetTextSize(fontsize);
	dbSetCursor(x,y);
	dbPrint(buffer);
	if(dbSpriteVisible(guiWindow[window].sprite)==1){
		dbDeleteImage(sprite);
		dbGetImage(sprite,0,0,guiWindow[window].width,guiWindow[window].height,1);
	}
	dbSetCurrentBitmap(0);
}

void dbGUI::AddWhiteBoxToWindow(int window, int x, int y, int width, int height){
	// Generic routine to draw a white box with a border
	window = window + guiWinStart;
	if(dbSpriteExist(window)!=1) return;
	dbSetCurrentBitmap(window);
	dbInk(dbRGB(255,255,255),dbRGB(255,255,255));
	dbBox(x,y,width+x,height+y);
	dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
	dbLine(x,y,width+x,y);
	dbLine(width+x,y,width+x,height+y);
	dbLine(width+x,height+y,x,height+y);
	dbLine(x,height+y,x,y);
	if(dbSpriteVisible(window)==1){
		dbDeleteImage(window);
		dbGetImage(window,0,0,dbBitmapWidth(window),dbBitmapHeight(window),1);
	}
	dbSetCurrentBitmap(0);
}

void dbGUI::AddCheckboxToWindow(int window, int parentwin, int x, int y, int width, int height, bool checked){
	// Add an Input box to a parent window
	int sprite = parentwin + guiWinStart;
	if(dbSpriteExist(sprite)!=1) return;
	guiWindow[window].sprite = sprite;
	guiWindow[window].type = 'C';
	guiWindow[window].x = x;
	guiWindow[window].y = y;
	guiWindow[window].width = width;
	guiWindow[window].height= height;
	guiWindow[window].but1 = checked;
	guiWindow[window].created = true;
	AddWhiteBoxToWindow(parentwin,x,y,width,height);
	RefreshCheckbox(window);
}

void dbGUI::AddInputToWindow(int window, int parentwin, int x, int y, int width, int height, int maxchars, char *font, int fontsize, int textcolor){
	// Add an Input box to a parent window
	int sprite = parentwin + guiWinStart;
	if(dbSpriteExist(sprite)!=1) return;
	guiWindow[window].sprite = sprite;
	guiWindow[window].type = 'I';
	guiWindow[window].maxchars = maxchars;
	guiWindow[window].x = x;
	guiWindow[window].y = y;
	guiWindow[window].width = width;
	guiWindow[window].height= height;
	guiWindow[window].fontsize = fontsize;
	guiWindow[window].textcolor = textcolor;
	sprintf(guiWindow[window].buffer,"");
	sprintf(guiWindow[window].font,font);
	AddWhiteBoxToWindow(parentwin,x,y,width,height);
	guiWindow[window].created = true;
}

void dbGUI::AddButtonToWindow(int window, int parentwin, int x, int y, int width, int height, char *buffer, char *font, int fontsize,int textcolor, int textx){
	// Add an Input box to a parent window
	int sprite = parentwin + guiWinStart;
	if(dbSpriteExist(sprite)!=1) return;
	dbSetCurrentBitmap(sprite);
	guiWindow[window].sprite = sprite;
	guiWindow[window].type = 'B';
	guiWindow[window].x = x;
	guiWindow[window].y = y;
	guiWindow[window].width = width;
	guiWindow[window].height= height;
	guiWindow[window].fontsize = fontsize;
	guiWindow[window].textcolor = textcolor;
	guiWindow[window].textoffset = textx;
	sprintf(guiWindow[window].buffer,buffer);
	sprintf(guiWindow[window].font,font);
	guiWindow[window].created = true;
	DrawButton(NULL,x+dbSpriteX(sprite),y+dbSpriteY(sprite),width,height,buffer,dbRGB(winColorR,winColorG,winColorB),false,textcolor,true,font,fontsize,textx);
	if(dbSpriteVisible(guiWindow[window].sprite)==1){
		dbDeleteImage(sprite);
		dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	}
	dbSetCurrentBitmap(0);

}

void dbGUI::RefreshButton(int window){
	// Add an Input box to a parent window
	int sprite = guiWindow[window].sprite;
	if(dbSpriteExist(sprite)!=1) return;
	int x = guiWindow[window].x;
	int y = guiWindow[window].y;
	int width = guiWindow[window].width;
	int height= guiWindow[window].height;
	int textcolor= guiWindow[window].textcolor;
	int fontsize = guiWindow[window].fontsize;
	int textx = guiWindow[window].textoffset;
	bool pressed = false;
	int facecolor= dbRGB(winColorR,winColorG,winColorB);
	if(GUIFocus==window){
		pressed = true;
		facecolor = dbRGB(winColorR-50,winColorG-50,winColorB-50);
	}
	dbSetCurrentBitmap(sprite);
	DrawButton(NULL,x,y,width,height,guiWindow[window].buffer,facecolor,pressed,textcolor,true,guiWindow[window].font,fontsize,textx);
	dbDeleteImage(sprite);
	dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	dbSetCurrentBitmap(0);
}

void dbGUI::SetInputText(int window, char *buffer, bool cursor){
	// Set the current text in an input window
	int sprite = guiWindow[window].sprite;
	if(dbSpriteExist(sprite)!=1) return;
	sprintf(guiWindow[window].buffer,buffer);
	PrepareInput(sprite,window);
	dbPrint(buffer);
	dbDeleteImage(sprite);
	dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	dbSetCurrentBitmap(0);
}

void dbGUI::PrepareInput(int sprite, int window){
	// Clear the Input box read for refresh
	dbSetCurrentBitmap(sprite);
	dbInk(dbRGB(255,255,255),dbRGB(255,255,255));
	dbBox(guiWindow[window].x+1,guiWindow[window].y+1,guiWindow[window].width+guiWindow[window].x-2,guiWindow[window].height+guiWindow[window].y-1);
	dbInk(guiWindow[window].textcolor,guiWindow[window].textcolor);
	dbSetTextFont(guiWindow[window].font);
	dbSetTextSize(guiWindow[window].fontsize);
	dbSetTextToNormal();
	dbSetCursor(guiWindow[window].x+2,guiWindow[window].y+2);
}

int dbGUI::KeyboardInput(int window){
	// handle keyboard input including backspace, Enter and TAB
	int result = -1;
	char *buffer = dbEntry();
	dbClearEntryBuffer();
	if(buffer){
		int buflen = strlen(buffer);
		if(buflen > 0){
			for(int cnt=0; cnt < buflen; cnt++){
				// Do not allow " as a character - will help stop SQL injection etc if SQL is used in the main program
				if(buffer[cnt] >= 32 && buffer[cnt] <= 122 && buffer[cnt] != 34 && buffer[cnt] != 94){
					if(strlen(guiWindow[window].buffer) < guiWindow[window].maxchars) sprintf(guiWindow[window].buffer,"%s%c",guiWindow[window].buffer,buffer[cnt]);
				} else {
					// Backspace
					if(buffer[cnt] == 8){
						int dellen = strlen(guiWindow[window].buffer)-1;
						if(dellen > 0){
							char tempbuf[256] = "";
							strncpy(tempbuf,guiWindow[window].buffer,dellen);
							sprintf(guiWindow[window].buffer,"%s",tempbuf);
						} else {
							strcpy(guiWindow[window].buffer,"");
						}
						cnt = buflen;
					}
					// Carriage Return
					if(buffer[cnt]==13){
						GUIFocus = 0;
						cnt = buflen;
						result = window;
					}
					// Tab
					if(buffer[cnt]==9){
						result = window;
						int sprite = guiWindow[window].sprite;
						int nextwin = window+1;
						int diff = 1;
						if(dbShiftKey()==1) diff = -1;
						while(nextwin > 0 && nextwin < 50){
							if(guiWindow[nextwin].sprite == sprite && guiWindow[nextwin].type == 'I'){
								GUIFocus = nextwin;
								cnt = buflen;
								RefreshInput(window);
								RefreshInput(nextwin);
								nextwin = -1;
							}
							nextwin=nextwin+diff;
						}
					}
				}
			}
			RefreshInput(window);
		}
	}
	return result;
}

void dbGUI::RefreshInput(int window){
	// refresh the display of a text inout window
	int sprite = guiWindow[window].sprite;
	if(!guiWindow[window].created || guiWindow[window].type!='I') return;
	PrepareInput(sprite,window);
	char buffer[256];
	sprintf(buffer,"%s",guiWindow[window].buffer);
	if(GUIFocus==window){
		sprintf(buffer,"%s%c",buffer,95);
	}
	dbPrint(buffer);
	dbDeleteImage(sprite);
	dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	dbSetCurrentBitmap(0);
}

void dbGUI::RefreshCheckbox(int window){
// refresh the display of a text inout window
	int sprite = guiWindow[window].sprite;
	if(!guiWindow[window].created || guiWindow[window].type!='C') return;
	int x = guiWindow[window].x;
	int y = guiWindow[window].y;
	int width = guiWindow[window].width;
	int height = guiWindow[window].height;

	dbSetCurrentBitmap(sprite);
	if(guiWindow[window].but1){
		dbInk(dbRGB(winColorR-50,winColorG-50,winColorB-50),dbRGB(0,0,0));
		dbBox(x+1,y+1,width+x,height+y);
		dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
		dbLine(x,y,x+width,y+height);
		dbLine(x+width,y,x,y+height);
	} else {
		dbInk(dbRGB(255,255,255),dbRGB(255,255,255));
		dbBox(x+1,y+1,width+x,height+y);
	}
	dbDeleteImage(sprite);
	dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	dbSetCurrentBitmap(0);
}

void dbGUI::AddListboxToWindow(int window, int parentwin, int x, int y, int width, int displayrows, int maxchars, char *font, int fontsize){
	// Setup the basic variables needed to create the listbox
	int sprite = parentwin + guiWinStart;
	if(dbSpriteExist(sprite)!=1) return;
	guiWindow[window].sprite = sprite;
	guiWindow[window].type = 'L';
	guiWindow[window].x = x;
	guiWindow[window].y = y;
	guiWindow[window].width = width;
	guiWindow[window].height= fontsize * displayrows + 3;
	guiWindow[window].displayrows = displayrows;
	guiWindow[window].fontsize = fontsize;
	guiWindow[window].maxitems = 0;
	guiWindow[window].maxchars = maxchars;
	guiWindow[window].topitem = 0;
	guiWindow[window].vscrollbar = false;
	guiWindow[window].rowselected = -1;
	guiWindow[window].but1 = false;
	guiWindow[window].but2 = false;
	guiWindow[window].but3 = false;
	sprintf(guiWindow[window].buffer,"");
	sprintf(guiWindow[window].font,font);
	guiWindow[window].listitem = NULL;
	guiWindow[window].itemcolor = NULL;
	AddWhiteBoxToWindow(parentwin,x,y,width,guiWindow[window].height);
	guiWindow[window].created = true;

}

void dbGUI::AddItemToListbox(int window,char *buffer, int textcolor){
	// append item to the bottom of the listbox and add scrollbar if the number exceeds the visible rows
	if(guiWindow[window].created && guiWindow[window].type=='L'){
		guiWindow[window].maxitems++;
		int maxitems = guiWindow[window].maxitems;
		if(maxitems==1){
			guiWindow[window].listitem = (char**)malloc(maxitems * sizeof(char*));
			guiWindow[window].itemcolor = (int*)malloc(maxitems * sizeof(int));
		} else {
			guiWindow[window].listitem = (char**)realloc(guiWindow[window].listitem,maxitems * sizeof(char*));
			guiWindow[window].itemcolor = (int*)realloc(guiWindow[window].itemcolor,maxitems * sizeof(char*));
		}	
		guiWindow[window].listitem[maxitems-1] = strdup(buffer);
		guiWindow[window].itemcolor[maxitems-1] = textcolor;
		// Add the scrollbar?
		if(guiWindow[window].maxitems > guiWindow[window].displayrows && guiWindow[window].vscrollbar==false){
			guiWindow[window].vscrollbar = true;
			guiWindow[window].scrollbary = 0;
			DrawButton(guiWindow[window].sprite,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y,16,16,"^",dbRGB(winColorR-50,winColorG-50,winColorB-50),false);
			DrawButton(guiWindow[window].sprite,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+guiWindow[window].height-16,16,16,"~",dbRGB(winColorR-50,winColorG-50,winColorB-50),false);
		}
		// Resize the movable button in the scrollbar?
		if(guiWindow[window].vscrollbar){
			guiWindow[window].scrollboxh = guiWindow[window].height-31;
			int boxsize = guiWindow[window].maxitems - guiWindow[window].displayrows + 1;
			if(boxsize<1) boxsize = 1;
			guiWindow[window].scrollboxh = guiWindow[window].scrollboxh / boxsize;
			if(guiWindow[window].scrollboxh < 10) guiWindow[window].scrollboxh = 10;
			DrawButton(guiWindow[window].sprite,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+15,16,guiWindow[window].height-31,NULL,dbRGB(100,100,100),false);
			DrawButton(guiWindow[window].sprite,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+15,16,guiWindow[window].scrollboxh,"==",dbRGB(winColorR-50,winColorG-50,winColorB-50),false);
		}
		RefreshListbox(window);
	}
}

char *dbGUI::GetListboxItem(int window, int item){
	// return the text contents of a listbox item number
	if(guiWindow[window].created && guiWindow[window].type=='L'){
		return guiWindow[window].listitem[item];
	}
	return NULL;
}

void dbGUI::RefreshListbox(int window){
	// redraw the current state of the listbox
	int sprite = guiWindow[window].sprite;
	if(!guiWindow[window].created || guiWindow[window].type!='L') return;
	PrepareInput(sprite,window);
	char buffer[256];
	int max = guiWindow[window].topitem+guiWindow[window].displayrows;
	if(max > guiWindow[window].maxitems) max = guiWindow[window].maxitems;
	int ypos = guiWindow[window].y+2;
	// Box has been reset - redraw the visible items and highlight the correct row if visible
	for(int cnt=guiWindow[window].topitem; cnt < max; cnt++){
		if(cnt < guiWindow[window].maxitems && cnt>=0){
			if(cnt==guiWindow[window].rowselected){
				dbInk(dbRGB(200,200,200),dbRGB(200,200,200));
				dbBox(guiWindow[window].x+1,ypos,guiWindow[window].width+guiWindow[window].x-2,ypos+guiWindow[window].fontsize);
			}
			dbInk(guiWindow[window].itemcolor[cnt],guiWindow[window].itemcolor[cnt]);
			dbSetTextFont(guiWindow[window].font);
			dbSetTextSize(guiWindow[window].fontsize);
			dbSetCursor(guiWindow[window].x+2,ypos);
			ypos = ypos + guiWindow[window].fontsize;
			dbPrint(guiWindow[window].listitem[cnt]);
		}
	}
	// redraw the current state of the vertical scrollbar
	if(guiWindow[window].vscrollbar){
		// up and down
		DrawButton(NULL,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y,16,16,"^",dbRGB(winColorR-50,winColorG-50,winColorB-50),guiWindow[window].but1);
		DrawButton(NULL,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+guiWindow[window].height-16,16,16,"~",dbRGB(winColorR-50,winColorG-50,winColorB-50),guiWindow[window].but3);
		// slider
		DrawButton(NULL,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+15,16,guiWindow[window].height-31,NULL,dbRGB(100,100,100),false,false);
		if(!guiWindow[window].but2){
			int ypos = (guiWindow[window].height - 32) / (guiWindow[window].maxitems - guiWindow[window].displayrows) * guiWindow[window].topitem;
			if(ypos > guiWindow[window].height-31-guiWindow[window].scrollboxh) ypos = guiWindow[window].height - 31-guiWindow[window].scrollboxh;
			guiWindow[window].scrollbary = ypos;
		}
		DrawButton(NULL,guiWindow[window].x+guiWindow[window].width+1,guiWindow[window].y+guiWindow[window].scrollbary+15,16,guiWindow[window].scrollboxh,"==",dbRGB(winColorR-50,winColorG-50,winColorB-50),guiWindow[window].but2);

	}
	if(dbSpriteVisible(guiWindow[window].sprite)==1){
		dbDeleteImage(sprite);
		dbGetImage(sprite,0,0,dbBitmapWidth(sprite),dbBitmapHeight(sprite),1);
	}
	dbSetCurrentBitmap(0);
}

void dbGUI::ClearListbox(int window){
	// Clear all items from the listbox
	if(guiWindow[window].created && guiWindow[window].type=='L'){
		for(int cnt=0; cnt < guiWindow[window].maxitems; cnt++){
			free(guiWindow[window].listitem[cnt]);
		}	
		free(guiWindow[window].listitem);
		free(guiWindow[window].itemcolor);
	}
	guiWindow[window].maxitems = 0;
	guiWindow[window].vscrollbar = false;
	guiWindow[window].topitem = 0;
	guiWindow[window].rowselected = -1;
	guiWindow[window].but1 = false;
	guiWindow[window].but2 = false;
	guiWindow[window].but3 = false;
	guiWindow[window].listitem = NULL;
	guiWindow[window].itemcolor = NULL;
	RefreshListbox(window);
}

int dbGUI::ListboxInput(int window, int mousex, int mousey){
	// Handle selecting a particular item within the listbox
	int result = -1;	
	if(!guiWindow[window].created || guiWindow[window].type!='L') return -1;
	guiWindow[window].rowselected = -1;
	int top, bottom;
	for(int cnt=0; cnt < guiWindow[window].displayrows; cnt++){
		top = (cnt*guiWindow[window].fontsize)+guiWindow[window].y+dbSpriteY(guiWindow[window].sprite);
		bottom = top + guiWindow[window].fontsize;
		if(mousey >= top && mousey <= bottom && cnt + guiWindow[window].topitem < cnt + guiWindow[window].maxitems){
			guiWindow[window].rowselected = cnt + guiWindow[window].topitem;
			result = window;
		}
	}
	return result;
}

void dbGUI::ListboxInputScrollbar(int window, int mousex, int mousey){
	// Handle scrolling the listbox up and down
	if(!guiWindow[window].created || guiWindow[window].type!='L') return;
	int uptop, upbottom, downtop, downbottom, midtop, midbottom;
	// top button
	uptop = guiWindow[window].y + dbSpriteY(guiWindow[window].sprite);
	upbottom = uptop + 16;
	if(mousey >= uptop && mousey < upbottom && !guiWindow[window].but2){
		guiWindow[window].topitem--;
		guiWindow[window].but1 = true;
	}
	// Bottom button
	downbottom = guiWindow[window].y + guiWindow[window].height + dbSpriteY(guiWindow[window].sprite);
	downtop = downbottom - 16;
	if(mousey >= downtop && mousey < downbottom && !guiWindow[window].but2){
		guiWindow[window].topitem++;
		guiWindow[window].but3 = true;
	}
	// scroll button
	midtop = guiWindow[window].scrollbary + guiWindow[window].y + dbSpriteY(guiWindow[window].sprite)+16;
	midbottom = guiWindow[window].scrollboxh + midtop;
	if(mousey >= midtop && mousey < midbottom || guiWindow[window].but2){
		int ymove = mousey - (midtop+(guiWindow[window].scrollboxh/2));
		if(ymove!=0){
			int ypos  = guiWindow[window].scrollbary + ymove;
			int ysize = guiWindow[window].height - 32 - guiWindow[window].scrollboxh;
			if(ypos<0) ypos=0;
			if(ypos>ysize) ypos = ysize;
			int ytops = guiWindow[window].maxitems - guiWindow[window].displayrows;
			guiWindow[window].topitem = (ytops * ypos) / ysize;
			guiWindow[window].scrollbary = guiWindow[window].scrollbary + ymove;
			if(guiWindow[window].scrollbary < 0) guiWindow[window].scrollbary = 0;
			if(guiWindow[window].scrollbary > ysize) guiWindow[window].scrollbary = ysize;
		}			
		guiWindow[window].but2 = true;
	}
	// the paging part of the scrollbar
	if(mousey >= upbottom && mousey < midtop && !guiWindow[window].but2){
		guiWindow[window].topitem = guiWindow[window].topitem - guiWindow[window].displayrows;
	}
	if(mousey >= midbottom && mousey < downtop && !guiWindow[window].but2){
		guiWindow[window].topitem = guiWindow[window].topitem + guiWindow[window].displayrows;
	}
	// ensure still within bounds
	if(guiWindow[window].topitem < 0) guiWindow[window].topitem = 0;
	if(guiWindow[window].topitem > guiWindow[window].maxitems - guiWindow[window].displayrows) guiWindow[window].topitem = guiWindow[window].maxitems - guiWindow[window].displayrows;
}

void dbGUI::ResetListbox(int window){
	if(!guiWindow[window].created || guiWindow[window].type!='L') return;
	guiWindow[window].rowselected = -1;
	guiWindow[window].topitem = 0;
	RefreshListbox(window);
}

void dbGUI::DrawButton(int sprite, int x, int y, int width, int height, char *buffer, int facecolor, bool pressed, int textcolor, bool raised, char *font, int fontsize, int textx){
	if(sprite!=NULL) dbSetCurrentBitmap(sprite);
	dbInk(facecolor,facecolor);
	dbBox(x,y,x+width,y+height);
	dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
	dbLine(x,y,x+width-1,y);
	dbLine(x+width-1,y,x+width-1,y+height);
	dbLine(x+width-1,y+height,x,y+height);
	dbLine(x,y+height,x,y);
	if(pressed){
		dbInk(dbRGB(edgeColorR-50,edgeColorG-50,edgeColorB-50),dbRGB(0,0,0));
	} else {
		if(raised){
			dbLine(x+1,y+height,x+1,y+1);
			dbLine(x+1,y+1,x+width-2,y+1);
			dbInk(dbRGB(0,0,10),dbRGB(0,0,0));
			dbLine(x+width-1,y,x+width-1,y+height);
			dbLine(x+width-1,y+height,x,y+height);
			dbLine(x+width-2,y+1,x+width-2,y+height-1);
			dbLine(x+width-2,y+height-1,x+1,y+height-1);
			dbInk(dbRGB(edgeColorR,edgeColorG,edgeColorB),dbRGB(0,0,0));
		}
	}
	// draw text on the button with some hard coded options
	if(buffer){
		if(strcmp(buffer,"^")==0){
			dbLine(x,y+height-1,x+(width/2),y);
			dbLine(x+(width/2),y,x+width-2,y+height-1);
		} else {
			if(strcmp(buffer,"~")==0){
				dbLine(x,y,x+(width/2),y+height-1);
				dbLine(x+(width/2),y+height-1,x+width-2,y);
			} else {
				if(strcmp(buffer,"==")==0){
					dbLine(x+2,y+(height/2)-2,x+width-3,y+(height/2)-2);
					dbLine(x+2,y+(height/2)+2,x+width-3,y+(height/2)+2);						
				} else {
					dbInk(textcolor,textcolor);
					dbSetTextFont(font);
					dbSetTextSize(fontsize);
					int texty = ((height - fontsize) / 2) + y;
					dbSetCursor(x+textx,texty);
					dbPrint(buffer);
				}
			}
		}
	}
	if(sprite!=NULL) dbSetCurrentBitmap(0);
}

void dbGUI::ResetButton(int sprite){
	for(int cnt=0; cnt < 50; cnt++){
		if(guiWindow[cnt].created && guiWindow[cnt].sprite == sprite & GUIFocus == cnt){
			GUIFocus = 0;
			GUILastFocus = 0;
			RefreshButton(cnt);
		}
	}
}

void dbGUI::ShowWindow(int window, int x, int y, bool show, int translucent){
	// Show the Window - meant for parent windows - unkown results if anything else tried
	int sprite = window + guiWinStart;
	if(dbSpriteExist(sprite)==1){	
		if(show){
			dbSetCurrentBitmap(sprite);
			dbDeleteImage(sprite);
			dbGetImage(sprite,0,0,guiWindow[window].width,guiWindow[window].height,1);
			dbSetCurrentBitmap(0);
			guiWindow[window].x = x;
			guiWindow[window].y = y;
			dbDeleteSprite(sprite);
			dbSprite(sprite,x,y,sprite);
			dbShowSprite(sprite);
			dbSetSpriteAlpha(sprite,translucent);
		} else {
			dbHideSprite(sprite);
			ResetButton(sprite);
		}
	}
}

void dbGUI::DeleteWindow(int window){
	// Delete a window - not full tested - tend not to need it for games
	if(dbSpriteExist(window)!=1) return;
	window = window + guiWinStart;
	dbDeleteSprite(window);
	dbDeleteImage(window);
	dbDeleteBitmap(window);
	guiWindow[window].created = false;
}

int dbGUI::MessageHandler(int mousex, int mousey, int mouseclick){
	// GUIFocus is set to the Window that is currently in control
	// In the case of listboxes, there are no separate windows for the scroll bar elements
	int result = -1;
	int currwin = OverWindow(mousex,mousey);
	if(GUILastFocus>0){
		switch(guiWindow[GUILastFocus].type){
			case 'I':
				if(currwin != GUILastFocus && mouseclick==1){
					GUIFocus = currwin;
					RefreshInput(GUILastFocus);
				}
				break;
			case 'B':
				if(currwin != GUILastFocus || (currwin == GUILastFocus && mouseclick!=1)){
					if(mouseclick!=1){
						if(currwin == GUIFocus) result = GUIFocus;
						GUIFocus = 0;
					} else {
						GUIFocus = currwin;
					}
					RefreshButton(GUILastFocus);
				}
				break;
			case 'L':
				if(mouseclick!=1 || currwin != GUILastFocus){
					if(guiWindow[GUILastFocus].but1 || guiWindow[GUILastFocus].but2 || guiWindow[GUILastFocus].but3){
						guiWindow[GUILastFocus].but1 = false;
						guiWindow[GUILastFocus].but2 = false;
						guiWindow[GUILastFocus].but3 = false;
						RefreshListbox(GUILastFocus);
					}
				}
				break;
			case 'C':
				if(mouseclick!=1 || currwin != GUILastFocus){
					GUILastFocus = 0;
				}
				break;
		}
	}
	if(mouseclick==1){
		GUIFocus = currwin;
		// New focus
		if(GUIFocus>0){
			switch(guiWindow[GUIFocus].type){
				case 'W':
					break;
				case 'I':
					if(GUIFocus != GUILastFocus){		
						RefreshInput(GUIFocus);
						dbClearEntryBuffer();
					}
					break;
				case 'B':
					RefreshButton(GUIFocus);
					break;
				case 'L':
					guiWindow[GUILastFocus].but1 = false;
					guiWindow[GUILastFocus].but3 = false;
					if((guiWindow[GUIFocus].vscrollbar && mousex < dbSpriteX(guiWindow[GUIFocus].sprite)+guiWindow[GUIFocus].x + guiWindow[GUIFocus].width) || !guiWindow[GUIFocus].vscrollbar){
						// Over the list of items
						result = ListboxInput(GUIFocus, mousex, mousey);
					} else {
						// Over the v-scrollbar
						ListboxInputScrollbar(GUIFocus, mousex, mousey);
					}
					RefreshListbox(GUIFocus);
					break;
				case 'C':
					if(GUIFocus != GUILastFocus){
						if(guiWindow[GUIFocus].but1){
							guiWindow[GUIFocus].but1 = false;
						} else {
							guiWindow[GUIFocus].but1 = true;
						}
						RefreshCheckbox(GUIFocus);
					}
					result = GUIFocus;
					break;
			}
			GUILastFocus = GUIFocus;
		}
	}
	// Handle keyboard inputs - specifically if an Input box has focus - outside of the mouse click switch statement
	// Input boxes maintain their focus so that this section will work
	if(GUIFocus>0){
		if(guiWindow[GUIFocus].type == 'I'){
			GUILastFocus = GUIFocus;
			result = KeyboardInput(GUIFocus);
		}
	}
	return result;
}

// Determine which "window" the mouse is hovering over
int dbGUI::OverWindow(int x, int y){
	int window = 1;
	int result = 0;
	while(dbSpriteExist(guiWindow[window].sprite)==1 && window < 50){
		if(dbSpriteVisible(guiWindow[window].sprite)==1){
			int x1 = guiWindow[window].x;
			int x2 = guiWindow[window].x+guiWindow[window].width;
			if(guiWindow[window].type=='L' && guiWindow[window].vscrollbar) x2=x2+16;
			int y1 = guiWindow[window].y;
			int y2 = guiWindow[window].y+guiWindow[window].height;
			if(guiWindow[window].type!='W'){
				x1=x1+dbSpriteX(guiWindow[window].sprite);
				x2=x2+dbSpriteX(guiWindow[window].sprite);
				y1=y1+dbSpriteY(guiWindow[window].sprite);
				y2=y2+dbSpriteY(guiWindow[window].sprite);
			}
			if(x >= x1 && x < x2 && y >= y1 && y < y2){
				result = window;
			}
		}
		window++;
	}
	return result;
}

bool dbGUI::GetCheckbox(int window){
	if(!guiWindow[window].created || guiWindow[window].type!='C') return false;
	return guiWindow[window].but1;
}

void dbGUI::SetCheckbox(int window, bool checked){
	if(!guiWindow[window].created || guiWindow[window].type!='C') return;
	guiWindow[window].but1 = checked;
	RefreshCheckbox(window);
}

char *dbGUI::GetInputText(int window){
	if(!guiWindow[window].created || guiWindow[window].type!='I') return "";
	return guiWindow[window].buffer;
}

int dbGUI::GetListboxSelection(int window){
	if(!guiWindow[window].created || guiWindow[window].type!='L') return -1;
	return guiWindow[window].rowselected;
}

void dbGUI::SetListboxSelection(int window, int selection, bool movetopage){
	if(!guiWindow[window].created || guiWindow[window].type!='L') return;
	if(selection > guiWindow[window].maxitems) return;
	guiWindow[window].rowselected = selection;
	if(movetopage){
		guiWindow[window].topitem = selection;
		if(guiWindow[window].topitem < 0) guiWindow[window].topitem = 0;
	}
	RefreshListbox(window);
}