Support deleting GUI Object event handlers following rP666, refs #5387.
[0ad.git] / source / gui / ObjectBases / IGUIObject.h
blobfaad41cf731b5fbdc9beadcd195cfcf4ff9e7cfa
1 /* Copyright (C) 2019 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
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.
25 #ifndef INCLUDED_IGUIOBJECT
26 #define INCLUDED_IGUIOBJECT
28 #include "gui/Scripting/JSInterface_IGUIObject.h"
29 #include "gui/SettingTypes/CGUISize.h"
30 #include "gui/SGUIMessage.h"
31 #include "lib/input.h" // just for IN_PASS
32 #include "ps/XML/Xeromyces.h"
34 #include <map>
35 #include <string>
36 #include <vector>
38 class CGUI;
39 class IGUIObject;
40 class IGUISetting;
42 using map_pObjects = std::map<CStr, IGUIObject*>;
44 #define GUI_OBJECT(obj) \
45 public: \
46 static IGUIObject* ConstructObject(CGUI& pGUI) \
47 { return new obj(pGUI); }
49 /**
50 * GUI object such as a button or an input-box.
51 * Abstract data type !
53 class IGUIObject
55 friend class CGUI;
57 // Allow getProperty to access things like GetParent()
58 friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
59 friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result);
60 friend bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result);
61 friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp);
63 public:
64 NONCOPYABLE(IGUIObject);
66 IGUIObject(CGUI& pGUI);
67 virtual ~IGUIObject();
69 /**
70 * This function checks if the mouse is hovering the
71 * rectangle that the base setting "size" makes.
72 * Although it is virtual, so one could derive
73 * an object from CButton, which changes only this
74 * to checking the circle that "size" makes.
76 * This function also returns true if there is a different
77 * GUI object shown on top of this one.
79 virtual bool IsMouseOver() const;
81 /**
82 * This function returns true if the mouse is hovering
83 * over this GUI object and if this GUI object is the
84 * topmost object in that screen location.
85 * For example when hovering dropdown list items, the
86 * buttons beneath the list won't return true here.
88 virtual bool IsMouseHovering() const { return m_MouseHovering; }
90 /**
91 * Test if mouse position is over an icon
93 virtual bool MouseOverIcon();
95 //--------------------------------------------------------
96 /** @name Leaf Functions */
97 //--------------------------------------------------------
98 //@{
100 /// Get object name, name is unique
101 const CStr& GetName() const { return m_Name; }
103 /// Get object name
104 void SetName(const CStr& Name) { m_Name = Name; }
106 // Get Presentable name.
107 // Will change all internally set names to something like "<unnamed object>"
108 CStr GetPresentableName() const;
111 * Builds the object hierarchy with references.
113 void AddChild(IGUIObject& pChild);
116 * Return all child objects of the current object.
118 const std::vector<IGUIObject*>& GetChildren() const { return m_Children; }
120 //@}
121 //--------------------------------------------------------
122 /** @name Settings Management */
123 //--------------------------------------------------------
124 //@{
127 * Registers the given setting variables with the GUI object.
128 * Enable XML and JS to modify the given variable.
130 * @param Type Setting type
131 * @param Name Setting reference name
133 template<typename T>
134 void RegisterSetting(const CStr& Name, T& Value);
137 * Returns whether there is a setting with the given name registered.
139 * @param Setting setting name
140 * @return True if settings exist.
142 bool SettingExists(const CStr& Setting) const;
145 * Get a mutable reference to the setting.
146 * If no such setting exists, an exception of type std::out_of_range is thrown.
147 * If the value is modified, there is no GUIM_SETTINGS_UPDATED message sent.
149 template <typename T>
150 T& GetSetting(const CStr& Setting);
152 template <typename T>
153 const T& GetSetting(const CStr& Setting) const;
156 * Set a setting by string, regardless of what type it is.
157 * Used to parse setting values from XML files.
158 * For example a CRect(10,10,20,20) is created from "10 10 20 20".
159 * Returns false if the conversion fails, otherwise true.
161 bool SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage);
164 * Assigns the given value to the setting identified by the given name.
165 * Uses move semantics, so do not read from Value after this call.
167 * @param SendMessage If true, a GUIM_SETTINGS_UPDATED message will be broadcasted to all GUI objects.
169 template <typename T>
170 void SetSetting(const CStr& Setting, T& Value, const bool SendMessage);
173 * This variant will copy the value.
175 template <typename T>
176 void SetSetting(const CStr& Setting, const T& Value, const bool SendMessage);
179 * Returns whether this object is set to be hidden or ghost.
181 bool IsEnabled() const;
184 * Returns whether this is object is set to be hidden.
186 bool IsHidden() const;
189 * Returns whether this object is set to be hidden or ghost.
191 bool IsHiddenOrGhost() const;
194 * Retrieves the configured sound filename from the given setting name and plays that once.
196 void PlaySound(const CStrW& soundPath) const;
199 * Send event to this GUI object (HandleMessage and ScriptEvent)
201 * @param type Type of GUI message to be handled
202 * @param EventName String representation of event name
203 * @return IN_HANDLED if event was handled, or IN_PASS if skipped
205 InReaction SendEvent(EGUIMessageType type, const CStr& EventName);
208 * All sizes are relative to resolution, and the calculation
209 * is not wanted in real time, therefore it is cached, update
210 * the cached size with this function.
212 virtual void UpdateCachedSize();
215 * Reset internal state of this object.
217 virtual void ResetStates();
220 * Set the script handler for a particular object-specific action
222 * @param Action Name of action
223 * @param Code Javascript code to execute when the action occurs
224 * @param pGUI GUI instance to associate the script with
226 void RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI& pGUI);
229 * Inheriting classes may append JS functions to the JS object representing this class.
231 virtual void RegisterScriptFunctions() {}
234 * Retrieves the JSObject representing this GUI object.
236 JSObject* GetJSObject();
238 //@}
239 protected:
240 //--------------------------------------------------------
241 /** @name Called by CGUI and friends
243 * Methods that the CGUI will call using
244 * its friendship, these should not
245 * be called by user.
246 * These functions' security are a lot
247 * what constitutes the GUI's
249 //--------------------------------------------------------
250 //@{
252 public:
254 * This function is called with different messages
255 * for instance when the mouse enters the object.
257 * @param Message GUI Message
259 virtual void HandleMessage(SGUIMessage& UNUSED(Message)) {}
262 * Calls an IGUIObject member function recursively on this object and its children.
263 * Aborts recursion at IGUIObjects that have the isRestricted function return true.
264 * The arguments of the callback function must be references.
266 template<typename... Args>
267 void RecurseObject(bool(IGUIObject::*isRestricted)() const, void(IGUIObject::*callbackFunction)(Args... args), Args&&... args)
269 if (!IsBaseObject())
271 if (isRestricted && (this->*isRestricted)())
272 return;
274 (this->*callbackFunction)(args...);
277 for (IGUIObject* const& obj : m_Children)
278 obj->RecurseObject(isRestricted, callbackFunction, args...);
281 protected:
283 * Draws the object.
285 virtual void Draw() = 0;
288 * Some objects need to handle the SDL_Event_ manually.
289 * For instance the input box.
291 * Only the object with focus will have this function called.
293 * Returns either IN_PASS or IN_HANDLED. If IN_HANDLED, then
294 * the key won't be passed on and processed by other handlers.
295 * This is used for keys that the GUI uses.
297 virtual InReaction ManuallyHandleEvent(const SDL_Event_* UNUSED(ev)) { return IN_PASS; }
300 * Loads a style.
302 void LoadStyle(const CStr& StyleName);
305 * Returns not the Z value, but the actual buffered Z value, i.e. if it's
306 * defined relative, then it will check its parent's Z value and add
307 * the relativity.
309 * @return Actual Z value on the screen.
311 virtual float GetBufferedZ() const;
314 * Set parent of this object
316 void SetParent(IGUIObject* pParent) { m_pParent = pParent; }
318 public:
320 CGUI& GetGUI() { return m_pGUI; }
321 const CGUI& GetGUI() const { return m_pGUI; }
324 * Take focus!
326 void SetFocus();
328 protected:
330 * Check if object is focused.
332 bool IsFocused() const;
335 * <b>NOTE!</b> This will not just return m_pParent, when that is
336 * need use it! There is one exception to it, when the parent is
337 * the top-node (the object that isn't a real object), this
338 * will return nullptr, so that the top-node's children are
339 * seemingly parentless.
341 * @return Pointer to parent
343 IGUIObject* GetParent() const;
346 * Handle additional children to the \<object\>-tag. In IGUIObject, this function does
347 * nothing. In CList and CDropDown, it handles the \<item\>, used to build the data.
349 * Returning false means the object doesn't recognize the child. Should be reported.
350 * Notice 'false' is default, because an object not using this function, should not
351 * have any additional children (and this function should never be called).
353 virtual bool HandleAdditionalChildren(const XMBElement& UNUSED(child), CXeromyces* UNUSED(pFile))
355 return false;
359 * Allow the GUI object to process after all child items were handled.
360 * Useful to avoid iterator invalidation with push_back calls.
362 virtual void AdditionalChildrenHandled() {}
365 * Cached size, real size m_Size is actually dependent on resolution
366 * and can have different *real* outcomes, this is the real outcome
367 * cached to avoid slow calculations in real time.
369 CRect m_CachedActualSize;
372 * Execute the script for a particular action.
373 * Does nothing if no script has been registered for that action.
374 * The mouse coordinates will be passed as the first argument.
376 * @param Action Name of action
378 void ScriptEvent(const CStr& Action);
381 * Execute the script for a particular action.
382 * Does nothing if no script has been registered for that action.
384 * @param Action Name of action
385 * @param paramData JS::HandleValueArray arguments to pass to the event.
387 void ScriptEvent(const CStr& Action, const JS::HandleValueArray& paramData);
390 * Assigns a JS function to the event name.
392 void SetScriptHandler(const CStr& Action, JS::HandleObject Function);
395 * Deletes an event handler assigned to the given name, if such a handler exists.
397 void UnsetScriptHandler(const CStr& Action);
400 * Inputes the object that is currently hovered, this function
401 * updates this object accordingly (i.e. if it's the object
402 * being inputted one thing happens, and not, another).
404 * @param pMouseOver Object that is currently hovered, can be nullptr too!
406 void UpdateMouseOver(IGUIObject* const& pMouseOver);
408 //@}
409 private:
410 //--------------------------------------------------------
411 /** @name Internal functions */
412 //--------------------------------------------------------
413 //@{
416 * Creates the JS object representing this page upon first use.
418 void CreateJSObject();
421 * Updates some internal data depending on the setting changed.
423 void PreSettingChange(const CStr& Setting);
424 void SettingChanged(const CStr& Setting, const bool SendMessage);
427 * Inputs a reference pointer, checks if the new inputted object
428 * if hovered, if so, then check if this's Z value is greater
429 * than the inputted object... If so then the object is closer
430 * and we'll replace the pointer with this.
431 * Also Notice input can be nullptr, which means the Z value demand
432 * is out. NOTICE you can't input nullptr as const so you'll have
433 * to set an object to nullptr.
435 * @param pObject Object pointer, can be either the old one, or
436 * the new one.
438 void ChooseMouseOverAndClosest(IGUIObject*& pObject);
441 * Returns whether this is the object all other objects are descendants of.
443 bool IsBaseObject() const;
446 * Returns whether this object is a child of the base object.
448 bool IsRootObject() const;
450 static void Trace(JSTracer* trc, void* data)
452 reinterpret_cast<IGUIObject*>(data)->TraceMember(trc);
455 void TraceMember(JSTracer* trc);
457 // Variables
458 protected:
459 // Name of object
460 CStr m_Name;
462 // Constructed on the heap, will be destroyed along with the the CGUI
463 std::vector<IGUIObject*> m_Children;
465 // Pointer to parent
466 IGUIObject* m_pParent;
468 //This represents the last click time for each mouse button
469 double m_LastClickTime[6];
472 * This variable is true if the mouse is hovering this object and
473 * this object is the topmost object shown in this location.
475 bool m_MouseHovering;
478 * Settings pool, all an object's settings are located here
480 std::map<CStr, IGUISetting*> m_Settings;
482 // An object can't function stand alone
483 CGUI& m_pGUI;
485 // Internal storage for registered script handlers.
486 std::map<CStr, JS::Heap<JSObject*> > m_ScriptHandlers;
488 // Cached JSObject representing this GUI object
489 JS::PersistentRootedObject m_JSObject;
491 // Cache references to settings for performance
492 bool m_Enabled;
493 bool m_Hidden;
494 CGUISize m_Size;
495 CStr m_Style;
496 CStr m_Hotkey;
497 float m_Z;
498 bool m_Absolute;
499 bool m_Ghost;
500 float m_AspectRatio;
501 CStrW m_Tooltip;
502 CStr m_TooltipStyle;
505 #endif // INCLUDED_IGUIOBJECT