1
0
forked from 0ad/0ad

Change GUI settings to explicitly be member variables.

Completes work starting in D2313 / a33fd55e81:
- Make C++ mistakes where values can be changed without messages being
sent easier to notice / harder to do.
- Make the IGUISetting interface more flexible, allowing custom settings
implementing their own logic. This is used to clean up hotkey code
introduced in 33af6da5e1.

Side effects:
- FromJSVal_Vector clears the vector being passed in. I have some vague
memory of not doing that in D24 / 2bae30c454 as an optimisation, but it
seems more like a footgun to me.
- Most usage of SetSettingFromString is replaced by direct method calls,
as we can generally cast to the proper GUI object type. Where we can't,
it is kept as a poor's man virtual dispatch.
- It moves a few member variables elsewhere, e.g. TextOwner now gets its
own member variable settings.

Differential Revision: https://code.wildfiregames.com/D3892
This was SVN commit r25392.
This commit is contained in:
wraitii 2021-05-06 08:22:37 +00:00
parent 4db5467717
commit 8b08f4ae7a
46 changed files with 797 additions and 945 deletions

View File

@ -441,8 +441,7 @@ void CGUI::SetObjectStyle(IGUIObject* pObject, const CStr& styleName)
{
// If the style is not recognised (or an empty string) then ApplyStyle will
// emit an error message. Thus we don't need to handle it here.
if (pObject->ApplyStyle(styleName))
pObject->m_Style = styleName;
pObject->ApplyStyle(styleName);
}
void CGUI::UnsetObjectStyle(IGUIObject* pObject)
@ -684,6 +683,12 @@ IGUIObject* CGUI::Xeromyces_ReadObject(const XMBData& xmb, XMBElement element, I
{
CStr name(attr.Value);
if (name.Left(2) == "__")
{
LOGERROR("GUI: Names starting with '__' are reserved for the engine (object: %s)", name.c_str());
continue;
}
for (const std::pair<CStr, CStr>& sub : NameSubst)
name.Replace(sub.first, sub.second);
@ -894,10 +899,10 @@ IGUIObject* CGUI::Xeromyces_ReadObject(const XMBData& xmb, XMBElement element, I
if (object->m_Absolute)
// If the object is absolute, we'll have to get the parent's Z buffered,
// and add to that!
object->SetSetting<float>("z", pParent->GetBufferedZ() + 10.f, false);
object->m_Z.Set(pParent->GetBufferedZ() + 10.f, false);
else
// If the object is relative, then we'll just store Z as "10"
object->SetSetting<float>("z", 10.f, false);
object->m_Z.Set(10.f, false);
}
if (!AddObject(*pParent, *object))

View File

@ -23,67 +23,107 @@
#include "ps/CLogger.h"
#include "scriptinterface/ScriptInterface.h"
template<typename T>
CGUISetting<T>::CGUISetting(IGUIObject& pObject, const CStr& Name, T& Value)
: m_pSetting(Value), m_Name(Name), m_pObject(pObject)
IGUISetting::IGUISetting(const CStr& name, IGUIObject* owner) : m_pObject(*owner)
{
m_pObject.RegisterSetting(name, this);
}
IGUISetting::IGUISetting(IGUISetting&& o) : m_pObject(o.m_pObject)
{
m_pObject.ReregisterSetting(o.GetName(), this);
}
bool IGUISetting::FromString(const CStrW& value, const bool sendMessage)
{
if (!DoFromString(value))
return false;
OnSettingChange(GetName(), sendMessage);
return true;
}
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
*/
bool IGUISetting::FromJSVal(const ScriptRequest& rq, JS::HandleValue value, const bool sendMessage)
{
if (!DoFromJSVal(rq, value))
return false;
OnSettingChange(GetName(), sendMessage);
return true;
}
void IGUISetting::OnSettingChange(const CStr& setting, bool sendMessage)
{
m_pObject.SettingChanged(setting, sendMessage);
}
template<typename T>
bool CGUISetting<T>::FromString(const CStrW& Value, const bool SendMessage)
bool CGUISimpleSetting<T>::DoFromString(const CStrW& value)
{
T settingValue;
if (!CGUI::ParseString<T>(&m_pObject.GetGUI(), Value, settingValue))
return false;
m_pObject.SetSetting<T>(m_Name, settingValue, SendMessage);
return true;
return CGUI::ParseString<T>(&m_pObject.GetGUI(), value, m_Setting);
};
template<>
bool CGUISetting<CGUIColor>::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage)
bool CGUISimpleSetting<CGUIColor>::DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value)
{
CGUIColor settingValue;
if (Value.isString())
if (value.isString())
{
CStr name;
if (!ScriptInterface::FromJSVal(rq, Value, name))
if (!ScriptInterface::FromJSVal(rq, value, name))
return false;
if (!settingValue.ParseString(m_pObject.GetGUI(), name))
if (!m_Setting.ParseString(m_pObject.GetGUI(), name))
{
LOGERROR("Invalid color '%s'", name.c_str());
return false;
}
}
else if (!ScriptInterface::FromJSVal<CColor>(rq, Value, settingValue))
return false;
m_pObject.SetSetting<CGUIColor>(m_Name, settingValue, SendMessage);
return true;
return ScriptInterface::FromJSVal<CColor>(rq, value, m_Setting);
};
template<typename T>
bool CGUISetting<T>::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage)
bool CGUISimpleSetting<T>::DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value)
{
T settingValue;
if (!ScriptInterface::FromJSVal<T>(rq, Value, settingValue))
return false;
m_pObject.SetSetting<T>(m_Name, settingValue, SendMessage);
return true;
return ScriptInterface::FromJSVal<T>(rq, value, m_Setting);
};
template<typename T>
void CGUISetting<T>::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value)
void CGUISimpleSetting<T>::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue value)
{
ScriptInterface::ToJSVal<T>(rq, Value, m_pSetting);
ScriptInterface::ToJSVal<T>(rq, value, m_Setting);
};
/**
* Explicitly instantiate CGUISimpleSetting for the basic types.
*/
#define TYPE(T) \
template class CGUISetting<T>; \
template class CGUISimpleSetting<T>;
TYPE(bool)
TYPE(i32)
TYPE(u32)
TYPE(float)
TYPE(CVector2D)
#include "ps/CStr.h"
TYPE(CStr)
TYPE(CStrW)
// TODO: make these inherit from CGUISimpleSetting directly.
#include "gui/SettingTypes/CGUISize.h"
TYPE(CGUISize)
TYPE(CGUIColor)
#include "gui/CGUISprite.h"
TYPE(CGUISpriteInstance)
#include "gui/SettingTypes/CGUIString.h"
TYPE(CGUIString)
#include "gui/SettingTypes/EAlign.h"
TYPE(EAlign)
TYPE(EVAlign)
#include "gui/SettingTypes/CGUIList.h"
TYPE(CGUIList)
#include "gui/SettingTypes/CGUISeries.h"
TYPE(CGUISeries)
#include "gui/GUISettingTypes.h"
#undef TYPE

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -20,6 +20,9 @@
#include "gui/ObjectBases/IGUIObject.h"
class IGUIObject;
class ScriptRequest;
/**
* This setting interface allows GUI objects to call setting function functions without having to know the setting type.
* This is fact is used for setting the value from a JS value or XML value (string) and when deleting the setting,
@ -29,69 +32,94 @@ class IGUISetting
{
public:
NONCOPYABLE(IGUISetting);
IGUISetting(const CStr& name, IGUIObject* owner);
IGUISetting() = default;
/**
* Parses the given string and assigns to the setting value. Used for parsing XML attributes.
*/
bool FromString(const CStrW& value, const bool sendMessage);
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
*/
bool FromJSVal(const ScriptRequest& rq, JS::HandleValue value, const bool sendMessage);
/**
* Converts the setting data to a JS::Value using ScriptInterface::ToJSVal.
*/
virtual void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue value) = 0;
protected:
IGUISetting(IGUISetting&& o);
virtual ~IGUISetting() = default;
/**
* Parses the given string and assigns to the setting value. Used for parsing XML attributes.
*/
virtual bool FromString(const CStrW& Value, const bool SendMessage) = 0;
virtual bool DoFromString(const CStrW& value) = 0;
virtual bool DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) = 0;
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
* Triggers the IGUIObject logic when a setting changes.
* This should be called by derived classes when something externally visible changes,
* unless overloaded to provide similar behaviour.
*/
virtual bool FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) = 0;
virtual void OnSettingChange(const CStr& setting, bool sendMessage);
/**
* Converts the setting data to a JS::Value using ScriptInterface::ToJSVal.
*/
virtual void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) = 0;
};
template<typename T>
class CGUISetting : public IGUISetting
{
public:
NONCOPYABLE(CGUISetting);
CGUISetting(IGUIObject& pObject, const CStr& Name, T& Value);
/**
* Parses the given string and assigns to the setting value. Used for parsing XML attributes.
*/
bool FromString(const CStrW& Value, const bool SendMessage) override;
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
*/
bool FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) override;
/**
* Converts the setting data to a JS::Value using ScriptInterface::ToJSVal.
*/
void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) override;
/**
* These members are public because they are either unmodifiable or free to be modified.
* In particular it avoids the need for setter templates specialized depending on copiability.
* Return the name of the setting, from JS.
*/
virtual CStr GetName() const = 0;
/**
* The object that stores this setting.
*/
IGUIObject& m_pObject;
};
/**
* Wraps a T. Makes sure the appropriate setting functions are called when modifying T,
* and likewise makes sure that JS/xml settings affect T appropriately,
* while being as transparent as possible to use from C++ code.
*/
template<typename T>
class CGUISimpleSetting : public IGUISetting
{
public:
template<typename... Args>
CGUISimpleSetting(IGUIObject* pObject, const CStr& Name, Args&&... args)
: IGUISetting(Name, pObject), m_Name(Name), m_Setting(args...)
{}
NONCOPYABLE(CGUISimpleSetting);
MOVABLE(CGUISimpleSetting);
operator const T&() const { return m_Setting; }
const T& operator*() const { return m_Setting; }
const T* operator->() const { return &m_Setting; }
/**
* Property name identifying the setting.
* 'Uglified' getter when you want direct access without triggering messages.
*/
T& GetMutable() { return m_Setting; }
/**
* 'Uglified' operator=, so that SendMessage is explicit.
*/
void Set(T value, bool sendMessage)
{
m_Setting = std::move(value);
OnSettingChange(m_Name, sendMessage);
}
protected:
CStr GetName() const override
{
return m_Name;
}
bool DoFromString(const CStrW& value) override;
bool DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) override;
void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue value) override;
const CStr m_Name;
/**
* Holds a reference to the value of the setting.
* The setting value is stored in the member class to optimize for draw calls of that class.
*/
T& m_pSetting;
T m_Setting;
};
#endif // INCLUDED_CGUISETTINGS

View File

@ -59,7 +59,7 @@ void SGenerateTextImage::SetupSpriteCall(
m_Indentation = Size.Width + BufferZone * 2;
}
CGUIText::CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const IGUIObject* pObject)
CGUIText::CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const EAlign align, const IGUIObject* pObject)
{
if (string.m_Words.empty())
return;
@ -76,13 +76,6 @@ CGUIText::CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& Font
int pos_last_img = -1; // Position in the string where last img (either left or right) were encountered.
// in order to avoid duplicate processing.
// get the alignment type for the control we are computing the text for since
// we are computing the horizontal alignment in this method in order to not have
// to run through the TextCalls a second time in the CalculateTextPosition method again
EAlign align = EAlign::LEFT;
if (pObject->SettingExists("text_align"))
align = pObject->GetSetting<EAlign>("text_align");
// Go through string word by word
for (int i = 0; i < static_cast<int>(string.m_Words.size()) - 1; ++i)
{

View File

@ -159,10 +159,11 @@ public:
* can be changed by tags.
* @param Width Width, 0 if no word-wrapping.
* @param BufferZone space between text and edge, and space between text and images.
* @param Align Horizontal alignment (left / center / right).
* @param pObject Optional parameter for error output. Used *only* if error parsing fails,
* and we need to be able to output which object the error occurred in to aid the user.
*/
CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const IGUIObject* pObject);
CGUIText(const CGUI& pGUI, const CGUIString& string, const CStrW& FontW, const float Width, const float BufferZone, const EAlign align, const IGUIObject* pObject);
/**
* Draw this CGUIText object

View File

@ -1,50 +0,0 @@
/* Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
*/
/*
This file is used by all bits of GUI code that need to repeat some code
for a variety of types (to avoid repeating the list of types in half a dozen
places, and to make it much easier to add a new type). Just do
#define TYPE(T) your_code_involving_T;
#include "gui/SettingTypes/GUISettingTypes.h"
#undef TYPE
to handle every possible type.
*/
#ifndef GUITYPE_IGNORE_COPYABLE
#include "gui/SettingTypes/EAlign.h"
TYPE(bool)
TYPE(i32)
TYPE(u32)
TYPE(float)
TYPE(EAlign)
TYPE(EVAlign)
TYPE(CVector2D)
#endif
#ifndef GUITYPE_IGNORE_NONCOPYABLE
#include "gui/SettingTypes/CGUIList.h"
#include "gui/SettingTypes/CGUISeries.h"
TYPE(CGUISize)
TYPE(CGUIColor)
TYPE(CGUIList)
TYPE(CGUISeries)
TYPE(CGUISpriteInstance)
TYPE(CGUIString)
TYPE(CStr)
TYPE(CStrW)
#endif

View File

@ -20,7 +20,7 @@
#include "GUITooltip.h"
#include "gui/CGUI.h"
#include "gui/ObjectBases/IGUIObject.h"
#include "gui/ObjectTypes/CTooltip.h"
#include "lib/timer.h"
#include "ps/CLogger.h"
@ -102,30 +102,21 @@ void GUITooltip::ShowTooltip(IGUIObject* obj, const CVector2D& pos, const CStr&
if (style.empty())
return;
// Must be a CTooltip*
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style);
// Objects in __tooltip_ are guaranteed to be CTooltip* by the engine.
CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style));
if (!tooltipobj || !tooltipobj->SettingExists("use_object"))
{
LOGERROR("Cannot find tooltip named '%s'", style.c_str());
return;
}
IGUIObject* usedobj; // object actually used to display the tooltip in
IGUIObject* usedobj; // object actually used to display the tooltip in.
const CStr& usedObjectName = tooltipobj->GetSetting<CStr>("use_object");
const CStr& usedObjectName = tooltipobj->GetUsedObject();
if (usedObjectName.empty())
{
usedobj = tooltipobj;
if (usedobj->SettingExists("_mousepos"))
{
usedobj->SetSetting<CVector2D>("_mousepos", pos, true);
}
else
{
LOGERROR("Object '%s' used by tooltip '%s' isn't a tooltip object!", usedObjectName.c_str(), style.c_str());
return;
}
tooltipobj->SetMousePos(pos);
}
else
{
@ -148,8 +139,7 @@ void GUITooltip::ShowTooltip(IGUIObject* obj, const CVector2D& pos, const CStr&
return;
}
// Every IGUIObject has a "hidden" setting
usedobj->SetSetting<bool>("hidden", false, true);
usedobj->SetHidden(false);
}
void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI)
@ -157,15 +147,14 @@ void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI)
if (style.empty())
return;
// Must be a CTooltip*
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style);
// Objects in __tooltip_ are guaranteed to be CTooltip* by the engine.
CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style));
if (!tooltipobj || !tooltipobj->SettingExists("use_object") || !tooltipobj->SettingExists("hide_object"))
{
LOGERROR("Cannot find tooltip named '%s' or it is not a tooltip", style.c_str());
return;
}
const CStr& usedObjectName = tooltipobj->GetSetting<CStr>("use_object");
const CStr& usedObjectName = tooltipobj->GetUsedObject();
if (!usedObjectName.empty())
{
IGUIObject* usedobj = pGUI.FindObjectByName(usedObjectName);
@ -179,18 +168,17 @@ void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI)
return;
}
if (tooltipobj->GetSetting<bool>("hide_object"))
// Every IGUIObject has a "hidden" setting
usedobj->SetSetting<bool>("hidden", true, true);
if (tooltipobj->ShouldHideObject())
usedobj->SetHidden(true);
}
else
tooltipobj->SetSetting<bool>("hidden", true, true);
tooltipobj->SetHidden(true);
}
static i32 GetTooltipDelay(const CStr& style, CGUI& pGUI)
{
// Must be a CTooltip*
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style);
// Objects in __tooltip_ are guaranteed to be CTooltip* by the engine.
CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style));
if (!tooltipobj)
{
@ -198,7 +186,7 @@ static i32 GetTooltipDelay(const CStr& style, CGUI& pGUI)
return 500;
}
return tooltipobj->GetSetting<i32>("delay");
return tooltipobj->GetTooltipDelay();
}
void GUITooltip::Update(IGUIObject* Nearest, const CVector2D& MousePos, CGUI& GUI)

View File

@ -33,17 +33,12 @@ IGUIButtonBehavior::IGUIButtonBehavior(IGUIObject& pObject)
: m_pObject(pObject),
m_Pressed(),
m_PressedRight(),
m_SoundDisabled(),
m_SoundEnter(),
m_SoundLeave(),
m_SoundPressed(),
m_SoundReleased()
m_SoundDisabled(&pObject, "sound_disabled"),
m_SoundEnter(&pObject, "sound_enter"),
m_SoundLeave(&pObject, "sound_leave"),
m_SoundPressed(&pObject, "sound_pressed"),
m_SoundReleased(&pObject, "sound_released")
{
m_pObject.RegisterSetting("sound_disabled", m_SoundDisabled);
m_pObject.RegisterSetting("sound_enter", m_SoundEnter);
m_pObject.RegisterSetting("sound_leave", m_SoundLeave);
m_pObject.RegisterSetting("sound_pressed", m_SoundPressed);
m_pObject.RegisterSetting("sound_released", m_SoundReleased);
}
IGUIButtonBehavior::~IGUIButtonBehavior()

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -84,12 +84,11 @@ protected:
bool m_Pressed;
bool m_PressedRight;
// Settings
CStrW m_SoundDisabled;
CStrW m_SoundEnter;
CStrW m_SoundLeave;
CStrW m_SoundPressed;
CStrW m_SoundReleased;
CGUISimpleSetting<CStrW> m_SoundDisabled;
CGUISimpleSetting<CStrW> m_SoundEnter;
CGUISimpleSetting<CStrW> m_SoundLeave;
CGUISimpleSetting<CStrW> m_SoundPressed;
CGUISimpleSetting<CStrW> m_SoundReleased;
private:
/**

View File

@ -43,43 +43,22 @@ IGUIObject::IGUIObject(CGUI& pGUI)
m_pParent(),
m_MouseHovering(),
m_LastClickTime(),
m_Enabled(),
m_Hidden(),
m_Size(),
m_Style(),
m_Hotkey(),
m_Z(),
m_Absolute(),
m_Ghost(),
m_AspectRatio(),
m_Tooltip(),
m_TooltipStyle()
m_Enabled(this, "enabled", true),
m_Hidden(this, "hidden", false),
m_Size(this, "size"),
m_Style(this, "style"),
m_Hotkey(this, "hotkey"),
m_Z(this, "z"),
m_Absolute(this, "absolute", true),
m_Ghost(this, "ghost", false),
m_AspectRatio(this, "aspectratio"),
m_Tooltip(this, "tooltip"),
m_TooltipStyle(this, "tooltip_style")
{
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
// TODO: Should be in the default style?
SetSetting<bool>("hidden", false, true);
SetSetting<bool>("ghost", false, true);
SetSetting<bool>("enabled", true, true);
SetSetting<bool>("absolute", true, true);
}
IGUIObject::~IGUIObject()
{
for (const std::pair<const CStr, IGUISetting*>& p : m_Settings)
delete p.second;
if (!m_ScriptHandlers.empty())
JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this);
@ -102,13 +81,20 @@ void IGUIObject::UnregisterChild(IGUIObject* child)
}
}
template<typename T>
void IGUIObject::RegisterSetting(const CStr& Name, T& Value)
void IGUIObject::RegisterSetting(const CStr& Name, IGUISetting* setting)
{
if (SettingExists(Name))
LOGERROR("The setting '%s' already exists on the object '%s'!", Name.c_str(), GetPresentableName().c_str());
else
m_Settings.emplace(Name, new CGUISetting<T>(*this, Name, Value));
m_Settings.emplace(Name, setting);
}
void IGUIObject::ReregisterSetting(const CStr& Name, IGUISetting* setting)
{
if (!SettingExists(Name))
LOGERROR("The setting '%s' must already exist on the object '%s'!", Name.c_str(), GetPresentableName().c_str());
else
m_Settings.at(Name) = setting;
}
bool IGUIObject::SettingExists(const CStr& Setting) const
@ -116,18 +102,6 @@ bool IGUIObject::SettingExists(const CStr& Setting) const
return m_Settings.find(Setting) != m_Settings.end();
}
template <typename T>
T& IGUIObject::GetSetting(const CStr& Setting)
{
return static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting;
}
template <typename T>
const T& IGUIObject::GetSetting(const CStr& Setting) const
{
return static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting;
}
bool IGUIObject::SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage)
{
const std::map<CStr, IGUISetting*>::iterator it = m_Settings.find(Setting);
@ -139,28 +113,6 @@ bool IGUIObject::SetSettingFromString(const CStr& Setting, const CStrW& Value, c
return it->second->FromString(Value, SendMessage);
}
template <typename T>
void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage)
{
PreSettingChange(Setting);
static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting = std::move(Value);
SettingChanged(Setting, SendMessage);
}
template <typename T>
void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage)
{
PreSettingChange(Setting);
static_cast<CGUISetting<T>* >(m_Settings.at(Setting))->m_pSetting = Value;
SettingChanged(Setting, SendMessage);
}
void IGUIObject::PreSettingChange(const CStr& Setting)
{
if (Setting == "hotkey")
m_pGUI.UnsetObjectHotkey(this, GetSetting<CStr>(Setting));
}
void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage)
{
if (Setting == "size")
@ -174,10 +126,8 @@ void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage)
if (m_Hidden)
RecurseObject(nullptr, &IGUIObject::ResetStates);
}
else if (Setting == "hotkey")
m_pGUI.SetObjectHotkey(this, GetSetting<CStr>(Setting));
else if (Setting == "style")
m_pGUI.SetObjectStyle(this, GetSetting<CStr>(Setting));
m_pGUI.SetObjectStyle(this, m_Style);
if (SendMessage)
{
@ -254,9 +204,9 @@ void IGUIObject::UpdateCachedSize()
// use its cached size instead of the screen. Notice
// it must have just been cached for it to work.
if (!m_Absolute && m_pParent && !IsRootObject())
m_CachedActualSize = m_Size.GetSize(m_pParent->m_CachedActualSize);
m_CachedActualSize = m_Size->GetSize(m_pParent->m_CachedActualSize);
else
m_CachedActualSize = m_Size.GetSize(CRect(0.f, 0.f, g_xres / g_GuiScale, g_yres / g_GuiScale));
m_CachedActualSize = m_Size->GetSize(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
// but maintain a constant aspect ratio.
@ -300,7 +250,7 @@ bool IGUIObject::ApplyStyle(const CStr& StyleName)
for (const std::pair<const CStr, CStrW>& p : m_pGUI.GetStyle(StyleName).m_SettingsDefaults)
{
if (SettingExists(p.first))
SetSettingFromString(p.first, p.second, true);
m_Settings.at(p.first)->FromString(p.second, true);
else if (StyleName != "default")
LOGWARNING("GUI object has no setting \"%s\", but the style \"%s\" defines it", p.first, StyleName.c_str());
}
@ -548,23 +498,3 @@ void IGUIObject::TraceMember(JSTracer* trc)
for (std::pair<const CStr, JS::Heap<JSObject*>>& handler : m_ScriptHandlers)
JS::TraceEdge(trc, &handler.second, "IGUIObject::m_ScriptHandlers");
}
// Instantiate templated functions:
// These functions avoid copies by working with a reference and move semantics.
#define TYPE(T) \
template void IGUIObject::RegisterSetting<T>(const CStr& Name, T& Value); \
template T& IGUIObject::GetSetting<T>(const CStr& Setting); \
template const T& IGUIObject::GetSetting<T>(const CStr& Setting) const; \
template void IGUIObject::SetSetting<T>(const CStr& Setting, T& Value, const bool SendMessage); \
#include "gui/GUISettingTypes.h"
#undef TYPE
// Copying functions - discouraged except for primitives.
#define TYPE(T) \
template void IGUIObject::SetSetting<T>(const CStr& Setting, const T& Value, const bool SendMessage); \
#define GUITYPE_IGNORE_NONCOPYABLE
#include "gui/GUISettingTypes.h"
#undef GUITYPE_IGNORE_NONCOPYABLE
#undef TYPE

View File

@ -25,6 +25,8 @@
#ifndef INCLUDED_IGUIOBJECT
#define INCLUDED_IGUIOBJECT
#include "gui/CGUISetting.h"
#include "gui/SettingTypes/CGUIHotkey.h"
#include "gui/SettingTypes/CGUISize.h"
#include "gui/SGUIMessage.h"
#include "lib/input.h" // just for IN_PASS
@ -55,6 +57,9 @@ class IGUIObject
{
friend class CGUI;
// For triggering message update handlers.
friend class IGUISetting;
// Allow getProperty to access things like GetParent()
template <typename T>
friend class JSI_GUIProxy;
@ -113,14 +118,11 @@ public:
//@{
/**
* Registers the given setting variables with the GUI object.
* Registers the given setting with the GUI object.
* Enable XML and JS to modify the given variable.
*
* @param Type Setting type
* @param Name Setting reference name
*/
template<typename T>
void RegisterSetting(const CStr& Name, T& Value);
void RegisterSetting(const CStr& Name, IGUISetting* setting);
void ReregisterSetting(const CStr& Name, IGUISetting* setting);
/**
* Returns whether there is a setting with the given name registered.
@ -130,40 +132,14 @@ public:
*/
bool SettingExists(const CStr& Setting) const;
/**
* Get a mutable reference to the setting.
* If no such setting exists, an exception of type std::out_of_range is thrown.
* If the value is modified, there is no GUIM_SETTINGS_UPDATED message sent.
*/
template <typename T>
T& GetSetting(const CStr& Setting);
template <typename T>
const T& GetSetting(const CStr& Setting) const;
/**
* Set a setting by string, regardless of what type it is.
* Used to parse setting values from XML files.
* For example a CRect(10,10,20,20) is created from "10 10 20 20".
* Returns false if the conversion fails, otherwise true.
* @return false if the setting does not exist or the conversion fails, otherwise true.
*/
bool SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage);
/**
* Assigns the given value to the setting identified by the given name.
* Uses move semantics, so do not read from Value after this call.
*
* @param SendMessage If true, a GUIM_SETTINGS_UPDATED message will be broadcasted to all GUI objects.
*/
template <typename T>
void SetSetting(const CStr& Setting, T& Value, const bool SendMessage);
/**
* This variant will copy the value.
*/
template <typename T>
void SetSetting(const CStr& Setting, const T& Value, const bool SendMessage);
/**
* Returns whether this object is set to be hidden or ghost.
*/
@ -174,6 +150,8 @@ public:
*/
bool IsHidden() const;
void SetHidden(bool hidden) { m_Hidden.Set(hidden, true); }
/**
* Returns whether this object is set to be hidden or ghost.
*/
@ -473,7 +451,6 @@ private:
/**
* Updates some internal data depending on the setting changed.
*/
void PreSettingChange(const CStr& Setting);
void SettingChanged(const CStr& Setting, const bool SendMessage);
/**
@ -545,18 +522,17 @@ protected:
// Cached JSObject representing this GUI object.
std::unique_ptr<IGUIProxyObject> m_JSObject;
// Cache references to settings for performance
bool m_Enabled;
bool m_Hidden;
CGUISize m_Size;
CStr m_Style;
CStr m_Hotkey;
float m_Z;
bool m_Absolute;
bool m_Ghost;
float m_AspectRatio;
CStrW m_Tooltip;
CStr m_TooltipStyle;
CGUISimpleSetting<bool> m_Enabled;
CGUISimpleSetting<bool> m_Hidden;
CGUISimpleSetting<CGUISize> m_Size;
CGUISimpleSetting<CStr> m_Style;
CGUIHotkey m_Hotkey;
CGUISimpleSetting<float> m_Z;
CGUISimpleSetting<bool> m_Absolute;
CGUISimpleSetting<bool> m_Ghost;
CGUISimpleSetting<float> m_AspectRatio;
CGUISimpleSetting<CStrW> m_Tooltip;
CGUISimpleSetting<CStr> m_TooltipStyle;
};
#endif // INCLUDED_IGUIOBJECT

View File

@ -28,8 +28,10 @@
#include <math.h>
IGUITextOwner::IGUITextOwner(IGUIObject& pObject)
: m_pObject(pObject),
m_GeneratedTextsValid()
: m_pObject(pObject),
m_GeneratedTextsValid(),
m_TextAlign(&pObject, "text_align", EAlign::LEFT),
m_TextVAlign(&pObject, "text_valign", EVAlign::TOP)
{
}
@ -46,7 +48,7 @@ CGUIText& IGUITextOwner::AddText()
CGUIText& IGUITextOwner::AddText(const CGUIString& Text, const CStrW& Font, const float& Width, const float& BufferZone)
{
// Avoids a move constructor
m_GeneratedTexts.emplace_back(m_pObject.GetGUI(), Text, Font, Width, BufferZone, &m_pObject);
m_GeneratedTexts.emplace_back(m_pObject.GetGUI(), Text, Font, Width, BufferZone, m_TextAlign, &m_pObject);
return m_GeneratedTexts.back();
}
@ -104,7 +106,7 @@ void IGUITextOwner::CalculateTextPosition(CRect& ObjSize, CVector2D& TextPos, CG
// loop through all of the TextCall objects again.
TextPos.X = ObjSize.left;
switch (m_pObject.GetSetting<EVAlign>("text_valign"))
switch (m_TextVAlign)
{
case EVAlign::TOP:
TextPos.Y = ObjSize.top;

View File

@ -30,6 +30,8 @@ GUI Object Base - Text Owner
#ifndef INCLUDED_IGUITEXTOWNER
#define INCLUDED_IGUITEXTOWNER
#include "gui/CGUISetting.h"
#include "gui/SettingTypes/EAlign.h"
#include "maths/Rect.h"
#include <vector>
@ -112,6 +114,9 @@ protected:
*/
void CalculateTextPosition(CRect& ObjSize, CVector2D& TextPos, CGUIText& Text);
CGUISimpleSetting<EAlign> m_TextAlign;
CGUISimpleSetting<EVAlign> m_TextVAlign;
private:
/**
* Reference to the IGUIObject.

View File

@ -27,34 +27,18 @@ CButton::CButton(CGUI& pGUI)
: IGUIObject(pGUI),
IGUIButtonBehavior(*static_cast<IGUIObject*>(this)),
IGUITextOwner(*static_cast<IGUIObject*>(this)),
m_BufferZone(),
m_Caption(),
m_Font(),
m_Sprite(),
m_SpriteOver(),
m_SpritePressed(),
m_SpriteDisabled(),
m_TextAlign(),
m_TextVAlign(),
m_TextColor(),
m_TextColorOver(),
m_TextColorPressed(),
m_TextColorDisabled()
m_BufferZone(this, "buffer_zone"),
m_Caption(this, "caption"),
m_Font(this, "font"),
m_Sprite(this, "sprite"),
m_SpriteOver(this, "sprite_over"),
m_SpritePressed(this, "sprite_pressed"),
m_SpriteDisabled(this, "sprite_disabled"),
m_TextColor(this, "textcolor"),
m_TextColorOver(this, "textcolor_over"),
m_TextColorPressed(this, "textcolor_pressed"),
m_TextColorDisabled(this, "textcolor_disabled")
{
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("caption", m_Caption);
RegisterSetting("font", m_Font);
RegisterSetting("sprite", m_Sprite);
RegisterSetting("sprite_over", m_SpriteOver);
RegisterSetting("sprite_pressed", m_SpritePressed);
RegisterSetting("sprite_disabled", m_SpriteDisabled);
RegisterSetting("text_align", m_TextAlign);
RegisterSetting("text_valign", m_TextVAlign);
RegisterSetting("textcolor", m_TextColor);
RegisterSetting("textcolor_over", m_TextColorOver);
RegisterSetting("textcolor_pressed", m_TextColorPressed);
RegisterSetting("textcolor_disabled", m_TextColorDisabled);
AddText();
}
@ -66,7 +50,7 @@ void CButton::SetupText()
{
ENSURE(m_GeneratedTexts.size() == 1);
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_CachedActualSize.GetWidth(), m_BufferZone, this);
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_CachedActualSize.GetWidth(), m_BufferZone, m_TextAlign, this);
CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]);
}
@ -110,13 +94,13 @@ void CButton::Draw()
const CGUIColor& CButton::ChooseColor()
{
if (!m_Enabled)
return m_TextColorDisabled ? m_TextColorDisabled : m_TextColor;
return *m_TextColorDisabled ? m_TextColorDisabled : m_TextColor;
if (!m_MouseHovering)
return m_TextColor;
if (m_Pressed)
return m_TextColorPressed ? m_TextColorPressed : m_TextColor;
return *m_TextColorPressed ? m_TextColorPressed : m_TextColor;
return m_TextColorOver ? m_TextColorOver : m_TextColor;
return *m_TextColorOver ? m_TextColorOver : m_TextColor;
}

View File

@ -77,19 +77,17 @@ protected:
virtual void CreateJSObject();
// Settings
float m_BufferZone;
CGUIString m_Caption;
CStrW m_Font;
CGUISpriteInstance m_Sprite;
CGUISpriteInstance m_SpriteOver;
CGUISpriteInstance m_SpritePressed;
CGUISpriteInstance m_SpriteDisabled;
EAlign m_TextAlign;
EVAlign m_TextVAlign;
CGUIColor m_TextColor;
CGUIColor m_TextColorOver;
CGUIColor m_TextColorPressed;
CGUIColor m_TextColorDisabled;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CGUIString> m_Caption;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteOver;
CGUISimpleSetting<CGUISpriteInstance> m_SpritePressed;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteDisabled;
CGUISimpleSetting<CGUIColor> m_TextColor;
CGUISimpleSetting<CGUIColor> m_TextColorOver;
CGUISimpleSetting<CGUIColor> m_TextColorPressed;
CGUISimpleSetting<CGUIColor> m_TextColorDisabled;
};
#endif // INCLUDED_CBUTTON

View File

@ -33,25 +33,15 @@
CChart::CChart(CGUI& pGUI)
: IGUIObject(pGUI),
IGUITextOwner(*static_cast<IGUIObject*>(this)),
m_AxisColor(),
m_AxisWidth(),
m_BufferZone(),
m_Font(),
m_FormatX(),
m_FormatY(),
m_SeriesColor(),
m_SeriesSetting(),
m_TextAlign()
m_AxisColor(this, "axis_color"),
m_AxisWidth(this, "axis_width"),
m_BufferZone(this, "buffer_zone"),
m_Font(this, "font"),
m_FormatX(this, "format_x"),
m_FormatY(this, "format_y"),
m_SeriesColor(this, "series_color"),
m_SeriesSetting(this, "series")
{
RegisterSetting("axis_color", m_AxisColor);
RegisterSetting("axis_width", m_AxisWidth);
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("font", m_Font);
RegisterSetting("format_x", m_FormatX);
RegisterSetting("format_y", m_FormatY);
RegisterSetting("series_color", m_SeriesColor);
RegisterSetting("series", m_SeriesSetting);
RegisterSetting("text_align", m_TextAlign);
}
CChart::~CChart()
@ -184,16 +174,16 @@ CRect CChart::GetChartRect() const
void CChart::UpdateSeries()
{
m_Series.clear();
m_Series.resize(m_SeriesSetting.m_Series.size());
m_Series.resize(m_SeriesSetting->m_Series.size());
for (size_t i = 0; i < m_SeriesSetting.m_Series.size(); ++i)
for (size_t i = 0; i < m_SeriesSetting->m_Series.size(); ++i)
{
CChartData& data = m_Series[i];
if (i < m_SeriesColor.m_Items.size() && !data.m_Color.ParseString(m_pGUI, m_SeriesColor.m_Items[i].GetOriginalString().ToUTF8(), 0))
LOGWARNING("GUI: Error parsing 'series_color' (\"%s\")", utf8_from_wstring(m_SeriesColor.m_Items[i].GetOriginalString()));
if (i < m_SeriesColor->m_Items.size() && !data.m_Color.ParseString(m_pGUI, m_SeriesColor->m_Items[i].GetOriginalString().ToUTF8(), 0))
LOGWARNING("GUI: Error parsing 'series_color' (\"%s\")", utf8_from_wstring(m_SeriesColor->m_Items[i].GetOriginalString()));
data.m_Points = m_SeriesSetting.m_Series[i];
data.m_Points = m_SeriesSetting->m_Series[i];
}
UpdateBounds();

View File

@ -82,15 +82,14 @@ protected:
bool m_EqualX, m_EqualY;
// Settings
CGUIColor m_AxisColor;
float m_AxisWidth;
float m_BufferZone;
CStrW m_Font;
CStrW m_FormatX;
CStrW m_FormatY;
CGUIList m_SeriesColor;
CGUISeries m_SeriesSetting;
EAlign m_TextAlign;
CGUISimpleSetting<CGUIColor> m_AxisColor;
CGUISimpleSetting<float> m_AxisWidth;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<CStrW> m_FormatX;
CGUISimpleSetting<CStrW> m_FormatY;
CGUISimpleSetting<CGUIList> m_SeriesColor;
CGUISimpleSetting<CGUISeries> m_SeriesSetting;
private:
/**

View File

@ -24,25 +24,16 @@
CCheckBox::CCheckBox(CGUI& pGUI)
: IGUIObject(pGUI),
IGUIButtonBehavior(*static_cast<IGUIObject*>(this)),
m_Checked(),
m_SpriteUnchecked(),
m_SpriteUncheckedOver(),
m_SpriteUncheckedPressed(),
m_SpriteUncheckedDisabled(),
m_SpriteChecked(),
m_SpriteCheckedOver(),
m_SpriteCheckedPressed(),
m_SpriteCheckedDisabled()
m_Checked(this, "checked"),
m_SpriteUnchecked(this, "sprite"),
m_SpriteUncheckedOver(this, "sprite_over"),
m_SpriteUncheckedPressed(this, "sprite_pressed"),
m_SpriteUncheckedDisabled(this, "sprite_disabled"),
m_SpriteChecked(this, "sprite2"),
m_SpriteCheckedOver(this, "sprite2_over"),
m_SpriteCheckedPressed(this, "sprite2_pressed"),
m_SpriteCheckedDisabled(this, "sprite2_disabled")
{
RegisterSetting("checked", m_Checked),
RegisterSetting("sprite", m_SpriteUnchecked);
RegisterSetting("sprite_over", m_SpriteUncheckedOver);
RegisterSetting("sprite_pressed", m_SpriteUncheckedPressed);
RegisterSetting("sprite_disabled", m_SpriteUncheckedDisabled);
RegisterSetting("sprite2", m_SpriteChecked);
RegisterSetting("sprite2_over", m_SpriteCheckedOver);
RegisterSetting("sprite2_pressed", m_SpriteCheckedPressed);
RegisterSetting("sprite2_disabled", m_SpriteCheckedDisabled);
}
CCheckBox::~CCheckBox()
@ -64,7 +55,7 @@ void CCheckBox::HandleMessage(SGUIMessage& Message)
{
case GUIM_PRESSED:
{
SetSetting<bool>("checked", !m_Checked, true);
m_Checked.Set(!m_Checked, true);
break;
}

View File

@ -47,15 +47,15 @@ public:
protected:
// Settings
bool m_Checked;
CGUISpriteInstance m_SpriteUnchecked;
CGUISpriteInstance m_SpriteUncheckedOver;
CGUISpriteInstance m_SpriteUncheckedPressed;
CGUISpriteInstance m_SpriteUncheckedDisabled;
CGUISpriteInstance m_SpriteChecked;
CGUISpriteInstance m_SpriteCheckedOver;
CGUISpriteInstance m_SpriteCheckedPressed;
CGUISpriteInstance m_SpriteCheckedDisabled;
CGUISimpleSetting<bool> m_Checked;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteUnchecked;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteUncheckedOver;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteUncheckedPressed;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteUncheckedDisabled;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteChecked;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteCheckedOver;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteCheckedPressed;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteCheckedDisabled;
};
#endif // INCLUDED_CCHECKBOX

View File

@ -32,46 +32,27 @@ CDropDown::CDropDown(CGUI& pGUI)
m_Open(),
m_HideScrollBar(),
m_ElementHighlight(-1),
m_ButtonWidth(),
m_DropDownSize(),
m_DropDownBuffer(),
m_MinimumVisibleItems(),
m_SoundClosed(),
m_SoundEnter(),
m_SoundLeave(),
m_SoundOpened(),
m_SpriteDisabled(),
m_SpriteList(),
m_Sprite2(),
m_Sprite2Over(),
m_Sprite2Pressed(),
m_Sprite2Disabled(),
m_TextColorDisabled(),
m_TextVAlign()
m_ButtonWidth(this, "button_width"),
m_DropDownSize(this, "dropdown_size"),
m_DropDownBuffer(this, "dropdown_buffer"),
m_MinimumVisibleItems(this, "minimum_visible_items"),
m_SoundClosed(this, "sound_closed"),
m_SoundEnter(this, "sound_enter"),
m_SoundLeave(this, "sound_leave"),
m_SoundOpened(this, "sound_opened"),
// Setting "sprite" is registered by CList and used as the background
m_SpriteDisabled(this, "sprite_disabled"),
m_SpriteList(this, "sprite_list"), // Background of the drop down list
m_Sprite2(this, "sprite2"), // Button that sits to the right
m_Sprite2Over(this, "sprite2_over"),
m_Sprite2Pressed(this, "sprite2_pressed"),
m_Sprite2Disabled(this, "sprite2_disabled"),
m_TextColorDisabled(this, "textcolor_disabled")
// Add these in CList! And implement TODO
//RegisterSetting("textcolor_over");
//RegisterSetting("textcolor_pressed");
{
RegisterSetting("button_width", m_ButtonWidth);
RegisterSetting("dropdown_size", m_DropDownSize);
RegisterSetting("dropdown_buffer", m_DropDownBuffer);
RegisterSetting("minimum_visible_items", m_MinimumVisibleItems);
RegisterSetting("sound_closed", m_SoundClosed);
RegisterSetting("sound_enter", m_SoundEnter);
RegisterSetting("sound_leave", m_SoundLeave);
RegisterSetting("sound_opened", m_SoundOpened);
// Setting "sprite" is registered by CList and used as the background
RegisterSetting("sprite_disabled", m_SpriteDisabled);
RegisterSetting("sprite_list", m_SpriteList); // Background of the drop down list
RegisterSetting("sprite2", m_Sprite2); // Button that sits to the right
RegisterSetting("sprite2_over", m_Sprite2Over);
RegisterSetting("sprite2_pressed", m_Sprite2Pressed);
RegisterSetting("sprite2_disabled", m_Sprite2Disabled);
RegisterSetting("textcolor_disabled", m_TextColorDisabled);
RegisterSetting("text_valign", m_TextVAlign);
// Add these in CList! And implement TODO
//RegisterSetting("textcolor_over");
//RegisterSetting("textcolor_pressed");
// Scrollbar is forced to be true.
SetSetting<bool>("scrollbar", true, true);
m_ScrollBar.Set(true, true);
}
CDropDown::~CDropDown()
@ -128,7 +109,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message)
CRect rect = GetListRect();
mouse.Y += scroll;
int set = -1;
for (int i = 0; i < static_cast<int>(m_List.m_Items.size()); ++i)
for (int i = 0; i < static_cast<int>(m_List->m_Items.size()); ++i)
{
if (mouse.Y >= rect.top + m_ItemsYPositions[i] &&
mouse.Y < rect.top + m_ItemsYPositions[i+1] &&
@ -178,7 +159,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message)
if (!m_Open)
{
if (m_List.m_Items.empty())
if (m_List->m_Items.empty())
return;
m_Open = true;
@ -228,7 +209,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message)
break;
++m_ElementHighlight;
SetSetting<i32>("selected", m_ElementHighlight, true);
m_Selected.Set(m_ElementHighlight, true);
break;
}
@ -243,7 +224,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message)
break;
--m_ElementHighlight;
SetSetting<i32>("selected", m_ElementHighlight, true);
m_Selected.Set(m_ElementHighlight, true);
break;
}
@ -299,7 +280,7 @@ InReaction CDropDown::ManuallyHandleKeys(const SDL_Event_* ev)
return IN_PASS;
// Set current selected item to highlighted, before
// then really processing these in CList::ManuallyHandleKeys()
SetSetting<i32>("selected", m_ElementHighlight, true);
m_Selected.Set(m_ElementHighlight, true);
update_highlight = true;
break;
@ -324,13 +305,13 @@ InReaction CDropDown::ManuallyHandleKeys(const SDL_Event_* ev)
int closest = -1;
int bestIndex = -1;
int difference = 1250;
for (int i = 0; i < static_cast<int>(m_List.m_Items.size()); ++i)
for (int i = 0; i < static_cast<int>(m_List->m_Items.size()); ++i)
{
int indexOfDifference = 0;
int diff = 0;
for (size_t j = 0; j < m_InputBuffer.length(); ++j)
{
diff = std::abs(static_cast<int>(m_List.m_Items[i].GetRawString().LowerCase()[j]) - static_cast<int>(m_InputBuffer[j]));
diff = std::abs(static_cast<int>(m_List->m_Items[i].GetRawString().LowerCase()[j]) - static_cast<int>(m_InputBuffer[j]));
if (diff == 0)
indexOfDifference = j+1;
else
@ -346,7 +327,7 @@ InReaction CDropDown::ManuallyHandleKeys(const SDL_Event_* ev)
// let's select the closest element. There should basically always be one.
if (closest != -1)
{
SetSetting<i32>("selected", closest, true);
m_Selected.Set(closest, true);
update_highlight = true;
GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60);
}
@ -453,15 +434,15 @@ void CDropDown::Draw()
if (!m_Enabled)
{
m_pGUI.DrawSprite(m_Sprite2Disabled ? m_Sprite2Disabled : m_Sprite2, bz + 0.05f, rect);
m_pGUI.DrawSprite(*m_Sprite2Disabled ? m_Sprite2Disabled : m_Sprite2, bz + 0.05f, rect);
}
else if (m_Open)
{
m_pGUI.DrawSprite(m_Sprite2Pressed ? m_Sprite2Pressed : m_Sprite2, bz + 0.05f, rect);
m_pGUI.DrawSprite(*m_Sprite2Pressed ? m_Sprite2Pressed : m_Sprite2, bz + 0.05f, rect);
}
else if (m_MouseHovering)
{
m_pGUI.DrawSprite(m_Sprite2Over ? m_Sprite2Over : m_Sprite2, bz + 0.05f, rect);
m_pGUI.DrawSprite(*m_Sprite2Over ? m_Sprite2Over : m_Sprite2, bz + 0.05f, rect);
}
else
m_pGUI.DrawSprite(m_Sprite2, bz + 0.05f, rect);
@ -483,12 +464,12 @@ void CDropDown::Draw()
// TODO: drawScrollbar as an argument of DrawList?
if (m_HideScrollBar)
m_ScrollBar = false;
m_ScrollBar.Set(false, false);
DrawList(m_ElementHighlight, m_SpriteList, m_SpriteSelectArea, m_TextColor);
if (m_HideScrollBar)
m_ScrollBar = old;
m_ScrollBar.Set(old, false);
}
}

View File

@ -123,22 +123,21 @@ protected:
double m_TimeOfLastInput;
// Settings
float m_ButtonWidth;
float m_DropDownSize;
float m_DropDownBuffer;
u32 m_MinimumVisibleItems;
CStrW m_SoundClosed;
CStrW m_SoundEnter;
CStrW m_SoundLeave;
CStrW m_SoundOpened;
CGUISpriteInstance m_SpriteDisabled;
CGUISpriteInstance m_SpriteList;
CGUISpriteInstance m_Sprite2;
CGUISpriteInstance m_Sprite2Over;
CGUISpriteInstance m_Sprite2Pressed;
CGUISpriteInstance m_Sprite2Disabled;
CGUIColor m_TextColorDisabled;
EVAlign m_TextVAlign;
CGUISimpleSetting<float> m_ButtonWidth;
CGUISimpleSetting<float> m_DropDownSize;
CGUISimpleSetting<float> m_DropDownBuffer;
CGUISimpleSetting<u32> m_MinimumVisibleItems;
CGUISimpleSetting<CStrW> m_SoundClosed;
CGUISimpleSetting<CStrW> m_SoundEnter;
CGUISimpleSetting<CStrW> m_SoundLeave;
CGUISimpleSetting<CStrW> m_SoundOpened;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteDisabled;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteList;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite2;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite2Over;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite2Pressed;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite2Disabled;
CGUISimpleSetting<CGUIColor> m_TextColorDisabled;
};
#endif // INCLUDED_CDROPDOWN

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -45,9 +45,8 @@ template<> bool ScriptInterface::FromJSVal(const ScriptRequest&, const JS::Handl
JSVAL_VECTOR(CHotkeyPicker::Key);
CHotkeyPicker::CHotkeyPicker(CGUI& pGUI) : IGUIObject(pGUI), m_TimeToCombination(1.f)
CHotkeyPicker::CHotkeyPicker(CGUI& pGUI) : IGUIObject(pGUI), m_TimeToCombination(this, "time_to_combination", 1.f)
{
RegisterSetting("time_to_combination", m_TimeToCombination);
// 8 keys at the same time is probably more than we'll ever need.
m_KeysPressed.reserve(8);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -59,7 +59,7 @@ protected:
void FireEvent(const CStr& event);
// Time without changes until a "combination" event is sent.
float m_TimeToCombination;
CGUISimpleSetting<float> m_TimeToCombination;
// Time of the last registered key change.
double m_LastKeyChange;

View File

@ -23,9 +23,8 @@
CImage::CImage(CGUI& pGUI)
: IGUIObject(pGUI),
m_Sprite()
m_Sprite(this, "sprite")
{
RegisterSetting("sprite", m_Sprite);
}
CImage::~CImage()

View File

@ -45,8 +45,7 @@ protected:
*/
virtual void Draw();
// Settings
CGUISpriteInstance m_Sprite;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
};
#endif // INCLUDED_CIMAGE

View File

@ -56,40 +56,24 @@ CInput::CInput(CGUI& pGUI)
m_iComposedLength(),
m_iComposedPos(),
m_iInsertPos(),
m_BufferPosition(),
m_BufferZone(),
m_Caption(),
m_Font(),
m_MaskChar(),
m_Mask(),
m_MaxLength(),
m_MultiLine(),
m_Readonly(),
m_ScrollBar(),
m_ScrollBarStyle(),
m_Sprite(),
m_SpriteSelectArea(),
m_TextColor(),
m_TextColorSelected()
m_BufferPosition(this, "buffer_position"),
m_BufferZone(this, "buffer_zone"),
m_Caption(this, "caption"),
m_Font(this, "font"),
m_MaskChar(this, "mask_char"),
m_Mask(this, "mask"),
m_MaxLength(this, "max_length"),
m_MultiLine(this, "multiline"),
m_Readonly(this, "readonly"),
m_ScrollBar(this, "scrollbar"),
m_ScrollBarStyle(this, "scrollbar_style"),
m_Sprite(this, "sprite"),
m_SpriteSelectArea(this, "sprite_selectarea"),
m_TextColor(this, "textcolor"),
m_TextColorSelected(this, "textcolor_selected"),
m_PlaceholderText(this, "placeholder_text"),
m_PlaceholderColor(this, "placeholder_color")
{
RegisterSetting("buffer_position", m_BufferPosition);
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("caption", m_Caption);
RegisterSetting("font", m_Font);
RegisterSetting("mask_char", m_MaskChar);
RegisterSetting("mask", m_Mask);
RegisterSetting("max_length", m_MaxLength);
RegisterSetting("multiline", m_MultiLine);
RegisterSetting("readonly", m_Readonly);
RegisterSetting("scrollbar", m_ScrollBar);
RegisterSetting("scrollbar_style", m_ScrollBarStyle);
RegisterSetting("sprite", m_Sprite);
RegisterSetting("sprite_selectarea", m_SpriteSelectArea);
RegisterSetting("textcolor", m_TextColor);
RegisterSetting("textcolor_selected", m_TextColorSelected);
RegisterSetting("placeholder_text", m_PlaceholderText);
RegisterSetting("placeholder_color", m_PlaceholderColor);
CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate);
CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI);
@ -103,12 +87,12 @@ CInput::~CInput()
void CInput::UpdateBufferPositionSetting()
{
SetSetting<i32>("buffer_position", m_iBufferPos, false);
m_BufferPosition.Set(m_iBufferPos, false);
}
void CInput::ClearComposedText()
{
m_Caption.erase(m_iInsertPos, m_iComposedLength);
m_Caption.GetMutable().erase(m_iInsertPos, m_iComposedLength);
m_iBufferPos = m_iInsertPos;
UpdateBufferPositionSetting();
m_iComposedLength = 0;
@ -119,6 +103,10 @@ InReaction CInput::ManuallyHandleKeys(const SDL_Event_* ev)
{
ENSURE(m_iBufferPos != -1);
// Get direct access to silently mutate m_Caption.
// (Messages don't currently need to be sent)
CStrW& caption = m_Caption.GetMutable();
switch (ev->ev.type)
{
case SDL_HOTKEYDOWN:
@ -139,7 +127,7 @@ InReaction CInput::ManuallyHandleKeys(const SDL_Event_* ev)
std::wstring text = wstring_from_utf8(ev->ev.text.text);
// Check max length
if (m_MaxLength != 0 && m_Caption.length() + text.length() > static_cast<size_t>(m_MaxLength))
if (m_MaxLength != 0 && caption.length() + text.length() > static_cast<size_t>(m_MaxLength))
return IN_HANDLED;
m_WantedX = 0.0f;
@ -153,10 +141,10 @@ InReaction CInput::ManuallyHandleKeys(const SDL_Event_* ev)
m_ComposingText = false;
}
if (m_iBufferPos == static_cast<int>(m_Caption.length()))
m_Caption.append(text);
if (m_iBufferPos == static_cast<int>(caption.length()))
caption.append(text);
else
m_Caption.insert(m_iBufferPos, text);
caption.insert(m_iBufferPos, text);
UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
@ -197,7 +185,7 @@ InReaction CInput::ManuallyHandleKeys(const SDL_Event_* ev)
m_ComposingText = ev->ev.edit.start != 0 || rawLength != 0;
if (m_ComposingText)
{
m_Caption.insert(m_iInsertPos, wtext);
caption.insert(m_iInsertPos, wtext);
// The text buffer is limited to SDL_TEXTEDITINGEVENT_TEXT_SIZE bytes, yet start
// increases without limit, so don't let it advance beyond the composed text length
@ -263,6 +251,10 @@ void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode)
wchar_t cooked = 0;
// Get direct access to silently mutate m_Caption.
// (Messages don't currently need to be sent)
CStrW& caption = m_Caption.GetMutable();
switch (keyCode)
{
case SDLK_TAB:
@ -282,15 +274,15 @@ void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode)
{
m_iBufferPos_Tail = -1;
if (m_Caption.empty() || m_iBufferPos == 0)
if (caption.empty() || m_iBufferPos == 0)
break;
if (m_iBufferPos == static_cast<int>(m_Caption.length()))
m_Caption = m_Caption.Left(static_cast<long>(m_Caption.length()) - 1);
if (m_iBufferPos == static_cast<int>(caption.length()))
caption = caption.Left(static_cast<long>(caption.length()) - 1);
else
m_Caption =
m_Caption.Left(m_iBufferPos - 1) +
m_Caption.Right(static_cast<long>(m_Caption.length()) - m_iBufferPos);
caption =
caption.Left(m_iBufferPos - 1) +
caption.Right(static_cast<long>(caption.length()) - m_iBufferPos);
--m_iBufferPos;
@ -309,12 +301,12 @@ void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode)
DeleteCurSelection();
else
{
if (m_Caption.empty() || m_iBufferPos == static_cast<int>(m_Caption.length()))
if (caption.empty() || m_iBufferPos == static_cast<int>(caption.length()))
break;
m_Caption =
m_Caption.Left(m_iBufferPos) +
m_Caption.Right(static_cast<long>(m_Caption.length()) - (m_iBufferPos + 1));
caption =
caption.Left(m_iBufferPos) +
caption.Right(static_cast<long>(caption.length()) - (m_iBufferPos + 1));
UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos);
}
@ -344,7 +336,7 @@ void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode)
return;
// Check max length
if (m_MaxLength != 0 && m_Caption.length() >= static_cast<size_t>(m_MaxLength))
if (m_MaxLength != 0 && caption.length() >= static_cast<size_t>(m_MaxLength))
break;
m_WantedX = 0.0f;
@ -353,12 +345,12 @@ void CInput::ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode)
DeleteCurSelection();
m_iBufferPos_Tail = -1;
if (m_iBufferPos == static_cast<int>(m_Caption.length()))
m_Caption += cooked;
if (m_iBufferPos == static_cast<int>(caption.length()))
caption += cooked;
else
m_Caption =
m_Caption.Left(m_iBufferPos) + cooked +
m_Caption.Right(static_cast<long>(m_Caption.length()) - m_iBufferPos);
caption =
caption.Left(m_iBufferPos) + cooked +
caption.Right(static_cast<long>(caption.length()) - m_iBufferPos);
UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos + 1);
@ -375,6 +367,8 @@ void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode)
{
bool shiftKeyPressed = g_scancodes[SDL_SCANCODE_LSHIFT] || g_scancodes[SDL_SCANCODE_RSHIFT];
const CStrW& caption = *m_Caption;
switch (keyCode)
{
case SDLK_HOME:
@ -411,7 +405,7 @@ void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode)
m_iBufferPos_Tail = m_iBufferPos;
}
m_iBufferPos = static_cast<long>(m_Caption.length());
m_iBufferPos = static_cast<long>(caption.length());
m_WantedX = 0.0f;
UpdateAutoScroll();
@ -474,7 +468,7 @@ void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode)
else if (!SelectingText())
m_iBufferPos_Tail = m_iBufferPos;
if (m_iBufferPos < static_cast<int>(m_Caption.length()))
if (m_iBufferPos < static_cast<int>(caption.length()))
++m_iBufferPos;
}
else
@ -607,7 +601,7 @@ void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode)
void CInput::SetupGeneratedPlaceholderText()
{
m_GeneratedPlaceholderText = CGUIText(m_pGUI, m_PlaceholderText, m_Font, 0, m_BufferZone, this);
m_GeneratedPlaceholderText = CGUIText(m_pGUI, m_PlaceholderText, m_Font, 0, m_BufferZone, EAlign::LEFT, this);
m_GeneratedPlaceholderTextValid = true;
}
@ -617,6 +611,10 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
// Get direct access to silently mutate m_Caption.
// (Messages don't currently need to be sent)
CStrW& caption = m_Caption.GetMutable();
if (hotkey == "paste")
{
if (m_Readonly)
@ -632,18 +630,18 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
SDL_free(utf8_text);
// Check max length
if (m_MaxLength != 0 && m_Caption.length() + text.length() > static_cast<size_t>(m_MaxLength))
text = text.substr(0, static_cast<size_t>(m_MaxLength) - m_Caption.length());
if (m_MaxLength != 0 && caption.length() + text.length() > static_cast<size_t>(m_MaxLength))
text = text.substr(0, static_cast<size_t>(m_MaxLength) - caption.length());
if (SelectingText())
DeleteCurSelection();
if (m_iBufferPos == static_cast<int>(m_Caption.length()))
m_Caption += text;
if (m_iBufferPos == static_cast<int>(caption.length()))
caption += text;
else
m_Caption =
m_Caption.Left(m_iBufferPos) + text +
m_Caption.Right(static_cast<long>(m_Caption.length()) - m_iBufferPos);
caption =
caption.Left(m_iBufferPos) + text +
caption.Right(static_cast<long>(caption.length()) - m_iBufferPos);
UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
@ -678,7 +676,7 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
virtualTo = m_iBufferPos;
}
CStrW text = m_Caption.Left(virtualTo).Right(virtualTo - virtualFrom);
CStrW text = caption.Left(virtualTo).Right(virtualTo - virtualFrom);
SDL_SetClipboardText(text.ToUTF8().c_str());
@ -702,10 +700,10 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
if (SelectingText())
DeleteCurSelection();
if (!m_Caption.empty() && m_iBufferPos != 0)
if (!caption.empty() && m_iBufferPos != 0)
{
m_iBufferPos_Tail = m_iBufferPos;
CStrW searchString = m_Caption.Left(m_iBufferPos);
CStrW searchString = caption.Left(m_iBufferPos);
// If we are starting in whitespace, adjust position until we get a non whitespace
while (m_iBufferPos > 0)
@ -748,22 +746,22 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
if (SelectingText())
DeleteCurSelection();
if (!m_Caption.empty() && m_iBufferPos < static_cast<int>(m_Caption.length()))
if (!caption.empty() && m_iBufferPos < static_cast<int>(caption.length()))
{
// Delete the word to the right of the cursor
m_iBufferPos_Tail = m_iBufferPos;
// Delete chars to the right unit we hit whitespace
while (++m_iBufferPos < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos < static_cast<int>(caption.length()))
{
if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos]))
if (iswspace(caption[m_iBufferPos]) || iswpunct(caption[m_iBufferPos]))
break;
}
// Eliminate any whitespace behind the word we just deleted
while (m_iBufferPos < static_cast<int>(m_Caption.length()))
while (m_iBufferPos < static_cast<int>(caption.length()))
{
if (!iswspace(m_Caption[m_iBufferPos]))
if (!iswspace(caption[m_iBufferPos]))
break;
++m_iBufferPos;
@ -786,9 +784,9 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
else if (!SelectingText())
m_iBufferPos_Tail = m_iBufferPos;
if (!m_Caption.empty() && m_iBufferPos != 0)
if (!caption.empty() && m_iBufferPos != 0)
{
CStrW searchString = m_Caption.Left(m_iBufferPos);
CStrW searchString = caption.Left(m_iBufferPos);
// If we are starting in whitespace, adjust position until we get a non whitespace
while (m_iBufferPos > 0)
@ -839,19 +837,19 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
else if (!SelectingText())
m_iBufferPos_Tail = m_iBufferPos;
if (!m_Caption.empty() && m_iBufferPos < static_cast<int>(m_Caption.length()))
if (!caption.empty() && m_iBufferPos < static_cast<int>(caption.length()))
{
// Select chars to the right until we hit whitespace
while (++m_iBufferPos < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos < static_cast<int>(caption.length()))
{
if (iswspace(m_Caption[m_iBufferPos]) || iswpunct(m_Caption[m_iBufferPos]))
if (iswspace(caption[m_iBufferPos]) || iswpunct(caption[m_iBufferPos]))
break;
}
// Also select any whitespace following the word we just selected
while (m_iBufferPos < static_cast<int>(m_Caption.length()))
while (m_iBufferPos < static_cast<int>(caption.length()))
{
if (!iswspace(m_Caption[m_iBufferPos]))
if (!iswspace(caption[m_iBufferPos]))
break;
++m_iBufferPos;
@ -886,6 +884,9 @@ void CInput::HandleMessage(SGUIMessage& Message)
IGUIObject::HandleMessage(Message);
IGUIScrollBarOwner::HandleMessage(Message);
// Cleans up operator[] usage.
const CStrW& caption = *m_Caption;
switch (Message.type)
{
case GUIM_SETTINGS_UPDATED:
@ -984,20 +985,20 @@ void CInput::HandleMessage(SGUIMessage& Message)
if (m_ComposingText)
break;
if (m_Caption.empty())
if (caption.empty())
break;
m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition();
if (m_iBufferPos >= (int)m_Caption.length())
m_iBufferPos = m_iBufferPos_Tail = m_Caption.length() - 1;
if (m_iBufferPos >= (int)caption.length())
m_iBufferPos = m_iBufferPos_Tail = caption.length() - 1;
// See if we are clicking over whitespace
if (iswspace(m_Caption[m_iBufferPos]))
if (iswspace(caption[m_iBufferPos]))
{
// see if we are in a section of whitespace greater than one character
if ((m_iBufferPos + 1 < (int) m_Caption.length() && iswspace(m_Caption[m_iBufferPos + 1])) ||
(m_iBufferPos - 1 > 0 && iswspace(m_Caption[m_iBufferPos - 1])))
if ((m_iBufferPos + 1 < (int) caption.length() && iswspace(caption[m_iBufferPos + 1])) ||
(m_iBufferPos - 1 > 0 && iswspace(caption[m_iBufferPos - 1])))
{
//
// We are clicking in an area with more than one whitespace character
@ -1007,7 +1008,7 @@ void CInput::HandleMessage(SGUIMessage& Message)
// skip the whitespace
while (m_iBufferPos > 0)
{
if (!iswspace(m_Caption[m_iBufferPos - 1]))
if (!iswspace(caption[m_iBufferPos - 1]))
break;
m_iBufferPos--;
@ -1015,52 +1016,52 @@ void CInput::HandleMessage(SGUIMessage& Message)
// now go until we hit white space or punctuation
while (m_iBufferPos > 0)
{
if (iswspace(m_Caption[m_iBufferPos - 1]))
if (iswspace(caption[m_iBufferPos - 1]))
break;
m_iBufferPos--;
if (iswpunct(m_Caption[m_iBufferPos]))
if (iswpunct(caption[m_iBufferPos]))
break;
}
// [2] Then the right
// go right until we are not in whitespace
while (++m_iBufferPos_Tail < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos_Tail < static_cast<int>(caption.length()))
{
if (!iswspace(m_Caption[m_iBufferPos_Tail]))
if (!iswspace(caption[m_iBufferPos_Tail]))
break;
}
if (m_iBufferPos_Tail == static_cast<int>(m_Caption.length()))
if (m_iBufferPos_Tail == static_cast<int>(caption.length()))
break;
// now go to the right until we hit whitespace or punctuation
while (++m_iBufferPos_Tail < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos_Tail < static_cast<int>(caption.length()))
{
if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail]))
if (iswspace(caption[m_iBufferPos_Tail]) || iswpunct(caption[m_iBufferPos_Tail]))
break;
}
}
else
{
// single whitespace so select word to the right
while (++m_iBufferPos_Tail < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos_Tail < static_cast<int>(caption.length()))
{
if (!iswspace(m_Caption[m_iBufferPos_Tail]))
if (!iswspace(caption[m_iBufferPos_Tail]))
break;
}
if (m_iBufferPos_Tail == static_cast<int>(m_Caption.length()))
if (m_iBufferPos_Tail == static_cast<int>(caption.length()))
break;
// Don't include the leading whitespace
m_iBufferPos = m_iBufferPos_Tail;
// now go to the right until we hit whitespace or punctuation
while (++m_iBufferPos_Tail < static_cast<int>(m_Caption.length()))
while (++m_iBufferPos_Tail < static_cast<int>(caption.length()))
{
if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail]))
if (iswspace(caption[m_iBufferPos_Tail]) || iswpunct(caption[m_iBufferPos_Tail]))
break;
}
}
@ -1071,17 +1072,17 @@ void CInput::HandleMessage(SGUIMessage& Message)
// go until we hit white space or punctuation
while (m_iBufferPos > 0)
{
if (iswspace(m_Caption[m_iBufferPos - 1]))
if (iswspace(caption[m_iBufferPos - 1]))
break;
m_iBufferPos--;
if (iswpunct(m_Caption[m_iBufferPos]))
if (iswpunct(caption[m_iBufferPos]))
break;
}
// go to the right until we hit whitespace or punctuation
while (++m_iBufferPos_Tail < static_cast<int>(m_Caption.length()))
if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail]))
while (++m_iBufferPos_Tail < static_cast<int>(caption.length()))
if (iswspace(caption[m_iBufferPos_Tail]) || iswpunct(caption[m_iBufferPos_Tail]))
break;
}
UpdateAutoScroll();
@ -1206,11 +1207,11 @@ void CInput::Draw()
if (m_ScrollBar && m_MultiLine)
IGUIScrollBarOwner::Draw();
CStrIntern font_name(m_Font.ToUTF8());
CStrIntern font_name(m_Font->ToUTF8());
wchar_t mask_char = L'*';
if (m_Mask && m_MaskChar.length() > 0)
mask_char = m_MaskChar[0];
if (m_Mask && m_MaskChar->length() > 0)
mask_char = (*m_MaskChar)[0];
m_pGUI.DrawSprite(m_Sprite, bz, m_CachedActualSize);
@ -1407,7 +1408,7 @@ void CInput::Draw()
if (i < (int)it->m_ListOfX.size())
{
if (!m_Mask)
x_pointer += font.GetCharacterWidth(m_Caption[it->m_ListStart + i]);
x_pointer += font.GetCharacterWidth((*m_Caption)[it->m_ListStart + i]);
else
x_pointer += font.GetCharacterWidth(mask_char);
}
@ -1493,7 +1494,7 @@ void CInput::Draw()
if (i != (int)it->m_ListOfX.size())
{
if (!m_Mask)
textRenderer.PrintfAdvance(L"%lc", m_Caption[it->m_ListStart + i]);
textRenderer.PrintfAdvance(L"%lc", (*m_Caption)[it->m_ListStart + i]);
else
textRenderer.PrintfAdvance(L"%lc", mask_char);
}
@ -1527,7 +1528,7 @@ void CInput::Draw()
tech->EndPass();
if (m_Caption.empty() && !m_PlaceholderText.GetRawString().empty())
if (m_Caption->empty() && !m_PlaceholderText->GetRawString().empty())
DrawPlaceholderText(bz, cliparea);
}
@ -1541,18 +1542,20 @@ void CInput::DrawPlaceholderText(float z, const CRect& clipping)
void CInput::UpdateText(int from, int to_before, int to_after)
{
if (m_MaxLength != 0 && m_Caption.length() > static_cast<size_t>(m_MaxLength))
m_Caption = m_Caption.substr(0, m_MaxLength);
CStrW& caption = m_Caption.GetMutable();
CStrIntern font_name(m_Font.ToUTF8());
if (m_MaxLength != 0 && caption.length() > static_cast<size_t>(m_MaxLength))
caption = caption.substr(0, m_MaxLength);
CStrIntern font_name(m_Font->ToUTF8());
wchar_t mask_char = L'*';
if (m_Mask && m_MaskChar.length() > 0)
mask_char = m_MaskChar[0];
if (m_Mask && m_MaskChar->length() > 0)
mask_char = (*m_MaskChar)[0];
// Ensure positions are valid after caption changes
m_iBufferPos = std::min(m_iBufferPos, static_cast<int>(m_Caption.size()));
m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast<int>(m_Caption.size()));
m_iBufferPos = std::min(m_iBufferPos, static_cast<int>(caption.size()));
m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast<int>(caption.size()));
UpdateBufferPositionSetting();
if (font_name.empty())
@ -1568,7 +1571,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
int to = 0; // make sure it's initialized
if (to_before == -1)
to = static_cast<int>(m_Caption.length());
to = static_cast<int>(caption.length());
CFontMetrics font(font_name);
@ -1671,7 +1674,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
if (destroy_row_to != m_CharacterPositions.end())
to = destroy_row_to->m_ListStart; // notice it will iterate [from, to), so it will never reach to.
else
to = static_cast<int>(m_Caption.length());
to = static_cast<int>(caption.length());
// Setup the first row
@ -1698,7 +1701,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
check_point_row_start += delta;
check_point_row_end += delta;
if (to != static_cast<int>(m_Caption.length()))
if (to != static_cast<int>(caption.length()))
to += delta;
}
}
@ -1711,9 +1714,9 @@ void CInput::UpdateText(int from, int to_before, int to_after)
for (int i = from; i < to; ++i)
{
if (m_Caption[i] == L'\n' && m_MultiLine)
if (caption[i] == L'\n' && m_MultiLine)
{
if (i == to-1 && to != static_cast<int>(m_Caption.length()))
if (i == to-1 && to != static_cast<int>(caption.length()))
break; // it will be added outside
current_line = m_CharacterPositions.insert(current_line, row);
@ -1726,12 +1729,12 @@ void CInput::UpdateText(int from, int to_before, int to_after)
}
else
{
if (m_Caption[i] == L' '/* || TODO Gee (2004-10-13): the '-' disappears, fix.
m_Caption[i] == L'-'*/)
if (caption[i] == L' '/* || TODO Gee (2004-10-13): the '-' disappears, fix.
caption[i] == L'-'*/)
last_word_started = i+1;
if (!m_Mask)
x_pos += font.GetCharacterWidth(m_Caption[i]);
x_pos += font.GetCharacterWidth(caption[i]);
else
x_pos += font.GetCharacterWidth(mask_char);
@ -1856,7 +1859,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
if (destroy_row_to != m_CharacterPositions.end())
to = destroy_row_to->m_ListStart; // notice it will iterate [from, to[, so it will never reach to.
else
to = static_cast<int>(m_Caption.length());
to = static_cast<int>(caption.length());
// Set current line, new rows will be added before current_line, so
@ -1909,7 +1912,7 @@ int CInput::GetMouseHoveringTextPosition() const
// Now get the height of the font.
// TODO: Get the real font
CFontMetrics font(CStrIntern(m_Font.ToUTF8()));
CFontMetrics font(CStrIntern(m_Font->ToUTF8()));
float spacing = (float)font.GetLineSpacing();
// Change mouse position relative to text.
@ -2000,9 +2003,9 @@ void CInput::DeleteCurSelection()
virtualTo = m_iBufferPos;
}
m_Caption =
m_Caption.Left(virtualFrom) +
m_Caption.Right(static_cast<long>(m_Caption.length()) - virtualTo);
// Silently change.
m_Caption.Set(m_Caption->Left(virtualFrom) + m_Caption->Right(static_cast<long>(m_Caption->length()) - virtualTo),
false);
UpdateText(virtualFrom, virtualTo, virtualFrom);
@ -2038,7 +2041,7 @@ void CInput::UpdateAutoScroll()
// Now get the height of the font.
// TODO: Get the real font
CFontMetrics font(CStrIntern(m_Font.ToUTF8()));
CFontMetrics font(CStrIntern(m_Font->ToUTF8()));
float spacing = (float)font.GetLineSpacing();
//float height = font.GetHeight();

View File

@ -216,24 +216,23 @@ protected:
static const CStr EventNamePress;
static const CStr EventNameTab;
// Settings
i32 m_BufferPosition;
float m_BufferZone;
CStrW m_Caption;
CGUIString m_PlaceholderText;
CStrW m_Font;
CStrW m_MaskChar;
bool m_Mask;
i32 m_MaxLength;
bool m_MultiLine;
bool m_Readonly;
bool m_ScrollBar;
CStr m_ScrollBarStyle;
CGUISpriteInstance m_Sprite;
CGUISpriteInstance m_SpriteSelectArea;
CGUIColor m_TextColor;
CGUIColor m_TextColorSelected;
CGUIColor m_PlaceholderColor;
CGUISimpleSetting<i32> m_BufferPosition;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CStrW> m_Caption;
CGUISimpleSetting<CGUIString> m_PlaceholderText;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<CStrW> m_MaskChar;
CGUISimpleSetting<bool> m_Mask;
CGUISimpleSetting<i32> m_MaxLength;
CGUISimpleSetting<bool> m_MultiLine;
CGUISimpleSetting<bool> m_Readonly;
CGUISimpleSetting<bool> m_ScrollBar;
CGUISimpleSetting<CStr> m_ScrollBarStyle;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteSelectArea;
CGUISimpleSetting<CGUIColor> m_TextColor;
CGUISimpleSetting<CGUIColor> m_TextColorSelected;
CGUISimpleSetting<CGUIColor> m_PlaceholderColor;
};
#endif // INCLUDED_CINPUT

View File

@ -38,49 +38,25 @@ CList::CList(CGUI& pGUI)
m_Modified(false),
m_PrevSelectedItem(-1),
m_LastItemClickTime(0),
m_BufferZone(),
m_Font(),
m_ScrollBar(),
m_ScrollBarStyle(),
m_ScrollBottom(false),
m_SoundDisabled(),
m_SoundSelected(),
m_Sprite(),
m_SpriteSelectArea(),
m_TextAlign(),
m_TextColor(),
m_TextColorSelected(),
m_Selected(),
m_AutoScroll(),
m_Hovered(),
m_List(),
m_ListData()
m_BufferZone(this, "buffer_zone"),
m_Font(this, "font"),
m_ScrollBar(this, "scrollbar", false),
m_ScrollBarStyle(this, "scrollbar_style"),
m_ScrollBottom(this, "scroll_bottom", false),
m_SoundDisabled(this, "sound_disabled"),
m_SoundSelected(this, "sound_selected"),
m_Sprite(this, "sprite"),
// Add sprite_disabled! TODO
m_SpriteSelectArea(this, "sprite_selectarea"),
m_TextColor(this, "textcolor"),
m_TextColorSelected(this, "textcolor_selected"),
m_Selected(this, "selected", -1), // Index selected. -1 is none.
m_AutoScroll(this, "auto_scroll", false),
m_Hovered(this, "hovered", -1),
// Each list item has both a name (in 'list') and an associated data string (in 'list_data')
m_List(this, "list"),
m_ListData(this, "list_data")
{
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("font", m_Font);
RegisterSetting("scrollbar", m_ScrollBar);
RegisterSetting("scrollbar_style", m_ScrollBarStyle);
RegisterSetting("scroll_bottom", m_ScrollBottom);
RegisterSetting("sound_disabled", m_SoundDisabled);
RegisterSetting("sound_selected", m_SoundSelected);
RegisterSetting("sprite", m_Sprite);
// Add sprite_disabled! TODO
RegisterSetting("sprite_selectarea", m_SpriteSelectArea);
RegisterSetting("text_align", m_TextAlign);
RegisterSetting("textcolor", m_TextColor);
RegisterSetting("textcolor_selected", m_TextColorSelected);
RegisterSetting("selected", m_Selected); // Index selected. -1 is none.
RegisterSetting("auto_scroll", m_AutoScroll);
RegisterSetting("hovered", m_Hovered);
// Each list item has both a name (in 'list') and an associated data string (in 'list_data')
RegisterSetting("list", m_List);
RegisterSetting("list_data", m_ListData);
SetSetting<bool>("scrollbar", false, true);
SetSetting<i32>("selected", -1, true);
SetSetting<i32>("hovered", -1, true);
SetSetting<bool>("auto_scroll", false, true);
// Add scroll-bar
CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI);
bar->SetRightAligned(true);
@ -123,14 +99,14 @@ void CList::SetupText(bool append)
if (append && !m_ItemsYPositions.empty())
buffered_y = m_ItemsYPositions.back();
m_ItemsYPositions.resize(m_List.m_Items.size() + 1);
m_ItemsYPositions.resize(m_List->m_Items.size() + 1);
for (size_t i = append ? m_List.m_Items.size() - 1 : 0; i < m_List.m_Items.size(); ++i)
for (size_t i = append ? m_List->m_Items.size() - 1 : 0; i < m_List->m_Items.size(); ++i)
{
CGUIText* text;
if (!m_List.m_Items[i].GetOriginalString().empty())
text = &AddText(m_List.m_Items[i], m_Font, width, m_BufferZone);
if (!m_List->m_Items[i].GetOriginalString().empty())
text = &AddText(m_List->m_Items[i], m_Font, width, m_BufferZone);
else
{
// Minimum height of a space character of the current font size
@ -143,7 +119,7 @@ void CList::SetupText(bool append)
buffered_y += text->GetSize().Height;
}
m_ItemsYPositions[m_List.m_Items.size()] = buffered_y;
m_ItemsYPositions[m_List->m_Items.size()] = buffered_y;
// Setup scrollbar
if (m_ScrollBar)
@ -221,7 +197,7 @@ void CList::HandleMessage(SGUIMessage& Message)
int hovered = GetHoveredItem();
if (hovered == -1)
break;
SetSetting<i32>("selected", hovered, true);
m_Selected.Set(hovered, true);
UpdateAutoScroll();
PlaySound(m_SoundSelected);
@ -240,7 +216,7 @@ void CList::HandleMessage(SGUIMessage& Message)
if (m_Hovered == -1)
break;
SetSetting<i32>("hovered", -1, true);
m_Hovered.Set(-1, true);
ScriptEvent(EventNameHoverChange);
break;
}
@ -251,7 +227,7 @@ void CList::HandleMessage(SGUIMessage& Message)
if (hovered == m_Hovered)
break;
SetSetting<i32>("hovered", hovered, true);
m_Hovered.Set(hovered, true);
ScriptEvent(EventNameHoverChange);
break;
}
@ -369,7 +345,7 @@ void CList::DrawList(const int& selected, const CGUISpriteInstance& sprite, cons
}
}
for (size_t i = 0; i < m_List.m_Items.size(); ++i)
for (size_t i = 0; i < m_List->m_Items.size(); ++i)
{
if (m_ItemsYPositions[i+1] - scroll < 0 ||
m_ItemsYPositions[i] - scroll > rect.GetHeight())
@ -400,8 +376,8 @@ void CList::DrawList(const int& selected, const CGUISpriteInstance& sprite, cons
void CList::AddItem(const CGUIString& str, const CGUIString& data)
{
// Do not send a settings-changed message
m_List.m_Items.push_back(str);
m_ListData.m_Items.push_back(data);
m_List.GetMutable().m_Items.push_back(str);
m_ListData.GetMutable().m_Items.push_back(data);
SetupText(true);
}
@ -428,9 +404,9 @@ bool CList::HandleAdditionalChildren(const XMBData& xmb, const XMBElement& child
void CList::SelectNextElement()
{
if (m_Selected != static_cast<int>(m_List.m_Items.size()) - 1)
if (m_Selected != static_cast<int>(m_List->m_Items.size()) - 1)
{
SetSetting<i32>("selected", m_Selected + 1, true);
m_Selected.Set(m_Selected + 1, true);
PlaySound(m_SoundSelected);
}
}
@ -439,7 +415,7 @@ void CList::SelectPrevElement()
{
if (m_Selected > 0)
{
SetSetting<i32>("selected", m_Selected - 1, true);
m_Selected.Set(m_Selected - 1, true);
PlaySound(m_SoundSelected);
}
}
@ -447,15 +423,15 @@ void CList::SelectPrevElement()
void CList::SelectFirstElement()
{
if (m_Selected >= 0)
SetSetting<i32>("selected", 0, true);
m_Selected.Set(0, true);
}
void CList::SelectLastElement()
{
const int index = static_cast<int>(m_List.m_Items.size()) - 1;
const int index = static_cast<int>(m_List->m_Items.size()) - 1;
if (m_Selected != index)
SetSetting<i32>("selected", index, true);
m_Selected.Set(index, true);
}
void CList::UpdateAutoScroll()
@ -494,7 +470,7 @@ int CList::GetHoveredItem()
mouse.X <= GetScrollBar(0).GetOuterRect().right)
return -1;
for (size_t i = 0; i < m_List.m_Items.size(); ++i)
for (size_t i = 0; i < m_List->m_Items.size(); ++i)
if (mouse.Y >= rect.top + m_ItemsYPositions[i] &&
mouse.Y < rect.top + m_ItemsYPositions[i + 1])
return i;

View File

@ -126,24 +126,22 @@ protected:
virtual int GetHoveredItem();
// Settings
float m_BufferZone;
CStrW m_Font;
bool m_ScrollBar;
CStr m_ScrollBarStyle;
bool m_ScrollBottom;
CStrW m_SoundDisabled;
CStrW m_SoundSelected;
CGUISpriteInstance m_Sprite;
CGUISpriteInstance m_SpriteSelectArea;
EAlign m_TextAlign;
CGUIColor m_TextColor;
CGUIColor m_TextColorSelected;
i32 m_Selected;
bool m_AutoScroll;
i32 m_Hovered;
CGUIList m_List;
CGUIList m_ListData;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<bool> m_ScrollBar;
CGUISimpleSetting<CStr> m_ScrollBarStyle;
CGUISimpleSetting<bool> m_ScrollBottom;
CGUISimpleSetting<CStrW> m_SoundDisabled;
CGUISimpleSetting<CStrW> m_SoundSelected;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteSelectArea;
CGUISimpleSetting<CGUIColor> m_TextColor;
CGUISimpleSetting<CGUIColor> m_TextColorSelected;
CGUISimpleSetting<i32> m_Selected;
CGUISimpleSetting<bool> m_AutoScroll;
CGUISimpleSetting<i32> m_Hovered;
CGUISimpleSetting<CGUIList> m_List;
CGUISimpleSetting<CGUIList> m_ListData;
private:
static const CStr EventNameSelectionChange;

View File

@ -109,11 +109,9 @@ const CStr CMiniMap::EventNameWorldClick = "WorldClick";
CMiniMap::CMiniMap(CGUI& pGUI) :
IGUIObject(pGUI),
m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true), m_MapScale(1.f),
m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(false),
m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(this, "mask", false),
m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0)
{
RegisterSetting("mask", m_Mask);
m_Clicking = false;
m_MouseHovering = false;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -84,7 +84,7 @@ protected:
bool m_TerrainDirty;
// Whether to draw a black square around and under the minimap.
bool m_Mask;
CGUISimpleSetting<bool> m_Mask;
ssize_t m_Width, m_Height;

View File

@ -33,26 +33,19 @@ const CStr COList::EventNameSelectionColumnChange = "SelectionColumnChange";
COList::COList(CGUI& pGUI)
: CList(pGUI),
m_SpriteHeading(),
m_Sortable(),
m_SelectedColumn(),
m_SelectedColumnOrder(),
m_SpriteAsc(),
m_SpriteDesc(),
m_SpriteNotSorted()
m_SpriteHeading(this, "sprite_heading"),
m_Sortable(this, "sortable"), // The actual sorting is done in JS for more versatility
m_SelectedColumn(this, "selected_column"),
m_SelectedColumnOrder(this, "selected_column_order"),
m_SpriteAsc(this, "sprite_asc"), // Show the order of sorting
m_SpriteDesc(this, "sprite_desc"),
m_SpriteNotSorted(this, "sprite_not_sorted")
{
RegisterSetting("sprite_heading", m_SpriteHeading);
RegisterSetting("sortable", m_Sortable); // The actual sorting is done in JS for more versatility
RegisterSetting("selected_column", m_SelectedColumn);
RegisterSetting("selected_column_order", m_SelectedColumnOrder);
RegisterSetting("sprite_asc", m_SpriteAsc); // Show the order of sorting
RegisterSetting("sprite_desc", m_SpriteDesc);
RegisterSetting("sprite_not_sorted", m_SpriteNotSorted);
}
void COList::SetupText()
{
m_ItemsYPositions.resize(m_List.m_Items.size() + 1);
m_ItemsYPositions.resize(m_List->m_Items.size() + 1);
// Delete all generated texts. Some could probably be saved,
// but this is easier, and this function will never be called
@ -82,7 +75,7 @@ void COList::SetupText()
// Generate texts
float buffered_y = 0.f;
for (size_t i = 0; i < m_List.m_Items.size(); ++i)
for (size_t i = 0; i < m_List->m_Items.size(); ++i)
{
m_ItemsYPositions[i] = buffered_y;
float shift = 0.0f;
@ -93,8 +86,8 @@ void COList::SetupText()
width *= m_TotalAvailableColumnWidth;
CGUIText* text;
if (!column.m_List.m_Items[i].GetOriginalString().empty())
text = &AddText(column.m_List.m_Items[i], m_Font, width, m_BufferZone);
if (!column.m_List->m_Items[i].GetOriginalString().empty())
text = &AddText(column.m_List->m_Items[i], m_Font, width, m_BufferZone);
else
{
// Minimum height of a space character of the current font size
@ -107,7 +100,7 @@ void COList::SetupText()
buffered_y += shift;
}
m_ItemsYPositions[m_List.m_Items.size()] = buffered_y;
m_ItemsYPositions[m_List->m_Items.size()] = buffered_y;
if (m_ScrollBar)
{
@ -158,14 +151,14 @@ void COList::HandleMessage(SGUIMessage& Message)
mouse.X < leftTopCorner.X + width &&
mouse.Y < leftTopCorner.Y + m_HeadingHeight)
{
if (column.m_Id != m_SelectedColumn)
if (column.m_Id != static_cast<CStr>(m_SelectedColumn))
{
SetSetting<i32>("selected_column_order", -1, true);
m_SelectedColumnOrder.Set(-1, true);
CStr selected_column = column.m_Id;
SetSetting<CStr>("selected_column", selected_column, true);
m_SelectedColumn.Set(selected_column, true);
}
else
SetSetting<i32>("selected_column_order", -m_SelectedColumnOrder, true);
m_SelectedColumnOrder.Set(-m_SelectedColumnOrder, true);
ScriptEvent(EventNameSelectionColumnChange);
PlaySound(m_SoundSelected);
@ -199,7 +192,14 @@ bool COList::HandleAdditionalChildren(const XMBData& xmb, const XMBElement& chil
}
else if (child.GetNodeName() == elmt_column)
{
COListColumn column;
CStr id;
XERO_ITER_ATTR(child, attr)
{
if (attr.Name == attr_id)
id = attr.Value;
}
COListColumn column(this, id);
for (XMBAttribute attr : child.GetAttributes())
{
@ -211,17 +211,13 @@ bool COList::HandleAdditionalChildren(const XMBData& xmb, const XMBElement& chil
if (!CGUI::ParseString<CGUIColor>(&m_pGUI, attr_value.FromUTF8(), column.m_TextColor))
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
}
else if (attr_name == "id")
{
column.m_Id = attr_value;
}
else if (attr_name == "hidden")
{
bool hidden = false;
if (!CGUI::ParseString<bool>(&m_pGUI, attr_value.FromUTF8(), hidden))
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
else
column.m_Hidden = hidden;
column.m_Hidden.Set(hidden, false);
}
else if (attr_name == "width")
{
@ -282,13 +278,6 @@ bool COList::HandleAdditionalChildren(const XMBData& xmb, const XMBElement& chil
void COList::AdditionalChildrenHandled()
{
SetupText();
// Do this after the last push_back call to avoid iterator invalidation
for (COListColumn& column : m_Columns)
{
RegisterSetting("list_" + column.m_Id, column.m_List);
RegisterSetting("hidden_" + column.m_Id, column.m_Hidden);
}
}
void COList::DrawList(const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& sprite_selected, const CGUIColor& textcolor)
@ -367,18 +356,18 @@ void COList::DrawList(const int& selected, const CGUISpriteInstance& sprite, con
if (m_Sortable)
{
const CGUISpriteInstance* pSprite;
if (m_SelectedColumn == column.m_Id)
if (*m_SelectedColumn == column.m_Id)
{
if (m_SelectedColumnOrder == 0)
LOGERROR("selected_column_order must not be 0");
if (m_SelectedColumnOrder != -1)
pSprite = &m_SpriteAsc;
pSprite = &*m_SpriteAsc;
else
pSprite = &m_SpriteDesc;
pSprite = &*m_SpriteDesc;
}
else
pSprite = &m_SpriteNotSorted;
pSprite = &*m_SpriteNotSorted;
m_pGUI.DrawSprite(*pSprite, bz + 0.1f, CRect(leftTopCorner + CVector2D(width - SORT_SPRITE_DIM, 0), leftTopCorner + CVector2D(width, SORT_SPRITE_DIM)));
}
@ -391,7 +380,7 @@ void COList::DrawList(const int& selected, const CGUISpriteInstance& sprite, con
// Draw list items for each column
const size_t objectsCount = m_Columns.size();
for (size_t i = 0; i < m_List.m_Items.size(); ++i)
for (size_t i = 0; i < m_List->m_Items.size(); ++i)
{
if (m_ItemsYPositions[i+1] - scroll < 0 ||
m_ItemsYPositions[i] - scroll > rect.GetHeight())

View File

@ -25,18 +25,21 @@
/**
* Represents a column.
*/
struct COListColumn
class COListColumn
{
public:
COListColumn(IGUIObject* owner, const CStr& cid)
: m_Width(0), m_Id(cid), m_List(owner, "list_" + cid), m_Hidden(owner, "hidden_" + cid, false)
{}
// Avoid copying the strings.
NONCOPYABLE(COListColumn);
MOVABLE(COListColumn);
COListColumn() : m_Width(0), m_Hidden(false) {}
CGUIColor m_TextColor;
CStr m_Id;
float m_Width;
CStrW m_Heading; // CGUIString??
CGUIList m_List;
bool m_Hidden;
CGUISimpleSetting<CGUIList> m_List;
CGUISimpleSetting<bool> m_Hidden;
};
/**
@ -73,14 +76,13 @@ protected:
*/
std::vector<COListColumn> m_Columns;
// Settings
CGUISpriteInstance m_SpriteHeading;
bool m_Sortable;
CStr m_SelectedColumn;
i32 m_SelectedColumnOrder;
CGUISpriteInstance m_SpriteAsc;
CGUISpriteInstance m_SpriteDesc;
CGUISpriteInstance m_SpriteNotSorted;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteHeading;
CGUISimpleSetting<bool> m_Sortable;
CGUISimpleSetting<CStr> m_SelectedColumn;
CGUISimpleSetting<i32> m_SelectedColumnOrder;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteAsc;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteDesc;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteNotSorted;
private:
static const CStr EventNameSelectionColumnChange;

View File

@ -23,13 +23,10 @@
CProgressBar::CProgressBar(CGUI& pGUI)
: IGUIObject(pGUI),
m_SpriteBackground(),
m_SpriteBar(),
m_Progress()
m_SpriteBackground(this, "sprite_background"),
m_SpriteBar(this, "sprite_bar"),
m_Progress(this, "progress") // Between 0 and 100.
{
RegisterSetting("sprite_background", m_SpriteBackground);
RegisterSetting("sprite_bar", m_SpriteBar);
RegisterSetting("progress", m_Progress); // between 0 and 100
}
CProgressBar::~CProgressBar()
@ -46,9 +43,9 @@ void CProgressBar::HandleMessage(SGUIMessage& Message)
if (Message.value == "progress")
{
if (m_Progress > 100.f)
SetSetting<float>("progress", 100.f, true);
m_Progress.Set(100.f, true);
else if (m_Progress < 0.f)
SetSetting<float>("progress", 0.f, true);
m_Progress.Set(0.f, true);
}
break;
default:

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -45,9 +45,9 @@ protected:
void HandleMessage(SGUIMessage& Message);
// Settings
CGUISpriteInstance m_SpriteBackground;
CGUISpriteInstance m_SpriteBar;
float m_Progress;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteBackground;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteBar;
CGUISimpleSetting<float> m_Progress;
};
#endif // INCLUDED_CPROGRESSBAR

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -27,7 +27,6 @@ CRadioButton::CRadioButton(CGUI& pGUI)
void CRadioButton::HandleMessage(SGUIMessage& Message)
{
IGUIButtonBehavior::HandleMessage(Message);
switch (Message.type)
{
case GUIM_PRESSED:
@ -36,10 +35,11 @@ void CRadioButton::HandleMessage(SGUIMessage& Message)
// Notice, if you use other objects within the parent object that has got
// the setting "checked", it too will change. Hence NO OTHER OBJECTS THAN
// RADIO BUTTONS SHOULD BE WITHIN IT!
obj->SetSetting<bool>("checked", false, true);
// TODO: this should be enforced in the engine, and then we could cast IGUIObject* to CRadioButton*.
obj->SetSettingFromString("checked", L"false", true);
}
SetSetting<bool>("checked", true, true);
m_Checked.Set(true, true);
break;
default:

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -21,7 +21,7 @@
#include "gui/ObjectTypes/CCheckBox.h"
/**
* Just like a check box, but it'll nullify its siblings (of the same kind),
* Just like a check box, but it'll nullify its siblings,
* and it won't switch itself.
*
* @see CCheckBox

View File

@ -27,21 +27,14 @@ const CStr CSlider::EventNameValueChange = "ValueChange";
CSlider::CSlider(CGUI& pGUI)
: IGUIObject(pGUI),
IGUIButtonBehavior(*static_cast<IGUIObject*>(this)),
m_ButtonSide(),
m_MaxValue(),
m_MinValue(),
m_Sprite(),
m_SpriteBar(),
m_Value()
m_ButtonSide(this, "button_width"),
m_MaxValue(this, "max_value"),
m_MinValue(this, "min_value"),
m_Sprite(this, "sprite"),
m_SpriteBar(this, "sprite_bar"),
m_Value(this, "value")
{
RegisterSetting("button_width", m_ButtonSide);
RegisterSetting("max_value", m_MaxValue);
RegisterSetting("min_value", m_MinValue);
RegisterSetting("sprite", m_Sprite);
RegisterSetting("sprite_bar", m_SpriteBar);
RegisterSetting("value", m_Value);
m_Value = Clamp(m_Value, m_MinValue, m_MaxValue);
m_Value.Set(Clamp<float>(m_Value, m_MinValue, m_MaxValue), false);
}
CSlider::~CSlider()
@ -61,7 +54,7 @@ float CSlider::GetSliderRatio() const
void CSlider::IncrementallyChangeValue(const float difference)
{
m_Value = Clamp(m_Value + difference, m_MinValue, m_MaxValue);
m_Value.Set(Clamp<float>(m_Value + difference, m_MinValue, m_MaxValue), true);
UpdateValue();
}
@ -72,11 +65,13 @@ void CSlider::HandleMessage(SGUIMessage& Message)
switch (Message.type)
{
/*
case GUIM_SETTINGS_UPDATED:
{
m_Value = Clamp(m_Value, m_MinValue, m_MaxValue);
m_Value.Set(Clamp<float>(m_Value, m_MinValue, m_MaxValue), true);
break;
}
*/
case GUIM_MOUSE_WHEEL_DOWN:
{
if (m_Pressed)
@ -119,7 +114,6 @@ void CSlider::Draw()
void CSlider::UpdateValue()
{
SetSetting<float>("value", m_Value, true);
ScriptEvent(EventNameValueChange);
}

View File

@ -61,12 +61,12 @@ protected:
void IncrementallyChangeValue(const float value);
// Settings
float m_ButtonSide;
float m_MinValue;
float m_MaxValue;
CGUISpriteInstance m_Sprite;
CGUISpriteInstance m_SpriteBar;
float m_Value;
CGUISimpleSetting<float> m_ButtonSide;
CGUISimpleSetting<float> m_MinValue;
CGUISimpleSetting<float> m_MaxValue;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<CGUISpriteInstance> m_SpriteBar;
CGUISimpleSetting<float> m_Value;
private:
CVector2D m_Mouse;

View File

@ -27,38 +27,18 @@ CText::CText(CGUI& pGUI)
: IGUIObject(pGUI),
IGUIScrollBarOwner(*static_cast<IGUIObject*>(this)),
IGUITextOwner(*static_cast<IGUIObject*>(this)),
m_BufferZone(),
m_Caption(),
m_Clip(),
m_Font(),
m_ScrollBar(),
m_ScrollBarStyle(),
m_ScrollBottom(),
m_ScrollTop(),
m_Sprite(),
m_TextAlign(),
m_TextVAlign(),
m_TextColor(),
m_TextColorDisabled()
m_BufferZone(this, "buffer_zone"),
m_Caption(this, "caption"),
m_Clip(this, "clip", true),
m_Font(this, "font"),
m_ScrollBar(this, "scrollbar", false),
m_ScrollBarStyle(this, "scrollbar_style"),
m_ScrollBottom(this, "scroll_bottom"),
m_ScrollTop(this, "scroll_top"),
m_Sprite(this, "sprite"),
m_TextColor(this, "textcolor"),
m_TextColorDisabled(this, "textcolor_disabled")
{
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("caption", m_Caption);
RegisterSetting("clip", m_Clip);
RegisterSetting("font", m_Font);
RegisterSetting("scrollbar", m_ScrollBar);
RegisterSetting("scrollbar_style", m_ScrollBarStyle);
RegisterSetting("scroll_bottom", m_ScrollBottom);
RegisterSetting("scroll_top", m_ScrollTop);
RegisterSetting("sprite", m_Sprite);
RegisterSetting("text_align", m_TextAlign);
RegisterSetting("text_valign", m_TextVAlign);
RegisterSetting("textcolor", m_TextColor);
RegisterSetting("textcolor_disabled", m_TextColorDisabled);
//SetSetting<bool>("ghost", true, true);
SetSetting<bool>("scrollbar", false, true);
SetSetting<bool>("clip", true, true);
// Add scroll-bar
CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI);
bar->SetRightAligned(true);
@ -82,7 +62,7 @@ void CText::SetupText()
if (m_ScrollBar && GetScrollBar(0).GetStyle())
width -= GetScrollBar(0).GetStyle()->m_Width;
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, width, m_BufferZone, this);
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, width, m_BufferZone, m_TextAlign, this);
if (!m_ScrollBar)
CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]);

View File

@ -74,20 +74,17 @@ protected:
*/
CVector2D m_TextPos;
// Settings
float m_BufferZone;
CGUIString m_Caption;
bool m_Clip;
CStrW m_Font;
bool m_ScrollBar;
CStr m_ScrollBarStyle;
bool m_ScrollBottom;
bool m_ScrollTop;
CGUISpriteInstance m_Sprite;
EAlign m_TextAlign;
EVAlign m_TextVAlign;
CGUIColor m_TextColor;
CGUIColor m_TextColorDisabled;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CGUIString> m_Caption;
CGUISimpleSetting<bool> m_Clip;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<bool> m_ScrollBar;
CGUISimpleSetting<CStr> m_ScrollBarStyle;
CGUISimpleSetting<bool> m_ScrollBottom;
CGUISimpleSetting<bool> m_ScrollTop;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<CGUIColor> m_TextColor;
CGUISimpleSetting<CGUIColor> m_TextColorDisabled;
};
#endif // INCLUDED_CTEXT

View File

@ -28,46 +28,24 @@
CTooltip::CTooltip(CGUI& pGUI)
: IGUIObject(pGUI),
IGUITextOwner(*static_cast<IGUIObject*>(this)),
m_BufferZone(),
m_Caption(),
m_Font(),
m_Sprite(),
m_Delay(),
m_TextColor(),
m_MaxWidth(),
m_Offset(),
m_Anchor(),
m_TextAlign(),
m_Independent(),
m_MousePos(),
m_UseObject(),
m_HideObject()
m_BufferZone(this, "buffer_zone"),
m_Caption(this, "caption"),
m_Font(this, "font"),
m_Sprite(this, "sprite"),
m_Delay(this, "delay", 500), // in milliseconds
m_TextColor(this, "textcolor"),
m_MaxWidth(this, "maxwidth"),
m_Offset(this, "offset"),
m_Anchor(this, "anchor", EVAlign::BOTTOM),
// This is used for tooltips that are hidden/revealed manually by scripts, rather than through the standard tooltip display mechanism
m_Independent(this, "independent"),
// Private settings:
// This is set by GUITooltip
m_MousePos(this, "_mousepos"),
// If the tooltip is just a reference to another object:
m_UseObject(this, "use_object"),
m_HideObject(this, "hide_object")
{
// If the tooltip is an object by itself:
RegisterSetting("buffer_zone", m_BufferZone);
RegisterSetting("caption", m_Caption);
RegisterSetting("font", m_Font);
RegisterSetting("sprite", m_Sprite);
RegisterSetting("delay", m_Delay); // in milliseconds
RegisterSetting("textcolor", m_TextColor);
RegisterSetting("maxwidth", m_MaxWidth);
RegisterSetting("offset", m_Offset);
RegisterSetting("anchor", m_Anchor);
RegisterSetting("text_align", m_TextAlign);
// This is used for tooltips that are hidden/revealed manually by scripts, rather than through the standard tooltip display mechanism
RegisterSetting("independent", m_Independent);
// Private settings:
// This is set by GUITooltip
RegisterSetting("_mousepos", m_MousePos);
// If the tooltip is just a reference to another object:
RegisterSetting("use_object", m_UseObject);
RegisterSetting("hide_object", m_HideObject);
// Defaults
SetSetting<i32>("delay", 500, true);
SetSetting<EVAlign>("anchor", EVAlign::BOTTOM, true);
SetSetting<EAlign>("text_align", EAlign::LEFT, true);
// Set up a blank piece of text, to be replaced with a more
// interesting message later
AddText();
@ -81,7 +59,7 @@ void CTooltip::SetupText()
{
ENSURE(m_GeneratedTexts.size() == 1);
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_MaxWidth, m_BufferZone, this);
m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_MaxWidth, m_BufferZone, m_TextAlign, this);
// Position the tooltip relative to the mouse:
@ -91,21 +69,21 @@ void CTooltip::SetupText()
float textheight = m_GeneratedTexts[0].GetSize().Height;
CGUISize size;
size.pixel.left = mousepos.X + m_Offset.X;
size.pixel.left = mousepos.X + m_Offset->X;
size.pixel.right = size.pixel.left + textwidth;
switch (m_Anchor)
{
case EVAlign::TOP:
size.pixel.top = mousepos.Y + m_Offset.Y;
size.pixel.top = mousepos.Y + m_Offset->Y;
size.pixel.bottom = size.pixel.top + textheight;
break;
case EVAlign::BOTTOM:
size.pixel.bottom = mousepos.Y + m_Offset.Y;
size.pixel.bottom = mousepos.Y + m_Offset->Y;
size.pixel.top = size.pixel.bottom - textheight;
break;
case EVAlign::CENTER:
size.pixel.top = mousepos.Y + m_Offset.Y - textheight/2.f;
size.pixel.top = mousepos.Y + m_Offset->Y - textheight/2.f;
size.pixel.bottom = size.pixel.top + textwidth;
break;
default:
@ -130,7 +108,7 @@ void CTooltip::SetupText()
else if (size.pixel.right > screenw)
size.pixel.left -= (size.pixel.right-screenw), size.pixel.right = screenw;
SetSetting<CGUISize>("size", size, true);
m_Size.Set(size, true);
}
void CTooltip::UpdateCachedSize()

View File

@ -35,6 +35,11 @@ public:
CTooltip(CGUI& pGUI);
virtual ~CTooltip();
const CStr& GetUsedObject() const { return m_UseObject; }
i32 GetTooltipDelay() const { return m_Delay; }
bool ShouldHideObject() const { return m_HideObject; }
void SetMousePos(const CVector2D& vec) { m_MousePos.Set(vec, true); }
protected:
void SetupText();
@ -52,21 +57,19 @@ protected:
virtual float GetBufferedZ() const;
// Settings
float m_BufferZone;
CGUIString m_Caption;
CStrW m_Font;
CGUISpriteInstance m_Sprite;
i32 m_Delay;
CGUIColor m_TextColor;
float m_MaxWidth;
CVector2D m_Offset;
EVAlign m_Anchor;
EAlign m_TextAlign;
bool m_Independent;
CVector2D m_MousePos;
CStr m_UseObject;
bool m_HideObject;
CGUISimpleSetting<float> m_BufferZone;
CGUISimpleSetting<CGUIString> m_Caption;
CGUISimpleSetting<CStrW> m_Font;
CGUISimpleSetting<CGUISpriteInstance> m_Sprite;
CGUISimpleSetting<i32> m_Delay;
CGUISimpleSetting<CGUIColor> m_TextColor;
CGUISimpleSetting<float> m_MaxWidth;
CGUISimpleSetting<CVector2D> m_Offset;
CGUISimpleSetting<EVAlign> m_Anchor;
CGUISimpleSetting<bool> m_Independent;
CGUISimpleSetting<CVector2D> m_MousePos;
CGUISimpleSetting<CStr> m_UseObject;
CGUISimpleSetting<bool> m_HideObject;
};
#endif // INCLUDED_CTOOLTIP

View File

@ -0,0 +1,46 @@
/* Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "CGUIHotkey.h"
#include "gui/ObjectBases/IGUIObject.h"
#include "scriptinterface/ScriptInterface.h"
bool CGUIHotkey::DoFromString(const CStrW& value)
{
m_pObject.GetGUI().UnsetObjectHotkey(&m_pObject, m_Setting);
m_Setting = value.ToUTF8();
m_pObject.GetGUI().SetObjectHotkey(&m_pObject, m_Setting);
return true;
}
bool CGUIHotkey::DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value)
{
m_pObject.GetGUI().UnsetObjectHotkey(&m_pObject, m_Setting);
if (!ScriptInterface::FromJSVal(rq, value, m_Setting))
return false;
m_pObject.GetGUI().SetObjectHotkey(&m_pObject, m_Setting);
return true;
}
void CGUIHotkey::OnSettingChange(const CStr& setting, bool sendMessage)
{
IGUISetting::OnSettingChange(setting, sendMessage);
}

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_CGUIHOTKEY
#define INCLUDED_CGUIHOTKEY
#include "gui/CGUISetting.h"
#include "ps/CStr.h"
/**
* Manages a hotkey setting for a GUI object.
*/
class CGUIHotkey : public CGUISimpleSetting<CStr>
{
public:
CGUIHotkey(IGUIObject* pObject, const CStr& Name) : CGUISimpleSetting<CStr>(pObject, Name)
{}
NONCOPYABLE(CGUIHotkey);
MOVABLE(CGUIHotkey);
bool DoFromString(const CStrW& value) override;
bool DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) override;
void OnSettingChange(const CStr& setting, bool sendMessage) override;
};
#endif // INCLUDED_CGUIHOTKEY

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -59,6 +59,7 @@ template<typename T> static bool FromJSVal_vector(const ScriptRequest& rq, JS::H
if (!JS::GetArrayLength(rq.cx, obj, &length))
FAIL("Failed to get array length");
out.clear();
out.reserve(length);
for (u32 i = 0; i < length; ++i)
{