Files
fs2open.github.com/code/lab/wmcgui.cpp
T

2921 lines
69 KiB
C++

/*
* wmcgui.cpp
* created by WMCoolmon
*
* You may not sell or otherwise commercially exploit the source or things you
* create based on the source.
*
*/
/*
* $Logfile: /Freespace2/code/lab/wmcgui.cpp $
* $Revision: 1.28.2.4 $
* $Date: 2007-02-12 00:23:39 $
* $Author: taylor $
*
* $Log: not supported by cvs2svn $
* Revision 1.28.2.3 2006/11/15 00:40:59 taylor
* fix some "stupid-windows-coder-mistakes" (otherwise known as "putting-more-than-you-should-into-header-files")
* (gets rid of some/many compiler warnings, C++ language violations, and strange little bugs/errors)
*
* Revision 1.28.2.2 2006/09/11 01:15:04 taylor
* fixes for stuff_string() bounds checking
*
* Revision 1.28.2.1 2006/08/19 04:26:32 taylor
* add render option for no glowmaps
* remove render option for fog (why was this even there??)
* add tech model view for missiles with special tech models (will hopefully help spur some work towards fixing the currently broken models)
* handle Z-buf issue that made the lab interface disappear when the transparent render option was ticked
*
* Revision 1.28 2006/03/22 18:20:06 taylor
* minor warning fixage
*
* Revision 1.27 2006/01/21 02:22:05 wmcoolmon
* Scripting updates; Special scripting image list; Better operator meta; Orientation type; Wing type; Texture type. Fix for MSVC7 compiling.
*
* Revision 1.26 2005/12/06 03:17:48 taylor
* cleanup some debug log messages:
* note that a nprintf() with "Warning" or "General" is basically the same thing as mprintf()
* make sure that OpenAL init failures always get to the debug log
*
* Revision 1.25 2005/12/04 19:07:48 wmcoolmon
* Final commit of codebase
*
* Revision 1.23 2005/10/22 20:17:18 wmcoolmon
* mission-set-nebula fixage; remainder of python code
*
* Revision 1.22 2005/10/09 00:43:08 wmcoolmon
* Extendable modular tables (XMTs); added weapon dialogs to the Lab
*
* Revision 1.21 2005/09/25 07:27:33 Goober5000
* and again
* --Goober5000
*
* Revision 1.20 2005/09/25 07:26:05 Goober5000
* try to fix the headers
* --Goober5000
*
*/
#include "lab/wmcgui.h"
#include "graphics/2d.h"
#include "hud/hudbrackets.h"
#include "parse/parselo.h"
#include "globalincs/linklist.h"
#include "io/key.h"
#include "freespace2/freespace.h"
#include "localization/localize.h"
//Gobals
GUISystem GUI_system;
//*****************************ClassInfoEntry*******************************
ClassInfoEntry::ClassInfoEntry()
{
CIEType = CIE_NONE;
for(uint i = 0; i < CIE_NUM_HANDLES; i++)
{
IMG_HANDLE_SET_INVALID(Handles[i].Image);
}
Coords[0] = Coords[1] = INT_MAX;
}
ClassInfoEntry::~ClassInfoEntry()
{
//Unload image handles
if(CIEType == CIE_IMAGE_NMCSD || CIEType == CIE_IMAGE || CIEType == CIE_IMAGE_BORDER)
{
int i = 0;
int num = sizeof(Handle)/sizeof(int);
for(; i < num; i++)
{
if(IMG_HANDLE_IS_VALID(Handles[i].Image))
IMG_UNLOAD(Handles[i].Image);
}
}
}
bool ObjectClassInfoEntry::Parse()
{
//Do we actually have a tag?
//This is hackish, but it should get the job done
if(check_for_string("<") && !check_for_string("</"))
{
char buf[NAME_LENGTH];
char buf2[NAME_LENGTH+3]; //for the end tag and name buffer
Assert( sizeof(buf2) >= (sizeof(buf) + 3) );
//Find the name of the thing we're parsing
parse_advance(1);
stuff_string(buf, F_NAME, sizeof(buf), ">");
parse_advance(1); //skip the end ">"
if(optional_string("+Name:"))
{
stuff_string(buf2, F_NAME, sizeof(buf2));
Name = buf2;
}
if(optional_string("+Coords:"))
{
stuff_int_list(Coords, 2, RAW_INTEGER_TYPE);
}
if(optional_string("+Size:"))
{
stuff_int_list(&Coords[2], 2, RAW_INTEGER_TYPE);
}
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK LOOK
//This is where you add specific classes to parse.
//Follow the current classes' example, this basically involves
//a !stricmp(), a resize() (to the number of entries) and multiple Entries[ID].Parse()
//=================================================
if(!stricmp(buf, "Window"))
{
Object = GT_WINDOW;
Entries.resize(WCI_NUM_ENTRIES);
//Fill it out
Entries[WCI_CAPTION].Parse("Caption", CIE_IMAGE_NMCSD);
Entries[WCI_HIDE].Parse("Hider", CIE_IMAGE_NMCSD);
Entries[WCI_CLOSE].Parse("Closer", CIE_IMAGE_NMCSD);
Entries[WCI_BODY].Parse("Body", CIE_IMAGE);
Entries[WCI_BORDER].Parse("Border", CIE_IMAGE_BORDER);
}
else if(!stricmp(buf, "Button"))
{
Object = GT_BUTTON;
Entries.resize(BCI_NUM_ENTRIES);
//Fill it out
Entries[BCI_BUTTON].Parse("Button", CIE_IMAGE_NMCSD);
}
//=================================================
//Make sure that the next token isn't an end tag, but
//is a tag
ObjectClassInfoEntry temp_ocie;
while(temp_ocie.Parse())
{
Subentries.push_back(temp_ocie);
temp_ocie = ObjectClassInfoEntry();
}
//We MUST have the end tag
strcpy(buf2, "</");
strcat(buf2, buf);
strcat(buf2, ">");
required_string(buf2);
return true;
}
return false;
}
bool ScreenClassInfoEntry::Parse()
{
if(check_for_string("#") && !check_for_string("#End"))
{
char buf[NAME_LENGTH];
//Find the name of the thing we're parsing
parse_advance(1);
stuff_string(buf, F_NAME, sizeof(buf));
Name = buf;
//Parse all objects for this screen
ObjectClassInfoEntry temp_ocie;
while(temp_ocie.Parse())
{
Entries.push_back(temp_ocie);
temp_ocie = ObjectClassInfoEntry();
}
return true;
}
return false;
}
void GUISystem::ParseClassInfo(char* filename)
{
if(ClassInfoParsed)
{
Warning(LOCATION, "Class info is being parsed twice");
DestroyClassInfo();
}
lcl_ext_open();
if(setjmp(parse_abort) != 0)
{
mprintf(("Unable to parse %s!\n", filename));
lcl_ext_close();
return;
}
read_file_text(filename);
reset_parse();
ScreenClassInfo.Parse();
bool rval;
do
{
ScreenClassInfoEntry* sciep = new ScreenClassInfoEntry;
rval = sciep->Parse();
if(rval)
list_append(&ScreenClassInfo, sciep);
} while(rval);
lcl_ext_close();
ClassInfoParsed = true;
}
void ClassInfoEntry::Parse(char* tag, int in_type)
{
char buf[MAX_FILENAME_LEN];
strcpy(buf, "+");
strcat(buf, tag);
if(in_type != CIE_IMAGE_BORDER)
strcat(buf, ":");
if(optional_string(buf))
{
CIEType = in_type;
if(in_type == CIE_IMAGE || in_type == CIE_IMAGE_NMCSD)
{
int num_frames;
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_N].Image = IMG_LOAD_ANIM(buf, &num_frames, NULL);
if(IMG_HANDLE_IS_VALID(Handles[CIE_HANDLE_N].Image) && num_frames)
{
if(num_frames > 1)
IMG_HANDLE_SET_FRAME(Handles[CIE_HANDLE_N].Image, Handles[CIE_HANDLE_M].Image, 1);
if(num_frames > 2)
IMG_HANDLE_SET_FRAME(Handles[CIE_HANDLE_N].Image, Handles[CIE_HANDLE_C].Image, 2);
if(num_frames > 3)
IMG_HANDLE_SET_FRAME(Handles[CIE_HANDLE_N].Image, Handles[CIE_HANDLE_S].Image, 3);
if(num_frames > 4)
IMG_HANDLE_SET_FRAME(Handles[CIE_HANDLE_N].Image, Handles[CIE_HANDLE_D].Image, 4);
IMG_HANDLE_SET_FRAME(Handles[CIE_HANDLE_N].Image, Handles[CIE_HANDLE_N].Image, 0);
}
else
Handles[CIE_HANDLE_N].Image = IMG_LOAD(buf);
if(in_type == CIE_IMAGE_NMCSD)
{
if(optional_string("+Mouseover:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_M].Image = IMG_LOAD(buf);
}
if(optional_string("+Clicked:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_C].Image = IMG_LOAD(buf);
}
if(optional_string("+Selected:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_S].Image = IMG_LOAD(buf);
}
if(optional_string("+Disabled:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_D].Image = IMG_LOAD(buf);
}
}
if(optional_string("+Coords:"))
stuff_int_list(Coords, 2, RAW_INTEGER_TYPE);
}
else if(in_type == CIE_IMAGE_BORDER)
{
if(optional_string("+Top Left:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_TL].Image = IMG_LOAD(buf);
}
if(optional_string("+Top Mid:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_TM].Image = IMG_LOAD(buf);
}
if(optional_string("+Top Right:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_TR].Image = IMG_LOAD(buf);
}
if(optional_string("+Mid Left:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_ML].Image = IMG_LOAD(buf);
}
if(optional_string("+Mid Right:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_MR].Image = IMG_LOAD(buf);
}
if(optional_string("+Bottom left:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_BL].Image = IMG_LOAD(buf);
}
if(optional_string("+Bottom Mid:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_BM].Image = IMG_LOAD(buf);
}
if(optional_string("+Bottom Right:"))
{
stuff_string(buf, F_NAME, sizeof(buf));
Handles[CIE_HANDLE_BR].Image = IMG_LOAD(buf);
}
}
else if(in_type == CIE_COORDS)
{
stuff_int_list(Coords, 2, RAW_INTEGER_TYPE);
}
}
#ifndef NDEBUG
//Do a little extra checking in debug mode
//This makes sure the skinnger knows if they did something bad
if(CIEType == CIE_IMAGE || CIEType == CIE_IMAGE_NMCSD)
{
int w,h,cw,ch;
IMG_INFO(Handles[0].Image, &w, &h);
for(uint i = 1; i < CIE_NUM_HANDLES; i++)
{
if(IMG_HANDLE_IS_VALID(Handles[i].Image))
{
IMG_INFO(Handles[i].Image, &cw, &ch);
if(cw != w || ch != h)
{
Warning(LOCATION, "Grouped image size unequal; Handle number %d under $%s: has a different size than base image type", i, tag);
}
}
}
}
#endif
}
int ClassInfoEntry::GetCoords(int *x, int *y)
{
int rval = CIE_GC_NONE_SET;
if(Coords[0]!=INT_MAX && x!=NULL)
{
*x=Coords[0];
rval |= CIE_GC_X_SET;
}
if(Coords[1]!=INT_MAX && x!=NULL)
{
*y=Coords[1];
rval |= CIE_GC_Y_SET;
}
return rval;
}
int ObjectClassInfoEntry::GetImageHandle(int id, int handle_num)
{
return Entries[id].GetImageHandle(handle_num);
}
int ObjectClassInfoEntry::GetCoords(int id, int *x, int *y)
{
return Entries[id].GetCoords(x, y);
}
int ObjectClassInfoEntry::GetObjectCoords(int *x, int *y, int *w, int *h)
{
int rval = CIE_GC_NONE_SET;
if(Coords[0] != INT_MAX && x != NULL)
{
*x = Coords[0];
rval |= CIE_GC_X_SET;
}
if(Coords[1] != INT_MAX && y != NULL)
{
*y = Coords[1];
rval |= CIE_GC_Y_SET;
}
if(Coords[2] != INT_MAX && w != NULL)
{
*w = Coords[2];
rval |= CIE_GC_W_SET;
}
if(Coords[3] != INT_MAX && h != NULL)
{
*h = Coords[3];
rval |= CIE_GC_H_SET;
}
return rval;
}
//*****************************GUIScreen*******************************
GUIScreen::GUIScreen(std::string in_Name)
{
//Set the name
Name = in_Name;
//Setup the parent system
//This can actually be null; but you must attach a screen to a
//system for it to be functional.
//this may allow for saving of screens in the future. Incredibly useful for HUDs.
OwnerSystem = NULL;
//Get class info
if(OwnerSystem != NULL)
{
OwnerSystem->PushScreen(this);
ScreenClassInfo = OwnerSystem->GetScreenClassInfo(Name);
}
else
{
ScreenClassInfo = NULL;
}
}
GUIScreen::~GUIScreen()
{
GUIObject* cgp = (GUIObject*)GET_FIRST(&Guiobjects);
GUIObject* cgp_next;
for(; cgp != END_OF_LIST(&Guiobjects); cgp = cgp_next)
{
cgp_next = (GUIObject*)GET_NEXT(cgp);
delete cgp;
}
//Get it out of the system
// nm; I just realized the linked list class should do this -WMC
/*
if(OwnerSystem != NULL && NOT_EMPTY(&OwnerSystem->Screens))
{
GUIScreen *csp_next;
for(GUIScreen *csp = (GUIScreen*)GET_FIRST(&OwnerSystem->Screens); csp != END_OF_LIST(&OwnerSystem->Screens); csp = csp_next)
{
csp_next = (GUIScreen*)GET_NEXT(csp);
if(csp == this)
list_remove(&OwnerSystem->Screens, csp);
}
}
*/
}
ObjectClassInfoEntry *GUIScreen::GetObjectClassInfo(GUIObject *cgp)
{
size_t len;
uint i;
ObjectClassInfoEntry *ociep;
if(cgp->Parent != NULL && cgp->Parent->InfoEntry != NULL)
{
ociep = &cgp->Parent->InfoEntry->Subentries[0];
len = cgp->Parent->InfoEntry->Subentries.size();
for(i = 0; i < len; i++)
{
if(ociep[i].Name == cgp->Name)
return &ociep[i];
}
for(i = 0; i < len; i++)
{
if(ociep[i].Name.size() == 0 && ociep[i].Object == cgp->Type)
return &ociep[i];
}
}
else if(cgp->Parent == NULL && ScreenClassInfo != NULL)
{
ociep = &ScreenClassInfo->Entries[0];
len = ScreenClassInfo->Entries.size();
for(i = 0; i < len; i++)
{
if(ociep[i].Name == cgp->Name)
return &ociep[i];
}
for(i = 0; i < len; i++)
{
if(ociep[i].Name.size() == 0 && ociep[i].Object == cgp->Type)
return &ociep[i];
}
}
//Generic templates - ie if you want every single OK button to look the same,
//or every single window to look the same.
if(OwnerSystem != NULL)
{
ociep = &OwnerSystem->GetClassInfo()->Entries[0];
len = OwnerSystem->GetClassInfo()->Entries.size();
for(i = 0; i < len; i++)
{
if(ociep[i].Name == cgp->Name)
return &ociep[i];
}
for(i = 0; i < len; i++)
{
if(ociep[i].Name.size() == 0 && ociep[i].Object == cgp->Type)
return &ociep[i];
}
}
return NULL;
}
//Adds objects to a screen
//IMPORTANT: Options added with the same name as
//older objects will make this function return
//a pointer to the original object with that name
GUIObject* GUIScreen::Add(GUIObject* new_gauge)
{
if(new_gauge == NULL)
return NULL;
Assert(this != NULL);
//First - do we have anything with the same name.
for(GUIObject *tgp = (GUIObject*) GET_FIRST(&Guiobjects); tgp != END_OF_LIST(&Guiobjects); tgp = (GUIObject*) GET_NEXT(tgp))
{
if(tgp->Name == new_gauge->Name)
{
//Get rid of the new gauge
//We don't want it; breaks skinning
delete new_gauge;
if(tgp->Type == new_gauge->Type)
{
//If the type of the existing object is the same
//as the new one, we can safely pass this one off
delete new_gauge;
return tgp;
}
else
{
//This is icky; we might cast a pointer after this.
//So return NULL with a warning
Warning(LOCATION, "Attempt to create another object with name '%s'; new object type was %d, existing object type was %d. This may cause null pointer issues.", tgp->Name.c_str(), new_gauge->Type, tgp->Type);
delete new_gauge;
return NULL;
}
}
}
//Add to the end of the list
list_append(&Guiobjects, new_gauge);
new_gauge->OwnerSystem = OwnerSystem;
new_gauge->OwnerScreen = this;
//If no position specified, try to find an empty spot.
//ALTERNATE IDEA:
//Try corners of windows.
/*
int TempX = -1;
int TempY = -1;
int TempTotal = 0;
GUIObject *agp, *bgp, *dgp;
bool problem = false;
//Do X first
if(new_gauge->Coords[0] < 0)
{
for(GUIObject *agp = (GUIObject*) GET_FIRST(&Guiobjects); agp != END_OF_LIST(&Guiobjects); agp = (GUIObject*) GET_NEXT(agp))
{
problem = false;
TempX = agp->Coords[2] + 1;
//More than 50% offscreen? This is unacceptable.
TempTotal = TempX + new_gauge->Coords[2];
if(TempTotal > gr_screen.max_w)
{
if((float)(TempTotal - gr_screen.max_w)/(float)TempTotal < 0.5f)
continue;
}
if(new_gauge->Coords[1] < 0)
{
for(GUIObject *bgp = (GUIObject*) GET_FIRST(&Guiobjects); bgp != END_OF_LIST(&Guiobjects); bgp = (GUIObject*) GET_NEXT(bgp))
{
problem = false;
TempY = bgp->Coords[3] + 1;
for(GUIObject *dgp = (GUIObject*) GET_FIRST(&Guiobjects); dgp != END_OF_LIST(&Guiobjects); dgp = (GUIObject*) GET_NEXT(dgp))
{
if(TempX > dgp->Coords[0] && TempX < dgp->Coords[2])
{
problem = true;
break;
}
}
}
}
else
{
for(GUIObject *dgp = (GUIObject*) GET_FIRST(&Guiobjects); dgp != END_OF_LIST(&Guiobjects); dgp = (GUIObject*) GET_NEXT(dgp))
{
if( TempX > dgp->Coords[0]
&& TempX < dgp->Coords[2]
&& new_gauge->Coords[1] > dgp->Coords[1]
&& new_gauge->Coords[1] < dgp->Coords[3])
{
problem = true;
break;
}
}
}
if(!problem)
break;
}
}
//Set actual coordinates
if(Coords[0] < 0)
{
if(TempX < 0)
Coords[0] = 0;
else
Coords[0] = TempX;
}
if(Coords[1] < 0)
{
if(TempY < 0)
Coords[1] = 0;
else
Coords[1] = TempY;
}*/
//For skinning
new_gauge->SetCIPointer();
//Set position and stuff
new_gauge->GetOIECoords(&new_gauge->Coords[0], &new_gauge->Coords[1], &new_gauge->Coords[2], &new_gauge->Coords[3]);
//In case we need to resize
new_gauge->OnRefreshSize();
return new_gauge;
}
void GUIScreen::DeleteObject(GUIObject* dgp)
{
DeletionCache.push_back(dgp);
}
int GUIScreen::OnFrame(float frametime, bool doevents)
{
GUIObject* cgp;
GUIObject* cgp_prev;
bool SomethingPressed = false;
if(NOT_EMPTY(&Guiobjects) && doevents)
{
//Note that children WILL be changing this variable as they go along,
//as they use up statuses.
int status = OwnerSystem->GetStatus();
//Pass the status on
GUIObject* cgp = (GUIObject*)GET_LAST(&Guiobjects);
cgp->Status |= (status & GST_KEYBOARD_STATUS);
for(; cgp != END_OF_LIST(&Guiobjects); cgp = cgp_prev)
{
//In case an object deletes itself
cgp_prev = (GUIObject*)GET_PREV(cgp);
cgp->LastStatus = cgp->Status;
cgp->Status = 0;
//If we are moving something, nothing else can get click events
if(OwnerSystem->GetGraspedObject() == NULL)
{
if(OwnerSystem->GetMouseX() >= cgp->Coords[0]
&& OwnerSystem->GetMouseX() <= cgp->Coords[2]
&& OwnerSystem->GetMouseY() >= cgp->Coords[1]
&& OwnerSystem->GetMouseY() <= cgp->Coords[3])
{
cgp->Status |= (status & GST_MOUSE_STATUS);
if(status & GST_MOUSE_PRESS)
{
SomethingPressed = true;
}
}
}
cgp->OnFrame(frametime, &status);
}
}
for(uint i = DeletionCache.size(); i > 0; i--)
{
delete DeletionCache[i-1];
DeletionCache.pop_back();
}
// save zbuffer so that we can reset it after drawing (FIXME: this could probably be done better)
int saved_zbuf = gr_zbuffer_get();
gr_zbuffer_set(GR_ZBUFF_NONE);
//Draw now. This prevents problems from an object deleting itself or moving around in the list
for(cgp = (GUIObject*)GET_LAST(&Guiobjects); cgp != END_OF_LIST(&Guiobjects); cgp = (GUIObject*)GET_PREV(cgp))
{
if(!doevents)
cgp->Status = 0;
cgp->OnDraw(frametime);
}
// reset zbuffer to saved value
gr_zbuffer_set(saved_zbuf);
if(SomethingPressed)
return GSOF_SOMETHINGPRESSED;
else
return GSOF_NOTHINGPRESSED;
}
//*****************************GUISystem*******************************
GUISystem::GUISystem()
{
GraspedGuiobject=ActiveObject=NULL;
Status=LastStatus=0;
//Fill out Guiobjects with some handy info
//On 2nd thought, don't. This is hackish.
/*
Guiobjects.OwnerSystem=this;
Guiobjects.Coords[0] = 0;
Guiobjects.Coords[1] = 0;
Guiobjects.Coords[2] = gr_screen.clip_width;
Guiobjects.Coords[3] = gr_screen.clip_height;
Guiobjects.ChildCoords[0] = gr_screen.clip_left;
Guiobjects.ChildCoords[1] = gr_screen.clip_top;
Guiobjects.ChildCoords[2] = gr_screen.clip_right;
Guiobjects.ChildCoords[3] = gr_screen.clip_bottom;*/
//Make ClassInfo all NULL
/*
for(uint i = 0; i < GT_NUM_TYPES; i++)
{
ClassInfo[i] = NULL;
}*/
ClassInfoParsed = false;
}
GUISystem::~GUISystem()
{
GUIScreen* csp = (GUIScreen*)GET_FIRST(&Screens);
GUIScreen* csp_next;
for(; csp != END_OF_LIST(&Screens); csp = csp_next)
{
csp_next = (GUIScreen*)GET_NEXT(csp);
delete csp;
}
DestroyClassInfo();
}
GUIScreen *GUISystem::PushScreen(GUIScreen *csp)
{
Assert(csp != NULL);
list_append(&Screens, csp);
csp->OwnerSystem = this;
csp->ScreenClassInfo = GetScreenClassInfo(csp->Name);
return csp;
}
//Removes a screen from a GUISystem
//Handy if you want to save window movements and such;
//just call this and it'll take care of everything
void GUISystem::PullScreen(GUIScreen *in_screen)
{
GUIScreen *csp_next;
for(GUIScreen *csp = (GUIScreen*)GET_FIRST(&Screens); csp != END_OF_LIST(&Screens); csp = csp_next)
{
csp_next = (GUIScreen*)GET_NEXT(csp);
if(csp == in_screen)
{
csp->prev->next = csp->next;
csp->next->prev = csp->prev;
csp->next = csp;
csp->prev = csp;
csp->OwnerSystem = NULL;
}
}
}
ScreenClassInfoEntry *GUISystem::GetScreenClassInfo(const std::string & screen_name)
{
ScreenClassInfoEntry *sciep;
for(sciep = (ScreenClassInfoEntry*)GET_FIRST(&ScreenClassInfo); sciep != END_OF_LIST(&ScreenClassInfo); sciep = (ScreenClassInfoEntry*)GET_NEXT(sciep))
{
if(sciep->GetName() == screen_name)
return sciep;
}
return NULL;
}
int GUISystem::OnFrame(float frametime, bool doevents, bool clearandflip)
{
//Set the global status variables for this frame
LastStatus = Status;
Status = GST_MOUSE_OVER;
bool something_pressed = false;
int unused_queue;
if(clearandflip)
gr_clear();
if(NOT_EMPTY(&Screens))
{
if(doevents)
{
KeyPressed = game_check_key();
//Add keyboard event stuff
if(KeyPressed)
{
Status |= GST_KEYBOARD_KEYPRESS;
if(KeyPressed & KEY_CTRLED)
Status |= GST_KEYBOARD_CTRL;
if(KeyPressed & KEY_ALTED)
Status |= GST_KEYBOARD_ALT;
if(KeyPressed & KEY_SHIFTED)
Status |= GST_KEYBOARD_SHIFT;
}
//Add mouse event stuff
if(mouse_down(MOUSE_LEFT_BUTTON))
Status |= GST_MOUSE_LEFT_BUTTON;
else if(mouse_down(MOUSE_MIDDLE_BUTTON))
Status |= GST_MOUSE_MIDDLE_BUTTON;
else if(mouse_down(MOUSE_RIGHT_BUTTON))
Status |= GST_MOUSE_RIGHT_BUTTON;
//Now that we are done setting status, add all that stuff to the unused queue
//Children will be changing this function as they do stuff with statuses
unused_queue = Status;
mouse_get_pos(&MouseX, &MouseY);
//Handle any grasped object (we are in the process of moving this)
if(GraspedGuiobject != NULL)
{
if(Status & GraspingButton)
{
something_pressed = true;
GraspedGuiobject->SetPosition(MouseX - GraspedDiff[0], MouseY - GraspedDiff[1]);
GraspedGuiobject->Status = (Status & GST_MOUSE_STATUS);
}
else
{
GraspedGuiobject = NULL;
}
}
}
GUIScreen *csp_prev; //so screens can delete themselves
for(GUIScreen* csp = (GUIScreen*)GET_LAST(&Screens); csp != END_OF_LIST(&Screens); csp = csp_prev)
{
csp_prev = (GUIScreen*)GET_PREV(csp);
if(csp->OnFrame(frametime, doevents) == GSOF_SOMETHINGPRESSED)
something_pressed = true;
}
}
if(clearandflip)
gr_flip();
if(something_pressed)
return GSOF_SOMETHINGPRESSED;
else
return GSOF_NOTHINGPRESSED;
}
void GUISystem::SetActiveObject(GUIObject *cgp)
{
if(cgp != NULL)
{
ActiveObject = cgp;
//Move everything to the end of the list
//This way, it gets precedence
while(cgp->Parent != NULL)
{
list_move_append(&cgp->Parent->Children, cgp);
cgp = cgp->Parent;
}
//Eventually, we make this last guy the last object in Guiobjects
list_move_append(&cgp->OwnerScreen->Guiobjects, cgp);
}
}
void GUISystem::SetGraspedObject(GUIObject *cgp, int button)
{
//Protect thyself!
if(cgp == NULL)
return;
GraspedGuiobject = cgp;
GraspingButton = button;
GraspedDiff[0] = MouseX - cgp->Coords[0];
GraspedDiff[1] = MouseY - cgp->Coords[1];
}
void GUISystem::DestroyClassInfo()
{
ScreenClassInfoEntry *sciep, *next_sciep;
for(sciep = (ScreenClassInfoEntry*)GET_FIRST(&ScreenClassInfo); sciep != END_OF_LIST(&ScreenClassInfo); sciep = next_sciep)
{
next_sciep = (ScreenClassInfoEntry*)GET_NEXT(sciep);
delete sciep;
}
ClassInfoParsed = false;
}
//*****************************GUIObject*******************************
GUIObject::GUIObject(std::string in_Name, int x_coord, int y_coord, int x_width, int y_height, int in_style)
{
//General stuff
next = prev = this;
LastStatus = Status = 0;
OwnerSystem = NULL;
OwnerScreen = NULL;
Parent = NULL;
CloseFunction = NULL;
//These would make no sense
//x_coord and y_coord of < 0 mean to let the parent handle placement.
if(x_width == 0 || y_height == 0)
return;
//No! Bad!
if(in_Name.length() < 1)
return;
Name = in_Name;
Coords[0] = x_coord;
Coords[1] = y_coord;
Coords[2] = x_coord + x_width;
Coords[3] = y_coord + y_height;
Style = in_style;
if(x_width > 0)
Style |= GS_NOAUTORESIZEX;
if(y_height > 0)
Style |= GS_NOAUTORESIZEY;
Type = GT_NONE;
InfoEntry = NULL;
}
GUIObject::~GUIObject()
{
if(CloseFunction != NULL)
CloseFunction(this);
//Set these properly
next->prev = prev;
prev->next = next;
DeleteChildren();
}
void GUIObject::DeleteChildren(GUIObject* exception)
{
GUIObject* cgp = (GUIObject*)GET_FIRST(&Children);
GUIObject* cgp_next;
for(; cgp != END_OF_LIST(&Children); cgp = cgp_next)
{
cgp_next = (GUIObject*)GET_NEXT(cgp);
delete cgp;
}
}
GUIObject* GUIObject::AddChildInternal(GUIObject *cgp)
{
if(cgp == NULL)
return NULL;
cgp->Style |= GS_INTERNALCHILD;
//Add to end of child list
list_append(&Children, cgp);
cgp->Parent = this;
cgp->OwnerSystem = OwnerSystem;
cgp->OwnerScreen = OwnerScreen;
//Update coordinates (Should be relative x/y and width/height) to absolute coordinates
cgp->Coords[0] += Coords[0];
cgp->Coords[1] += Coords[1];
cgp->Coords[2] += Coords[0];
cgp->Coords[3] += Coords[1];
//For skinning
cgp->SetCIPointer();
//Check position
cgp->GetOIECoords(&cgp->Coords[0], &cgp->Coords[1], &cgp->Coords[2], &cgp->Coords[3]);
//In case we need to resize
cgp->OnRefreshSize();
return cgp;
}
GUIObject* GUIObject::AddChild(GUIObject* cgp)
{
if(cgp == NULL)
return NULL;
//AddInternalChild must be used
if(cgp->Style & GS_INTERNALCHILD)
return NULL;
//Add to end of child list
list_append(&Children, cgp);
cgp->Parent = this;
cgp->OwnerSystem = OwnerSystem;
cgp->OwnerScreen = OwnerScreen;
//Update coordinates (Should be relative x/y and width/height) to absolute coordinates
cgp->Coords[0] += ChildCoords[0];
cgp->Coords[1] += ChildCoords[1];
cgp->Coords[2] += ChildCoords[0];
cgp->Coords[3] += ChildCoords[1];
//For skinning
cgp->SetCIPointer();
//Check position
cgp->GetOIECoords(&cgp->Coords[0], &cgp->Coords[1], &cgp->Coords[2], &cgp->Coords[3]);
//In case we need to resize
cgp->OnRefreshSize();
return cgp;
}
void GUIObject::Delete()
{
if(OwnerScreen != NULL)
OwnerScreen->DeleteObject(this);
else
delete this;
}
void GUIObject::OnDraw(float frametime)
{
DoDraw(frametime);
if(!(Style & GS_HIDDEN))
{
GUIObject *cgp_prev;
for(GUIObject* cgp = (GUIObject*)GET_LAST(&Children); cgp != END_OF_LIST(&Children); cgp = cgp_prev)
{
cgp_prev = (GUIObject*)GET_PREV(cgp);
cgp->OnDraw(frametime);
}
}
}
int GUIObject::OnFrame(float frametime, int *unused_queue)
{
int rval = OF_TRUE;
GUIObject *cgp_prev; //Elements will move themselves to the end of the list if they become active
for(GUIObject *cgp = (GUIObject*)GET_LAST(&Children); cgp != END_OF_LIST(&Children); cgp = cgp_prev)
{
cgp_prev = (GUIObject*)GET_PREV(cgp);
cgp->LastStatus = cgp->Status;
cgp->Status = 0;
if(Status & GST_MOUSE_OVER)
{
if(OwnerSystem->GetMouseX() >= cgp->Coords[0]
&& OwnerSystem->GetMouseX() <= cgp->Coords[2]
&& OwnerSystem->GetMouseY() >= cgp->Coords[1]
&& OwnerSystem->GetMouseY() <= cgp->Coords[3])
{
cgp->Status |= (Status & GST_MOUSE_STATUS);
}
}
if(cgp == GET_LAST(&Children))
{
cgp->Status |= (Status & GST_KEYBOARD_STATUS);
}
cgp->OnFrame(frametime, &Status);
}
if(Status)
{
//MOUSE OVER
if(Status & GST_MOUSE_OVER)
{
rval = DoMouseOver(frametime);
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
if(rval == OF_TRUE)
(*unused_queue) &= ~GST_MOUSE_OVER;
}
//MOUSE DOWN
if(Status & GST_MOUSE_PRESS)
{
rval = DoMouseDown(frametime);
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
if(rval == OF_TRUE)
(*unused_queue) &= ~(GST_MOUSE_LEFT_BUTTON | GST_MOUSE_RIGHT_BUTTON | GST_MOUSE_MIDDLE_BUTTON);
}
//MOUSE UP
if((LastStatus & GST_MOUSE_PRESS) && !(OwnerSystem->GetStatus() & GST_MOUSE_PRESS))
{
rval = DoMouseUp(frametime);
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
if(rval == OF_TRUE)
(*unused_queue) &= ~(GST_MOUSE_LEFT_BUTTON | GST_MOUSE_RIGHT_BUTTON | GST_MOUSE_MIDDLE_BUTTON);
}
//KEY STATE
if((Status & GST_KEYBOARD_CTRL) || (Status & GST_KEYBOARD_ALT) || (Status & GST_KEYBOARD_SHIFT))
{
rval = DoKeyState(frametime);
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
if(rval == OF_TRUE)
(*unused_queue) &= ~(GST_KEYBOARD_CTRL | GST_KEYBOARD_ALT | GST_KEYBOARD_SHIFT);
}
//KEYPRESS
if(Status & GST_KEYBOARD_KEYPRESS)
{
rval = DoKeyPress(frametime);
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
if(rval == OF_TRUE)
(*unused_queue) &= ~GST_KEYBOARD_KEYPRESS;
}
}
if(!(Status & GST_MOUSE_OVER) && (LastStatus & GST_MOUSE_OVER))
{
rval = DoMouseOut(frametime);
}
/*if(rval == OF_DESTROYED)
return OF_DESTROYED;*/
/*if(!child_keypress && (Status & GST_KEY_PRESSED))
rval = DoKeyPress(OwnerSystem->CurrentKeyChar,frametime);*/
return DoFrame(frametime);
}
void GUIObject::OnMove(int dx, int dy)
{
Coords[0]+=dx;
Coords[1]+=dy;
Coords[2]+=dx;
Coords[3]+=dy;
ChildCoords[0]+=dx;
ChildCoords[1]+=dy;
ChildCoords[2]+=dx;
ChildCoords[3]+=dy;
for(GUIObject *cgp = (GUIObject*)GET_FIRST(&Children); cgp != END_OF_LIST(&Children); cgp = (GUIObject*)GET_NEXT(cgp))
{
cgp->OnMove(dx, dy);
}
DoMove(dx, dy);
}
int GUIObject::GetCIECoords(int id, int *x, int *y)
{
if(InfoEntry!=NULL)
{
int rv = InfoEntry->GetCoords(id, x, y);
if(rv & CIE_GC_X_SET)
{
if(*x < 0)
*x += Coords[2];
else
*x += Coords[0];
}
if(rv & CIE_GC_Y_SET)
{
if(*y < 0)
*y += Coords[3];
else
*y += Coords[1];
}
return rv;
}
return CIE_GC_NONE_SET;
}
int GUIObject::GetOIECoords(int *x1, int *y1, int *x2, int *y2)
{
if(InfoEntry != NULL)
{
int rv = InfoEntry->GetObjectCoords(x1, y1, x2, y2);
if(Parent != NULL)
{
if(rv & CIE_GC_X_SET)
{
if(*x1 < 0)
*x1 += Parent->ChildCoords[2];
else
*x1 += Parent->ChildCoords[0];
}
if(rv & CIE_GC_Y_SET)
{
if(*y1 < 0)
*y1 += Parent->ChildCoords[3];
else
*y1 += Parent->ChildCoords[1];
}
}
else
{
if(rv & CIE_GC_X_SET)
{
if(*x1 < 0)
*x1 += gr_screen.clip_right;
else
*x1 += gr_screen.clip_left;
}
if(rv & CIE_GC_Y_SET)
{
if(*y1 < 0)
*y1 += gr_screen.clip_bottom;
else
*y1 += gr_screen.clip_top;
}
}
if(rv & CIE_GC_W_SET)
{
*x2 = *x1 + *x2;
Style |= GS_NOAUTORESIZEX;
}
if(rv & CIE_GC_H_SET)
{
*y2 = *y1 + *y2;
Style |= GS_NOAUTORESIZEY;
}
return rv;
}
return CIE_GC_NONE_SET;
}
//Call this after an object's type is set to enable the GUIObject CIE functions
void GUIObject::SetCIPointer()
{
if(OwnerScreen)
InfoEntry=OwnerScreen->GetObjectClassInfo(this);
}
void GUIObject::SetPosition(int x, int y)
{
int dx, dy;
dx = x - Coords[0];
dy = y - Coords[1];
if(dx == 0 && dy == 0)
return;
if(Parent != NULL)
{
//Don't let stuff get moved outside client window
if(Coords[2] + dx > Parent->Coords[2])
dx = Parent->Coords[2] - Coords[2];
if(Coords[3] + dy > gr_screen.clip_bottom)
dy = Parent->Coords[3] - Coords[3];
//Check these last, so we're sure we can move stuff around still
if(Coords[0] + dx < gr_screen.clip_left)
dx = Parent->Coords[0] - Coords[0];
if(Coords[1] + dy < gr_screen.clip_top)
dy = Parent->Coords[1] - Coords[1];
}
OnMove(dx, dy);
}
//*****************************Window*******************************
int Window::DoRefreshSize()
{
float num;
int w=0, h=0;
//Top left, top right, bottom left, bottom right
int CornerWidths[4];
//Determine left border's width
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML), &BorderSizes[0], NULL);
else
BorderSizes[0] = W_BORDERHEIGHT;
//Determine right border's width
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR), &BorderSizes[2], NULL);
else
BorderSizes[2] = W_BORDERWIDTH;
//Determine top border height
bool custom_top = true;
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TL)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TL), NULL, &BorderSizes[1]);
else if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR), NULL, &BorderSizes[1]);
else if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM), NULL, &BorderSizes[1]);
else
{
custom_top = false;
BorderSizes[1] = W_BORDERHEIGHT;
}
//Determine bottom border height
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL), NULL, &BorderSizes[3]);
else if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR), NULL, &BorderSizes[3]);
else if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM), NULL, &BorderSizes[3]);
else
BorderSizes[3] = W_BORDERHEIGHT;
//Determine corner sizes
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TL)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL), &CornerWidths[0], NULL);
else
CornerWidths[0] = BorderSizes[0];
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR), &CornerWidths[1], NULL);
else
CornerWidths[1] = BorderSizes[2];
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL), &CornerWidths[2], NULL);
else
CornerWidths[2] = BorderSizes[0];
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR)))
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL), &CornerWidths[3], NULL);
else
CornerWidths[3] = BorderSizes[2];
//Do child stuff
ChildCoords[0] = Coords[0] + BorderSizes[0];
if(custom_top || (Style & WS_NOTITLEBAR))
ChildCoords[1] = Coords[1] + BorderSizes[1]; //Set earlier on
else
ChildCoords[1] = Coords[1] + gr_get_font_height() + 5 + 3*W_BORDERHEIGHT;
ChildCoords[2] = Coords[2] - BorderSizes[2];
ChildCoords[3] = Coords[3] - BorderSizes[3];
if(!(Style & GS_NOAUTORESIZEX))
{
ChildCoords[2] = Coords[2] = 0;
}
if(!(Style & GS_NOAUTORESIZEY))
{
ChildCoords[3] = Coords[3] = 0;
}
for(GUIObject *cgp = (GUIObject*)GET_FIRST(&Children); cgp != END_OF_LIST(&Children); cgp = (GUIObject*)GET_NEXT(cgp))
{
//SetPosition children around so they're within the upper-left corner of dialog
if(cgp->Coords[0] < ChildCoords[0])
cgp->SetPosition(ChildCoords[0], cgp->Coords[1] + BorderSizes[0]);
if(cgp->Coords[1] < ChildCoords[1])
cgp->SetPosition(cgp->Coords[0], Coords[1] + BorderSizes[1]);
//Resize window to fit children
if(cgp->Coords[2] > ChildCoords[2] && !(Style & GS_NOAUTORESIZEX))
{
ChildCoords[2] = cgp->Coords[2];
Coords[2] = cgp->Coords[2] + BorderSizes[2];
}
if(cgp->Coords[3] > ChildCoords[3] && !(Style & GS_NOAUTORESIZEY))
{
ChildCoords[3] = cgp->Coords[3];
Coords[3] = cgp->Coords[3] + BorderSizes[3];
}
}
//Find caption coordinates
if(!(Style & WS_NOTITLEBAR))
{
int close_w,close_h,hide_w,hide_h;
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_CLOSE)))
IMG_INFO(GetCIEImageHandle(WCI_CLOSE), &close_w, &close_h);
else
gr_get_string_size(&close_w, &close_h, "X");
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_HIDE)))
IMG_INFO(GetCIEImageHandle(WCI_HIDE), &hide_w, &hide_h);
else
gr_get_string_size(&hide_w, &hide_h, "-");
int caption_min_size;
if(Caption.size() > 0)
{
gr_get_string_size(&w, &h, (char *)Caption.c_str());
caption_min_size = w + close_w + hide_w;
}
else
{
caption_min_size = close_w + hide_w;
}
if((Coords[2] - Coords[0]) < (caption_min_size))
Coords[2] = Coords[0] + caption_min_size + BorderSizes[0] + BorderSizes[2];
if(Caption.size() > 0)
{
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_CAPTION)))
{
int cw, ch;
CaptionCoords[0] = Coords[0] + BorderSizes[0];
CaptionCoords[1] = Coords[1] + BorderSizes[1];
GetCIECoords(WCI_CAPTION, &CaptionCoords[0], &CaptionCoords[1]);
//do the image
IMG_INFO(GetCIEImageHandle(WCI_CAPTION), &cw, &ch);
num = (float) w / cw;
CaptionRectList = bitmap_rect_list(Coords[0] + CornerWidths[2], Coords[1], w, ch, 0, 0, 1.0f, 1.0f);
h = ch;
}
else
{
h += 5;
CaptionCoords[0] = Coords[0] +(((Coords[2]-Coords[0]) - w) / 2);
CaptionCoords[1] = Coords[1] + BorderSizes[1];
}
CaptionCoords[2] = CaptionCoords[0] + w;
CaptionCoords[3] = CaptionCoords[1] + h;
}
//Find close coordinates now
CloseCoords[0] = Coords[2] - close_w;
CloseCoords[1] = Coords[1] + BorderSizes[1];
GetCIECoords(WCI_CLOSE, &CloseCoords[0], &CloseCoords[1]);
CloseCoords[2] = CloseCoords[0] + close_w;
CloseCoords[3] = CloseCoords[1] + close_h;
//Find hide coordinates now
HideCoords[0] = CloseCoords[0] - hide_w;
HideCoords[1] = CloseCoords[1];
GetCIECoords(WCI_HIDE, &HideCoords[0], &HideCoords[1]);
HideCoords[2] = HideCoords[0] + hide_w;
HideCoords[3] = HideCoords[1] + hide_h;
}
//Do bitmap stuff
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM)))
{
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM), &w, &h);
num = (float)((Coords[2]-CornerWidths[3])-(Coords[0]+CornerWidths[2])) / (float)w;
BorderRectLists[CIE_HANDLE_TM] = bitmap_rect_list(Coords[0] + CornerWidths[2], Coords[1], fl2i(w*num),h,0,0,num,1.0f);
//gr_bitmap_list(&BorderRectLists[CIE_HANDLE_BM], 1, false);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM)))
{
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM), &w, &h);
num = (float)((Coords[2]-CornerWidths[3])-(Coords[0]+CornerWidths[2])) / (float)w;
BorderRectLists[CIE_HANDLE_BM] = bitmap_rect_list(Coords[0] + CornerWidths[2], Coords[3]-h, fl2i(w*num),h,0,0,num,1.0f);
//gr_bitmap_list(&BorderRectLists[CIE_HANDLE_BM], 1, false);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML)))
{
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML), &w, &h);
num = (float)((Coords[3]-BorderSizes[3])-(Coords[1]+BorderSizes[1])) / (float)h;
BorderRectLists[CIE_HANDLE_ML] = bitmap_rect_list(Coords[0], Coords[1] + BorderSizes[1], w,fl2i(h*num),0,0,1.0f,num);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR)))
{
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR), &w, &h);
num = (float)((Coords[3]-BorderSizes[3])-(Coords[1]+BorderSizes[1])) / (float)h;
BorderRectLists[CIE_HANDLE_MR] = bitmap_rect_list(Coords[2]-w, Coords[1] + BorderSizes[1], w,fl2i(h*num),0,0,1.0f,num);
}
return OF_TRUE;
}
int Window::DoMouseOver(float frametime)
{
if(OwnerSystem->GetMouseX() >= HideCoords[0]
&& OwnerSystem->GetMouseX() <= HideCoords[2]
&& OwnerSystem->GetMouseY() >= HideCoords[1]
&& OwnerSystem->GetMouseY() <= HideCoords[3])
{
HideHighlight = true;
}
else
HideHighlight = false;
if(OwnerSystem->GetMouseX() >= CloseCoords[0]
&& OwnerSystem->GetMouseX() <= CloseCoords[2]
&& OwnerSystem->GetMouseY() >= CloseCoords[1]
&& OwnerSystem->GetMouseY() <= CloseCoords[3])
{
CloseHighlight = true;
}
else
CloseHighlight = false;
return OF_TRUE;
}
int Window::DoMouseDown(float frametime)
{
OwnerSystem->SetActiveObject(this);
if(Style & WS_NONMOVEABLE)
return OF_TRUE;
if((OwnerSystem->GetGraspedObject() == NULL)
&& (Status & GST_MOUSE_LEFT_BUTTON)
&& OwnerSystem->GetMouseX() >= CaptionCoords[0]
&& ((OwnerSystem->GetMouseX() < CaptionCoords[2]) || ((Style & WS_NOTITLEBAR) && OwnerSystem->GetMouseX() <= Coords[2]))
&& OwnerSystem->GetMouseY() >= CaptionCoords[1]
&& ((OwnerSystem->GetMouseY() <= CaptionCoords[3]) || ((Style & WS_NOTITLEBAR) && OwnerSystem->GetMouseY() <= Coords[2])))
{
OwnerSystem->SetGraspedObject(this, GST_MOUSE_LEFT_BUTTON);
}
//All further movement of grasped objects is handled by GUISystem
return OF_TRUE;
}
int Window::DoMouseUp(float frametime)
{
if (Style & WS_NONMOVEABLE)
return OF_TRUE;
if(CloseHighlight)
{
Delete();
return OF_TRUE;
}
if(HideHighlight)
{
if(Style & GS_HIDDEN)
{
Coords[3] = UnhiddenHeight;
Style &= ~GS_HIDDEN;
}
else
{
UnhiddenHeight = Coords[3];
Coords[3] = Coords[1] + BorderSizes[1] + BorderSizes[3];
Style |= GS_HIDDEN;
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM)))
{
int h;
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM), NULL, &h);
BorderRectLists[CIE_HANDLE_BM].screen_rect.y = Coords[3] - h;
}
}
return OF_TRUE;
}
int Window::DoMouseOut(float frametime)
{
HideHighlight = false;
CloseHighlight = false;
return OF_TRUE;
}
void Window::DoMove(int dx, int dy)
{
CloseCoords[0] += dx;
CloseCoords[1] += dy;
CloseCoords[2] += dx;
CloseCoords[3] += dy;
HideCoords[0] += dx;
HideCoords[1] += dy;
HideCoords[2] += dx;
HideCoords[3] += dy;
CaptionCoords[0] += dx;
CaptionCoords[1] += dy;
CaptionCoords[2] += dx;
CaptionCoords[3] += dy;
//Handle moving the border around
uint i;
for(i = 0; i < 8; i++)
{
BorderRectLists[i].screen_rect.x += dx;
BorderRectLists[i].screen_rect.y += dy;
}
//now the caption
CaptionRectList.screen_rect.x += dx;
CaptionRectList.screen_rect.y += dy;
}
void draw_open_rect(int x1, int y1, int x2, int y2, bool resize = false)
{
gr_line(x1, y1, x2, y1, resize);
gr_line(x2, y1, x2, y2, resize);
gr_line(x2, y2, x1, y2, resize);
gr_line(x1, y2, x1, y1, resize);
}
void Window::DoDraw(float frametime)
{
gr_set_color_fast(&Color_text_normal);
int w, h;
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TL)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TL));
IMG_DRAW(Coords[0], Coords[1]);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR));
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TR), &w, NULL);
IMG_DRAW(Coords[2] - w, Coords[1]);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL)))
{
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL), NULL, &h);
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BL));
IMG_DRAW(Coords[0], Coords[3] - h);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR));
IMG_INFO(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BR), &w, &h);
//IMG_DRAW(Coords[2] - w, Coords[3] - h, false);
IMG_DRAW(Coords[2]-w, Coords[3] - h);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_TM));
gr_bitmap_list(&BorderRectLists[CIE_HANDLE_TM], 1, false);
}
else
{
gr_line(Coords[0] + BorderSizes[0], Coords[1], Coords[2] - BorderSizes[2], Coords[1], false);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_BM));
gr_bitmap_list(&BorderRectLists[CIE_HANDLE_BM], 1, false);
}
else
{
gr_line(Coords[0] + BorderSizes[0], Coords[3], Coords[2] - BorderSizes[2], Coords[3], false);
}
if(!(Style & GS_HIDDEN))
{
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_ML));
gr_bitmap_list(&BorderRectLists[CIE_HANDLE_ML], 1, false);
}
else
{
gr_line(Coords[0], Coords[1] + BorderSizes[1], Coords[0], Coords[3] - BorderSizes[3], false);
}
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR)))
{
IMG_SET(GetCIEImageHandle(WCI_BORDER, CIE_HANDLE_MR));
gr_bitmap_list(&BorderRectLists[CIE_HANDLE_MR], 1, false);
}
else
{
gr_line(Coords[2], Coords[1] + BorderSizes[1], Coords[2], Coords[3] - BorderSizes[3], false);
}
}
if(!(Style & WS_NOTITLEBAR))
{
//Draw the caption background
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_CAPTION)))
{
IMG_SET(GetCIEImageHandle(WCI_CAPTION));
gr_bitmap_list(&CaptionRectList, 1, false);
}
else
{
draw_open_rect(Coords[0], Coords[1], Coords[2], CaptionCoords[3]);
}
//Close button
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_CLOSE)))
{
if(CloseHighlight && IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_CLOSE, CIE_HANDLE_M)))
IMG_SET(GetCIEImageHandle(WCI_CLOSE, CIE_HANDLE_M));
else
IMG_SET(GetCIEImageHandle(WCI_CLOSE));
IMG_DRAW(CloseCoords[0], CloseCoords[1]);
}
else
{
if(CloseHighlight)
gr_set_color_fast(&Color_text_active);
else
gr_set_color_fast(&Color_text_normal);
gr_string(CloseCoords[0], CloseCoords[1], "X", false);
}
//Hide button
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_HIDE)))
{
if(HideHighlight && IMG_HANDLE_IS_VALID(GetCIEImageHandle(WCI_HIDE, CIE_HANDLE_M)))
IMG_SET(GetCIEImageHandle(WCI_HIDE, CIE_HANDLE_M));
else
IMG_SET(GetCIEImageHandle(WCI_HIDE));
IMG_DRAW(HideCoords[0], HideCoords[1]);
}
else
{
if(HideHighlight)
gr_set_color_fast(&Color_text_active);
else
gr_set_color_fast(&Color_text_normal);
gr_string(HideCoords[0], HideCoords[1], "-", false);
}
//Caption text
gr_set_color_fast(&Color_text_normal);
gr_string(CaptionCoords[0], CaptionCoords[1], (char *)Caption.c_str(), false);
}
}
Window::Window(std::string in_caption, int x_coord, int y_coord, int x_width, int y_width, int in_style)
:GUIObject(in_caption, x_coord,y_coord,x_width,y_width,in_style)
{
Caption = in_caption;
CloseHighlight = false;
HideHighlight = false;
//Set the type
Type = GT_WINDOW;
}
//*****************************Button*******************************
Button::Button(std::string in_caption, int x_coord, int y_coord, void (*in_function)(Button *caller), int x_width, int y_height, int in_style)
:GUIObject(in_caption, x_coord, y_coord, x_width, y_height, in_style)
{
Caption = in_caption;
function = in_function;
IsDown = false;
//Set the type
Type = GT_BUTTON;
}
int Button::DoRefreshSize()
{
int w, h;
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(BCI_BUTTON)))
{
IMG_INFO(GetCIEImageHandle(BCI_BUTTON), &w, &h);
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + w;
}
if(!(Style & GS_NOAUTORESIZEY))
{
Coords[3] = Coords[1] + h;
}
}
else
{
gr_get_string_size(&w, &h, (char *)Caption.c_str());
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + w;
}
if(!(Style & GS_NOAUTORESIZEY))
{
Coords[3] = Coords[1] + h;
}
}
return OF_TRUE;
}
void Button::DoDraw(float frametime)
{
if(IMG_HANDLE_IS_VALID(GetCIEImageHandle(BCI_BUTTON)))
{
IMG_SET(GetCIEImageHandle(BCI_BUTTON));
if((Status & GST_MOUSE_OVER) && IMG_HANDLE_IS_VALID(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_M)))
IMG_SET(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_M));
else if((Status & GST_MOUSE_LEFT_BUTTON) && IMG_HANDLE_IS_VALID(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_C)))
IMG_SET(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_C));
else if((Style & BS_STICKY) && IsDown && IMG_HANDLE_IS_VALID(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_S)))
IMG_SET(GetCIEImageHandle(BCI_BUTTON, CIE_HANDLE_S));
IMG_DRAW(Coords[0], Coords[1]);
}
else
{
if(Status == 0)
gr_set_color_fast(&Color_text_normal);
else if(Status & GST_MOUSE_OVER)
gr_set_color_fast(&Color_text_active);
else
gr_set_color_fast(&Color_text_selected);
draw_open_rect(Coords[0], Coords[1], Coords[2], Coords[3], false);
int half_x, half_y;
gr_get_string_size(&half_x, &half_y, (char *)Caption.c_str());
half_x = Coords[0] +(((Coords[2]-Coords[0]) - half_x) / 2);
half_y = Coords[1] +(((Coords[3]-Coords[1]) - half_y) / 2);
gr_string(half_x, half_y, (char *)Caption.c_str(), false);
}
}
int Button::DoMouseDown(float frametime)
{
OwnerSystem->SetActiveObject(this);
if(!(Style & BS_STICKY))
IsDown = true;
return OF_TRUE;
}
int Button::DoMouseUp(float frametime)
{
if(function != NULL)
{
function(this);
}
if(!(Style & BS_STICKY))
IsDown = false;
else
IsDown = !IsDown;
return OF_TRUE;
}
int Button::DoMouseOut(float frametime)
{
if(!(Style & BS_STICKY))
IsDown = false;
return OF_TRUE;
}
//*****************************Menu*******************************
TreeItem::TreeItem()
:LinkedList()
{
Function = NULL;
Data=0;
ShowThis=true;
ShowChildren=false;
DeleteData=true;
memset(Coords, 0, sizeof(Coords));
}
void TreeItem::ClearAllItems()
{
LinkedList* cgp = GET_FIRST(&Children);
LinkedList* cgp_next;
for(; cgp != END_OF_LIST(&Children); cgp = cgp_next)
{
cgp_next = GET_NEXT(cgp);
delete cgp;
}
}
TreeItem::~TreeItem()
{
ClearAllItems();
}
void Tree::CalcItemsSize(TreeItem *items, int DrawData[4])
{
//DrawData
//0 - indent
//1 - largest width so far
//2 - total height so far
//3 - Are we done?
int w, h;
int temp_largest = DrawData[1];
for(TreeItem* tip = (TreeItem*)GET_FIRST(items); tip != END_OF_LIST(items); tip = (TreeItem*)GET_NEXT(tip))
{
if(!DrawData[3])
{
gr_get_string_size(&w, &h, (char*)tip->Name.c_str());
if((w + DrawData[0]) > temp_largest)
temp_largest = w + DrawData[0];
//This should really be moved to where we handle the scrolling code
//I'm not doing that right now. :)
//Or at least this should be called from that
if(((DrawData[2] + h) > Coords[3] && (Style & GS_NOAUTORESIZEY))
|| (temp_largest > Coords[2] && (Style & GS_NOAUTORESIZEX))
//|| ((Coords[0] + w) > OwnerSystem->Guiobjects.Coords[2])
//|| ((Coords[1] + h) > OwnerSystem->Guiobjects.Coords[3])
)
{
DrawData[3] = 1;
tip->ShowThis = false;
}
else
tip->ShowThis = true;
//Do we care?
if(tip->ShowThis)
{
if((w + DrawData[0]) > DrawData[1])
DrawData[1] = w + DrawData[0];
tip->Coords[0] = Coords[0] + DrawData[0];
tip->Coords[1] = Coords[1] + DrawData[2];
tip->Coords[2] = Coords[0] + DrawData[0] + w;
tip->Coords[3] = Coords[1] + DrawData[2] + h;
DrawData[2] += h;
if(NOT_EMPTY(&tip->Children) && tip->ShowChildren)
{
//Indent
DrawData[0] += TI_INDENT_PER_LEVEL;
CalcItemsSize((TreeItem*)&tip->Children, DrawData);
DrawData[0] -= TI_INDENT_PER_LEVEL;
}
}
}
if(DrawData[3] || !tip->ShowThis)
{
tip->ShowThis = false;
tip->ShowChildren = false;
tip->Coords[0] = tip->Coords[1] = tip->Coords[2] = tip->Coords[3] = -1;
}
}
}
int Tree::DoRefreshSize()
{
//DrawData
//0 - indent
//1 - largest width so far
//2 - total height so far
//3 - Are we done? 0=no,1=yes
int DrawData[4] = {TI_INITIAL_INDENT,0,TI_INITIAL_INDENT_VERTICAL,0};
CalcItemsSize(&Items, DrawData);
//CalcItemsSize takes into account limited height/width
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + DrawData[1] + TI_BORDER_WIDTH;
}
if(!(Style & GS_NOAUTORESIZEY))
{
Coords[3] = Coords[1] + DrawData[2] + TI_BORDER_HEIGHT;
if(Parent != NULL)
{
if(DrawData[2] >= Parent->ChildCoords[3])
{
//The parent must resize.
}
}
}
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + DrawData[1];
}
return OF_TRUE;
}
Tree::Tree(std::string in_name, int x_coord, int y_coord, void* in_associateditem, int x_width, int y_height, int in_style)
:GUIObject(in_name, x_coord, y_coord, x_width, y_height, in_style)
{
AssociatedItem = in_associateditem;
//Set the type
Type = GT_MENU;
}
void Tree::DrawItems(TreeItem *items)
{
for(TreeItem* tip = (TreeItem*)GET_FIRST(items); tip != END_OF_LIST(items); tip = (TreeItem*)GET_NEXT(tip))
{
if(tip->ShowThis)
{
if(SelectedItem == tip)
gr_set_color_fast(&Color_text_selected);
else if(HighlightedItem == tip)
gr_set_color_fast(&Color_text_active);
else
gr_set_color_fast(&Color_text_normal);
gr_string(tip->Coords[0], tip->Coords[1], (char*)tip->Name.c_str(), false);
if(NOT_EMPTY(&tip->Children) && tip->ShowChildren)
{
DrawItems((TreeItem*)&tip->Children);
}
}
}
}
void Tree::DoDraw(float frametime)
{
if(EMPTY(&Items))
return;
DrawItems(&Items);
gr_set_color_fast(&Color_text_normal);
draw_open_rect(Coords[0], Coords[1], Coords[2], Coords[3]);
}
TreeItem* Tree::HitTest(TreeItem *items)
{
TreeItem *hti = NULL; //Highlighted item
for(TreeItem *tip = (TreeItem*)GET_FIRST(items);tip != END_OF_LIST(items); tip = (TreeItem*)GET_NEXT(tip))
{
if(OwnerSystem->GetMouseX() >= tip->Coords[0]
&& OwnerSystem->GetMouseX() <= tip->Coords[2]
&& OwnerSystem->GetMouseY() >= tip->Coords[1]
&& OwnerSystem->GetMouseY() <= tip->Coords[3])
{
hti = tip;
}
if(hti != NULL)
return hti;
else if(NOT_EMPTY(&tip->Children) && tip->ShowChildren)
hti = HitTest((TreeItem*)&tip->Children);
if(hti != NULL)
return hti;
}
return hti;
}
int Tree::DoMouseOver(float frametime)
{
HighlightedItem = HitTest(&Items);
return OF_TRUE;
}
int Tree::DoMouseDown(float frametime)
{
OwnerSystem->SetActiveObject(this);
return OF_TRUE;
}
int Tree::DoMouseUp(float frametime)
{
OwnerSystem->SetActiveObject(this);
if(HighlightedItem != NULL)
{
SelectedItem = HighlightedItem;
SelectedItem->ShowChildren = !SelectedItem->ShowChildren;
if(NOT_EMPTY(&SelectedItem->Children))
{
OnRefreshSize(); //Unfortunately
}
if(SelectedItem->Function != NULL)
{
SelectedItem->Function(this);
}
}
return OF_TRUE;
}
void Tree::MoveTreeItems(int dx, int dy, TreeItem *items)
{
for(TreeItem *tip = (TreeItem*)GET_FIRST(items);tip != END_OF_LIST(items); tip = (TreeItem*)GET_NEXT(tip))
{
if(tip->ShowThis)
{
tip->Coords[0] += dx;
tip->Coords[1] += dy;
tip->Coords[2] += dx;
tip->Coords[3] += dy;
if(NOT_EMPTY(&tip->Children) && tip->ShowChildren)
MoveTreeItems(dx, dy, (TreeItem*)&tip->Children);
}
}
}
void Tree::DoMove(int dx, int dy)
{
MoveTreeItems(dx, dy, &Items);
}
TreeItem* Tree::AddItem(TreeItem *parent, std::string in_name, int in_data, bool in_delete_data, void (*in_function)(Tree* caller))
{
TreeItem *ni = new TreeItem;
ni->Parent = parent;
ni->Name = in_name;
ni->Data = in_data;
ni->DeleteData = in_delete_data;
ni->Function = in_function;
if(parent != NULL)
list_append(&parent->Children, ni);
else
list_append(&Items, ni);
OnRefreshSize();
return ni;
}
void Tree::ClearItems()
{
Items.ClearAllItems();
}
//*****************************Text*******************************
int Text::DoRefreshSize()
{
int width;
if(Style & GS_NOAUTORESIZEX)
width = Coords[2] - Coords[0];
else if(Parent != NULL && (Parent->Style & GS_NOAUTORESIZEX))
width = Parent->ChildCoords[2] - Coords[0];
else
width = gr_screen.clip_right - Coords[0];
NumLines = split_str((char*)Content.c_str(), width, LineLengths, LineStartPoints, MAX_TEXT_LINES);
//Find the shortest width we need to show all the shortened strings
int longest_width = 0;
int width_test;
for(int i = 0; i < NumLines; i++)
{
gr_get_string_size(&width_test, NULL, LineStartPoints[i], LineLengths[i]);
if(width_test > longest_width)
longest_width = width_test;
}
if(longest_width < width)
width = longest_width;
//Resize along the Y axis
if(Style & GS_NOAUTORESIZEY)
{
int new_height = (Coords[3] - Coords[1]) / gr_get_font_height();
if(new_height < NumLines)
NumLines = new_height;
}
else
{
Coords[3] = Coords[1] + gr_get_font_height() * NumLines;
if(Parent != NULL)
{
if(Coords[3] >= Parent->ChildCoords[3] && (Parent->Style & GS_NOAUTORESIZEY))
{
Coords[3] = Coords[1] + (Parent->ChildCoords[3] - Coords[1]);
NumLines = (Coords[3] - Coords[1]) / gr_get_font_height();
}
}
}
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + width;
}
if(Style & T_EDITTABLE)
{
ChildCoords[0] = Coords[0] + 1;
ChildCoords[1] = Coords[1] + 1;
ChildCoords[2] = Coords[2] - 1;
ChildCoords[3] = Coords[3] - 1;
}
else
{
ChildCoords[0] = Coords[0];
ChildCoords[1] = Coords[1];
ChildCoords[2] = Coords[2];
ChildCoords[3] = Coords[3];
}
//Tell the parent to recalculate its size too
return OF_TRUE;
}
int Text::DoMouseDown(float frametime)
{
//Make this the active object
if(Style & T_EDITTABLE)
{
OwnerSystem->SetActiveObject(this);
//For now, always set the cursor pos to the end
CursorPos = Content.size();
return OF_TRUE;
}
else
{
return OF_FALSE;
}
}
void Text::DoDraw(float frametime)
{
if(OwnerSystem->GetActiveObject() != this)
gr_set_color_fast(&Color_text_normal);
else
gr_set_color_fast(&Color_text_active);
if(Style & T_EDITTABLE)
{
draw_open_rect(Coords[0], Coords[1], Coords[2], Coords[3]);
}
//Don't draw anything. Besides, it crashes
if(!Content.length())
return;
int font_height = gr_get_font_height();
for(int i = 0; i < NumLines; i++)
{
gr_string(ChildCoords[0], ChildCoords[1] + (i*font_height), (char*)Content.substr(LineStartPoints[i] - Content.c_str(), LineLengths[i]).c_str(), false);
}
}
extern int keypad_to_ascii(int c);
int Text::DoKeyPress(float frametime)
{
if(!(Style & T_EDITTABLE))
return OF_FALSE;
switch(OwnerSystem->GetKeyPressed())
{
case KEY_BACKSP:
Content = Content.substr(0, Content.length() - 1);
break;
case KEY_ENTER:
if(SaveType & T_ST_ONENTER)
{
if(Save())
OwnerSystem->SetActiveObject(Parent);
else
Load();
}
break;
case KEY_ESC:
Load();
OwnerSystem->SetActiveObject(Parent);
break;
default:
{
//Figure out what key, exactly, we have
int symbol = keypad_to_ascii(OwnerSystem->GetKeyPressed());
if(symbol == -1)
symbol = key_to_ascii(OwnerSystem->GetKeyPressed());
//Is it ok with us?
if(iscntrl(symbol))
{
return OF_FALSE; //Guess not
}
else if(SaveType & T_ST_INT)
{
if(!isdigit(symbol) && symbol != '-')
return OF_FALSE;
}
else if(SaveType & T_ST_FLOAT)
{
if(!isdigit(symbol) && symbol != '.' && symbol != '-')
return OF_FALSE;
}
else if(SaveType & T_ST_UBYTE)
{
if(!isdigit(symbol))
return OF_FALSE;
}
else if(!isalnum(symbol) && symbol != ' ')
{
return OF_FALSE;
}
//We can add the letter to the box. Cheers.
//If this warning bothers you, go ahead and cast it.
Content += symbol;
if(SaveType & T_ST_REALTIME)
{
Save();
}
}
}
OnRefreshSize();
return OF_TRUE;
}
Text::Text(std::string in_name, std::string in_content, int x_coord, int y_coord, int x_width, int y_height, int in_style)
:GUIObject(in_name, x_coord, y_coord, x_width, y_height, in_style)
{
Content = in_content;
NumLines = 0;
SaveType = T_ST_NONE;
CursorPos = -1; //Not editing
Type = GT_TEXT;
}
void Text::SetText(std::string in_content)
{
Content = in_content;
OnRefreshSize();
}
void Text::SetText(int the_int)
{
char buf[33];
sprintf(buf, "%d", the_int);
Content = buf;
OnRefreshSize();
}
void Text::SetText(float the_float)
{
char buf[32];
sprintf(buf, "%f", the_float);
Content = buf;
OnRefreshSize();
}
void Text::AddLine(std::string in_line)
{
Content += in_line;
OnRefreshSize();
}
void Text::SetSaveLoc(int *int_ptr, int save_method, int max_value, int min_value)
{
Assert(int_ptr != NULL); //Naughty.
Assert(min_value < max_value); //Mmm-hmm.
SaveType = T_ST_INT;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
iSavePointer = int_ptr;
SaveMax = max_value;
SaveMin = min_value;
}
void Text::SetSaveLoc(short int *sint_ptr, int save_method, short int max_value, short int min_value)
{
Assert(sint_ptr != NULL); //Naughty.
Assert(min_value < max_value); //Mmm-hmm.
SaveType = T_ST_SINT;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
siSavePointer = sint_ptr;
SaveMax = max_value;
SaveMin = min_value;
}
void Text::SetSaveLoc(float *ptr, int save_method, float max_value, float min_value)
{
Assert(ptr != NULL); //Naughty.
Assert(min_value < max_value); //Causes problems with floats
SaveType = T_ST_FLOAT;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
flSavePointer = ptr;
flSaveMax = max_value;
flSaveMin = min_value;
}
void Text::SetSaveLoc(char *ptr, int save_method, uint max_length, uint min_length)
{
Assert(ptr != NULL); //Naughty.
SaveType = T_ST_CHAR;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
chSavePointer = ptr;
uSaveMax = max_length;
uSaveMin = min_length;
}
void Text::SetSaveStringAlloc(char **ptr, int save_method, int mem_flags, uint max_length, uint min_length)
{
Assert(ptr != NULL); //Naughty.
if(mem_flags == T_ST_NEW)
SaveType = T_ST_NEW;
else if(mem_flags == T_ST_MALLOC)
SaveType = T_ST_MALLOC;
else
return; //This MUST use some sort of mem allocation
SaveType |= T_ST_CHAR;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
chpSavePointer = ptr;
uSaveMax = max_length;
uSaveMin = min_length;
}
void Text::SetSaveLoc(ubyte *ptr, int save_method, int max_value, int min_value)
{
Assert(ptr != NULL); //Naughty.
Assert(min_value < max_value); //Mmm-hmm.
SaveType = T_ST_UBYTE;
if(save_method == T_ST_CLOSE)
SaveType |= T_ST_CLOSE;
else if(save_method == T_ST_REALTIME)
SaveType |= T_ST_REALTIME;
else if(save_method == T_ST_ONENTER)
SaveType |= T_ST_ONENTER;
ubSavePointer = ptr;
SaveMax = max_value;
SaveMin = min_value;
}
bool Text::Save()
{
if(SaveType == T_ST_NONE)
return false;
if(SaveType & T_ST_INT)
{
int the_int = atoi(Content.c_str());
if(the_int <= SaveMax && the_int >= SaveMin)
{
*iSavePointer = the_int;
return true;
}
}
else if(SaveType & T_ST_SINT)
{
int the_sint = atoi(Content.c_str());
if(the_sint <= SaveMax && the_sint >= SaveMin)
{
*siSavePointer = the_sint;
return true;
}
}
else if(SaveType & T_ST_FLOAT)
{
float the_float = (float)atof(Content.c_str());
if(the_float <= flSaveMax && the_float >= flSaveMin)
{
*flSavePointer = the_float;
return true;
}
}
else if(SaveType & T_ST_CHAR)
{
size_t len = Content.length();
if(SaveType & T_ST_NEW
&& len < uSaveMax)
{
if(*chpSavePointer != NULL)
delete[] *chpSavePointer;
*chpSavePointer = new char[len + 1];
strcpy(*chpSavePointer, Content.c_str());
return true;
}
else if(SaveType & T_ST_MALLOC
&& len < uSaveMax)
{
if(*chpSavePointer != NULL)
vm_free(*chpSavePointer);
*chpSavePointer = (char*)vm_malloc(sizeof(char) * (len + 1));
strcpy(*chpSavePointer, Content.c_str());
return true;
}
else if(len < uSaveMax)
{
strcpy(chSavePointer, Content.c_str());
return true;
}
}
else if(SaveType & T_ST_UBYTE)
{
int the_int = atoi(Content.c_str());
if(the_int <= SaveMax && the_int >= SaveMin)
{
*ubSavePointer = (ubyte)the_int;
return true;
}
}
return false;
}
void Text::Load()
{
if(SaveType == T_ST_NONE)
return;
if(SaveType & T_ST_INT)
SetText(*iSavePointer);
else if(SaveType & T_ST_FLOAT)
SetText(*flSavePointer);
else if((SaveType & T_ST_CHAR) && (SaveType & (T_ST_MALLOC | T_ST_NEW)))
SetText(*chpSavePointer);
else if(SaveType & T_ST_CHAR)
SetText(chSavePointer);
else if(SaveType & T_ST_UBYTE)
SetText(*ubSavePointer);
else
Warning(LOCATION, "Unknown type (or no type) given in Text::Load() - nothing happened.");
}
//*****************************Checkbox*******************************
Checkbox::Checkbox(std::string in_label, int x_coord, int y_coord, void (*in_function)(Checkbox *caller), int x_width, int y_height, int in_style)
:GUIObject(in_label, x_coord, y_coord, x_width, y_height, in_style)
{
Label = in_label;
function = in_function;
IsChecked = false;
HighlightStatus = 0;
FlagPtr = NULL;
//Set the type
Type = GT_CHECKBOX;
}
int Checkbox::DoRefreshSize()
{
int w, h,tw,th;
gr_get_string_size(&w, &h, (char *)Label.c_str());
tw = w;
th = h;
gr_get_string_size(&w, &h, "X");
tw += w;
th += h + CB_TEXTCHECKDIST; //Spacing b/t 'em
CheckCoords[0] = Coords[0];
CheckCoords[1] = Coords[1];
CheckCoords[2] = Coords[0] + w;
CheckCoords[3] = Coords[1] + h;
if(!(Style & GS_NOAUTORESIZEX))
{
Coords[2] = Coords[0] + tw;
}
if(!(Style & GS_NOAUTORESIZEY))
{
Coords[3] = Coords[1] + th;
}
return OF_TRUE;
}
void Checkbox::DoMove(int dx, int dy)
{
CheckCoords[0] += dx;
CheckCoords[2] += dx;
CheckCoords[1] += dy;
CheckCoords[3] += dy;
}
void Checkbox::DoDraw(float frametime)
{
if(HighlightStatus == 1)
gr_set_color_fast(&Color_text_active);
else if(HighlightStatus == 2)
gr_set_color_fast(&Color_text_selected);
else
gr_set_color_fast(&Color_text_normal);
draw_open_rect(CheckCoords[0], CheckCoords[1], CheckCoords[2], CheckCoords[3], false);
if((IsChecked && FlagPtr == NULL) || (FlagPtr!= NULL && ((*FlagPtr) & Flag)))
gr_string(CheckCoords[0], CheckCoords[1], "X", false);
gr_set_color_fast(&Color_text_normal);
gr_string(CheckCoords[2] + CB_TEXTCHECKDIST, CheckCoords[1], (char *)Label.c_str(), false);
}
int Checkbox::DoMouseOver(float frametime)
{
if(OwnerSystem->GetMouseX() >= CheckCoords[0]
&& OwnerSystem->GetMouseX() <= CheckCoords[2]
&& OwnerSystem->GetMouseY() >= CheckCoords[1]
&& OwnerSystem->GetMouseY() <= CheckCoords[3])
HighlightStatus = 1;
return OF_TRUE;
}
int Checkbox::DoMouseDown(float frametime)
{
OwnerSystem->SetActiveObject(this);
if(OwnerSystem->GetMouseX() >= CheckCoords[0]
&& OwnerSystem->GetMouseX() <= CheckCoords[2]
&& OwnerSystem->GetMouseY() >= CheckCoords[1]
&& OwnerSystem->GetMouseY() <= CheckCoords[3])
HighlightStatus = 2;
return OF_TRUE;
}
int Checkbox::DoMouseUp(float frametime)
{
if(OwnerSystem->GetMouseX() >= CheckCoords[0]
&& OwnerSystem->GetMouseX() <= CheckCoords[2]
&& OwnerSystem->GetMouseY() >= CheckCoords[1]
&& OwnerSystem->GetMouseY() <= CheckCoords[3])
{
HighlightStatus = 1;
if(function != NULL)
{
function(this);
}
if(FlagPtr != NULL)
{
if(!(*FlagPtr & Flag))
{
*FlagPtr |= Flag;
IsChecked = true;
}
else
{
*FlagPtr &= ~Flag;
IsChecked = false;
}
}
else
{
IsChecked = !IsChecked;
}
}
return OF_TRUE;
}
int Checkbox::DoMouseOut(float frametime)
{
HighlightStatus = 0;
return OF_TRUE;
}
//*****************************ImageAnim*******************************
ImageAnim::ImageAnim(std::string in_name, std::string in_imagename, int x_coord, int y_coord, int x_width, int y_width, int in_style)
:GUIObject(in_name, x_coord, y_coord, x_width, y_width, in_style)
{
//Load the image
IsSet = false;
ImageHandle = -1;
ImageFlags = 0;
TotalFrames = 0;
FPS = 0;
Stop();
Type = GT_IMAGEANIM;
}
void ImageAnim::DoDraw(float frametime)
{
//Do nothing if nothing to draw
if(ImageHandle == -1)
return;
if(PlayType != PT_STOPPED)
{
if(PlayType == PT_PLAYING)
ElapsedTime += frametime;
else if(PlayType == PT_PLAYING_REVERSE)
ElapsedTime -= frametime;
Progress = ElapsedTime/TotalTime;
}
int CurrentFrame = fl2i(Progress * TotalFrames);
if(Progress > 1.0f)
{
if(ImageFlags & IF_BOUNCE)
{
Progress = 1.0f;
CurrentFrame = TotalFrames;
PlayType = PT_PLAYING_REVERSE;
}
else if(ImageFlags & IF_REPEAT)
{
Progress = 0.0f;
CurrentFrame = 0;
PlayType = PT_PLAYING;
}
else
{
Progress = 1.0f;
CurrentFrame = TotalFrames;
PlayType = PT_STOPPED;
}
}
else if(Progress < 1.0f)
{
if(ImageFlags & IF_BOUNCE)
{
Progress = 0.0f;
CurrentFrame = 0;
PlayType = PT_PLAYING;
}
else if(ImageFlags & IF_REPEAT && ImageFlags & (IF_REVERSED))
{
Progress = 1.0f;
CurrentFrame = TotalFrames;
PlayType = PT_PLAYING_REVERSE;
}
else
{
Progress = 0.0f;
CurrentFrame = 0;
PlayType = PT_STOPPED;
}
}
//IMG_SET_FRAME(ImageHandle, CurrentFrame);
gr_set_bitmap( ImageHandle + CurrentFrame, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1-((Progress - (float)(CurrentFrame / TotalFrames)) / (float)(TotalFrames/CurrentFrame)));
IMG_DRAW(Coords[0], Coords[1]);
gr_set_bitmap( ImageHandle + CurrentFrame + 1, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, ((Progress - (float)(CurrentFrame / TotalFrames)) / (float)(TotalFrames/CurrentFrame)));
IMG_DRAW(Coords[0], Coords[1]);
}
int ImageAnim::DoRefreshSize()
{
//TODO: Fill this in
return OF_FALSE;
}
void ImageAnim::SetImage(std::string in_imagename)
{
if(in_imagename.size())
{
ImageHandle = IMG_LOAD_ANIM((char*)in_imagename.c_str(), &TotalFrames, &FPS);
TotalTime = (float) (TotalFrames/FPS);
if(IMG_HANDLE_IS_INVALID(ImageHandle))
{
ImageHandle = IMG_LOAD((char*)in_imagename.c_str());
if(IMG_HANDLE_IS_VALID(ImageHandle))
TotalFrames = 1;
else
TotalFrames = 0;
FPS = 0;
TotalTime = 0.0f;
}
}
//This takes care of setting up the play-flags
Stop();
IsSet = true;
OnRefreshSize();
}
void ImageAnim::Play(bool in_isreversed)
{
if(ImageFlags & IF_REVERSED)
PlayType = PT_PLAYING;
}
void ImageAnim::Pause()
{
if(PlayType == PT_PLAYING)
PlayType = PT_STOPPED;
else
PlayType = PT_STOPPED_REVERSE;
}
void ImageAnim::Stop()
{
if(ImageFlags & IF_REVERSED)
PlayType = PT_STOPPED_REVERSE;
else
PlayType = PT_STOPPED;
Progress = 0.0f;
ElapsedTime = 0.0f;
}
#ifdef USE_PYTHON
//*****************************HUDGauge*******************************
HUDGauge::HUDGauge(std::string in_name, int x_coord, int y_coord, PyBytecode in_drawfunc, int x_width, int y_height, int in_style)
:GUIObject(in_name, x_coord, y_coord, x_width, y_height, in_style)
{
Name = in_name;
DrawFunc = in_drawfunc;
//Set the type
Type = GT_HUDGAUGE;
}
void HUDGauge::DoDraw(float frametime)
{
if(DrawFunc.Get() != NULL)
{
}
}
HUDGauge::~HUDGauge()
{
}
#endif // USE_PYTHON