/* Copyright (C) 2015 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 .
*/
/*
The base class of an object
--Overview--
All objects are derived from this class, it's an ADT
so it can't be used per se
Also contains a Dummy object which is used for
completely blank objects.
--Usage--
Write about how to use it here
--Examples--
Provide examples of how to use this code, if necessary
--More info--
Check GUI.h
*/
#ifndef INCLUDED_IGUIOBJECT
#define INCLUDED_IGUIOBJECT
#include "GUIbase.h"
#include "GUItext.h"
#include "gui/scripting/JSInterface_IGUIObject.h"
#include "lib/input.h" // just for IN_PASS
#include "ps/XML/Xeromyces.h"
#include
#include
struct SGUISetting;
struct SGUIStyle;
class CGUI;
class JSObject;
ERROR_TYPE(GUI, UnableToParse);
/**
* Setting Type
* @see SGUISetting
*
* For use of later macros, all names should be GUIST_ followed
* by the code name (case sensitive!).
*/
#define TYPE(T) GUIST_##T,
enum EGUISettingType
{
#include "GUItypes.h"
};
#undef TYPE
/**
* A GUI Setting is anything that can be inputted from XML as
* \-attributes (with exceptions). For instance:
* \
*
* "style" will be a SGUISetting.
*/
struct SGUISetting
{
SGUISetting() : m_pSetting(NULL) {}
void *m_pSetting;
EGUISettingType m_Type;
};
/**
* Base settings, all objects possess these settings
* in their m_BaseSettings
* Instructions can be found in the documentations.
*/
/*struct SGUIBaseSettings
{
//int banan;
bool m_Absolute;
CStr m_Caption; // Is usually set within an XML element and not in the attributes
bool m_Enabled;
bool m_Ghost;
bool m_Hidden;
CClientArea m_Size;
CStr m_Style;
float m_Z;
};*/
//////////////////////////////////////////////////////////
/**
* GUI object such as a button or an input-box.
* Abstract data type !
*/
class IGUIObject
{
friend class CGUI;
friend class CInternalCGUIAccessorBase;
friend class IGUIScrollBar;
friend class GUITooltip;
// Allow getProperty to access things like GetParent()
friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp);
friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, jsval* vp);
public:
IGUIObject();
virtual ~IGUIObject();
/**
* Checks if mouse is hovering this object.
* The mouse position is cached in CGUI.
*
* This function checks if the mouse is hovering the
* rectangle that the base setting "size" makes.
* Although it is virtual, so one could derive
* an object from CButton, which changes only this
* to checking the circle that "size" makes.
*
* @return true if mouse is hovering
*/
virtual bool MouseOver();
/**
* Test if mouse position is over an icon
*/
virtual bool MouseOverIcon();
//--------------------------------------------------------
/** @name Leaf Functions */
//--------------------------------------------------------
//@{
/// Get object name, name is unique
const CStr& GetName() const { return m_Name; }
/// Get object name
void SetName(const CStr& Name) { m_Name = Name; }
// Get Presentable name.
// Will change all internally set names to something like ""
CStr GetPresentableName() const;
/**
* Adds object and its children to the map, it's name being the
* first part, and the second being itself.
*
* @param ObjectMap Adds this to the map_pObjects.
*
* @throws PSERROR_GUI_ObjectNeedsName Name is missing
* @throws PSERROR_GUI_NameAmbiguity Name is already taken
*/
void AddToPointersMap(map_pObjects& ObjectMap);
/**
* Notice nothing will be returned or thrown if the child hasn't
* been inputted into the GUI yet. This is because that's were
* all is checked. Now we're just linking two objects, but
* it's when we're inputting them into the GUI we'll check
* validity! Notice also when adding it to the GUI this function
* will inevitably have been called by CGUI::AddObject which
* will catch the throw and return the error code.
* i.e. The user will never put in the situation wherein a throw
* must be caught, the GUI's internal error handling will be
* completely transparent to the interfacially sequential model.
*
* @param pChild Child to add
*
* @throws PSERROR_GUI from CGUI::UpdateObjects().
*/
void AddChild(IGUIObject* pChild);
//@}
//--------------------------------------------------------
/** @name Iterate
* Used to iterate over all children of this object.
*/
//--------------------------------------------------------
//@{
vector_pObjects::iterator begin() { return m_Children.begin(); }
vector_pObjects::iterator end() { return m_Children.end(); }
//@}
//--------------------------------------------------------
/** @name Settings Management */
//--------------------------------------------------------
//@{
/**
* Checks if settings exists, only available for derived
* classes that has this set up, that's why the base
* class just returns false
*
* @param Setting setting name
* @return True if settings exist.
*/
bool SettingExists(const CStr& Setting) const;
/**
* All sizes are relative to resolution, and the calculation
* is not wanted in real time, therefore it is cached, update
* the cached size with this function.
*/
virtual void UpdateCachedSize();
/**
* Set a setting by string, regardless of what type it is.
*
* example a CRect(10,10,20,20) would be "10 10 20 20"
*
* @param Setting Setting by name
* @param Value Value to set to
* @param SkipMessage Does not send a GUIM_SETTINGS_UPDATED if true
*
* @return PSRETURN (PSRETURN_OK if successful)
*/
PSRETURN SetSetting(const CStr& Setting, const CStrW& Value, const bool& SkipMessage = false);
/**
* Retrieves the type of a named setting.
*
* @param Setting Setting by name
* @param Type Stores an EGUISettingType
* @return PSRETURN (PSRETURN_OK if successful)
*/
PSRETURN GetSettingType(const CStr& Setting, EGUISettingType& Type) const;
/**
* Set the script handler for a particular object-specific action
*
* @param Action Name of action
* @param Code Javascript code to execute when the action occurs
* @param pGUI GUI instance to associate the script with
*/
void RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI* pGUI);
/**
* Retrieves the JSObject representing this GUI object.
*/
JSObject* GetJSObject();
//@}
protected:
//--------------------------------------------------------
/** @name Called by CGUI and friends
*
* Methods that the CGUI will call using
* its friendship, these should not
* be called by user.
* These functions' security are a lot
* what constitutes the GUI's
*/
//--------------------------------------------------------
//@{
/**
* Add a setting to m_Settings
*
* @param Type Setting type
* @param Name Setting reference name
*/
void AddSetting(const EGUISettingType& Type, const CStr& Name);
/**
* Calls Destroy on all children, and deallocates all memory.
* MEGA TODO Should it destroy it's children?
*/
virtual void Destroy();
public:
/**
* This function is called with different messages
* for instance when the mouse enters the object.
*
* @param Message GUI Message
*/
virtual void HandleMessage(SGUIMessage& UNUSED(Message)) {}
protected:
/**
* Draws the object.
*
* @throws PSERROR if any. But this will mostlikely be
* very rare since if an object is drawn unsuccessfully
* it'll probably only output in the Error log, and not
* disrupt the whole GUI drawing.
*/
virtual void Draw() = 0;
/**
* Some objects need to handle the SDL_Event_ manually.
* For instance the input box.
*
* Only the object with focus will have this function called.
*
* Returns either IN_PASS or IN_HANDLED. If IN_HANDLED, then
* the key won't be passed on and processed by other handlers.
* This is used for keys that the GUI uses.
*/
virtual InReaction ManuallyHandleEvent(const SDL_Event_* UNUSED(ev)) { return IN_PASS; }
/**
* Loads a style.
*
* @param GUIinstance Reference to the GUI
* @param StyleName Style by name
*/
void LoadStyle(CGUI& GUIinstance, const CStr& StyleName);
/**
* Loads a style.
*
* @param Style The style object.
*/
void LoadStyle(const SGUIStyle& Style);
/**
* Returns not the Z value, but the actual buffered Z value, i.e. if it's
* defined relative, then it will check its parent's Z value and add
* the relativity.
*
* @return Actual Z value on the screen.
*/
virtual float GetBufferedZ() const;
void SetGUI(CGUI* const& pGUI);
/**
* Set parent of this object
*/
void SetParent(IGUIObject* pParent) { m_pParent = pParent; }
/**
* Reset internal state of this object
*/
virtual void ResetStates()
{
// Notify the gui that we aren't hovered anymore
UpdateMouseOver(NULL);
}
public:
CGUI* GetGUI() { return m_pGUI; }
const CGUI* GetGUI() const { return m_pGUI; }
/**
* Take focus!
*/
void SetFocus();
protected:
/**
* Check if object is focused.
*/
bool IsFocused() const;
/**
* NOTE! This will not just return m_pParent, when that is
* need use it! There is one exception to it, when the parent is
* the top-node (the object that isn't a real object), this
* will return NULL, so that the top-node's children are
* seemingly parentless.
*
* @return Pointer to parent
*/
IGUIObject* GetParent() const;
/**
* Get Mouse from CGUI.
*/
CPos GetMousePos() const;
/**
* Handle additional children to the \-tag. In IGUIObject, this function does
* nothing. In CList and CDropDown, it handles the \- , used to build the data.
*
* Returning false means the object doesn't recognize the child. Should be reported.
* Notice 'false' is default, because an object not using this function, should not
* have any additional children (and this function should never be called).
*/
virtual bool HandleAdditionalChildren(const XMBElement& UNUSED(child), CXeromyces* UNUSED(pFile))
{
return false;
}
/**
* Cached size, real size m_Size is actually dependent on resolution
* and can have different *real* outcomes, this is the real outcome
* cached to avoid slow calculations in real time.
*/
CRect m_CachedActualSize;
/**
* Send event to this GUI object (HandleMessage and ScriptEvent)
*
* @param type Type of GUI message to be handled
* @param EventName String representation of event name
* @return IN_HANDLED if event was handled, or IN_PASS if skipped
*/
InReaction SendEvent(EGUIMessageType type, const CStr& EventName);
/**
* Execute the script for a particular action.
* Does nothing if no script has been registered for that action.
* The mouse coordinates will be passed as the first argument.
*
* @param Action Name of action
*/
void ScriptEvent(const CStr& Action);
/**
* Execute the script for a particular action.
* Does nothing if no script has been registered for that action.
*
* @param Action Name of action
* @param Argument Argument to pass to action
*/
void ScriptEvent(const CStr& Action, JS::HandleValue Argument);
void SetScriptHandler(const CStr& Action, JS::HandleObject Function);
/**
* Inputes the object that is currently hovered, this function
* updates this object accordingly (i.e. if it's the object
* being inputted one thing happens, and not, another).
*
* @param pMouseOver Object that is currently hovered,
* can OF COURSE be NULL too!
*/
void UpdateMouseOver(IGUIObject* const& pMouseOver);
//@}
private:
//--------------------------------------------------------
/** @name Internal functions */
//--------------------------------------------------------
//@{
/**
* Inputs a reference pointer, checks if the new inputted object
* if hovered, if so, then check if this's Z value is greater
* than the inputted object... If so then the object is closer
* and we'll replace the pointer with this.
* Also Notice input can be NULL, which means the Z value demand
* is out. NOTICE you can't input NULL as const so you'll have
* to set an object to NULL.
*
* @param pObject Object pointer, can be either the old one, or
* the new one.
*/
void ChooseMouseOverAndClosest(IGUIObject*& pObject);
// Is the object a Root object, in philosophy, this means it
// has got no parent, and technically, it's got the m_BaseObject
// as parent.
bool IsRootObject() const;
/**
* Logs an invalid setting search and returns the correct return result
*
* @return the error result
*/
PSRETURN LogInvalidSettings(const CStr8& Setting) const;
static void Trace(JSTracer* trc, void* data)
{
reinterpret_cast
(data)->TraceMember(trc);
}
void TraceMember(JSTracer* trc);
// Variables
protected:
// Name of object
CStr m_Name;
// Constructed on the heap, will be destroyed along with the the object
// TODO Gee: really the above?
vector_pObjects m_Children;
// Pointer to parent
IGUIObject *m_pParent;
//This represents the last click time for each mouse button
double m_LastClickTime[6];
/**
* This is an array of true or false, each element is associated with
* a string representing a setting. Number of elements is equal to
* number of settings.
*
* A true means the setting has been manually set in the file when
* read. This is important to know because I don't want to force
* the user to include its \-XML-files first, so somehow
* the GUI needs to know which settings were set, and which is meant
* to.
*/
// More variables
// Is mouse hovering the object? used with the function MouseOver()
bool m_MouseHovering;
/**
* Settings pool, all an object's settings are located here
* If a derived object has got more settings that the base
* settings, it's because they have a new version of the
* function SetupSettings().
*
* @see SetupSettings()
*/
public:
std::map m_Settings;
private:
// An object can't function stand alone
CGUI *m_pGUI;
// Internal storage for registered script handlers.
std::map > m_ScriptHandlers;
// Cached JSObject representing this GUI object
DefPersistentRooted m_JSObject;
};
/**
* Dummy object used primarily for the root object
* or objects of type 'empty'
*/
class CGUIDummyObject : public IGUIObject
{
GUI_OBJECT(CGUIDummyObject)
public:
virtual void Draw() {}
// Empty can never be hovered. It is only a category.
virtual bool MouseOver() { return false; }
};
#endif // INCLUDED_IGUIOBJECT