Files
fs2open.github.com/code/lab/wmcgui.h
T
Echelon9 522eb962ff Fix a range of issue identified via clang warnings
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@10860 387891d4-d844-0410-90c0-e4c51a9137d3
2014-07-05 10:38:08 +10:00

710 lines
19 KiB
C++

/*
* wmcgui.h
* created by WMCoolmon
*
* You may not sell or otherwise commercially exploit the source or things you
* create based on the source.
*
*/
#include "globalincs/alphacolors.h"
#include "globalincs/linklist.h"
#include "io/mouse.h"
#include "globalincs/pstypes.h"
#include <string>
#include <limits.h>
//*****************************Low-level abstraction*******************************
//Lame attempt to keep things from being exceedingly difficult when switching to ferrium
#ifndef FERRIUM
#define IMG_HANDLE int
#define IMG_HANDLE_SET_INVALID(h) h = -1
#define IMG_HANDLE_IS_INVALID(h) (h==-1)
#define IMG_HANDLE_IS_VALID(h) (h!=-1)
#define IMG_HANDLE_SET_FRAME(dh,h,f)(dh = h + f)
#define IMG_LOAD(f) bm_load(f)
#define IMG_LOAD_ANIM(f,n,fps) bm_load_animation(f,n,fps)
#define IMG_UNLOAD(a) bm_unload(a)
#define IMG_SET(h) gr_set_bitmap(h)
#define IMG_SET_FRAME(h, f) gr_set_bitmap(h + f)
#define IMG_DRAW(x,y) gr_bitmap(x,y,GR_RESIZE_NONE)
#define IMG_INFO(ha,w,h) bm_get_info(ha,w,h)
#endif
//*****************************LinkedList*******************************
struct LinkedList
{
friend class GUISystem;
friend class GUIObject;
friend class Tree;
friend struct TreeItem;
friend class Window;
public:
struct LinkedList *next, *prev;
LinkedList(){ next = this; prev = this; }
virtual ~LinkedList(){ prev->next = next; next->prev = prev; }
};
//*****************************ClassInfoEntry*******************************
//This is chiefly used in conjunction with GUISystem to store information
//about classes
//T - Top
//L - Left
//R - Right
//B - Bottom
//N - Normal
//M - Mouseovered
//C - Clicked
//S - Selected/Active (for windows)
//D - Disabled
//A - Active
//I - Inactive
//Types of CIEs
#define CIE_NONE -1
#define CIE_IMAGE 0
#define CIE_IMAGE_NMCSD 1
#define CIE_IMAGE_BORDER 2
#define CIE_COORDS 3
#define CIE_TEXT 4
//NMCSD Handles
#define CIE_HANDLE_N 0
#define CIE_HANDLE_M 1
#define CIE_HANDLE_C 3
#define CIE_HANDLE_S 3
#define CIE_HANDLE_D 4
//Border handles
#define CIE_HANDLE_TL 0
#define CIE_HANDLE_TM 1
#define CIE_HANDLE_TR 2
#define CIE_HANDLE_ML 3
#define CIE_HANDLE_MR 4
#define CIE_HANDLE_BL 5
#define CIE_HANDLE_BM 6
#define CIE_HANDLE_BR 7
//Text
#define CIE_COLOR_R 0
#define CIE_COLOR_G 1
#define CIE_COLOR_B 2
#define CIE_COLOR_A 3
//Return vals
#define CIE_GC_NONE_SET 0
#define CIE_GC_X_SET (1<<0)
#define CIE_GC_Y_SET (1<<1)
#define CIE_GC_W_SET (1<<2)
#define CIE_GC_H_SET (1<<3)
//Global stuff
#define CIE_NUM_HANDLES 8 //We need 8 for border
union Handle
{
ubyte Colors[4];
IMG_HANDLE Image;
};
//Individual info
class ClassInfoEntry
{
int CIEType;
Handle Handles[CIE_NUM_HANDLES];
int Coords[2];
public:
//--CONSTRUCTORS
ClassInfoEntry();
~ClassInfoEntry();
//--SET FUNCTIONS
void Parse(char* tag, int in_type);
//--GET FUNCTIONS
int GetImageHandle(int ID=CIE_HANDLE_N){return Handles[ID].Image;}
ubyte GetColorHandle(int ColorID, int ID=CIE_HANDLE_N){if(this==NULL){return 0;}else{return Handles[ID].Colors[ColorID];}}
//Copies the coordinates to the given location if coordinates are set.
int GetCoords(int *x, int *y);
};
//Entries for an object, ie a window or button
class ObjectClassInfoEntry
{
friend class GUIScreen;
private:
int Object;
SCP_string Name; //Do we want this to only apply to a specific object?
//If so, set name
int Coords[4];
SCP_vector<ObjectClassInfoEntry> Subentries;
SCP_vector<ClassInfoEntry> Entries;
public:
ObjectClassInfoEntry(){Object=-1;Coords[0]=Coords[1]=Coords[2]=Coords[3]=INT_MAX;}
bool Parse();
int GetImageHandle(int id, int handle_num);
int GetCoords(int id, int *x, int *y);
int GetObjectCoords(int *x, int *y, int *w, int *h);
};
//Entries for a screen.
class ScreenClassInfoEntry : public LinkedList
{
friend class GUIScreen;
private:
SCP_string Name;
SCP_vector<ObjectClassInfoEntry> Entries;
public:
bool Parse();
SCP_string GetName(){return Name;}
};
//*****************************GUIObject*******************************
//What type a GUIObject is, mostly for debugging
#define GT_NONE 0
#define GT_WINDOW 1
#define GT_BUTTON 2
#define GT_MENU 3
#define GT_TEXT 4
#define GT_CHECKBOX 5
#define GT_IMAGEANIM 6
#define GT_HUDGAUGE 7
#define GT_NUM_TYPES 8 //Total number of types
//States of being for GUIObjects
#define GST_NORMAL 0
#define GST_MOUSE_LEFT_BUTTON (1<<0)
#define GST_MOUSE_RIGHT_BUTTON (1<<1)
#define GST_MOUSE_MIDDLE_BUTTON (1<<2)
#define GST_MOUSE_OVER (1<<3)
#define GST_KEYBOARD_CTRL (1<<4)
#define GST_KEYBOARD_ALT (1<<5)
#define GST_KEYBOARD_SHIFT (1<<6)
#define GST_KEYBOARD_KEYPRESS (1<<7)
#define GST_MOUSE_PRESS (GST_MOUSE_LEFT_BUTTON | GST_MOUSE_RIGHT_BUTTON | GST_MOUSE_MIDDLE_BUTTON)
#define GST_MOUSE_STATUS (GST_MOUSE_LEFT_BUTTON | GST_MOUSE_RIGHT_BUTTON | GST_MOUSE_MIDDLE_BUTTON | GST_MOUSE_OVER)
#define GST_KEYBOARD_STATUS (GST_KEYBOARD_CTRL | GST_KEYBOARD_ALT | GST_KEYBOARD_SHIFT | GST_KEYBOARD_KEYPRESS)
//GUIObject styles
#define GS_NOAUTORESIZEX (1<<0)
#define GS_NOAUTORESIZEY (1<<1)
#define GS_HIDDEN (1<<2)
#define GS_INTERNALCHILD (1<<3)
//DoFrame return values
#define OF_TRUE -1
#define OF_FALSE -2
//#define OF_DESTROYED -3 //If a call to DoFrame results in the object destroying itself
//(ie the close button was pressed)
class GUIObject : public LinkedList
{
friend class Window; //Hack, because I can't figure out how to let it access protected
friend class Menu; //This too
friend class Text; //And this
friend class Tree; //By, the way...THIS
friend class Checkbox;
friend class Button;
friend class ImageAnim;
friend class HUDGauge;
friend class GUIScreen;
friend class GUISystem;
private:
class GUISystem *OwnerSystem; //What system this object is associated with
class GUIScreen *OwnerScreen;
int Coords[4]; //Upper left corner (x, y) and lower right corner (x, y)
int ChildCoords[4]; //Coordinates where children may frolick
int Type;
SCP_string Name;
int LastStatus;
int Status;
int Style;
class ObjectClassInfoEntry* InfoEntry;
void (*CloseFunction)(GUIObject *caller);
class GUIObject* Parent;
LinkedList Children;
int GetOIECoords(int *x1, int *y1, int *x2, int *y2);
GUIObject *AddChildInternal(GUIObject* cgp);
protected:
//ON FUNCTIONS
//These handle the calling of do functions, mostly.
void OnDraw(float frametime);
int OnFrame(float frametime, int *unused_queue);
void OnMove(int dx, int dy);
void OnRefreshSize(){if(DoRefreshSize() != OF_FALSE && Parent!=NULL)Parent->OnRefreshSize();}
void OnRefreshSkin(){SetCIPointer(); DoRefreshSkin();}
//DO FUNCTIONS
//Used by individual objects to define actions when that event happens
virtual void DoDraw(float frametime){}
virtual int DoFrame(float frametime){return OF_FALSE;}
virtual int DoRefreshSize(){return OF_FALSE;}
virtual void DoRefreshSkin(){}
virtual void DoMove(int dx, int dy){}
virtual int DoMouseOver(float frametime){return OF_FALSE;}
virtual int DoMouseDown(float frametime){return OF_FALSE;}
virtual int DoMouseUp(float frametime){return OF_FALSE;} //In other words, a click
virtual int DoMouseOut(float frametime){return OF_FALSE;}
virtual int DoKeyState(float frametime){return OF_FALSE;}
virtual int DoKeyPress(float frametime){return OF_FALSE;}
//CALCULATESIZE
//Sort of an on and do function; if you define your own, the following MUST be included at the end:
//"if(Parent!=NULL)Parent->OnRefreshSize();"
//PRIVATE ClassInfo FUNCTIONS
void SetCIPointer();
int GetCIEImageHandle(int id, int handleid=0){if(InfoEntry!=NULL){return InfoEntry->GetImageHandle(id, handleid);}else{return -1;}}
int GetCIECoords(int id, int *x, int *y);
public:
//CONSTRUCTION/DESTRUCTION
//Derive your class's constructer from the GUIObject one
GUIObject(const SCP_string &in_Name="", int x_coord = 0, int y_coord = 0, int x_width = -1, int y_height = -1, int in_style = 0);
~GUIObject();
void Delete();
//CHILD FUNCTIONS
//Used for managing children. :)
GUIObject *AddChild(GUIObject* cgp);
void DeleteChildren(GUIObject* exception = NULL);
//SET FUNCTIONS
void SetPosition(int x, int y);
void SetCloseFunction(void (*in_closefunc)(GUIObject* caller)){CloseFunction = in_closefunc;}
//GET FUNCTIONS
int GetWidth(){return Coords[2]-Coords[0];}
int GetHeight(){return Coords[3]-Coords[1];}
};
//*****************************GUIScreen*******************************
#define GSOF_NOTHINGPRESSED -1
#define GSOF_SOMETHINGPRESSED -2
class GUIScreen : public LinkedList
{
friend class GUISystem;
private:
SCP_string Name;
GUISystem* OwnerSystem;
ScreenClassInfoEntry* ScreenClassInfo;
GUIObject Guiobjects;
SCP_vector<GUIObject*> DeletionCache;
public:
GUIScreen(const SCP_string &in_Name="");
~GUIScreen();
ObjectClassInfoEntry *GetObjectClassInfo(GUIObject *cgp);
//Set funcs
GUIObject *Add(GUIObject* new_gauge);
void DeleteObject(GUIObject* dgp);
//On funcs
int OnFrame(float frametime, bool doevents);
};
//*****************************GUISystem*******************************
class GUISystem
{
friend class GUIScreen; //I didn't want to do this, but it's the easiest way
//to keep it from being confusing about how to remove GUIScreens
private:
GUIScreen Screens;
GUIObject* ActiveObject;
//Moving stuff
GUIObject* GraspedGuiobject;
int GraspingButton; //Button flag for button used to grasp the object
int GraspedDiff[2]; //Diff between initial mouse position and object corner
//Linked list of screen class info
bool ClassInfoParsed;
ScreenClassInfoEntry ScreenClassInfo;
//Mouse/status
int MouseX;
int MouseY;
int KeyPressed;
int Status, LastStatus;
void DestroyClassInfo();
public:
GUISystem();
~GUISystem();
//-----
GUIScreen* PushScreen(GUIScreen *csp);
void PullScreen(GUIScreen *in_screen);
ScreenClassInfoEntry *GetClassInfo(){return &ScreenClassInfo;}
ScreenClassInfoEntry *GetScreenClassInfo(const SCP_string & screen_name);
//-----
//Set stuff
void ParseClassInfo(char* section);
void SetActiveObject(GUIObject *cgp);
void SetGraspedObject(GUIObject *cgp, int button);
//Get stuff
int GetMouseX(){return MouseX;}
int GetMouseY(){return MouseY;}
int GetStatus(){return Status;}
//int *GetLimits(){return Guiobjects.ChildCoords;}
GUIObject* GetActiveObject(){return ActiveObject;}
GUIObject* GetGraspedObject(){return GraspedGuiobject;}
int GetKeyPressed(){return KeyPressed;}
int OnFrame(float frametime, bool doevents, bool clearandflip);
};
//*****************************Window*******************************
#define W_BORDERWIDTH 1
#define W_BORDERHEIGHT 1
#define WS_NOTITLEBAR (1<<31) // doesn't have a title bar (ie, no title or min/close buttons)
#define WS_NONMOVEABLE (1<<30) // can't be moved around
#define WCI_CAPTION 0
#define WCI_CAPTION_TEXT 1
#define WCI_BORDER 2
#define WCI_BODY 3
#define WCI_HIDE 4
#define WCI_CLOSE 5
#define WCI_COORDS 6
#define WCI_NUM_ENTRIES 7
class Window : public GUIObject
{
SCP_string Caption;
//Close
bool CloseHighlight;
int CloseCoords[4];
//Hide
bool HideHighlight;
int HideCoords[4];
//Caption text
int CaptionCoords[4];
//Old height
int UnhiddenHeight;
//Skinning stuff
//Left width, top height, right width, bottom height
int BorderSizes[4];
bitmap_rect_list BorderRectLists[8];
bitmap_rect_list CaptionRectList;
shader WindowShade;
protected:
void DoDraw(float frametime);
void DoMove(int dx, int dy);
int DoRefreshSize();
int DoMouseOver(float frametime);
int DoMouseDown(float frametime);
int DoMouseUp(float frametime);
int DoMouseOut(float frametime);
bool HasChildren(){return NOT_EMPTY(&Children);}
public:
Window(const SCP_string &in_caption, int x_coord, int y_coord, int x_width = -1, int y_height = -1, int in_style = 0);
void SetCaption(const SCP_string &in_caption){Caption = in_caption;}
void ClearContent();
};
//*****************************Button*******************************
//#define DEFAULT_BUTTON_WIDTH 50
#define B_BORDERWIDTH 1
#define B_BORDERHEIGHT 1
#define DEFAULT_BUTTON_HEIGHT 15
#define BS_STICKY (1<<31) //Button stays pressed
#define BCI_COORDS 0
#define BCI_BUTTON 1
#define BCI_NUM_ENTRIES 2
class Button : public GUIObject
{
SCP_string Caption;
void (*function)(Button *caller);
bool IsDown; //Does it look pressed?
protected:
void DoDraw(float frametime);
int DoRefreshSize();
int DoMouseDown(float frametime);
int DoMouseUp(float frametime);
int DoMouseOut(float frametime);
public:
Button(const SCP_string &in_caption, int x_coord, int y_coord, void (*in_function)(Button *caller) = NULL, int x_width = -1, int y_height = -1, int in_style = 0);
void SetPressed(bool in_isdown){IsDown = in_isdown;}
};
//*****************************Tree*******************************
//In pixels
#define TI_BORDER_WIDTH 1
#define TI_BORDER_HEIGHT 1
#define TI_INITIAL_INDENT 2
#define TI_INITIAL_INDENT_VERTICAL 2
#define TI_INDENT_PER_LEVEL 10
#define TI_SPACE_BETWEEN_VERTICAL 2
// forward declaration
class Tree;
struct TreeItem : public LinkedList
{
friend class Tree;
private:
SCP_string Name;
void (*Function)(Tree *caller);
int Data;
bool DeleteData; //Do we delete data for the user?
bool ShowThis;
bool ShowChildren;
int Coords[4]; //For hit testing
TreeItem *Parent;
LinkedList Children;
public:
//Get
TreeItem * GetParentItem(){return Parent;}
int GetData(){return Data;}
bool HasChildren(){return NOT_EMPTY(&Children);}
void ClearAllItems();
TreeItem();
~TreeItem();
};
class Tree : public GUIObject
{
TreeItem Items;
void *AssociatedItem;
TreeItem *SelectedItem;
TreeItem *HighlightedItem;
TreeItem* HitTest(TreeItem *items);
void MoveTreeItems(int dx, int dy, TreeItem *items);
void CalcItemsSize(TreeItem *items, int *DrawData);
void DrawItems(TreeItem *items);
protected:
void DoDraw(float frametime);
void DoMove(int dx, int dy);
int DoRefreshSize();
int DoMouseOver(float frametime);
int DoMouseDown(float frametime);
int DoMouseUp(float frametime);
public:
Tree(const SCP_string &in_name, int x_coord, int y_coord, void* in_associateditem = NULL, int x_width = -1, int y_width = -1, int in_style = 0);
//void LoadItemList(TreeItem *in_list, unsigned int count);
TreeItem* AddItem(TreeItem *parent, const SCP_string &in_name, int in_data = 0, bool in_delete_data = true, void (*in_function)(Tree *caller) = NULL);
void ClearItems();
TreeItem* GetSelectedItem(){return SelectedItem;}
};
//*****************************Text*******************************
#define MAX_TEXT_LINES 100
#define T_EDITTABLE (1<<31)
//What type?
#define T_ST_NONE 0 //No saving
#define T_ST_INT (1<<0)
#define T_ST_SINT (1<<1)
#define T_ST_CHAR (1<<2)
#define T_ST_FLOAT (1<<3)
#define T_ST_UBYTE (1<<4)
//When do we save changes?
#define T_ST_ONENTER (1<<21)
#define T_ST_CLOSE (1<<22)
#define T_ST_REALTIME (1<<23)
//If dynamically allocated, then how?
#define T_ST_NEW (1<<30) //Allocated using new
#define T_ST_MALLOC (1<<31) //Allocated using malloc
class Text : public GUIObject
{
SCP_string Content;
//Used to display stuff; change only from calculate func
int NumLines;
int LineLengths[MAX_TEXT_LINES];
const char *LineStartPoints[MAX_TEXT_LINES];
//Used for editing
int CursorPos; //Line #, then position in line
int SaveType;
union
{
short *siSavePointer;
int *iSavePointer;
ubyte *ubSavePointer;
float *flSavePointer;
char *chSavePointer;
char **chpSavePointer;
};
union{int SaveMax;float flSaveMax;uint uSaveMax;};
union{int SaveMin;float flSaveMin;uint uSaveMin;};
protected:
void DoDraw(float frametime);
int DoRefreshSize();
int DoMouseDown(float frametime);
int DoKeyPress(float frametime);
public:
Text(const SCP_string &in_name, const SCP_string &in_content, int x_coord, int y_coord, int x_width = -1, int y_width = -1, int in_style = 0);
//Set
void SetText(const SCP_string &in_content);
void SetText(int the_int);
void SetText(float the_float);
void SetSaveLoc(int *ptr, int save_method, int max_value=INT_MAX, int min_value=INT_MIN);
void SetSaveLoc(short int *sint_ptr, int save_method, short int max_value=SHRT_MAX, short int min_value=SHRT_MIN);
void SetSaveLoc(float *ptr, int save_method, float max_value=INT_MAX, float min_value=INT_MIN);
void SetSaveLoc(char *ptr, int save_method, uint max_len=UINT_MAX, uint min_len = 0);
void SetSaveLoc(ubyte *ptr, int save_method, int max_value=UCHAR_MAX, int min_value=0);
void SetSaveStringAlloc(char **ptr, int save_method, int mem_flags, uint max_len=UINT_MAX, uint min_len = 0);
void AddLine(const SCP_string &in_line);
//Get?
bool Save();
void Load();
};
//*****************************Checkbox*******************************
#define CB_TEXTCHECKDIST 2
class Checkbox : public GUIObject
{
SCP_string Label;
void (*function)(Checkbox *caller);
//For toggling flags with this thing
int* FlagPtr;
int Flag;
bool *BoolFlagPtr;
int CheckCoords[4];
bool IsChecked; //Is it checked?
int HighlightStatus;
protected:
void DoDraw(float frametime);
void DoMove(int dx, int dy);
int DoRefreshSize();
int DoMouseOver(float frametime);
int DoMouseDown(float frametime);
int DoMouseUp(float frametime);
int DoMouseOut(float frametime);
public:
Checkbox(const SCP_string &in_label, int x_coord, int y_coord, void (*in_function)(Checkbox *caller) = NULL, int x_width = -1, int y_height = DEFAULT_BUTTON_HEIGHT, int in_style = 0);
bool GetChecked() {
return IsChecked;
}
void SetLabel(const SCP_string &in_label) {
Label = in_label;
}
void SetChecked(bool in_ischecked) {
IsChecked = in_ischecked;
}
void SetFlag(int* in_flag_ptr, int in_flag) {
FlagPtr = in_flag_ptr;
Flag = in_flag;
if ( (FlagPtr != NULL) && (*FlagPtr & Flag) ) {
IsChecked = true;
}
}
void SetFlag(uint* in_flag_ptr, int in_flag) {
SetFlag((int*)in_flag_ptr, in_flag);
}
void SetBool(bool *in_bool_ptr) {
BoolFlagPtr = in_bool_ptr;
}
};
//*****************************ImageAnim*******************************
#define PT_STOPPED 0
#define PT_PLAYING 1
#define PT_PLAYING_REVERSE 2
#define PT_STOPPED_REVERSE 3
#define IF_NONE 0
#define IF_BOUNCE 1
#define IF_REPEAT 2
#define IF_REVERSED 3
class ImageAnim : public GUIObject
{
SCP_string ImageAnimName;
IMG_HANDLE ImageHandle;
int TotalFrames;
int FPS;
bool IsSet; //Something of a hack, this is called so that
//SetImage overrides skin image
float Progress;
float ElapsedTime;
float TotalTime;
int PlayType;
int ImageFlags;
protected:
void DoDraw(float frametime);
int DoRefreshSize();
public:
ImageAnim(const SCP_string &in_name, const SCP_string &in_imagename, int x_coord, int y_coord, int x_width = -1, int y_width = -1, int in_style = 0);
void SetImage(const SCP_string &in_imagename);
void Play(bool in_isreversed);
void Pause();
void Stop();
};
//*****************************GLOBALS*******************************
extern GUISystem GUI_system;