mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 17:46:53 -10:00
There are a lot of changes here that should probably be examined, namely the Debug Console (which had conflicts) and Yarn's "any resolution" mainhalls code (Which also had conflicts) but for the most part this should be fairly clean. git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10912 387891d4-d844-0410-90c0-e4c51a9137d3
2601 lines
65 KiB
C++
2601 lines
65 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.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#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);
|
|
}
|
|
|
|
//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_s(buf2, "</");
|
|
strcat_s(buf2, buf);
|
|
strcat_s(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)
|
|
{
|
|
int rval;
|
|
|
|
if (ClassInfoParsed) {
|
|
Warning(LOCATION, "Class info is being parsed twice");
|
|
DestroyClassInfo();
|
|
}
|
|
|
|
if ((rval = setjmp(parse_abort)) != 0) {
|
|
mprintf(("WMCGUI: Unable to parse '%s'! Error code = %i.\n", filename, rval));
|
|
return;
|
|
}
|
|
|
|
read_file_text(filename);
|
|
reset_parse();
|
|
ScreenClassInfo.Parse();
|
|
|
|
bool flag;
|
|
do {
|
|
ScreenClassInfoEntry* sciep = new ScreenClassInfoEntry;
|
|
flag = sciep->Parse();
|
|
if (flag) {
|
|
list_append(&ScreenClassInfo, sciep);
|
|
}
|
|
} while(flag);
|
|
|
|
ClassInfoParsed = true;
|
|
}
|
|
|
|
void ClassInfoEntry::Parse(char* tag, int in_type)
|
|
{
|
|
char buf[MAX_FILENAME_LEN];
|
|
strcpy_s(buf, "+");
|
|
strcat_s(buf, tag);
|
|
if (in_type != CIE_IMAGE_BORDER) {
|
|
strcat_s(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 && y!=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(const SCP_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;
|
|
}
|
|
}
|
|
|
|
ObjectClassInfoEntry *GUIScreen::GetObjectClassInfo(GUIObject *cgp)
|
|
{
|
|
size_t len;
|
|
uint i;
|
|
|
|
if (cgp->Parent != NULL && cgp->Parent->InfoEntry != NULL) {
|
|
len = cgp->Parent->InfoEntry->Subentries.size();
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (cgp->Parent->InfoEntry->Subentries[i].Name == cgp->Name) {
|
|
return &cgp->Parent->InfoEntry->Subentries[i];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if ( cgp->Parent->InfoEntry->Subentries[i].Name.size() == 0
|
|
&& cgp->Parent->InfoEntry->Subentries[i].Object == cgp->Type ) {
|
|
return &cgp->Parent->InfoEntry->Subentries[i];
|
|
}
|
|
}
|
|
} else if (cgp->Parent == NULL && ScreenClassInfo != NULL) {
|
|
len = ScreenClassInfo->Entries.size();
|
|
for (i = 0; i < len; i++) {
|
|
if (ScreenClassInfo->Entries[i].Name == cgp->Name) {
|
|
return &ScreenClassInfo->Entries[i];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if( ScreenClassInfo->Entries[i].Name.size() == 0 &&
|
|
ScreenClassInfo->Entries[i].Object == cgp->Type ) {
|
|
return &ScreenClassInfo->Entries[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) {
|
|
len = OwnerSystem->GetClassInfo()->Entries.size();
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (OwnerSystem->GetClassInfo()->Entries[i].Name == cgp->Name) {
|
|
return &OwnerSystem->GetClassInfo()->Entries[i];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if( OwnerSystem->GetClassInfo()->Entries[i].Name.size() == 0 &&
|
|
OwnerSystem->GetClassInfo()->Entries[i].Object == cgp->Type) {
|
|
return &OwnerSystem->GetClassInfo()->Entries[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
|
|
|
|
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;
|
|
|
|
//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
|
|
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 (size_t 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
|
|
cgp = (GUIObject*)GET_FIRST(&Guiobjects);
|
|
|
|
while (cgp != END_OF_LIST(&Guiobjects)) {
|
|
if ( !doevents ) {
|
|
cgp->Status = 0;
|
|
}
|
|
|
|
cgp->OnDraw(frametime);
|
|
|
|
cgp = (GUIObject*)GET_NEXT(cgp);
|
|
}
|
|
|
|
// 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;
|
|
MouseX = MouseY = 0;
|
|
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 SCP_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;
|
|
|
|
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;
|
|
}
|
|
|
|
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(const SCP_string &in_Name, int x_coord, int y_coord, int x_width, int y_height, int in_style)
|
|
{
|
|
//General stuff
|
|
LastStatus = Status = 0;
|
|
OwnerSystem = NULL;
|
|
OwnerScreen = NULL;
|
|
Parent = NULL;
|
|
CloseFunction = NULL;
|
|
|
|
list_init(this);
|
|
list_init(&Children);
|
|
|
|
//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);
|
|
}
|
|
|
|
DeleteChildren();
|
|
|
|
// Set these properly
|
|
next->prev = prev;
|
|
prev->next = next;
|
|
}
|
|
|
|
void GUIObject::DeleteChildren(GUIObject* exception)
|
|
{
|
|
if ( EMPTY(&Children) ) {
|
|
return;
|
|
}
|
|
|
|
GUIObject* cgp = (GUIObject*)GET_FIRST(&Children);
|
|
GUIObject* cgp_temp;
|
|
|
|
while (cgp != END_OF_LIST(&Children)) {
|
|
cgp_temp = cgp;
|
|
cgp = (GUIObject*)GET_NEXT(cgp);
|
|
delete cgp_temp;
|
|
}
|
|
|
|
list_init(&Children);
|
|
}
|
|
|
|
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
|
|
GUIObject *cgp = (GUIObject*)GET_LAST(&Children);
|
|
|
|
for ( ; (cgp != NULL) && (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_TRUE) {
|
|
(*unused_queue) &= ~GST_MOUSE_OVER;
|
|
}
|
|
}
|
|
|
|
//MOUSE DOWN
|
|
if (Status & GST_MOUSE_PRESS) {
|
|
rval = DoMouseDown(frametime);
|
|
|
|
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_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_TRUE) {
|
|
(*unused_queue) &= ~(GST_KEYBOARD_CTRL | GST_KEYBOARD_ALT | GST_KEYBOARD_SHIFT);
|
|
}
|
|
}
|
|
|
|
//KEYPRESS
|
|
if (Status & GST_KEYBOARD_KEYPRESS) {
|
|
rval = DoKeyPress(frametime);
|
|
|
|
if (rval == OF_TRUE) {
|
|
(*unused_queue) &= ~GST_KEYBOARD_KEYPRESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(Status & GST_MOUSE_OVER) && (LastStatus & GST_MOUSE_OVER)) {
|
|
rval = DoMouseOut(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 = 0,close_h = 0;
|
|
int hide_w = 0, hide_h = 0;
|
|
|
|
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, Caption.c_str());
|
|
caption_min_size = w + close_w + hide_w + 5;
|
|
} 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 - (close_w + hide_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, GR_RESIZE_NONE);
|
|
}
|
|
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, GR_RESIZE_NONE);
|
|
}
|
|
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] + (CaptionCoords[3] - CaptionCoords[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;
|
|
|
|
// change the hidden height too if needed
|
|
if (Style & GS_HIDDEN) {
|
|
UnhiddenHeight += 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, int resize_mode = GR_RESIZE_NONE)
|
|
{
|
|
gr_line(x1, y1, x2, y1, resize_mode);
|
|
gr_line(x2, y1, x2, y2, resize_mode);
|
|
gr_line(x2, y2, x1, y2, resize_mode);
|
|
gr_line(x1, y2, x1, y1, resize_mode);
|
|
}
|
|
|
|
extern void gr_opengl_shade(int x, int y, int w, int h, int resize_mode);
|
|
|
|
void Window::DoDraw(float frametime)
|
|
{
|
|
int w, h;
|
|
|
|
// if the window has no title bar, and no content, then don't draw any of it
|
|
if ( (Style & WS_NOTITLEBAR) && !HasChildren() ) {
|
|
return;
|
|
}
|
|
|
|
// shade the background of the window so that it's just slightly transparent
|
|
gr_set_shader(&WindowShade);
|
|
gr_opengl_shade(Coords[0], Coords[1], Coords[2], Coords[3], GR_RESIZE_NONE);
|
|
|
|
gr_set_color_fast(&Color_text_normal);
|
|
|
|
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, GR_RESIZE_NONE);
|
|
} else {
|
|
gr_line(Coords[0] + BorderSizes[0], Coords[1], Coords[2] - BorderSizes[2], Coords[1], GR_RESIZE_NONE);
|
|
}
|
|
|
|
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, GR_RESIZE_NONE);
|
|
} else {
|
|
gr_line(Coords[0] + BorderSizes[0], Coords[3], Coords[2] - BorderSizes[2], Coords[3], GR_RESIZE_NONE);
|
|
}
|
|
|
|
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, GR_RESIZE_NONE);
|
|
} else {
|
|
gr_line(Coords[0], Coords[1] + BorderSizes[1], Coords[0], Coords[3] - BorderSizes[3], GR_RESIZE_NONE);
|
|
}
|
|
|
|
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, GR_RESIZE_NONE);
|
|
} else {
|
|
gr_line(Coords[2], Coords[1] + BorderSizes[1], Coords[2], Coords[3] - BorderSizes[3], GR_RESIZE_NONE);
|
|
}
|
|
}
|
|
|
|
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, GR_RESIZE_NONE);
|
|
} 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", GR_RESIZE_NONE);
|
|
}
|
|
|
|
|
|
//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], "-", GR_RESIZE_NONE);
|
|
}
|
|
|
|
//Caption text
|
|
gr_set_color_fast(&Color_text_normal);
|
|
|
|
gr_string(CaptionCoords[0], CaptionCoords[1], Caption.c_str(), GR_RESIZE_NONE);
|
|
}
|
|
}
|
|
|
|
void Window::ClearContent()
|
|
{
|
|
if ( !HasChildren() ) {
|
|
return;
|
|
}
|
|
|
|
LinkedList *cgp = GET_FIRST(&Children);
|
|
LinkedList *cgp_next;
|
|
|
|
while ( cgp && (cgp != END_OF_LIST(&Children)) ) {
|
|
cgp_next = GET_NEXT(cgp);
|
|
delete cgp;
|
|
cgp = cgp_next;
|
|
}
|
|
}
|
|
|
|
Window::Window(const SCP_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;
|
|
|
|
// create a shader for the window
|
|
gr_create_shader(&WindowShade, 0, 0, 0, 200);
|
|
}
|
|
|
|
//*****************************Button*******************************
|
|
|
|
Button::Button(const SCP_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, 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, 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, Caption.c_str(), GR_RESIZE_NONE);
|
|
}
|
|
}
|
|
|
|
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;
|
|
Parent = NULL;
|
|
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, 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)) ) {
|
|
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]) {
|
|
}
|
|
}
|
|
}
|
|
|
|
return OF_TRUE;
|
|
}
|
|
|
|
Tree::Tree(const SCP_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;
|
|
|
|
SelectedItem = NULL;
|
|
HighlightedItem = NULL;
|
|
|
|
//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], tip->Name.c_str(), GR_RESIZE_NONE);
|
|
|
|
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, const SCP_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();
|
|
|
|
LinkedList* cgp = GET_FIRST(&Items);
|
|
LinkedList* cgp_next;
|
|
for (; cgp != END_OF_LIST(&Items); cgp = cgp_next) {
|
|
cgp_next = GET_NEXT(cgp);
|
|
delete cgp;
|
|
}
|
|
}
|
|
|
|
//*****************************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(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), Content.substr(LineStartPoints[i] - Content.c_str(), LineLengths[i]).c_str(), GR_RESIZE_NONE);
|
|
}
|
|
}
|
|
|
|
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.
|
|
Content += char(symbol);
|
|
if (SaveType & T_ST_REALTIME) {
|
|
Save();
|
|
}
|
|
}
|
|
}
|
|
OnRefreshSize();
|
|
return OF_TRUE;
|
|
}
|
|
|
|
Text::Text(const SCP_string &in_name, const SCP_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(const SCP_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(const SCP_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) {
|
|
short the_sint = (short)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(const SCP_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;
|
|
BoolFlagPtr = NULL;
|
|
|
|
//Set the type
|
|
Type = GT_CHECKBOX;
|
|
}
|
|
|
|
int Checkbox::DoRefreshSize()
|
|
{
|
|
int w, h,tw,th;
|
|
gr_get_string_size(&w, &h, 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) && (BoolFlagPtr == NULL)))
|
|
|| ((FlagPtr != NULL) && ((*FlagPtr) & Flag))
|
|
|| ((BoolFlagPtr != NULL) && (*BoolFlagPtr)) ) {
|
|
gr_string(CheckCoords[0], CheckCoords[1], "X", GR_RESIZE_NONE);
|
|
}
|
|
|
|
gr_set_color_fast(&Color_text_normal);
|
|
gr_string(CheckCoords[2] + CB_TEXTCHECKDIST, CheckCoords[1], Label.c_str(), GR_RESIZE_NONE);
|
|
}
|
|
|
|
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 if (BoolFlagPtr != NULL) {
|
|
*BoolFlagPtr = !(*BoolFlagPtr);
|
|
IsChecked = *BoolFlagPtr;
|
|
} else {
|
|
IsChecked = !IsChecked;
|
|
}
|
|
}
|
|
|
|
return OF_TRUE;
|
|
}
|
|
|
|
int Checkbox::DoMouseOut(float frametime)
|
|
{
|
|
HighlightStatus = 0;
|
|
|
|
return OF_TRUE;
|
|
}
|
|
|
|
//*****************************ImageAnim*******************************
|
|
ImageAnim::ImageAnim(const SCP_string &in_name, const SCP_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(const SCP_string &in_imagename)
|
|
{
|
|
if (in_imagename.size()) {
|
|
ImageHandle = IMG_LOAD_ANIM(in_imagename.c_str(), &TotalFrames, &FPS);
|
|
TotalTime = (float) (TotalFrames/FPS);
|
|
if (IMG_HANDLE_IS_INVALID(ImageHandle)) {
|
|
ImageHandle = IMG_LOAD(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;
|
|
}
|