/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* * This is the top class of the whole GUI, all objects * and settings are stored within this class. */ #ifndef INCLUDED_CGUI #define INCLUDED_CGUI #include "GUITooltip.h" #include "GUIbase.h" #include "lib/input.h" #include "ps/Shapes.h" #include "ps/XML/Xeromyces.h" #include "scriptinterface/ScriptInterface.h" #include ERROR_TYPE(GUI, JSOpenFailed); extern const double SELECT_DBLCLICK_RATE; /** * Contains a list of values for new defaults to objects. */ struct SGUIStyle { // Take advantage of moving the entire map instead and avoiding unintended copies. NONCOPYABLE(SGUIStyle); MOVABLE(SGUIStyle); SGUIStyle() = default; std::map m_SettingsDefaults; }; class JSObject; // The GUI stores a JSObject*, so needs to know that JSObject exists class IGUIObject; class CGUISpriteInstance; struct CGUIColor; class CGUIText; struct SGUIIcon; class CGUIString; class CGUISprite; struct SGUIImageEffects; struct SGUIScrollBarStyle; class GUITooltip; /** * The main object that represents a whole GUI page. * * No interfacial functions throws. */ class CGUI { NONCOPYABLE(CGUI); private: // Private typedefs using ConstructObjectFunction = IGUIObject* (*)(CGUI*); public: CGUI(const shared_ptr& runtime); ~CGUI(); /** * Initializes the GUI, needs to be called before the GUI is used */ void Initialize(); /** * Performs processing that should happen every frame * (including sending the "Tick" event to scripts) */ void TickObjects(); /** * Sends a specified script event to every object * * @param EventName String representation of event name */ void SendEventToAll(const CStr& EventName); /** * Sends a specified script event to every object * * @param EventName String representation of event name * @param paramData JS::HandleValueArray storing the arguments passed to the event handler. */ void SendEventToAll(const CStr& EventName, JS::HandleValueArray paramData); /** * Displays the whole GUI */ void Draw(); /** * Draw GUI Sprite * * @param Sprite Object referring to the sprite (which also caches * calculations for faster rendering) * @param CellID Number of the icon cell to use. (Ignored if this sprite doesn't * have any images with "cell-size") * @param Z Drawing order, depth value * @param Rect Position and Size * @param Clipping The sprite shouldn't be drawn outside this rectangle */ void DrawSprite(const CGUISpriteInstance& Sprite, int CellID, const float& Z, const CRect& Rect, const CRect& Clipping = CRect()); /** * Clean up, call this to clean up all memory allocated * within the GUI. */ void Destroy(); /** * The replacement of Process(), handles an SDL_Event_ * * @param ev SDL Event, like mouse/keyboard input */ InReaction HandleEvent(const SDL_Event_* ev); /** * Load a GUI XML file into the GUI. * * VERY IMPORTANT! All \-files must be read before * everything else! * * @param Filename Name of file * @param Paths Set of paths; all XML and JS files loaded will be added to this */ void LoadXmlFile(const VfsPath& Filename, boost::unordered_set& Paths); /** * Return the object which is an ancestor of every other GUI object. */ IGUIObject* GetBaseObject() const { return m_BaseObject; }; /** * Checks if object exists and return true or false accordingly * * @param Name String name of object * @return true if object exists */ bool ObjectExists(const CStr& Name) const; /** * Returns the GUI object with the desired name, or NULL * if no match is found, * * @param Name String name of object * @return Matching object, or NULL */ IGUIObject* FindObjectByName(const CStr& Name) const; /** * Returns the GUI object under the mouse, or NULL if none. */ IGUIObject* FindObjectUnderMouse() const; /** * Returns the current screen coordinates of the cursor. */ const CPos& GetMousePos() const { return m_MousePos; }; /** * Returns the currently pressed mouse buttons. */ const unsigned int& GetMouseButtons() { return m_MouseButtons; }; const SGUIScrollBarStyle* GetScrollBarStyle(const CStr& style) const; /** * The GUI needs to have all object types inputted and * their constructors. Also it needs to associate a type * by a string name of the type. * * To add a type: * @code * AddObjectType("button", &CButton::ConstructObject); * @endcode * * @param str Reference name of object type * @param pFunc Pointer of function ConstuctObject() in the object * * @see CGUI#ConstructObject() */ void AddObjectType(const CStr& str, ConstructObjectFunction pFunc) { m_ObjectTypes[str] = pFunc; } /** * Update Resolution, should be called every time the resolution * of the OpenGL screen has been changed, this is because it needs * to re-cache all its actual sizes * * Needs no input since screen resolution is global. * * @see IGUIObject#UpdateCachedSize() */ void UpdateResolution(); /** * Check if an icon exists */ bool HasIcon(const CStr& name) const { return (m_Icons.count(name) != 0); } /** * Get Icon (a const reference, can never be changed) */ const SGUIIcon& GetIcon(const CStr& name) const { return m_Icons.at(name); } /** * Check if a style exists */ bool HasStyle(const CStr& name) const { return (m_Styles.count(name) != 0); } /** * Get Style if it exists, otherwise throws an exception. */ const SGUIStyle& GetStyle(const CStr& name) const { return m_Styles.at(name); } /** * Check if a predefined color of that name exists. */ bool HasPreDefinedColor(const CStr& name) const { return (m_PreDefinedColors.count(name) != 0); } /** * Resolve the predefined color if it exists, otherwise throws an exception. */ const CGUIColor& GetPreDefinedColor(const CStr& name) const { return m_PreDefinedColors.at(name); } shared_ptr GetScriptInterface() { return m_ScriptInterface; }; JS::Value GetGlobalObject() { return m_ScriptInterface->GetGlobalObject(); }; /** * Updates the object pointers, needs to be called each * time an object has been added or removed. * * This function is atomic, meaning if it throws anything, it will * have seen it through that nothing was ultimately changed. * * @throws PSERROR_GUI that is thrown from IGUIObject::AddToPointersMap(). */ void UpdateObjects(); private: /** * Adds an object to the GUI's object database * Private, since you can only add objects through * XML files. Why? Because it enables the GUI to * be much more encapsulated and safe. * * @throws Rethrows PSERROR_GUI from IGUIObject::AddChild(). */ void AddObject(IGUIObject* pObject); /** * You input the name of the object type, and let's * say you input "button", then it will construct a * CGUIObjet* as a CButton. * * @param str Name of object type * @return Newly constructed IGUIObject (but constructed as a subclass) */ IGUIObject* ConstructObject(const CStr& str); public: /** * Get Focused Object. */ IGUIObject* GetFocusedObject() { return m_FocusedObject; } /** * Change focus to new object. * Will send LOST_FOCUS/GOT_FOCUS messages as appropriate. * pObject can be NULL to remove all focus. */ void SetFocusedObject(IGUIObject* pObject); private: //-------------------------------------------------------- /** @name XML Reading Xeromyces specific subroutines * * These does not throw! * Because when reading in XML files, it won't be fatal * if an error occurs, perhaps one particular object * fails, but it'll still continue reading in the next. * All Error are reported with ReportParseError */ //-------------------------------------------------------- /* Xeromyces_* functions tree (ReadRootObjects) | +-