LCOV - code coverage report
Current view: top level - source/gui/ObjectBases - IGUIObject.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 12 26 46.2 %
Date: 2023-01-19 00:18:29 Functions: 10 20 50.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : /*
      19             :  * The base class of an object.
      20             :  * All objects are derived from this class.
      21             :  * It's an abstract data type, so it can't be used per se.
      22             :  * Also contains a Dummy object which is used for completely blank objects.
      23             :  */
      24             : 
      25             : #ifndef INCLUDED_IGUIOBJECT
      26             : #define INCLUDED_IGUIOBJECT
      27             : 
      28             : #include "gui/CGUISetting.h"
      29             : #include "gui/SettingTypes/CGUIHotkey.h"
      30             : #include "gui/SettingTypes/CGUISize.h"
      31             : #include "gui/SGUIMessage.h"
      32             : #include "lib/input.h" // just for IN_PASS
      33             : #include "ps/CStr.h"
      34             : #include "ps/XML/Xeromyces.h"
      35             : #include "scriptinterface/ScriptTypes.h"
      36             : 
      37             : #include <map>
      38             : #include <vector>
      39             : 
      40             : class CCanvas2D;
      41             : class CGUI;
      42             : class CGUISize;
      43             : class IGUIObject;
      44             : class IGUIProxyObject;
      45             : class IGUISetting;
      46             : 
      47             : template <typename T>
      48             : class JSI_GUIProxy;
      49             : 
      50             : #define GUI_OBJECT(obj) \
      51             : public: \
      52             :     static IGUIObject* ConstructObject(CGUI& pGUI) \
      53             :         { return new obj(pGUI); }
      54             : 
      55             : /**
      56             :  * GUI object such as a button or an input-box.
      57             :  * Abstract data type !
      58             :  */
      59             : class IGUIObject
      60             : {
      61             :     friend class CGUI;
      62             : 
      63             :     // For triggering message update handlers.
      64             :     friend class IGUISetting;
      65             : 
      66             :     // Allow getProperty to access things like GetParent()
      67             :     template <typename T>
      68             :     friend class JSI_GUIProxy;
      69             : 
      70             : public:
      71             :     NONCOPYABLE(IGUIObject);
      72             : 
      73             :     IGUIObject(CGUI& pGUI);
      74             :     virtual ~IGUIObject();
      75             : 
      76             :     /**
      77             :      * This function checks if the mouse is hovering the
      78             :      * rectangle that the base setting "size" makes.
      79             :      * Although it is virtual, so one could derive
      80             :      * an object from CButton, which changes only this
      81             :      * to checking the circle that "size" makes.
      82             :      *
      83             :      * This function also returns true if there is a different
      84             :      * GUI object shown on top of this one.
      85             :      */
      86             :     virtual bool IsMouseOver() const;
      87             : 
      88             :     /**
      89             :      * This function returns true if the mouse is hovering
      90             :      * over this GUI object and if this GUI object is the
      91             :      * topmost object in that screen location.
      92             :      * For example when hovering dropdown list items, the
      93             :      * buttons beneath the list won't return true here.
      94             :      */
      95           0 :     virtual bool IsMouseHovering() const { return m_MouseHovering; }
      96             : 
      97             :     //--------------------------------------------------------
      98             :     /** @name Leaf Functions */
      99             :     //--------------------------------------------------------
     100             :     //@{
     101             : 
     102             :     /// Get object name, name is unique
     103           0 :     const CStr& GetName() const { return m_Name; }
     104             : 
     105             :     /// Get object name
     106           4 :     void SetName(const CStr& Name) { m_Name = Name; }
     107             : 
     108             :     // Get Presentable name.
     109             :     //  Will change all internally set names to something like "<unnamed object>"
     110             :     CStr GetPresentableName() const;
     111             : 
     112             :     /**
     113             :      * Return all child objects of the current object.
     114             :      */
     115           0 :     const std::vector<IGUIObject*>& GetChildren() const { return m_Children; }
     116             : 
     117             :     //@}
     118             :     //--------------------------------------------------------
     119             :     /** @name Settings Management */
     120             :     //--------------------------------------------------------
     121             :     //@{
     122             : 
     123             :     /**
     124             :      * Registers the given setting with the GUI object.
     125             :      * Enable XML and JS to modify the given variable.
     126             :      */
     127             :     void RegisterSetting(const CStr& Name, IGUISetting* setting);
     128             :     void ReregisterSetting(const CStr& Name, IGUISetting* setting);
     129             : 
     130             :     /**
     131             :      * Returns whether there is a setting with the given name registered.
     132             :      *
     133             :      * @param Setting setting name
     134             :      * @return True if settings exist.
     135             :      */
     136             :     bool SettingExists(const CStr& Setting) const;
     137             : 
     138             :     /**
     139             :      * Set a setting by string, regardless of what type it is.
     140             :      * Used to parse setting values from XML files.
     141             :      * For example a CRect(10,10,20,20) is created from "10 10 20 20".
     142             :      * @return false if the setting does not exist or the conversion fails, otherwise true.
     143             :      */
     144             :     bool SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage);
     145             : 
     146             :     /**
     147             :      * Returns whether this object is set to be hidden or ghost.
     148             :      */
     149             :     bool IsEnabled() const;
     150             : 
     151             :     /**
     152             :      * Returns whether this is object is set to be hidden.
     153             :      */
     154             :     bool IsHidden() const;
     155             : 
     156           0 :     void SetHidden(bool hidden) { m_Hidden.Set(hidden, true); }
     157             : 
     158             :     /**
     159             :      * Returns whether this object is set to be hidden or ghost.
     160             :      */
     161             :     bool IsHiddenOrGhost() const;
     162             : 
     163             :     /**
     164             :      * Retrieves the configured sound filename from the given setting name and plays that once.
     165             :      */
     166             :     void PlaySound(const CStrW& soundPath) const;
     167             : 
     168             :     /**
     169             :      * Send event to this GUI object (HandleMessage and ScriptEvent)
     170             :      *
     171             :      * @param type Type of GUI message to be handled
     172             :      * @param eventName String representation of event name
     173             :      * @return IN_HANDLED if event was handled, or IN_PASS if skipped
     174             :      */
     175             :     InReaction SendEvent(EGUIMessageType type, const CStr& eventName);
     176             : 
     177             :     /**
     178             :      * Same as SendEvent, but passes mouse coordinates and button state as an argument.
     179             :      */
     180             :     InReaction SendMouseEvent(EGUIMessageType type, const CStr& eventName);
     181             : 
     182             :     /**
     183             :      * All sizes are relative to resolution, and the calculation
     184             :      * is not wanted in real time, therefore it is cached, update
     185             :      * the cached size with this function.
     186             :      */
     187             :     virtual void UpdateCachedSize();
     188             : 
     189             :     /**
     190             :      * Updates and returns the size of the object.
     191             :      */
     192             :     CRect GetComputedSize();
     193             : 
     194           0 :     virtual const CStrW& GetTooltipText() const { return m_Tooltip; }
     195           0 :     virtual const CStr& GetTooltipStyle() const { return m_TooltipStyle; }
     196             : 
     197             :     /**
     198             :      * Reset internal state of this object.
     199             :      */
     200             :     virtual void ResetStates();
     201             : 
     202             :     /**
     203             :      * Set the script handler for a particular object-specific action
     204             :      *
     205             :      * @param eventName Name of action
     206             :      * @param Code Javascript code to execute when the action occurs
     207             :      * @param pGUI GUI instance to associate the script with
     208             :      */
     209             :     void RegisterScriptHandler(const CStr& eventName, const CStr& Code, CGUI& pGUI);
     210             : 
     211             :     /**
     212             :      * Retrieves the JSObject representing this GUI object.
     213             :      */
     214             :     JSObject* GetJSObject();
     215             : 
     216             :     //@}
     217             : protected:
     218             :     //--------------------------------------------------------
     219             :     /** @name Called by CGUI and friends
     220             :      *
     221             :      * Methods that the CGUI will call using
     222             :      * its friendship, these should not
     223             :      * be called by user.
     224             :      * TODO: this comment is old and the following interface should be cleaned up.
     225             :      */
     226             :     //--------------------------------------------------------
     227             :     //@{
     228             : 
     229             : public:
     230             : 
     231             :     /**
     232             :      * Called on every GUI tick unless the object or one of its parent is hidden/ghost.
     233             :      */
     234           8 :     virtual void Tick() {};
     235             : 
     236             :     /**
     237             :      * This function is called with different messages
     238             :      * for instance when the mouse enters the object.
     239             :      *
     240             :      * @param Message GUI Message
     241             :      */
     242           4 :     virtual void HandleMessage(SGUIMessage& UNUSED(Message)) {}
     243             : 
     244             :     /**
     245             :      * Calls an IGUIObject member function recursively on this object and its children.
     246             :      * Aborts recursion at IGUIObjects that have the isRestricted function return true.
     247             :      * The arguments of the callback function must be references.
     248             :     */
     249             :     template<typename... Args>
     250          61 :     void RecurseObject(bool(IGUIObject::*isRestricted)() const, void(IGUIObject::*callbackFunction)(Args... args), Args&&... args)
     251             :     {
     252          61 :         if (!IsBaseObject())
     253             :         {
     254          24 :             if (isRestricted && (this->*isRestricted)())
     255           0 :                 return;
     256             : 
     257          24 :             (this->*callbackFunction)(args...);
     258             :         }
     259             : 
     260          85 :         for (IGUIObject* const& obj : m_Children)
     261          24 :             obj->RecurseObject(isRestricted, callbackFunction, args...);
     262             :     }
     263             : 
     264             : protected:
     265             :     /**
     266             :      * Draws the object.
     267             :      */
     268             :     virtual void Draw(CCanvas2D& canvas) = 0;
     269             : 
     270             :     /**
     271             :      * Some objects need to be able to pre-emptively process SDL_Event_.
     272             :      *
     273             :      * Only the object with focus will have this function called.
     274             :      *
     275             :      * Returns either IN_PASS or IN_HANDLED. If IN_HANDLED, then
     276             :      * the event won't be passed on and processed by other handlers.
     277             :      */
     278           0 :     virtual InReaction PreemptEvent(const SDL_Event_* UNUSED(ev)) { return IN_PASS; }
     279             : 
     280             :     /**
     281             :      * Some objects need to handle the text-related SDL_Event_ manually.
     282             :      * For instance the input box.
     283             :      *
     284             :      * Only the object with focus will have this function called.
     285             :      *
     286             :      * Returns either IN_PASS or IN_HANDLED. If IN_HANDLED, then
     287             :      * the key won't be passed on and processed by other handlers.
     288             :      * This is used for keys that the GUI uses.
     289             :      */
     290           0 :     virtual InReaction ManuallyHandleKeys(const SDL_Event_* UNUSED(ev)) { return IN_PASS; }
     291             : 
     292             :     /**
     293             :      * Applies the given style to the object.
     294             :      *
     295             :      * Returns false if the style is not recognised (and thus has
     296             :      * not been applied).
     297             :      */
     298             :     bool ApplyStyle(const CStr& StyleName);
     299             : 
     300             :     /**
     301             :      * Returns not the Z value, but the actual buffered Z value, i.e. if it's
     302             :      * defined relative, then it will check its parent's Z value and add
     303             :      * the relativity.
     304             :      *
     305             :      * @return Actual Z value on the screen.
     306             :      */
     307             :     virtual float GetBufferedZ() const;
     308             : 
     309             :     /**
     310             :      * Add an object to the hierarchy.
     311             :      */
     312             :     void RegisterChild(IGUIObject* child);
     313             : 
     314             :     /**
     315             :      * Remove an object from the hierarchy.
     316             :      */
     317             :     void UnregisterChild(IGUIObject* child);
     318             : 
     319             :     /**
     320             :      * Set parent of this object
     321             :      */
     322           4 :     void SetParent(IGUIObject* pParent) { m_pParent = pParent; }
     323             : 
     324             : public:
     325             : 
     326           4 :     CGUI& GetGUI() { return m_pGUI; }
     327             :     const CGUI& GetGUI() const { return m_pGUI; }
     328             : 
     329             :     /**
     330             :      * Take focus!
     331             :      */
     332             :     void SetFocus();
     333             : 
     334             :     /**
     335             :      * Release focus.
     336             :      */
     337             :     void ReleaseFocus();
     338             : 
     339             : protected:
     340             :     /**
     341             :      * Check if object is focused.
     342             :      */
     343             :     bool IsFocused() const;
     344             : 
     345             :     /**
     346             :      * <b>NOTE!</b> This will not just return m_pParent, when that is
     347             :      * need use it! There is one exception to it, when the parent is
     348             :      * the top-node (the object that isn't a real object), this
     349             :      * will return nullptr, so that the top-node's children are
     350             :      * seemingly parentless.
     351             :      *
     352             :      * @return Pointer to parent
     353             :      */
     354             :     IGUIObject* GetParent() const;
     355             : 
     356             :     /**
     357             :      * Handle additional children to the \<object\>-tag. In IGUIObject, this function does
     358             :      * nothing. In CList and CDropDown, it handles the \<item\>, used to build the data.
     359             :      *
     360             :      * Returning false means the object doesn't recognize the child. Should be reported.
     361             :      * Notice 'false' is default, because an object not using this function, should not
     362             :      * have any additional children (and this function should never be called).
     363             :      */
     364           0 :     virtual bool HandleAdditionalChildren(const XMBData& UNUSED(file), const XMBElement& UNUSED(child))
     365             :     {
     366           0 :         return false;
     367             :     }
     368             : 
     369             :     /**
     370             :      * Allow the GUI object to process after all child items were handled.
     371             :      * Useful to avoid iterator invalidation with push_back calls.
     372             :      */
     373           4 :     virtual void AdditionalChildrenHandled() {}
     374             : 
     375             :     /**
     376             :      * Cached size, real size m_Size is actually dependent on resolution
     377             :      * and can have different *real* outcomes, this is the real outcome
     378             :      * cached to avoid slow calculations in real time.
     379             :      */
     380             :     CRect m_CachedActualSize;
     381             : 
     382             :     /**
     383             :      * Execute the script for a particular action.
     384             :      * Does nothing if no script has been registered for that action.
     385             :      * The mouse coordinates will be passed as the first argument.
     386             :      *
     387             :      * @param eventName Name of action
     388             :      */
     389             :     void ScriptEvent(const CStr& eventName);
     390             : 
     391             :     /**
     392             :      * Execute the script for a particular action.
     393             :      * Does nothing if no script has been registered for that action.
     394             :      * The mouse coordinates will be passed as the first argument.
     395             :      *
     396             :      * @param eventName Name of action
     397             :      *
     398             :      * @return True if the script returned something truthy.
     399             :      */
     400             :     bool ScriptEventWithReturn(const CStr& eventName);
     401             : 
     402             :     /**
     403             :      * Execute the script for a particular action.
     404             :      * Does nothing if no script has been registered for that action.
     405             :      *
     406             :      * @param eventName Name of action
     407             :      * @param paramData JS::HandleValueArray arguments to pass to the event.
     408             :      */
     409             :     void ScriptEvent(const CStr& eventName, const JS::HandleValueArray& paramData);
     410             : 
     411             :     /**
     412             :      * Execute the script for a particular action.
     413             :      * Does nothing if no script has been registered for that action.
     414             :      *
     415             :      * @param eventName Name of action
     416             :      * @param paramData JS::HandleValueArray arguments to pass to the event.
     417             :      *
     418             :      * @return True if the script returned something truthy.
     419             :      */
     420             :     bool ScriptEventWithReturn(const CStr& eventName, const JS::HandleValueArray& paramData);
     421             : 
     422             :     /**
     423             :      * Assigns a JS function to the event name.
     424             :      */
     425             :     void SetScriptHandler(const CStr& eventName, JS::HandleObject Function);
     426             : 
     427             :     /**
     428             :      * Deletes an event handler assigned to the given name, if such a handler exists.
     429             :      */
     430             :     void UnsetScriptHandler(const CStr& eventName);
     431             : 
     432             :     /**
     433             :      * Inputes the object that is currently hovered, this function
     434             :      * updates this object accordingly (i.e. if it's the object
     435             :      * being inputted one thing happens, and not, another).
     436             :      *
     437             :      * @param pMouseOver Object that is currently hovered, can be nullptr too!
     438             :      */
     439             :     void UpdateMouseOver(IGUIObject* const& pMouseOver);
     440             : 
     441             :     //@}
     442             : private:
     443             :     //--------------------------------------------------------
     444             :     /** @name Internal functions */
     445             :     //--------------------------------------------------------
     446             :     //@{
     447             : 
     448             :     /**
     449             :      * Creates the JS object representing this page upon first use.
     450             :      * This function (and its derived versions) are defined in the GUIProxy implementation file for convenience.
     451             :      */
     452             :     virtual void CreateJSObject();
     453             : 
     454             :     /**
     455             :      * Updates some internal data depending on the setting changed.
     456             :      */
     457             :     void SettingChanged(const CStr& Setting, const bool SendMessage);
     458             : 
     459             :     /**
     460             :      * Inputs a reference pointer, checks if the new inputted object
     461             :      * if hovered, if so, then check if this's Z value is greater
     462             :      * than the inputted object... If so then the object is closer
     463             :      * and we'll replace the pointer with this.
     464             :      * Also Notice input can be nullptr, which means the Z value demand
     465             :      *  is out. NOTICE you can't input nullptr as const so you'll have
     466             :      * to set an object to nullptr.
     467             :      *
     468             :      * @param pObject   Object pointer, can be either the old one, or
     469             :      *                  the new one.
     470             :      */
     471             :     void ChooseMouseOverAndClosest(IGUIObject*& pObject);
     472             : 
     473             :     /**
     474             :      * Returns whether this is the object all other objects are descendants of.
     475             :      */
     476             :     bool IsBaseObject() const;
     477             : 
     478             :     /**
     479             :      * Returns whether this object is a child of the base object.
     480             :      */
     481             :     bool IsRootObject() const;
     482             : 
     483           0 :     static void Trace(JSTracer* trc, void* data)
     484             :     {
     485           0 :         reinterpret_cast<IGUIObject*>(data)->TraceMember(trc);
     486           0 :     }
     487             : 
     488             :     void TraceMember(JSTracer* trc);
     489             : 
     490             : // Variables
     491             : protected:
     492             :     static const CStr EventNameMouseEnter;
     493             :     static const CStr EventNameMouseMove;
     494             :     static const CStr EventNameMouseLeave;
     495             : 
     496             :     // Name of object
     497             :     CStr m_Name;
     498             : 
     499             :     // Constructed on the heap, will be destroyed along with the the CGUI
     500             :     std::vector<IGUIObject*> m_Children;
     501             : 
     502             :     // Pointer to parent
     503             :     IGUIObject* m_pParent;
     504             : 
     505             :     //This represents the last click time for each mouse button
     506             :     double m_LastClickTime[6];
     507             : 
     508             :     /**
     509             :      * This variable is true if the mouse is hovering this object and
     510             :      * this object is the topmost object shown in this location.
     511             :      */
     512             :     bool m_MouseHovering;
     513             : 
     514             :     /**
     515             :      * Settings pool, all an object's settings are located here
     516             :      */
     517             :     std::map<CStr, IGUISetting*> m_Settings;
     518             : 
     519             :     // An object can't function stand alone
     520             :     CGUI& m_pGUI;
     521             : 
     522             :     // Internal storage for registered script handlers.
     523             :     std::map<CStr, JS::Heap<JSObject*> > m_ScriptHandlers;
     524             : 
     525             :     // Cached JSObject representing this GUI object.
     526             :     std::unique_ptr<IGUIProxyObject> m_JSObject;
     527             : 
     528             :     CGUISimpleSetting<bool> m_Enabled;
     529             :     CGUISimpleSetting<bool> m_Hidden;
     530             :     CGUISimpleSetting<CGUISize> m_Size;
     531             :     CGUISimpleSetting<CStr> m_Style;
     532             :     CGUIHotkey m_Hotkey;
     533             :     CGUISimpleSetting<float> m_Z;
     534             :     CGUISimpleSetting<bool> m_Absolute;
     535             :     CGUISimpleSetting<bool> m_Ghost;
     536             :     CGUISimpleSetting<float> m_AspectRatio;
     537             :     CGUISimpleSetting<CStrW> m_Tooltip;
     538             :     CGUISimpleSetting<CStr> m_TooltipStyle;
     539             : };
     540             : 
     541             : #endif // INCLUDED_IGUIOBJECT

Generated by: LCOV version 1.13