#pragma once #include "CIntObject.h" #include "SDL_Extensions.h" #include "../FunctionList.h" #include "../Gfx/Basic.h" #include "../Gfx/Manager.h" struct SDL_Surface; class CAnimImage; class CLabel; class CAnimation; class CDefHandler; /* * CPicture.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ // Window GUI class class CSimpleWindow : public CIntObject { public: SDL_Surface * bitmap; //background virtual void show(); CSimpleWindow():bitmap(NULL){}; //c-tor virtual ~CSimpleWindow(); //d-tor }; // Image class class CPicture : public CIntObject { Gfx::PImage image; public: Rect * srcRect; //if NULL then whole surface will be used inline Gfx::PImage getImage() { return image; }; CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color CPicture(Gfx::PImage BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface CPicture(const std::string &bmpname, int x=0, int y=0); CPicture(Gfx::PImage BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface ~CPicture(); void init(); //set alpha value for whole surface. Note: may be messed up if surface is shared // 0=transparent, 255=opaque void setAlpha(int value); void scaleTo(Point size); void createSimpleRect(const Rect &r, bool screenFormat, ui32 color); void show(); void showAll(); void convertToScreenBPP(); void colorizeAndConvert(PlayerColor player); void colorize(PlayerColor player); }; /// area filled with specific texture class CFilledTexture : CIntObject { SDL_Surface * texture; public: CFilledTexture(std::string imageName, Rect position); ~CFilledTexture(); void showAll(); }; namespace config{ struct ButtonInfo; } typedef std::pair PairOfStrings; /// Base class for buttons. class CButton : public CKeyShortcut { public: enum ButtonState { NORMAL = 0, PRESSED = 1, BLOCKED = 2, HIGHLIGHTED = 3 }; protected: ButtonState state;//current state of button from enum Gfx::PAnimation images; //images for this button Gfx::CImage* state2image[4]; std::string helpBox; //for right-click help std::string status; CButton(); //c-tor public: CFunctionList callback; CLabel * text; //text overlay CButton( const CFunctionList & flist, Point position, const std::string & animName, size_t animOffs = 0, size_t imagesNum = 4, const PairOfStrings * helpStr = nullptr, int key = SDLK_UNKNOWN ); virtual ~CButton(); //d-tor void clickRight(tribool down, bool previousState); void clickLeft(tribool down, bool previousState); void hover(bool on); void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE); void swapImages(); void setState(ButtonState newState); ButtonState getState() const { return state; }; //just to make code clearer void block(bool on); bool isBlocked() const { return state == BLOCKED; }; bool isHighlighted() const { return state == HIGHLIGHTED; }; void showAll(); }; /// Typical Heroes 3 button which can be inactive or active and can /// hold further information if you right-click it class CAdventureMapButton : public CButton { std::vector imageNames;//store list of images that can be used by this button public: std::map hoverTexts; //text for statusbar bool actOnDown,//runs when mouse is pressed down over it, not when up hoverable,//if true, button will be highlighted when hovered borderEnabled, soundDisabled; SDL_Color borderColor; void clickRight(tribool down, bool previousState); virtual void clickLeft(tribool down, bool previousState); void hover (bool on); CAdventureMapButton(); //c-tor CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList &Callback, int x, int y, const std::string &animName, int key=0, std::vector * add = NULL, bool playerColoredButton = false );//c-tor CAdventureMapButton( const std::pair &help, const CFunctionList &Callback, int x, int y, const std::string &animName, int key=0, std::vector * add = NULL, bool playerColoredButton = false );//c-tor CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList &Callback, config::ButtonInfo *info, int key=0);//c-tor void init(const CFunctionList &Callback, const std::map &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector * add, int x, int y, int key ); void setOffset(int o) {}; void setIndex(size_t index, bool playerColoredButton=false); void setImage(Gfx::PAnimation anim, bool playerColoredButton=false, int animFlags=0); void setPlayerColor(PlayerColor player); void showAll(); }; /// A button which can be selected/deselected class CHighlightableButton : public CAdventureMapButton { public: CHighlightableButton(const CFunctionList &onSelect, const CFunctionList &onDeselect, const std::map &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector * add, int x, int y, int key=0); CHighlightableButton(const std::pair &help, const CFunctionList &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector * add = NULL, bool playerColoredButton = false );//c-tor CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector * add = NULL, bool playerColoredButton = false );//c-tor bool onlyOn;//button can not be de-selected bool selected;//state of highlightable button int ID; //for identification CFunctionList callback2; //when de-selecting void select(bool on); void clickLeft(tribool down, bool previousState); }; /// A group of buttons where one button can be selected class CHighlightableButtonsGroup : public CIntObject { public: CFunctionList2 onChange; //called when changing selected button with new button's id std::vector buttons; bool musicLike; //determines the behaviour of this group //void addButton(const std::map &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid); void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor void addButton(const std::map &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList &OnSelect=0, int key=0); //creates new button CHighlightableButtonsGroup(const CFunctionList2 &OnChange, bool musicLikeButtons = false); ~CHighlightableButtonsGroup(); void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id void selectionChanged(int to); void show(); void showAll(); void block(ui8 on); }; /// A typical slider which can be orientated horizontally/vertically. class CSlider : public CIntObject { public: CAdventureMapButton *left, *right, *slider; //if vertical then left=up int capacity,//how many elements can be active at same time amount, //how many elements positions, //number of highest position (0 if there is only one) value; //first active element bool horizontal; bool wheelScrolling; bool keyScrolling; boost::function moved; void redrawSlider(); void sliderClicked(); void moveLeft(); void moveRight(); void moveTo(int to); void block(bool on); void setAmount(int to); void keyPressed(const SDL_KeyboardEvent & key); void wheelScrolled(bool down, bool in); void clickLeft(tribool down, bool previousState); void mouseMoved (const SDL_MouseMotionEvent & sEvent); void showAll(); CSlider(int x, int y, int totalw, boost::function Moved, int Capacity, int Amount, int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue ~CSlider(); void moveToMax(); }; /// Used as base for Tabs and List classes class CObjectList : public CIntObject { public: typedef boost::function CreateFunc; typedef boost::function DestroyFunc; private: CreateFunc createObject; DestroyFunc destroyObject; protected: //Internal methods for safe creation of items (Children capturing and activation/deactivation if needed) void deleteItem(CIntObject* item); CIntObject* createItem(size_t index); CObjectList(CreateFunc create, DestroyFunc destroy = DestroyFunc());//Protected constructor }; /// Window element with multiple tabs class CTabbedInt : public CObjectList { private: CIntObject * activeTab; size_t activeID; public: //CreateFunc, DestroyFunc - see CObjectList //Pos - position of object, all tabs will be moved to this position //ActiveID - ID of initially active tab CTabbedInt(CreateFunc create, DestroyFunc destroy = DestroyFunc(), Point position=Point(), size_t ActiveID=0); void setActive(size_t which); //recreate active tab void reset(); //return currently active item CIntObject * getItem(); }; /// List of IntObjects with optional slider class CListBox : public CObjectList { private: std::list< CIntObject* > items; size_t first; size_t totalSize; Point itemOffset; CSlider * slider; void updatePositions(); public: //CreateFunc, DestroyFunc - see CObjectList //Pos - position of first item //ItemOffset - distance between items in the list //VisibleSize - maximal number of displayable at once items //TotalSize //Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown) //SliderPos - position of slider, if present CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize, size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() ); //recreate all visible items void reset(); //change or get total amount of items in the list void resize(size_t newSize); size_t size(); //return item with index which or null if not present CIntObject * getItem(size_t which); //return currently active items const std::list< CIntObject * > & getItems(); //get index of this item. -1 if not found size_t getIndexOf(CIntObject * item); //scroll list to make item which visible void scrollTo(size_t which); //scroll list to specified position void moveToPos(size_t which); void moveToNext(); void moveToPrev(); size_t getPos(); }; class CTextContainer : public virtual CIntObject { protected: void blitLine(SDL_Surface * to, Point where, std::string what); CTextContainer(EAlignment alignment, EFonts font, SDL_Color color); //CTextContainer() {}; public: EAlignment alignment; EFonts font; SDL_Color color; }; /// Label which shows text class CLabel : public CTextContainer { protected: virtual std::string visibleText(); public: std::string text; CPicture *bg; bool autoRedraw; //whether control will redraw itself on setTxt Point textOffset; //text will be blitted at pos + textOffset with appropriate alignment bool ignoreLeadingWhitespace; virtual void setTxt(const std::string &Txt); void showAll(); //shows statusbar (with current text) CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = ""); }; class CBoundedLabel : public CLabel { public: ui32 maxW; //longest line of text in px ui32 maxH; //total height needed to print all lines std::vector lines; CBoundedLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = "") : CLabel (x, y, Font, Align, Color, Text){}; void setTxt(const std::string &Txt); void setBounds(int limitW, int limitH); virtual void recalculateLines(const std::string &Txt); void showAll(); }; //Small helper class to manage group of similar labels class CLabelGroup : public CIntObject { std::list labels; EFonts font; EAlignment align; const SDL_Color &color; public: CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE); void add(int x=0, int y=0, const std::string &text = ""); }; /// a multi-line label that tries to fit text with given available width and height; if not possible, it creates a slider for scrolling text class CTextBox : public CBoundedLabel { public: int sliderStyle; std::vector effects; CSlider *slider; //CTextBox( std::string Text, const Point &Pos, int w, int h, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE); CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE); void showAll(); //shows statusbar (with current text) void recalculateLines(const std::string &Txt); void sliderMoved(int to); }; /// Status bar which is shown at the bottom of the in-game screens class CGStatusBar : public CLabel { bool textLock; //Used for blocking changes to the text void init(); public: CGStatusBar *oldStatusBar; //statusbar interface overloads void print(const std::string & Text); //prints text and refreshes statusbar void clear();//clears statusbar and refreshes std::string getCurrent(); //returns currently displayed text void show(); //shows statusbar (with current text) //CGStatusBar(int x, int y, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE, const std::string &Text = ""); CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar CGStatusBar(int x, int y, std::string name, int maxw=-1); ~CGStatusBar(); void calcOffset(); void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called const static Point edgeOffset; //Amount to move text from side when alignment is left or right }; /// UIElement which can get input focus class CFocusable : public virtual CIntObject { public: bool focus; //only one focusable control can have focus at one moment void giveFocus(); //captures focus void moveFocus(); //moves focus to next active control (may be used for tab switching) static std::list focusables; //all existing objs static CFocusable *inputWithFocus; //who has focus now CFocusable(); ~CFocusable(); }; /// Text input box where players can enter text class CTextInput : public CLabel, public CFocusable { protected: std::string visibleText(); public: CFunctionList cb; CFunctionList filters; void setTxt(const std::string &nText, bool callCb = false); CTextInput(const Rect &Pos, EFonts font, const CFunctionList &CB); CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList &CB); CTextInput(const Rect &Pos, SDL_Surface *srf = NULL); void clickLeft(tribool down, bool previousState) override; void keyPressed(const SDL_KeyboardEvent & key) override; bool captureThisEvent(const SDL_KeyboardEvent & key) override; //Filter that will block all characters not allowed in filenames static void filenameFilter(std::string &text, const std::string & oldText); //Filter that will allow only input of numbers in range min-max (min-max are allowed) //min-max should be set via something like boost::bind static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue); }; /// Shows a text by moving the mouse cursor over the object class CHoverableArea: public virtual CIntObject { public: std::string hoverText; virtual void hover (bool on); CHoverableArea(); virtual ~CHoverableArea(); }; /// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it class LRClickableAreaWText: public CHoverableArea { public: std::string text; LRClickableAreaWText(); LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = ""); virtual ~LRClickableAreaWText(); void init(); virtual void clickLeft(tribool down, bool previousState); virtual void clickRight(tribool down, bool previousState); }; /// Basic class for windows class CWindowObject : public CIntObject { CPicture * createBg(std::string imageName, bool playerColored); int getUsedEvents(int options); CIntObject *shadow; void setShadow(bool on); int options; protected: CPicture * background; //Simple function with call to GH.popInt void close(); //Used only if RCLICK_POPUP was set void clickRight(tribool down, bool previousState); //To display border void showAll(); //change or set background image void setBackground(std::string filename); void updateShadow(); public: enum EOptions { PLAYER_COLORED=1, //background will be player-colored RCLICK_POPUP=2, // window will behave as right-click popup BORDERED=4, // window will have border if current resolution is bigger than size of window SHADOW_DISABLED=8 //this window won't display any shadow }; /* * options - EOpions enum * imageName - name for background image, can be empty * centerAt - position of window center. Default - center of the screen */ CWindowObject(int options, std::string imageName, Point centerAt); CWindowObject(int options, std::string imageName = ""); ~CWindowObject(); };