Changeset View
Changeset View
Standalone View
Standalone View
source/gui/IGUIObject.cpp
Show All 24 Lines | |||||
#include "gui/scripting/JSInterface_IGUIObject.h" | #include "gui/scripting/JSInterface_IGUIObject.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "soundmanager/ISoundManager.h" | #include "soundmanager/ISoundManager.h" | ||||
IGUIObject::IGUIObject(CGUI& pGUI) | IGUIObject::IGUIObject(CGUI& pGUI) | ||||
: m_pGUI(pGUI), m_pParent(nullptr), m_MouseHovering(false), m_LastClickTime() | : m_pGUI(pGUI), | ||||
{ | m_pParent(), | ||||
AddSetting<bool>("enabled"); | m_MouseHovering(), | ||||
AddSetting<bool>("hidden"); | m_LastClickTime(), | ||||
AddSetting<CClientArea>("size"); | m_Enabled(), | ||||
AddSetting<CStr>("style"); | m_Hidden(), | ||||
AddSetting<CStr>("hotkey"); | m_Size(), | ||||
AddSetting<float>("z"); | m_Style(), | ||||
AddSetting<bool>("absolute"); | m_Hotkey(), | ||||
AddSetting<bool>("ghost"); | m_Z(), | ||||
AddSetting<float>("aspectratio"); | m_Absolute(), | ||||
AddSetting<CStrW>("tooltip"); | m_Ghost(), | ||||
AddSetting<CStr>("tooltip_style"); | m_AspectRatio(), | ||||
m_Tooltip(), | |||||
m_TooltipStyle() | |||||
{ | |||||
RegisterSetting("enabled", m_Enabled); | |||||
RegisterSetting("hidden", m_Hidden); | |||||
RegisterSetting("size", m_Size); | |||||
RegisterSetting("style", m_Style); | |||||
RegisterSetting("hotkey", m_Hotkey); | |||||
RegisterSetting("z", m_Z); | |||||
RegisterSetting("absolute", m_Absolute); | |||||
RegisterSetting("ghost", m_Ghost); | |||||
RegisterSetting("aspectratio", m_AspectRatio); | |||||
RegisterSetting("tooltip", m_Tooltip); | |||||
RegisterSetting("tooltip_style", m_TooltipStyle); | |||||
// Setup important defaults | // Setup important defaults | ||||
// TODO: Should be in the default style? | |||||
SetSetting<bool>("hidden", false, true); | SetSetting<bool>("hidden", false, true); | ||||
SetSetting<bool>("ghost", false, true); | SetSetting<bool>("ghost", false, true); | ||||
SetSetting<bool>("enabled", true, true); | SetSetting<bool>("enabled", true, true); | ||||
SetSetting<bool>("absolute", true, true); | SetSetting<bool>("absolute", true, true); | ||||
} | } | ||||
IGUIObject::~IGUIObject() | IGUIObject::~IGUIObject() | ||||
{ | { | ||||
for (const std::pair<CStr, IGUISetting*>& p : m_Settings) | for (const std::pair<CStr, IGUISetting*>& p : m_Settings) | ||||
delete p.second; | delete p.second; | ||||
elexis: ```
- for (const std::pair<CStr, IGUISetting*>& p : m_Settings)
- delete p.second;
```
This… | |||||
if (!m_ScriptHandlers.empty()) | if (!m_ScriptHandlers.empty()) | ||||
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this); | JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetJSRuntime(), Trace, this); | ||||
} | } | ||||
//------------------------------------------------------------------- | //------------------------------------------------------------------- | ||||
// Functions | // Functions | ||||
//------------------------------------------------------------------- | //------------------------------------------------------------------- | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | void IGUIObject::AddToPointersMap(map_pObjects& ObjectMap) | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
ObjectMap[m_Name] = this; | ObjectMap[m_Name] = this; | ||||
} | } | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void IGUIObject::AddSetting(const CStr& Name) | void IGUIObject::RegisterSetting(const CStr& Name, T& Value) | ||||
{ | { | ||||
if (SettingExists(Name)) | if (SettingExists(Name)) | ||||
LOGERROR("The setting '%s' already exists on the object '%s'!", Name.c_str(), GetPresentableName().c_str()); | LOGERROR("The setting '%s' already exists on the object '%s'!", Name.c_str(), GetPresentableName().c_str()); | ||||
else | else | ||||
m_Settings.emplace(Name, new CGUISetting<T>(*this, Name)); | m_Settings.emplace(Name, new CGUISetting<T>(*this, Name, Value)); | ||||
} | } | ||||
bool IGUIObject::SettingExists(const CStr& Setting) const | bool IGUIObject::SettingExists(const CStr& Setting) const | ||||
{ | { | ||||
return m_Settings.find(Setting) != m_Settings.end(); | return m_Settings.find(Setting) != m_Settings.end(); | ||||
} | } | ||||
template <typename T> | template <typename T> | ||||
Show All 18 Lines | bool IGUIObject::SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage) | ||||
} | } | ||||
return it->second->FromString(Value, SendMessage); | return it->second->FromString(Value, SendMessage); | ||||
} | } | ||||
template <typename T> | template <typename T> | ||||
void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage) | void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage) | ||||
{ | { | ||||
PreSettingChange(Setting); | PreSettingChange(Setting); | ||||
static_cast<CGUISetting<T>* >(m_Settings[Setting])->m_pSetting = std::move(Value); | static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting = std::move(Value); | ||||
SettingChanged(Setting, SendMessage); | SettingChanged(Setting, SendMessage); | ||||
} | } | ||||
template <typename T> | template <typename T> | ||||
void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage) | void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage) | ||||
{ | { | ||||
PreSettingChange(Setting); | PreSettingChange(Setting); | ||||
static_cast<CGUISetting<T>* >(m_Settings[Setting])->m_pSetting = Value; | static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting = Value; | ||||
SettingChanged(Setting, SendMessage); | SettingChanged(Setting, SendMessage); | ||||
} | } | ||||
void IGUIObject::PreSettingChange(const CStr& Setting) | void IGUIObject::PreSettingChange(const CStr& Setting) | ||||
{ | { | ||||
if (Setting == "hotkey") | if (Setting == "hotkey") | ||||
m_pGUI.UnsetObjectHotkey(this, GetSetting<CStr>(Setting)); | m_pGUI.UnsetObjectHotkey(this, GetSetting<CStr>(Setting)); | ||||
} | } | ||||
void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage) | void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage) | ||||
{ | { | ||||
if (Setting == "size") | if (Setting == "size") | ||||
{ | { | ||||
// If setting was "size", we need to re-cache itself and all children | // If setting was "size", we need to re-cache itself and all children | ||||
RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); | RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); | ||||
} | } | ||||
else if (Setting == "hidden") | else if (Setting == "hidden") | ||||
{ | { | ||||
// Hiding an object requires us to reset it and all children | // Hiding an object requires us to reset it and all children | ||||
if (GetSetting<bool>(Setting)) | if (m_Hidden) | ||||
RecurseObject(nullptr, &IGUIObject::ResetStates); | RecurseObject(nullptr, &IGUIObject::ResetStates); | ||||
} | } | ||||
else if (Setting == "hotkey") | else if (Setting == "hotkey") | ||||
m_pGUI.SetObjectHotkey(this, GetSetting<CStr>(Setting)); | m_pGUI.SetObjectHotkey(this, GetSetting<CStr>(Setting)); | ||||
if (SendMessage) | if (SendMessage) | ||||
{ | { | ||||
SGUIMessage msg(GUIM_SETTINGS_UPDATED, Setting); | SGUIMessage msg(GUIM_SETTINGS_UPDATED, Setting); | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
void IGUIObject::ResetStates() | void IGUIObject::ResetStates() | ||||
{ | { | ||||
// Notify the gui that we aren't hovered anymore | // Notify the gui that we aren't hovered anymore | ||||
UpdateMouseOver(nullptr); | UpdateMouseOver(nullptr); | ||||
} | } | ||||
void IGUIObject::UpdateCachedSize() | void IGUIObject::UpdateCachedSize() | ||||
{ | { | ||||
const CClientArea& ca = GetSetting<CClientArea>("size"); | |||||
const float aspectratio = GetSetting<float>("aspectratio"); | |||||
// If absolute="false" and the object has got a parent, | // If absolute="false" and the object has got a parent, | ||||
// use its cached size instead of the screen. Notice | // use its cached size instead of the screen. Notice | ||||
// it must have just been cached for it to work. | // it must have just been cached for it to work. | ||||
if (!GetSetting<bool>("absolute") && m_pParent && !IsRootObject()) | if (!m_Absolute && m_pParent && !IsRootObject()) | ||||
m_CachedActualSize = ca.GetClientArea(m_pParent->m_CachedActualSize); | m_CachedActualSize = m_Size.GetClientArea(m_pParent->m_CachedActualSize); | ||||
else | else | ||||
m_CachedActualSize = ca.GetClientArea(CRect(0.f, 0.f, g_xres / g_GuiScale, g_yres / g_GuiScale)); | m_CachedActualSize = m_Size.GetClientArea(CRect(0.f, 0.f, g_xres / g_GuiScale, g_yres / g_GuiScale)); | ||||
// In a few cases, GUI objects have to resize to fill the screen | // In a few cases, GUI objects have to resize to fill the screen | ||||
// but maintain a constant aspect ratio. | // but maintain a constant aspect ratio. | ||||
// Adjust the size to be the max possible, centered in the original size: | // Adjust the size to be the max possible, centered in the original size: | ||||
if (aspectratio) | if (m_AspectRatio) | ||||
{ | { | ||||
if (m_CachedActualSize.GetWidth() > m_CachedActualSize.GetHeight()*aspectratio) | if (m_CachedActualSize.GetWidth() > m_CachedActualSize.GetHeight() * m_AspectRatio) | ||||
{ | { | ||||
float delta = m_CachedActualSize.GetWidth() - m_CachedActualSize.GetHeight()*aspectratio; | float delta = m_CachedActualSize.GetWidth() - m_CachedActualSize.GetHeight() * m_AspectRatio; | ||||
m_CachedActualSize.left += delta/2.f; | m_CachedActualSize.left += delta/2.f; | ||||
m_CachedActualSize.right -= delta/2.f; | m_CachedActualSize.right -= delta/2.f; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
float delta = m_CachedActualSize.GetHeight() - m_CachedActualSize.GetWidth()/aspectratio; | float delta = m_CachedActualSize.GetHeight() - m_CachedActualSize.GetWidth() / m_AspectRatio; | ||||
m_CachedActualSize.bottom -= delta/2.f; | m_CachedActualSize.bottom -= delta/2.f; | ||||
m_CachedActualSize.top += delta/2.f; | m_CachedActualSize.top += delta/2.f; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void IGUIObject::LoadStyle(const CStr& StyleName) | void IGUIObject::LoadStyle(const CStr& StyleName) | ||||
{ | { | ||||
Show All 10 Lines | if (SettingExists(p.first)) | ||||
SetSettingFromString(p.first, p.second, true); | SetSettingFromString(p.first, p.second, true); | ||||
else if (StyleName != "default") | else if (StyleName != "default") | ||||
LOGWARNING("GUI object has no setting \"%s\", but the style \"%s\" defines it", p.first, StyleName.c_str()); | LOGWARNING("GUI object has no setting \"%s\", but the style \"%s\" defines it", p.first, StyleName.c_str()); | ||||
} | } | ||||
} | } | ||||
float IGUIObject::GetBufferedZ() const | float IGUIObject::GetBufferedZ() const | ||||
{ | { | ||||
const float Z = GetSetting<float>("z"); | if (m_Absolute) | ||||
return m_Z; | |||||
if (GetSetting<bool>("absolute")) | |||||
return Z; | |||||
{ | { | ||||
if (GetParent()) | if (GetParent()) | ||||
return GetParent()->GetBufferedZ() + Z; | return GetParent()->GetBufferedZ() + m_Z; | ||||
else | else | ||||
{ | |||||
// In philosophy, a parentless object shouldn't be able to have a relative sizing, | // In philosophy, a parentless object shouldn't be able to have a relative sizing, | ||||
// but we'll accept it so that absolute can be used as default without a complaint. | // but we'll accept it so that absolute can be used as default without a complaint. | ||||
// Also, you could consider those objects children to the screen resolution. | // Also, you could consider those objects children to the screen resolution. | ||||
return Z; | return m_Z; | ||||
} | |||||
} | } | ||||
} | } | ||||
void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI& pGUI) | void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI& pGUI) | ||||
{ | { | ||||
JSContext* cx = pGUI.GetScriptInterface()->GetContext(); | JSContext* cx = pGUI.GetScriptInterface()->GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue globalVal(cx, pGUI.GetGlobalObject()); | JS::RootedValue globalVal(cx, pGUI.GetGlobalObject()); | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | JSObject* IGUIObject::GetJSObject() | ||||
if (!m_JSObject.initialized()) | if (!m_JSObject.initialized()) | ||||
CreateJSObject(); | CreateJSObject(); | ||||
return m_JSObject.get(); | return m_JSObject.get(); | ||||
} | } | ||||
bool IGUIObject::IsHidden() const | bool IGUIObject::IsHidden() const | ||||
{ | { | ||||
// Statically initialise some strings, so we don't have to do | return m_Hidden; | ||||
// lots of allocation every time this function is called | |||||
static const CStr strHidden("hidden"); | |||||
return GetSetting<bool>(strHidden); | |||||
} | } | ||||
bool IGUIObject::IsHiddenOrGhost() const | bool IGUIObject::IsHiddenOrGhost() const | ||||
{ | { | ||||
static const CStr strGhost("ghost"); | return m_Hidden || m_Ghost; | ||||
return IsHidden() || GetSetting<bool>(strGhost); | |||||
} | } | ||||
void IGUIObject::PlaySound(const CStr& settingName) const | void IGUIObject::PlaySound(const CStrW& soundPath) const | ||||
{ | { | ||||
if (!g_SoundManager) | if (g_SoundManager && !soundPath.empty()) | ||||
return; | |||||
const CStrW& soundPath = GetSetting<CStrW>(settingName); | |||||
if (!soundPath.empty()) | |||||
g_SoundManager->PlayAsUI(soundPath.c_str(), false); | g_SoundManager->PlayAsUI(soundPath.c_str(), false); | ||||
} | } | ||||
CStr IGUIObject::GetPresentableName() const | CStr IGUIObject::GetPresentableName() const | ||||
{ | { | ||||
// __internal(), must be at least 13 letters to be able to be | // __internal(), must be at least 13 letters to be able to be | ||||
// an internal name | // an internal name | ||||
if (m_Name.length() <= 12) | if (m_Name.length() <= 12) | ||||
Show All 31 Lines | void IGUIObject::TraceMember(JSTracer* trc) | ||||
for (std::pair<const CStr, JS::Heap<JSObject*>>& handler : m_ScriptHandlers) | for (std::pair<const CStr, JS::Heap<JSObject*>>& handler : m_ScriptHandlers) | ||||
JS_CallObjectTracer(trc, &handler.second, "IGUIObject::m_ScriptHandlers"); | JS_CallObjectTracer(trc, &handler.second, "IGUIObject::m_ScriptHandlers"); | ||||
} | } | ||||
// Instantiate templated functions: | // Instantiate templated functions: | ||||
// These functions avoid copies by working with a reference and move semantics. | // These functions avoid copies by working with a reference and move semantics. | ||||
#define TYPE(T) \ | #define TYPE(T) \ | ||||
template void IGUIObject::AddSetting<T>(const CStr& Name); \ | template void IGUIObject::RegisterSetting<T>(const CStr& Name, T& Value); \ | ||||
template T& IGUIObject::GetSetting<T>(const CStr& Setting); \ | template T& IGUIObject::GetSetting<T>(const CStr& Setting); \ | ||||
template const T& IGUIObject::GetSetting<T>(const CStr& Setting) const; \ | template const T& IGUIObject::GetSetting<T>(const CStr& Setting) const; \ | ||||
template void IGUIObject::SetSetting<T>(const CStr& Setting, T& Value, const bool SendMessage); \ | template void IGUIObject::SetSetting<T>(const CStr& Setting, T& Value, const bool SendMessage); \ | ||||
#include "gui/GUItypes.h" | #include "gui/GUItypes.h" | ||||
#undef TYPE | #undef TYPE | ||||
// Copying functions - discouraged except for primitives. | // Copying functions - discouraged except for primitives. | ||||
#define TYPE(T) \ | #define TYPE(T) \ | ||||
template void IGUIObject::SetSetting<T>(const CStr& Setting, const T& Value, const bool SendMessage); \ | template void IGUIObject::SetSetting<T>(const CStr& Setting, const T& Value, const bool SendMessage); \ | ||||
#define GUITYPE_IGNORE_NONCOPYABLE | #define GUITYPE_IGNORE_NONCOPYABLE | ||||
#include "gui/GUItypes.h" | #include "gui/GUItypes.h" | ||||
#undef GUITYPE_IGNORE_NONCOPYABLE | #undef GUITYPE_IGNORE_NONCOPYABLE | ||||
#undef TYPE | #undef TYPE |
Wildfire Games · Phabricator
This deletes the CGUISetting pointer, not the setting value of type T in CGUISetting, so this deletion must be kept if we don't want the leak reported by valgrind:
Found P178 / D2331 while verifying, of course theres more than that.