/* Copyright (c) 2005-2007 Lode Vandevenne All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Lode Vandevenne nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef gui_h #define gui_h #include "lpi_color.h" #include "lpi_event.h" #include "lpi_texture.h" #include "lpi_text.h" namespace lpi { namespace gui { void initBuiltInGuiTextures(); //////////////////////////////////////////////////////////////////////////////// //ENUMS///////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //direction for gui elements like scrollbars and stuff enum Direction { H, //horizontal V //vertical }; struct TextureSet //contains the actual texture data, not just pointers { private: Texture texture[128]; public: Texture& operator[](int index); }; extern Texture builtInTexture[128]; /* MultiLineText text divided over multiple lines, and functions to let it create the lines in different ways, such as (including, but not limited to) -use ascii 10 chars of the string for new lines -break off between letters in limited rectangle -break off between words in limited rectangle the multiple line text is represented by an array of integers (line) containing the positions of the first letter of each new line all functions that need to draw text this way HAVE to use this class from now on */ class MultiLineText { private: std::vector line; //if the value is -1, it's no new line, it means the end is reached std::vector lineMarkup; //only used of useFormatting is true: then it has to remember the start-markup of every line, which will be generated at the start with the function generateLineMarkup public: std::string text; Markup markup; //the markup currently used bool char10; //if true, ascii code 10 will act as newline and ascii code 13 will be ignored bool useFormatting; //if true, the # codes of formatted text are used. See the printFormatted function for more about this! void resetLines(); void splitWords(int width); //markup must be given to be able to calculate width ==> max amount of letters in one line void splitLetters(int width); void splitChar10(); //only make a new line at ascii code 10 characters void generateLineMarkup(); //only used it useFormatting is true void setText(const std::string& text); void addText(const std::string& text); unsigned long getNumLines() const; std::string getLine(unsigned long i) const; //returns string filled with only that line void draw(int x, int y, unsigned long startLine, unsigned long endLine) const; void draw(int x, int y) const; void cursorAtCharPos(unsigned long pos, unsigned long& cline, unsigned long& column) const; int charAtCursorPos(unsigned long cline, unsigned long column) const; MultiLineText(); }; /* a BackPanel is a collection of 9 textures that should be tileable (except the corners) so that you can make a variable size rectangle with it */ class BackPanel { public: ColorRGB colorMod; //used for modifying the textures ColorRGB fillColor; /* enable side and/or center texture if center is disabled, fillColor is used instead for the center if sides are disabled, the center texture is used for the whole thing */ bool enableSides; bool enableCenter; //pointers to the 9 different textures making up a panel that can have any size const Texture* t00; //top left corner const Texture* t01; //top side const Texture* t02; //top right corner const Texture* t10; //left side const Texture* t11; //center const Texture* t12; //right side const Texture* t20; //bottom left corner const Texture* t21; //bottom side const Texture* t22; //bottom right corner //draw the panel at x, y position, with given width and height void draw(int x, int y, int width, int height) const; //constructors BackPanel(); BackPanel(int style); //used to quickly generate working BackPanel prototypes in parameters BackPanel(const ColorRGB& color); //used for color prototypes //make panel with flat color (no textures but fill color) void makeUntextured(const ColorRGB& fillColor); //give 9 separate textures void makeTextured9(const Texture* t00=&builtInTexture[0], const Texture* t01=&builtInTexture[1], const Texture* t02=&builtInTexture[2], const Texture* t10=&builtInTexture[3], const Texture* t11=&builtInTexture[4], const Texture* t12=&builtInTexture[5], const Texture* t20=&builtInTexture[6], const Texture* t21=&builtInTexture[7], const Texture* t22=&builtInTexture[8], const ColorRGB& colorMod=RGB_White); //give 1 texture, the other 8 are assumed to have successive memory locations void makeTextured(const Texture* t00=&builtInTexture[0], const ColorRGB& colorMod=RGB_White); }; #define DEFAULTPANEL BackPanel(1) #define COLORPANEL(color) BackPanel(color) /* a BackRule is a collection of 3 textures (the center one tileable) that can form a horizontal or vertical line */ class BackRule { public: ColorRGB colorMod; //used for modifying the tetures /* if sides are disabled, the center texture is used for the whole thing */ bool enableSides; Direction direction; //the 3 different textures making up the line const Texture* t0; //left or top corner const Texture* t1; //tilable center const Texture* t2; //right or bottom corner //draw the line at x, y position, with given length void draw(int x, int y, int length) const; //constructors BackRule(); BackRule(int style); //for prototypes //give 3 separate textures void makeHorizontal(const Texture* t0=&builtInTexture[41], Texture* t1=&builtInTexture[42], Texture* t2=&builtInTexture[43], const ColorRGB& colorMod=RGB_White); //give 1 texture, the other 2 are assumed to have successive memory locations void makeHorizontal1(const Texture* t0=&builtInTexture[41], const ColorRGB& colorMod=RGB_White); //give 3 separate textures void makeVertical(const Texture* t0=&builtInTexture[44], Texture* t1=&builtInTexture[45], Texture* t2=&builtInTexture[46], const ColorRGB& colorMod=RGB_White); //give 1 texture, the other 2 are assumed to have successive memory locations void makeVertical1(const Texture* t0=&builtInTexture[44], const ColorRGB& colorMod=RGB_White); }; #define DEFAULTHRULE BackRule(1) #define DEFAULTVRULE BackRule(2) struct GuiSet //contains the actual texture data, not just pointers { const Texture* windowTextures[9]; const Texture* buttonTextures[9]; const Texture* buttonOverTextures[9]; const Texture* buttonDownTextures[9]; const Texture* arrowN; //for scrollbars, arrow of droplist, ... const Texture* arrowE; const Texture* arrowS; const Texture* arrowW; const Texture* scroller; //for scrollbars const Texture* emptyButton; const Texture* roundButton; const Texture* slider; //the button of a slider, the simplified scrollbar (the slider is what the scroller is to scrollbars) const Texture* scrollbarBackground; const Texture* checkBox[2]; const Texture* bullet[2]; const Texture* hline[3]; const Texture* vline[3]; const Texture* smiley; const Texture* windowTop[3]; const Texture* closeButton; const Texture* resizer; //the resizer at bottom right of a window const Texture* whiteButton; //can easily be given any color with color mods const Texture* whiteRoundButton; const Texture* scrollBarPairCorner; //the cornerpiece of a scrollbarpair const Texture* crossHair; //for example to indicate a 2D location on a map, color picker, ... const BackPanel* windowPanel; const BackPanel* buttonPanel; const BackPanel* buttonOverPanel; const BackPanel* buttonDownPanel; const BackRule* sliderHRule; const BackRule* sliderVRule; ColorRGB mainColor; //if the mouse is not over or down a button ColorRGB mouseOverColor; //this isn't for panel buttons, but for image buttons like the arrows of a scrollbar, ... ColorRGB mouseDownColor; //this isn't for panel buttons, but for image buttons like the arrows of a scrollbar, ... Markup panelButtonMarkup[3]; Markup textButtonMarkup[3]; }; extern BackPanel builtInPanel[4]; extern BackRule builtInRule[2]; extern GuiSet builtInGuiSet; #define TESTIDS 16 #define NUM_MOUSE_BUTTONS 2 struct MouseState { bool downhere_bool1; bool downhere_bool2; bool justdown_prev; bool justdownhere_prev; bool justuphere_bool1; bool justuphere_bool2; bool grabbed_grabbed; bool grabbed_prev; int grabx; int graby; int grabrelx; int grabrely; int doubleClickState; double doubleClickTime; //in seconds MouseState(); }; /* WHAT TO CHECK IF GUIELEMENTS AND SUBCLASSES AREN'T DOING WHAT THEY'RE SUPPOSED TO DO? -Check sizex and sizey -The gui element constructors and make functions must be called AFTER the textures are loaded, otherwise the textures have size 0 and thus the gui element will have size 0 -mouse functions like pressed() work only once per time, pressed will return "true" only once per guielement, until the mouse button is up again and then down again */ class Element { public: Element(); //constructor virtual ~Element() { }; bool selfActivate; ////basic Element variables int x; //position of upper left corner of this element on screen int y; int x2; //position of the bottom right corner of this element on screen int y2; int getSizex() const { return x2 - x; } //get the size of this element int getSizey() const { return y2 - y; } //obviously the functoins below are best used after setting x and y void setSizex(const int sizex) { x2 = x + sizex; } //change x2, y2 to get the given size void setSizey(const int sizey) { y2 = y + sizey; } int getCenterx() const { return (x + x2) / 2; } //the center in screen coordinates int getCentery() const { return (y + y2) / 2; } int getRelCenterx() const { return (x2 - x) / 2; } //the half of the size int getRelCentery() const { return (y2 - y) / 2; } int shape; //mouse sensitive shape of this element, shapes: 0: rectangle 1: triangle pointing up 2: triangle pointing right 3: triangle pointing down 4: triangle pointing left (5: triangle pointing topleft) (6: triangle pointing topright) (7: triangle pointing bottomright) (8: triangle pointing bottomleft) (9: circle) (10: 45�) int minSizex; //you can't resize this element to something smaller than this int minSizey; bool isVisible() { return visible; } //if false, the draw() function doesn't draw anything bool isActive() { return active; } //if false, handle() does nothing, and mouse tests return always false bool isPresent() { return present; } //if true, it reacts to the mouse. if false, it ignores the mouse, even if forceActive is true, if a gui element isn't present, it really isn't present void setVisible(bool i_visible) { visible = i_visible; } void setActive(bool i_active) { active = i_active; } void setPresent(bool i_present) { present = i_present; } void totallyDisable() {visible = active = present = false;} //this sets visible, active and present all at once void totallyEnable() {visible = active = present = true;} int getX0() { return x; } int getY0() { return y; } int getX1() { return x2; } int getY1() { return y2; } void setX0(int x0) { this->x = x0; } void setY0(int y0) { this->y = y0; } void setX1(int x1) { this->x2 = x1; } void setY1(int y1) { this->y2 = y1; } ////basic Element functions void draw() const; //will draw the actual widget, and if it's enabled, the label, do NOT overload this function virtual void drawWidget() const = 0; //called by draw(), this one can be overloaded for each widget defined below void handle(); virtual void handleWidget(); void move(int x, int y); virtual void moveWidget(int /*x*/, int /*y*/); void autoActivate(); void moveTo(int x, int y); void moveCenterTo(int x, int y); void resize(int x, int y, int x2, int y2); //especially useful for windows and their container; parameters are the new values for x, y, x2 and y2 so this function can both move the object to a target and resize void growX(int d) { resize(x + d, y , x2 , y2 ); } //growing can also be shrinking void growY(int d) { resize(x , y + d, x2 , y2 ); } void growX2(int d) { resize(x , y , x2 + d, y2 ); } void growY2(int d) { resize(x , y , x2 , y2 + d); } void growSizex(int sizex) { resize(x2 - sizex, y , x2 , y ); } //growing can also be shrinking void growSizey(int sizey) { resize(x , y2 - sizey, x2 , y ); } void growSizex2(int sizex) { resize(x , y , x + sizex, y2 ); } void growSizey2(int sizey) { resize(x , y , x2 , y + sizey); } virtual void resizeWidget(); //always called after resize, will resize the other elements to the correct size virtual bool isContainer() const; //returns 0 if the type of element isn't a container, 1 if it is (Window, Container, ...); this value is used by for example Container: it brings containers to the top of the screen if you click on them. Actually so far it's only been used for that mouse test. It's something for containers, by containers :p void putInScreen(); //puts element in screen if it's outside ////initial position of this element relative to it's container or master (if it has one), these variables are only used by it's master if this master needs them and are never updated or changed by this element itself int ix; int iy; int ix2; int iy2; int iMasterSizex; int iMasterSizey; //the parameters below are the coordinates of the master void saveInitialPosition(int x,int y,int x2,int y2){ix=this->x-x;iy=this->y-y;ix2=this->x2-x;iy2=this->y2-y;this->iMasterSizex=x2-x;this->iMasterSizey=y2-y;} ////"sticky" variables, this tells which side of this gui element will stick to which side of a resizing container this element is part of and the container has to use and handle these variables, not this gui element itself //useful for elements of containers, and also for buttons of scrollbars and stuff double leftSticky; //0: follows left side of container, 1: follows right side of container, between 0-1: weighed average double topSticky; //0: follows top side of container, 1: follows bottom side of container, between 0-1: weighed average double rightSticky; //0: follows left side of container, 1: follows right side of container, between 0-1: weighed average double bottomSticky; //0: follows top side of container, 1: follows bottom side of container, between 0-1: weighed average //if leftsticky and rightsticky have the same value, this element won't resize in the x direction when it's master resizes, it'll only translate. Same for top and bottom. //if a sticky value is -1.0, it'll always keep the same relative size //if a sticky value is -2.0, it means: "do NOT move or resize this element if the master is resized". HOWEVER moving when the master is moved with move or moveTo should still work!!! //if a sticky value is -3.0, it means the same as -2.0, except it WILL move when it goes outside it's master, in other words it'll always stay inside void resizeSticky(int x, int y, int x2, int y2); //see implementation and locations where it's used what this function does; the parameters are the new sides of the master void setSticky(double left, double top, double right, double bottom) {leftSticky = left; topSticky = top; rightSticky = right; bottomSticky = bottom;} ////optional part "label" std::string label; int labelX; //label position is relative to the position of the element int labelY; Markup labelMarkup; void drawLabel() const; void makeLabel(const std::string& label, int labelX, int labelY, const Markup& labelMarkup); /* Idee voor verandering mouse states: -getMouseState weg -verschillende functies werken onafhankelijk, bv grab en pressed verpesten elkaars status niet (==> minder kans op conflicten die anders met verschillende testIDs worden opgelost) --> this means, if you test grabbed and then mouseJustDown, mouseJustDown can still return true, but if you test mouseJustDown and immediatly mouseJustDown again, the second one will always return false -is er iets beters dan testIDs te vinden? misschien maar 1 soort test voor outside, en aparte versies voor inside (zoals selfactivate, gui container grabbed test, ...) die de outside niet beinvloeden --> maak versie met test id private, publieke versies roepen die op met testid 0 --> of een versie met niet testid, maar waar je de nodige state variabelen zelf geeft! -als element active is mogen de mouse states nog werken, maar niet als het niet mouseActive is -laat alle namen beginnen met "mouse" -containers zetten mouseActive zelf aan en af -de boolean die nu "present" heet is een manier van van buitenaf altijd mouseActive uit te zetten zonder dat het door container geregeld wordt (voor bv als je op een container meerdere dingen hebt zitten maar soms de ene dan de andere zichtbaar mogen zijn) -verwijder alle referenties naar "forceActive"!!!!!!! -verander alle booleans die ik nu nieuw gemaakt heb, naar 1 enkele struct waarin alles zit, inclusief grabx en graby -mouseActive hernoemen naar !elementOver (door container gezet, betekent dat er een ander element overheen dit element is) de functies: //-bool mouseJustUp: mouse up or not over element for the first time after being down -bool mouseDoubleClick: mouse double clicked anywhere, but using internal variables of this element to remember the states -bool mouseTimeDown: mouse is down but only returns true every so many milliseconds -bool mouseJustHere: when the mouse is just over (-void mouseJustDownIgnore: let mouseJustDown not work the next frame (same as calling mouseJustDown once and not using the return value)) -bool mouseGrabbedActive: this is active in grab or is being grabbed, this is used for handling of elements by the container, it's really impossible otherwise with the mouseOver tests and stuff (grabbed can be active if not mouseOver...). For the rest: uses same variables as grabbed of the mousestate --> so this one can return true in a case where mouseActive is not true. Because of the way containers set mouseActive true and false... //and then the ones that return false if active is false: -pressing (mouseDown and active) -pressed (mouseJustDown and active) -clicked (mouseJustUp and active) -grabbed (mouseGrabbed and active) */ ////MOUSE RELATED STUFF int mouseGetRelPosX() const; //returns relative mouse positions (relative to x and y of the elemnt) int mouseGetRelPosY() const; //returns relative mouse positions (relative to x and y of the elemnt) virtual bool mouseOver() const; //mouse cursor over the element (and no other element lpiged by gui container above it) bool mouseDown(MouseButton button = LMB) const; //mouse is over and down bool mouseDownHere(MouseState& state, MouseButton button = LMB) const; //mouse is over, down, and was pressed while it was on here bool mouseDownHere(MouseButton button = LMB); bool mouseGrabbed(MouseState& state, MouseButton button = LMB) const; //like mouseDownHere, but keeps returning true if you move the mouse away from the element while keeping button pressed bool mouseGrabbed(MouseButton button = LMB); void mouseGrab(MouseState& state) const; //sets states as if element were grabbed void mouseGrab(MouseButton button = LMB); void mouseUngrab(MouseState& state) const; //sets states as if element were not grabbed void mouseUngrab(MouseButton button = LMB); int mouseGetGrabX(const MouseState& state) const { return state.grabx; } //absolute location where you last started grabbing (x) int mouseGetGrabX(MouseButton button = LMB) const { return mouseGetGrabX(_mouseState[button]); } int mouseGetGrabY(const MouseState& state) const { return state.graby; } int mouseGetGrabY(MouseButton button = LMB) const { return mouseGetGrabY(_mouseState[button]); } int mouseGetRelGrabX(const MouseState& state) const { return state.grabrelx; } //relative location where you last started grabbing (x) int mouseGetRelGrabX(MouseButton button = LMB) const { return mouseGetRelGrabX(_mouseState[button]); } int mouseGetRelGrabY(const MouseState& state) const { return state.grabrely; } int mouseGetRelGrabY(MouseButton button = LMB) const { return mouseGetRelGrabY(_mouseState[button]); } bool mouseJustDown(bool& prevstate, MouseButton button = LMB) const; //generalized version with only boolean given bool mouseJustDown(MouseState& state, MouseButton button = LMB) const; //mouse down for the first time after being up or not over the element bool mouseJustDown(MouseButton button = LMB); bool mouseJustDownHere(bool& prevstate, MouseButton button = LMB) const; bool mouseJustDownHere(MouseState& state, MouseButton button = LMB) const; //mouse down for the first time after being up, only returns true if the mouse was above it before you clicked already bool mouseJustDownHere(MouseButton button = LMB); bool mouseJustUpHere(MouseState& state, MouseButton button = LMB) const; //mouse up for first time after being down, and over the element (so if you have mouse down on element and move mouse away, this will NOT return true, only if you release mouse button while cursor is over it, and mousedownhere) bool mouseJustUpHere(MouseButton button = LMB); bool pressed(MouseButton button = LMB); //mouseJustDown and active bool clicked(MouseButton button = LMB); //mouseJustUp and active bool mouseScrollUp() const; //scrolled up while on this element bool mouseScrollDown() const; //scrolled down while on this element double doubleClickTime; //maximum time for a doubleclick void setDoubleClickTime(double i_doubleClickTime) { doubleClickTime = i_doubleClickTime; } double getDoubleClickTime() { return doubleClickTime; } bool mouseDoubleClicked(MouseState& state, MouseButton button = LMB) const; //double clicked on this element bool mouseDoubleClicked(MouseButton button = LMB); MouseState& getMouseStateForContainer() { return mouse_state_for_containers; } ////END MOUSE RELATED STUFF virtual void setElementOver(bool state); //ALL gui types that have gui elements inside of them, must set elementOver of all gui elements inside of them too! ==> overload this virtual function for those virtual bool hasElementOver() const; ////special visible parts, for example for debugging void drawBorder(const ColorRGB& color = RGB_White); //add background rectangle void addBackgroundRectangle(const ColorRGB& color) { this->hasBackgroundRectangle = true; this->backgroundRectangleColor = color; } private: //for the timeDown function mutable float downTime; //rectangle behind it bool hasBackgroundRectangle; ColorRGB backgroundRectangleColor; //some mouse variables MouseState auto_activate_mouse_state; MouseState _mouseState[NUM_MOUSE_BUTTONS]; MouseState mouse_state_for_containers; //for bookkeeping of containers that contain this element protected: bool elementOver; //this used to be called mouseActive (and had opposite meaning) bool visible; //if false, the draw() function doesn't draw anything bool active; //if false, handle() does nothing, and mouse tests return always false bool present; //if true, it reacts to the mouse. if false, it ignores the mouse, even if forceActive is true, if a gui element isn't present, it really isn't present }; //Dummy = exactly the same as Element but not abstract, nothing implemented except pure virtuals of Element class Dummy : public Element { void drawWidget() const {} }; class Button : public Element { /* the button has 3 separate graphical elements: *) text *) an image *) a panel (resisable rectangle with sides) */ public: Button(); ////part "back image" bool enableImage; const Texture* image[3]; //0=normal, 1=mouse over, 2=mouse down int imageOffsetx; int imageOffsety; ColorRGB imageColor[3]; //0=normal, 1=mouse over, 2=mouse down ////part "front image" bool enableImage2; const Texture* image2[3]; //0=normal, 1=mouse over, 2=mouse down int imageOffsetx2; int imageOffsety2; ColorRGB imageColor2[3]; //0=normal, 1=mouse over, 2=mouse down ////part "text" bool enableText; std::string text; int textOffsetx; int textOffsety; Markup markup[3]; void autoTextSize(int extrasize = 0); //will automaticly adjust it's size to fit text size void centerText(); //center the text in the texture if the button has a texture (sizex and sizey used for size) ////part "panel" bool enablePanel; const BackPanel* panel[3]; int panelOffsetx; int panelOffsety; //special options /* mouseDownVisualStyle: when to change the image of the button to the mouseDown image 0: only when mouseDown() 1: only when mouseDownHere() 2: only when grabbed() */ int mouseDownVisualStyle; ////make functions //make full void make(int x, int y, int sizex, int sizey, //basic properties bool enableImage, Texture* texture1, Texture* texture2, Texture* texture3, int imageOffsetx, int imageOffsety, const ColorRGB& imageColor1, const ColorRGB& imageColor2, const ColorRGB& imageColor3, //image bool enableText, const std::string& text, int textOffsetx, int textOffsety, const Markup& markup1, const Markup& markup2, const Markup& markup3, //text bool enablePanel, const BackPanel* panel1 = &builtInPanel[1], const BackPanel* panel2 = &builtInPanel[2], const BackPanel* panel2 = &builtInPanel[3], int panelOffsetx = 0, int panelOffsety = 0, //panel int shape = 0); //image only constructor (without offset) void makeImage(int x, int y, const Texture* texture1, const Texture* texture2, const Texture* texture3, const ColorRGB& imageColor1 = RGB_White, const ColorRGB& imageColor2 = RGB_Brightred, const ColorRGB& imageColor3 = RGB_Grey, //image int shape = 0); void makeImage(int x, int y, const Texture* texture123, const ColorRGB& imageColor1 = RGB_White, const ColorRGB& imageColor2 = RGB_Brightred, const ColorRGB& imageColor3 = RGB_Grey, int shape = 0); void addFrontImage(const Texture* texture1, const Texture* texture2, const Texture* texture3, const ColorRGB& imageColor1 = RGB_White, const ColorRGB& imageColor2 = RGB_Brightred, const ColorRGB& imageColor3 = RGB_Grey); void addFrontImage(const Texture* texture); //text only constructor (without offset) void makeText(int x, int y, //basic properties const std::string& text, //text const GuiSet* set = &builtInGuiSet, int shape = 0 /*special options*/); //panel + text constructor (text always in center of panel, no offsets and thinking needed) //this is the constructor with default parameters void makeTextPanel(int x, int y, const std::string& text = "", int sizex = 64, int sizey = 24, //basic properties + actual text const GuiSet* set = &builtInGuiSet, //panel int shape = 0); virtual void drawWidget() const; private: mutable MouseState mutable_button_drawing_mouse_test; }; //The Scrollbar class Scrollbar : public Element { private: float oldTime; //bool scrollTimeTrigger; void init(); public: //get length and begin and end coordinates of the slider part (the part between the up and down buttons) (relative to x, y of the scrollbar) int getSliderSize() const; int getSliderStart() const; int getSliderEnd() const; virtual void handleWidget(); virtual void drawWidget() const; virtual void resizeWidget(); Direction direction; //0 = vertical, 1 = horizontal //int sizeButton; //size of the up and down button //int sizeScroller; //size of the center button double scrollSize; //length of the total scrollbar (in steps) double scrollPos; //position of the scroller on the bar (in steps) double scrollSpeed; //if speedMode == 0: steps / second, if speedMode == 1: seconds / whole bar double absoluteSpeed; //steps / second int speedMode; const Texture* txUp; //texture of the "up" button (left button if it's horizontal) const Texture* txUpOver; //on mouseover const Texture* txDown; //texture of the "down" button (right button if horizontal) const Texture* txDownOver; //mouseover const Texture* txScroller; //texture of the center button (the scroller) const Texture* txScrollerOver; //mouseover const Texture* txBack; //texture of the background (the slider) //only one shared color modifier and a color modifier on mouseover/down ColorRGB colorMod; ColorRGB colorModOver; ColorRGB colorModDown; //buttons of the scrollbar Button buttonUp; Button buttonDown; Button scroller; void setRelativeScrollSpeed(); //time = time to scroll from top to bottom (in seconds) void setRelativePosition(float position); //position = 0.0-1.0 Scrollbar(); void makeVertical(int x, int y, int length = 80, double scrollSize = 100, double scrollPos = 0, double offset = 0, double scrollSpeed = 1, const GuiSet* set = &builtInGuiSet, int speedMode = 1); void makeHorizontal(int x, int y, int length = 80, double scrollSize = 100, double scrollPos = 0, double offset = 0, double scrollSpeed = 1, const GuiSet* set = &builtInGuiSet, int speedMode = 1); void showValue(int x, int y, const Markup& valueMarkup, int type); //type: 0=don't, 1=float, 2=int virtual void moveWidget(int x, int y); void scroll(int dir); //make it scroll from an external command virtual void setElementOver(bool state); //scrollbar has buttons in it that need to be set inactive too so has its own function for this defined double offset; //used as an offset of ScrollPos to get/set the scroll value with offset added with the functions below double getValue() const; void setValue(double value); void randomize(); //it will get a random value int enableValue; //if 1, value is shown everytime you draw as floating point, if 2, as integer (value = offset + scrollPos) Markup valueMarkup; //text style of the value int valueX; //x position of the value (relative) int valueY; //y position of the value (relative) }; class ScrollbarPair : public Element { private: const GuiSet* scrollbarGuiSet; //the guiSet used for the scrollbars has to be remembered for when remaking them public: ScrollbarPair(); void make(int x, int y, int sizex, int sizey, double scrollSizeH = 100, double scrollSizeV = 100, const GuiSet* set = &builtInGuiSet); Scrollbar vbar; Scrollbar hbar; const Texture* txCorner; //the corner piece between the two scrollbars virtual void handleWidget(); virtual void drawWidget() const; virtual void resizeWidget(); virtual void moveWidget(int x, int y); virtual void setElementOver(bool state); bool venabled; bool henabled; void disableV(); void disableH(); void enableV(); void enableH(); bool conserveCorner; //if false, the cornerpiece will disappear if one scrollbar is gone, if true, it'll only disappear if both scrollbars are disabled //size of the area without the scrollbars int getVisiblex() const; //returns x2 - x - vbar.getWidth() if there's a vbar, or x2 - x if there's no vbar int getVisibley() const; //returns y2 - y - hbar.getHeight() if there's a hbar, or y2 - y if there's no hbar }; //the Slider is a simplified version of the scrollbar (no up and down buttons) that also looks different class Slider : public Element { public: Slider(); double getValue() const; //a number between 0.0 and scrollSize void setValue(double value); double getRelValue() const; //a number between 0.0 and 1.0 void setRelValue(double value); Direction direction; Button slider; //(by default round) button const BackRule* ruler; //the line behind the button double scrollSize; double scrollPos; void makeHorizontal(int x, int y, int length = 100, double scrollSize = 100, const GuiSet* set = &builtInGuiSet); void makeVertical(int x, int y, int length = 100, double scrollSize = 100, const GuiSet* set = &builtInGuiSet); double screenPosToScrollPos(int screenPos); int scrollPosToScreenPos(double scrollPos); virtual void drawWidget() const; virtual void handleWidget(); virtual void moveWidget(int x, int y); virtual void resizeWidget(); virtual void setElementOver(bool state); }; class Invisible : public Element { public: void make(int x, int y, int x2, int y2); virtual void drawWidget() const; }; /* An invisible grid of numx * numy rectangles, it can return over which square the mouse is (top left one has coordinates 0, 0) */ class Matrix : public Element { //nothing required in here! it's a Element! public: void make(int x, int y, int x2, int y2, int numx, int numy); unsigned long numx; unsigned long numy; unsigned long getTileX() const; unsigned long getTileY() const; int getScreenX(int tilex) const; int getScreenY(int tiley) const; }; /* similar to Matrix, except here the size of the rectangles is constant, and not the number of them (if the gui element resizes) */ class Grid : public Element { //nothing required in here! it's a Element! public: void make(int x, int y, int x2, int y2, int tileSizeX, int tileSizeY); void setNumTiles(int amount); //real amount can be larger, as the width of rows will stay the same, it'll add rows at the bottom or remove rows Grid(); //returns x position on screen of center of given tile int getTileCenterx(int index) const; //index = index of the tile //returns y position on screen of center of given tile int getTileCentery(int index) const; //index = index of the tile bool showGrid; ColorRGB gridColor; virtual void drawWidget() const; int tileSizeX; int tileSizeY; unsigned long getNumx() const; unsigned long getNumy() const; unsigned long getNumElements() const; int getTileX() const; int getTileY() const; int getTile() const; //returns index of the tile int getScreenX(int tilex) const; int getScreenY(int tiley) const; }; class Container : public Element { private: void initElement(Element* element, int x, int y, double leftSticky, double topSticky, double rightSticky, double bottomSticky); public: std::vector element; Container(); virtual void handleWidget(); //you're supposed to handle() before you draw() virtual void drawWidget() const; void pushTop(Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void pushBottom(Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void insert(unsigned long pos, Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void pushTop(Element* element); void pushBottom(Element* element); void insert(unsigned long pos, Element* element); void remove(Element* element); unsigned long size() const; virtual bool isContainer() const; void clear(); //clears all the elements void putInside(unsigned long i); virtual void moveWidget(int x, int y); void make(int x, int y, int sizex, int sizey, int areax = 0, int areay = 0, int areasizex = -1, int areasizey = -1, //areax and areay are relative to the container! double areaLeftSticky = 0, double areaTopSticky = 0, double areaRightSticky = 1, double areaBottomSticky = 1); bool keepElementsInside; //will not allow you to drag elements outside (if the element is dragged(), it'll be kept inside the container) void getRelativeElementPos(Element& element, int& ex, int& ey) const; virtual void resizeWidget(); virtual void setElementOver(bool state); ////the initial position of the elements of this container and container itself at that point void saveInitialPositions(); //sets the "ix, iy, ix2, iy2, masterSizex and masterSizey" parameters or all elements ////everything concerning the scrollability ScrollbarPair bars; int getVisibleSizex() const; int getVisibleSizey() const; int getVisiblex() const; int getVisibley() const; int getVisiblex2() const; int getVisibley2() const; //the scrollable area "behind" or "inside" the container Invisible area; //the area that can be scrolled will be represented by this, so it's move function and such can easily be called while you scroll int oldScrollx; //used to move elements every frame when you scroll the bars int oldScrolly; void moveAreaTo(int x, int y); //moves the area to given position, and all the elements, but not the bars and x, y, x2, y2. Used when you scroll. void setScrollSizeToElements(); //makes the size of the scroll area as big as the elements void initBars(); void updateBars(); void toggleBars(); //turns the bars on or of depending on if they're needed or not }; class Group : public Container { public: virtual bool mouseOver() const; //difference with the mouseOver from other guielements, is that it checks all sub elements, not itself, for mouseovers }; class Panel : public Element { private: BackPanel panel; public: Panel(); void make(int x, int y, int sizex, int sizey, const GuiSet* set = &builtInGuiSet, int shape=0); void makeUntextured(int x, int y, int sizex, int sizey, const ColorRGB& fillColor); //give 1 texture, the other 8 are assumed to have successive memory locations void makeTextured(int x, int y, int sizex, int sizey, const Texture* t00, const ColorRGB& colorMod = RGB_White, int shape=0); void setSize(int x, int y, int sizex, int sizey); virtual void drawWidget() const; }; class Rule : public Element { private: BackRule line; public: Rule(); //give 3 separate textures void makeHorizontal(int x, int y, int length, const GuiSet* set = &builtInGuiSet); //give 1 texture, the other 2 are assumed to have successive memory locations void makeHorizontal1(int x, int y, int length, Texture* t0=&builtInTexture[41], const ColorRGB& colorMod=RGB_White); //give 3 separate textures void makeVertical(int x, int y, int length, const GuiSet* set = &builtInGuiSet); //give 1 texture, the other 2 are assumed to have successive memory locations void makeVertical1(int x, int y, int length, Texture* t0=&builtInTexture[44], const ColorRGB& colorMod=RGB_White); void setSize(int x, int y, int length); virtual void drawWidget() const; }; //Window is a container for other gui elements that'll move and get drawn at the command of the window //now WITH container in it! class Window : public Element { private: public: void disableCenterTexture() { panel.enableCenter = false; } void setFillColor(const ColorRGB& color) { panel.fillColor = color; } Window(); ////obligatory part "panel" BackPanel panel; ////obligatory part "container" Container container; int getContainerLowest() const; int getContainerHighest() const; int getContainerLeftmost() const; int getContainerRightmost() const; //get the parameters for the container surface on which the elements in the window will be int getContainerx() const { return container.x; } int getContainery() const { return container.y; } int getContainerx2() const { return container.x2; } int getContainery2() const { return container.y2; } int getContainerSizex() const { return container.getSizex(); } int getContainerSizey() const { return container.getSizey(); } //if a parameter is -1, it's set to left void setContainerBorders(int left = 0, int up = -1, int right = -1, int down = -1); void pushTop(Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void pushBottom(Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void insert(int pos, Element* element, int x, int y, double leftSticky=0.0, double topSticky=0.0, double rightSticky=0.0, double bottomSticky=0.0); void pushTop(Element* element); void pushBottom(Element* element); void insert(int pos, Element* element); void remove(Element* element); int size(); void putInside(int i); //these scrollbars will be part of the container void addScrollbars(int areax = 0, int areay = 0, int areasizex = -1, int areasizey = -1, //areax and areay are relative to the container! double areaLeftSticky = 0, double areaTopSticky = 0, double areaRightSticky = 1, double areaBottomSticky = 1); ////optional part "top" Rule top; //not a "back" one, so that you can easily detect mouse on it, for dragging void addTop(Texture * t0 = &builtInTexture[47], int offsetLeft = 0, int offsetRight = 0, int offsetTop = 0, const ColorRGB& colorMod = ColorRGB(96, 96, 255)); bool enableTop; //enable the top bar of the window (then you can drag it with this instead of everywhere on the window) ////optional part "title" std::string title; int titleX; //position of title, relative to the top bar (NOT relative to the window but to the TOP BAR!) int titleY; Markup titleMarkup; void addTitle(const std::string& title, int titleX = 2, int titleY = 4, const Markup& titleMarkup = TS_W); void setTitle(const std::string& title); //only to be used after "addTitle" (or the x, y position will be messed up) ////optional part "close button" bool closed; Button closeButton; void addCloseButton(int offsetX = 0, int offsetY = 0, const GuiSet* set = &builtInGuiSet); //ofsset from top *right* corner, choose style of close button by making it, it's the built in texture by default bool closeEnabled; //close button is enabled ////optional part "resizer" = draggable bottom right corner with diagonally striped image bool enableResizer; Button resizer; void addResizer(const GuiSet* set = &builtInGuiSet, bool overContainer = false, int offsetX = 0, int offsetY = 0); //ofsset = from bottom right corner bool resizerOverContainer; ////the make functions void make(int x, int y, int sizex, int sizey, const GuiSet* set = &builtInGuiSet, int shape=0); void makeUntextured(int x, int y, int sizex, int sizey, const ColorRGB& fillColor); void makeTextured(int x, int y, int sizex, int sizey, const Texture* t00, const ColorRGB& colorMod = RGB_White, int shape=0); int getRelContainerStart() const { return container.y - y; } int getRelContentStart() const; void setSize(int x, int y, int sizex, int sizey); ////overloaded functions virtual void drawWidget() const; virtual void moveWidget(int x, int y); virtual void handleWidget(); virtual bool isContainer() const; virtual void setElementOver(bool state); //window has top bar in it that needs to be set inactive too so has it's own function for this defined virtual void resizeWidget(); ////other functions void initContainer(); ////useful for the close button void close() { closed = 1; totallyDisable(); } //use this if closed == 1 void unClose() { closed = 0; totallyEnable(); } void toggleClose() { if(closed) unClose(); else close(); } void setColor(const ColorRGB& color) { panel.colorMod = color; } }; class DropMenu : public Element { private: std::vector