Index: source/gui/CGUI.cpp =================================================================== --- source/gui/CGUI.cpp +++ source/gui/CGUI.cpp @@ -441,8 +441,7 @@ { // 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 @@ { 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& sub : NameSubst) name.Replace(sub.first, sub.second); @@ -894,10 +899,10 @@ 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("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("z", 10.f, false); + object->m_Z.Set(10.f, false); } if (!AddObject(*pParent, *object)) Index: source/gui/CGUISetting.h =================================================================== --- source/gui/CGUISetting.h +++ source/gui/CGUISetting.h @@ -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 @@ { 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; - - /** - * Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data. - */ - virtual bool FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) = 0; - - /** - * Converts the setting data to a JS::Value using ScriptInterface::ToJSVal. - */ - virtual void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) = 0; -}; - -template -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; + virtual bool DoFromString(const CStrW& value) = 0; + virtual bool DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) = 0; /** - * Converts the setting data to a JS::Value using ScriptInterface::ToJSVal. + * 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. */ - void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) override; + virtual void OnSettingChange(const CStr& setting, bool sendMessage); /** - * 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 +class CGUISimpleSetting : public IGUISetting +{ +public: + template + 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; } + + /** + * 'Uglified' getter when you want direct access without triggering messages. + */ + T& GetMutable() { return m_Setting; } /** - * Property name identifying the 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 Index: source/gui/CGUISetting.cpp =================================================================== --- source/gui/CGUISetting.cpp +++ source/gui/CGUISetting.cpp @@ -23,67 +23,107 @@ #include "ps/CLogger.h" #include "scriptinterface/ScriptInterface.h" -template +IGUISetting::IGUISetting(const CStr& name, IGUIObject* owner) : m_pObject(*owner) +{ + m_pObject.RegisterSetting(name, this); +} -CGUISetting::CGUISetting(IGUIObject& pObject, const CStr& Name, T& Value) - : m_pSetting(Value), m_Name(Name), m_pObject(pObject) +IGUISetting::IGUISetting(IGUISetting&& o) : m_pObject(o.m_pObject) { + m_pObject.ReregisterSetting(o.GetName(), this); } -template -bool CGUISetting::FromString(const CStrW& Value, const bool SendMessage) +bool IGUISetting::FromString(const CStrW& value, const bool sendMessage) { - T settingValue; + if (!DoFromString(value)) + return false; + + OnSettingChange(GetName(), sendMessage); + return true; +} - if (!CGUI::ParseString(&m_pObject.GetGUI(), Value, settingValue)) +/** + * 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; - m_pObject.SetSetting(m_Name, settingValue, SendMessage); + OnSettingChange(GetName(), sendMessage); return true; +} + +void IGUISetting::OnSettingChange(const CStr& setting, bool sendMessage) +{ + m_pObject.SettingChanged(setting, sendMessage); +} + +template +bool CGUISimpleSetting::DoFromString(const CStrW& value) +{ + return CGUI::ParseString(&m_pObject.GetGUI(), value, m_Setting); }; template<> -bool CGUISetting::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) +bool CGUISimpleSetting::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(rq, Value, settingValue)) - return false; - m_pObject.SetSetting(m_Name, settingValue, SendMessage); - return true; + return ScriptInterface::FromJSVal(rq, value, m_Setting); }; template -bool CGUISetting::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) +bool CGUISimpleSetting::DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) { - T settingValue; - if (!ScriptInterface::FromJSVal(rq, Value, settingValue)) - return false; - - m_pObject.SetSetting(m_Name, settingValue, SendMessage); - return true; + return ScriptInterface::FromJSVal(rq, value, m_Setting); }; template -void CGUISetting::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) +void CGUISimpleSetting::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue value) { - ScriptInterface::ToJSVal(rq, Value, m_pSetting); + ScriptInterface::ToJSVal(rq, value, m_Setting); }; +/** + * Explicitly instantiate CGUISimpleSetting for the basic types. + */ #define TYPE(T) \ - template class CGUISetting; \ + template class CGUISimpleSetting; + +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 Index: source/gui/CGUIText.h =================================================================== --- source/gui/CGUIText.h +++ source/gui/CGUIText.h @@ -159,10 +159,11 @@ * 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 Index: source/gui/CGUIText.cpp =================================================================== --- source/gui/CGUIText.cpp +++ source/gui/CGUIText.cpp @@ -59,7 +59,7 @@ 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 @@ 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("text_align"); - // Go through string word by word for (int i = 0; i < static_cast(string.m_Words.size()) - 1; ++i) { Index: source/gui/GUISettingTypes.h =================================================================== --- source/gui/GUISettingTypes.h +++ /dev/null @@ -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 . - */ - -/* -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 Index: source/gui/GUITooltip.cpp =================================================================== --- source/gui/GUITooltip.cpp +++ source/gui/GUITooltip.cpp @@ -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 @@ 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(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("use_object"); + const CStr& usedObjectName = tooltipobj->GetUsedObject(); if (usedObjectName.empty()) { usedobj = tooltipobj; - - if (usedobj->SettingExists("_mousepos")) - { - usedobj->SetSetting("_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 @@ return; } - // Every IGUIObject has a "hidden" setting - usedobj->SetSetting("hidden", false, true); + usedobj->SetHidden(false); } void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI) @@ -157,15 +147,14 @@ 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(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("use_object"); + const CStr& usedObjectName = tooltipobj->GetUsedObject(); if (!usedObjectName.empty()) { IGUIObject* usedobj = pGUI.FindObjectByName(usedObjectName); @@ -179,18 +168,17 @@ return; } - if (tooltipobj->GetSetting("hide_object")) - // Every IGUIObject has a "hidden" setting - usedobj->SetSetting("hidden", true, true); + if (tooltipobj->ShouldHideObject()) + usedobj->SetHidden(true); } else - tooltipobj->SetSetting("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(pGUI.FindObjectByName("__tooltip_" + style)); if (!tooltipobj) { @@ -198,7 +186,7 @@ return 500; } - return tooltipobj->GetSetting("delay"); + return tooltipobj->GetTooltipDelay(); } void GUITooltip::Update(IGUIObject* Nearest, const CVector2D& MousePos, CGUI& GUI) Index: source/gui/ObjectBases/IGUIButtonBehavior.h =================================================================== --- source/gui/ObjectBases/IGUIButtonBehavior.h +++ source/gui/ObjectBases/IGUIButtonBehavior.h @@ -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 @@ bool m_Pressed; bool m_PressedRight; - // Settings - CStrW m_SoundDisabled; - CStrW m_SoundEnter; - CStrW m_SoundLeave; - CStrW m_SoundPressed; - CStrW m_SoundReleased; + CGUISimpleSetting m_SoundDisabled; + CGUISimpleSetting m_SoundEnter; + CGUISimpleSetting m_SoundLeave; + CGUISimpleSetting m_SoundPressed; + CGUISimpleSetting m_SoundReleased; private: /** Index: source/gui/ObjectBases/IGUIButtonBehavior.cpp =================================================================== --- source/gui/ObjectBases/IGUIButtonBehavior.cpp +++ source/gui/ObjectBases/IGUIButtonBehavior.cpp @@ -33,17 +33,12 @@ : 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() Index: source/gui/ObjectBases/IGUIObject.h =================================================================== --- source/gui/ObjectBases/IGUIObject.h +++ source/gui/ObjectBases/IGUIObject.h @@ -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 @@ { friend class CGUI; + // For triggering message update handlers. + friend class IGUISetting; + // Allow getProperty to access things like GetParent() template friend class JSI_GUIProxy; @@ -113,14 +118,11 @@ //@{ /** - * 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 - 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 @@ */ 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 - T& GetSetting(const CStr& Setting); - - template - 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 - void SetSetting(const CStr& Setting, T& Value, const bool SendMessage); - - /** - * This variant will copy the value. - */ - template - 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 @@ */ 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 @@ /** * 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 @@ // Cached JSObject representing this GUI object. std::unique_ptr 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 m_Enabled; + CGUISimpleSetting m_Hidden; + CGUISimpleSetting m_Size; + CGUISimpleSetting m_Style; + CGUIHotkey m_Hotkey; + CGUISimpleSetting m_Z; + CGUISimpleSetting m_Absolute; + CGUISimpleSetting m_Ghost; + CGUISimpleSetting m_AspectRatio; + CGUISimpleSetting m_Tooltip; + CGUISimpleSetting m_TooltipStyle; }; #endif // INCLUDED_IGUIOBJECT Index: source/gui/ObjectBases/IGUIObject.cpp =================================================================== --- source/gui/ObjectBases/IGUIObject.cpp +++ source/gui/ObjectBases/IGUIObject.cpp @@ -43,43 +43,22 @@ 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("hidden", false, true); - SetSetting("ghost", false, true); - SetSetting("enabled", true, true); - SetSetting("absolute", true, true); } IGUIObject::~IGUIObject() { - for (const std::pair& p : m_Settings) - delete p.second; - if (!m_ScriptHandlers.empty()) JS_RemoveExtraGCRootsTracer(m_pGUI.GetScriptInterface()->GetGeneralJSContext(), Trace, this); @@ -102,13 +81,20 @@ } } -template -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(*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 @@ return m_Settings.find(Setting) != m_Settings.end(); } -template -T& IGUIObject::GetSetting(const CStr& Setting) -{ - return static_cast* >(m_Settings.at(Setting))->m_pSetting; -} - -template -const T& IGUIObject::GetSetting(const CStr& Setting) const -{ - return static_cast* >(m_Settings.at(Setting))->m_pSetting; -} - bool IGUIObject::SetSettingFromString(const CStr& Setting, const CStrW& Value, const bool SendMessage) { const std::map::iterator it = m_Settings.find(Setting); @@ -139,28 +113,6 @@ return it->second->FromString(Value, SendMessage); } -template -void IGUIObject::SetSetting(const CStr& Setting, T& Value, const bool SendMessage) -{ - PreSettingChange(Setting); - static_cast* >(m_Settings.at(Setting))->m_pSetting = std::move(Value); - SettingChanged(Setting, SendMessage); -} - -template -void IGUIObject::SetSetting(const CStr& Setting, const T& Value, const bool SendMessage) -{ - PreSettingChange(Setting); - static_cast* >(m_Settings.at(Setting))->m_pSetting = Value; - SettingChanged(Setting, SendMessage); -} - -void IGUIObject::PreSettingChange(const CStr& Setting) -{ - if (Setting == "hotkey") - m_pGUI.UnsetObjectHotkey(this, GetSetting(Setting)); -} - void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage) { if (Setting == "size") @@ -174,10 +126,8 @@ if (m_Hidden) RecurseObject(nullptr, &IGUIObject::ResetStates); } - else if (Setting == "hotkey") - m_pGUI.SetObjectHotkey(this, GetSetting(Setting)); else if (Setting == "style") - m_pGUI.SetObjectStyle(this, GetSetting(Setting)); + m_pGUI.SetObjectStyle(this, m_Style); if (SendMessage) { @@ -254,9 +204,9 @@ // 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 @@ for (const std::pair& 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 @@ for (std::pair>& 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(const CStr& Name, T& Value); \ - template T& IGUIObject::GetSetting(const CStr& Setting); \ - template const T& IGUIObject::GetSetting(const CStr& Setting) const; \ - template void IGUIObject::SetSetting(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(const CStr& Setting, const T& Value, const bool SendMessage); \ - -#define GUITYPE_IGNORE_NONCOPYABLE -#include "gui/GUISettingTypes.h" -#undef GUITYPE_IGNORE_NONCOPYABLE -#undef TYPE Index: source/gui/ObjectBases/IGUITextOwner.h =================================================================== --- source/gui/ObjectBases/IGUITextOwner.h +++ source/gui/ObjectBases/IGUITextOwner.h @@ -30,6 +30,8 @@ #ifndef INCLUDED_IGUITEXTOWNER #define INCLUDED_IGUITEXTOWNER +#include "gui/CGUISetting.h" +#include "gui/SettingTypes/EAlign.h" #include "maths/Rect.h" #include @@ -112,6 +114,9 @@ */ void CalculateTextPosition(CRect& ObjSize, CVector2D& TextPos, CGUIText& Text); + CGUISimpleSetting m_TextAlign; + CGUISimpleSetting m_TextVAlign; + private: /** * Reference to the IGUIObject. Index: source/gui/ObjectBases/IGUITextOwner.cpp =================================================================== --- source/gui/ObjectBases/IGUITextOwner.cpp +++ source/gui/ObjectBases/IGUITextOwner.cpp @@ -28,8 +28,10 @@ #include 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(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 @@ // loop through all of the TextCall objects again. TextPos.X = ObjSize.left; - switch (m_pObject.GetSetting("text_valign")) + switch (m_TextVAlign) { case EVAlign::TOP: TextPos.Y = ObjSize.top; Index: source/gui/ObjectTypes/CButton.h =================================================================== --- source/gui/ObjectTypes/CButton.h +++ source/gui/ObjectTypes/CButton.h @@ -77,19 +77,17 @@ 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 m_BufferZone; + CGUISimpleSetting m_Caption; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_SpriteOver; + CGUISimpleSetting m_SpritePressed; + CGUISimpleSetting m_SpriteDisabled; + CGUISimpleSetting m_TextColor; + CGUISimpleSetting m_TextColorOver; + CGUISimpleSetting m_TextColorPressed; + CGUISimpleSetting m_TextColorDisabled; }; #endif // INCLUDED_CBUTTON Index: source/gui/ObjectTypes/CButton.cpp =================================================================== --- source/gui/ObjectTypes/CButton.cpp +++ source/gui/ObjectTypes/CButton.cpp @@ -27,34 +27,18 @@ : IGUIObject(pGUI), IGUIButtonBehavior(*static_cast(this)), IGUITextOwner(*static_cast(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 @@ { 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 @@ 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; } Index: source/gui/ObjectTypes/CChart.h =================================================================== --- source/gui/ObjectTypes/CChart.h +++ source/gui/ObjectTypes/CChart.h @@ -82,15 +82,14 @@ 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 m_AxisColor; + CGUISimpleSetting m_AxisWidth; + CGUISimpleSetting m_BufferZone; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_FormatX; + CGUISimpleSetting m_FormatY; + CGUISimpleSetting m_SeriesColor; + CGUISimpleSetting m_SeriesSetting; private: /** Index: source/gui/ObjectTypes/CChart.cpp =================================================================== --- source/gui/ObjectTypes/CChart.cpp +++ source/gui/ObjectTypes/CChart.cpp @@ -33,25 +33,15 @@ CChart::CChart(CGUI& pGUI) : IGUIObject(pGUI), IGUITextOwner(*static_cast(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 @@ 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(); Index: source/gui/ObjectTypes/CCheckBox.h =================================================================== --- source/gui/ObjectTypes/CCheckBox.h +++ source/gui/ObjectTypes/CCheckBox.h @@ -47,15 +47,15 @@ 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 m_Checked; + CGUISimpleSetting m_SpriteUnchecked; + CGUISimpleSetting m_SpriteUncheckedOver; + CGUISimpleSetting m_SpriteUncheckedPressed; + CGUISimpleSetting m_SpriteUncheckedDisabled; + CGUISimpleSetting m_SpriteChecked; + CGUISimpleSetting m_SpriteCheckedOver; + CGUISimpleSetting m_SpriteCheckedPressed; + CGUISimpleSetting m_SpriteCheckedDisabled; }; #endif // INCLUDED_CCHECKBOX Index: source/gui/ObjectTypes/CCheckBox.cpp =================================================================== --- source/gui/ObjectTypes/CCheckBox.cpp +++ source/gui/ObjectTypes/CCheckBox.cpp @@ -24,25 +24,16 @@ CCheckBox::CCheckBox(CGUI& pGUI) : IGUIObject(pGUI), IGUIButtonBehavior(*static_cast(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 @@ { case GUIM_PRESSED: { - SetSetting("checked", !m_Checked, true); + m_Checked.Set(!m_Checked, true); break; } Index: source/gui/ObjectTypes/CDropDown.h =================================================================== --- source/gui/ObjectTypes/CDropDown.h +++ source/gui/ObjectTypes/CDropDown.h @@ -123,22 +123,21 @@ 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 m_ButtonWidth; + CGUISimpleSetting m_DropDownSize; + CGUISimpleSetting m_DropDownBuffer; + CGUISimpleSetting m_MinimumVisibleItems; + CGUISimpleSetting m_SoundClosed; + CGUISimpleSetting m_SoundEnter; + CGUISimpleSetting m_SoundLeave; + CGUISimpleSetting m_SoundOpened; + CGUISimpleSetting m_SpriteDisabled; + CGUISimpleSetting m_SpriteList; + CGUISimpleSetting m_Sprite2; + CGUISimpleSetting m_Sprite2Over; + CGUISimpleSetting m_Sprite2Pressed; + CGUISimpleSetting m_Sprite2Disabled; + CGUISimpleSetting m_TextColorDisabled; }; #endif // INCLUDED_CDROPDOWN Index: source/gui/ObjectTypes/CDropDown.cpp =================================================================== --- source/gui/ObjectTypes/CDropDown.cpp +++ source/gui/ObjectTypes/CDropDown.cpp @@ -32,46 +32,27 @@ 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("scrollbar", true, true); + m_ScrollBar.Set(true, true); } CDropDown::~CDropDown() @@ -128,7 +109,7 @@ CRect rect = GetListRect(); mouse.Y += scroll; int set = -1; - for (int i = 0; i < static_cast(m_List.m_Items.size()); ++i) + for (int i = 0; i < static_cast(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 @@ if (!m_Open) { - if (m_List.m_Items.empty()) + if (m_List->m_Items.empty()) return; m_Open = true; @@ -228,7 +209,7 @@ break; ++m_ElementHighlight; - SetSetting("selected", m_ElementHighlight, true); + m_Selected.Set(m_ElementHighlight, true); break; } @@ -243,7 +224,7 @@ break; --m_ElementHighlight; - SetSetting("selected", m_ElementHighlight, true); + m_Selected.Set(m_ElementHighlight, true); break; } @@ -299,7 +280,7 @@ return IN_PASS; // Set current selected item to highlighted, before // then really processing these in CList::ManuallyHandleKeys() - SetSetting("selected", m_ElementHighlight, true); + m_Selected.Set(m_ElementHighlight, true); update_highlight = true; break; @@ -324,13 +305,13 @@ int closest = -1; int bestIndex = -1; int difference = 1250; - for (int i = 0; i < static_cast(m_List.m_Items.size()); ++i) + for (int i = 0; i < static_cast(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(m_List.m_Items[i].GetRawString().LowerCase()[j]) - static_cast(m_InputBuffer[j])); + diff = std::abs(static_cast(m_List->m_Items[i].GetRawString().LowerCase()[j]) - static_cast(m_InputBuffer[j])); if (diff == 0) indexOfDifference = j+1; else @@ -346,7 +327,7 @@ // let's select the closest element. There should basically always be one. if (closest != -1) { - SetSetting("selected", closest, true); + m_Selected.Set(closest, true); update_highlight = true; GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60); } @@ -453,15 +434,15 @@ 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 @@ // 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); } } Index: source/gui/ObjectTypes/CHotkeyPicker.h =================================================================== --- source/gui/ObjectTypes/CHotkeyPicker.h +++ source/gui/ObjectTypes/CHotkeyPicker.h @@ -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 @@ void FireEvent(const CStr& event); // Time without changes until a "combination" event is sent. - float m_TimeToCombination; + CGUISimpleSetting m_TimeToCombination; // Time of the last registered key change. double m_LastKeyChange; Index: source/gui/ObjectTypes/CHotkeyPicker.cpp =================================================================== --- source/gui/ObjectTypes/CHotkeyPicker.cpp +++ source/gui/ObjectTypes/CHotkeyPicker.cpp @@ -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 @@ 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); } Index: source/gui/ObjectTypes/CImage.h =================================================================== --- source/gui/ObjectTypes/CImage.h +++ source/gui/ObjectTypes/CImage.h @@ -45,8 +45,7 @@ */ virtual void Draw(); - // Settings - CGUISpriteInstance m_Sprite; + CGUISimpleSetting m_Sprite; }; #endif // INCLUDED_CIMAGE Index: source/gui/ObjectTypes/CImage.cpp =================================================================== --- source/gui/ObjectTypes/CImage.cpp +++ source/gui/ObjectTypes/CImage.cpp @@ -23,9 +23,8 @@ CImage::CImage(CGUI& pGUI) : IGUIObject(pGUI), - m_Sprite() + m_Sprite(this, "sprite") { - RegisterSetting("sprite", m_Sprite); } CImage::~CImage() Index: source/gui/ObjectTypes/CInput.h =================================================================== --- source/gui/ObjectTypes/CInput.h +++ source/gui/ObjectTypes/CInput.h @@ -216,24 +216,23 @@ 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 m_BufferPosition; + CGUISimpleSetting m_BufferZone; + CGUISimpleSetting m_Caption; + CGUISimpleSetting m_PlaceholderText; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_MaskChar; + CGUISimpleSetting m_Mask; + CGUISimpleSetting m_MaxLength; + CGUISimpleSetting m_MultiLine; + CGUISimpleSetting m_Readonly; + CGUISimpleSetting m_ScrollBar; + CGUISimpleSetting m_ScrollBarStyle; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_SpriteSelectArea; + CGUISimpleSetting m_TextColor; + CGUISimpleSetting m_TextColorSelected; + CGUISimpleSetting m_PlaceholderColor; }; #endif // INCLUDED_CINPUT Index: source/gui/ObjectTypes/CInput.cpp =================================================================== --- source/gui/ObjectTypes/CInput.cpp +++ source/gui/ObjectTypes/CInput.cpp @@ -56,40 +56,24 @@ 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 @@ void CInput::UpdateBufferPositionSetting() { - SetSetting("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 @@ { 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 @@ std::wstring text = wstring_from_utf8(ev->ev.text.text); // Check max length - if (m_MaxLength != 0 && m_Caption.length() + text.length() > static_cast(m_MaxLength)) + if (m_MaxLength != 0 && caption.length() + text.length() > static_cast(m_MaxLength)) return IN_HANDLED; m_WantedX = 0.0f; @@ -153,10 +141,10 @@ m_ComposingText = false; } - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption.append(text); + if (m_iBufferPos == static_cast(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 @@ 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 @@ 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 @@ { m_iBufferPos_Tail = -1; - if (m_Caption.empty() || m_iBufferPos == 0) + if (caption.empty() || m_iBufferPos == 0) break; - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption = m_Caption.Left(static_cast(m_Caption.length()) - 1); + if (m_iBufferPos == static_cast(caption.length())) + caption = caption.Left(static_cast(caption.length()) - 1); else - m_Caption = - m_Caption.Left(m_iBufferPos - 1) + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + caption = + caption.Left(m_iBufferPos - 1) + + caption.Right(static_cast(caption.length()) - m_iBufferPos); --m_iBufferPos; @@ -309,12 +301,12 @@ DeleteCurSelection(); else { - if (m_Caption.empty() || m_iBufferPos == static_cast(m_Caption.length())) + if (caption.empty() || m_iBufferPos == static_cast(caption.length())) break; - m_Caption = - m_Caption.Left(m_iBufferPos) + - m_Caption.Right(static_cast(m_Caption.length()) - (m_iBufferPos + 1)); + caption = + caption.Left(m_iBufferPos) + + caption.Right(static_cast(caption.length()) - (m_iBufferPos + 1)); UpdateText(m_iBufferPos, m_iBufferPos + 1, m_iBufferPos); } @@ -344,7 +336,7 @@ return; // Check max length - if (m_MaxLength != 0 && m_Caption.length() >= static_cast(m_MaxLength)) + if (m_MaxLength != 0 && caption.length() >= static_cast(m_MaxLength)) break; m_WantedX = 0.0f; @@ -353,12 +345,12 @@ DeleteCurSelection(); m_iBufferPos_Tail = -1; - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption += cooked; + if (m_iBufferPos == static_cast(caption.length())) + caption += cooked; else - m_Caption = - m_Caption.Left(m_iBufferPos) + cooked + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + caption = + caption.Left(m_iBufferPos) + cooked + + caption.Right(static_cast(caption.length()) - m_iBufferPos); UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos + 1); @@ -375,6 +367,8 @@ { 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 @@ m_iBufferPos_Tail = m_iBufferPos; } - m_iBufferPos = static_cast(m_Caption.length()); + m_iBufferPos = static_cast(caption.length()); m_WantedX = 0.0f; UpdateAutoScroll(); @@ -474,7 +468,7 @@ else if (!SelectingText()) m_iBufferPos_Tail = m_iBufferPos; - if (m_iBufferPos < static_cast(m_Caption.length())) + if (m_iBufferPos < static_cast(caption.length())) ++m_iBufferPos; } else @@ -607,7 +601,7 @@ 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 @@ std::string hotkey = static_cast(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 @@ SDL_free(utf8_text); // Check max length - if (m_MaxLength != 0 && m_Caption.length() + text.length() > static_cast(m_MaxLength)) - text = text.substr(0, static_cast(m_MaxLength) - m_Caption.length()); + if (m_MaxLength != 0 && caption.length() + text.length() > static_cast(m_MaxLength)) + text = text.substr(0, static_cast(m_MaxLength) - caption.length()); if (SelectingText()) DeleteCurSelection(); - if (m_iBufferPos == static_cast(m_Caption.length())) - m_Caption += text; + if (m_iBufferPos == static_cast(caption.length())) + caption += text; else - m_Caption = - m_Caption.Left(m_iBufferPos) + text + - m_Caption.Right(static_cast(m_Caption.length()) - m_iBufferPos); + caption = + caption.Left(m_iBufferPos) + text + + caption.Right(static_cast(caption.length()) - m_iBufferPos); UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1); @@ -678,7 +676,7 @@ 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 @@ 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 @@ if (SelectingText()) DeleteCurSelection(); - if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) + if (!caption.empty() && m_iBufferPos < static_cast(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(m_Caption.length())) + while (++m_iBufferPos < static_cast(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(m_Caption.length())) + while (m_iBufferPos < static_cast(caption.length())) { - if (!iswspace(m_Caption[m_iBufferPos])) + if (!iswspace(caption[m_iBufferPos])) break; ++m_iBufferPos; @@ -786,9 +784,9 @@ 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 @@ else if (!SelectingText()) m_iBufferPos_Tail = m_iBufferPos; - if (!m_Caption.empty() && m_iBufferPos < static_cast(m_Caption.length())) + if (!caption.empty() && m_iBufferPos < static_cast(caption.length())) { // Select chars to the right until we hit whitespace - while (++m_iBufferPos < static_cast(m_Caption.length())) + while (++m_iBufferPos < static_cast(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(m_Caption.length())) + while (m_iBufferPos < static_cast(caption.length())) { - if (!iswspace(m_Caption[m_iBufferPos])) + if (!iswspace(caption[m_iBufferPos])) break; ++m_iBufferPos; @@ -886,6 +884,9 @@ 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 @@ 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 @@ // 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 @@ // 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(m_Caption.length())) + while (++m_iBufferPos_Tail < static_cast(caption.length())) { - if (!iswspace(m_Caption[m_iBufferPos_Tail])) + if (!iswspace(caption[m_iBufferPos_Tail])) break; } - if (m_iBufferPos_Tail == static_cast(m_Caption.length())) + if (m_iBufferPos_Tail == static_cast(caption.length())) break; // now go to the right until we hit whitespace or punctuation - while (++m_iBufferPos_Tail < static_cast(m_Caption.length())) + while (++m_iBufferPos_Tail < static_cast(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(m_Caption.length())) + while (++m_iBufferPos_Tail < static_cast(caption.length())) { - if (!iswspace(m_Caption[m_iBufferPos_Tail])) + if (!iswspace(caption[m_iBufferPos_Tail])) break; } - if (m_iBufferPos_Tail == static_cast(m_Caption.length())) + if (m_iBufferPos_Tail == static_cast(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(m_Caption.length())) + while (++m_iBufferPos_Tail < static_cast(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 @@ // 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(m_Caption.length())) - if (iswspace(m_Caption[m_iBufferPos_Tail]) || iswpunct(m_Caption[m_iBufferPos_Tail])) + while (++m_iBufferPos_Tail < static_cast(caption.length())) + if (iswspace(caption[m_iBufferPos_Tail]) || iswpunct(caption[m_iBufferPos_Tail])) break; } UpdateAutoScroll(); @@ -1206,11 +1207,11 @@ 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 @@ 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 @@ 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 @@ 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::UpdateText(int from, int to_before, int to_after) { - if (m_MaxLength != 0 && m_Caption.length() > static_cast(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(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(m_Caption.size())); - m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast(m_Caption.size())); + m_iBufferPos = std::min(m_iBufferPos, static_cast(caption.size())); + m_iBufferPos_Tail = std::min(m_iBufferPos_Tail, static_cast(caption.size())); UpdateBufferPositionSetting(); if (font_name.empty()) @@ -1568,7 +1571,7 @@ int to = 0; // make sure it's initialized if (to_before == -1) - to = static_cast(m_Caption.length()); + to = static_cast(caption.length()); CFontMetrics font(font_name); @@ -1671,7 +1674,7 @@ 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(m_Caption.length()); + to = static_cast(caption.length()); // Setup the first row @@ -1698,7 +1701,7 @@ check_point_row_start += delta; check_point_row_end += delta; - if (to != static_cast(m_Caption.length())) + if (to != static_cast(caption.length())) to += delta; } } @@ -1711,9 +1714,9 @@ 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(m_Caption.length())) + if (i == to-1 && to != static_cast(caption.length())) break; // it will be added outside current_line = m_CharacterPositions.insert(current_line, row); @@ -1726,12 +1729,12 @@ } 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 @@ 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(m_Caption.length()); + to = static_cast(caption.length()); // Set current line, new rows will be added before current_line, so @@ -1909,7 +1912,7 @@ // 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 @@ virtualTo = m_iBufferPos; } - m_Caption = - m_Caption.Left(virtualFrom) + - m_Caption.Right(static_cast(m_Caption.length()) - virtualTo); + // Silently change. + m_Caption.Set(m_Caption->Left(virtualFrom) + m_Caption->Right(static_cast(m_Caption->length()) - virtualTo), + false); UpdateText(virtualFrom, virtualTo, virtualFrom); @@ -2038,7 +2041,7 @@ // 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(); Index: source/gui/ObjectTypes/CList.h =================================================================== --- source/gui/ObjectTypes/CList.h +++ source/gui/ObjectTypes/CList.h @@ -126,24 +126,22 @@ 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 m_BufferZone; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_ScrollBar; + CGUISimpleSetting m_ScrollBarStyle; + CGUISimpleSetting m_ScrollBottom; + CGUISimpleSetting m_SoundDisabled; + CGUISimpleSetting m_SoundSelected; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_SpriteSelectArea; + CGUISimpleSetting m_TextColor; + CGUISimpleSetting m_TextColorSelected; + CGUISimpleSetting m_Selected; + CGUISimpleSetting m_AutoScroll; + CGUISimpleSetting m_Hovered; + CGUISimpleSetting m_List; + CGUISimpleSetting m_ListData; private: static const CStr EventNameSelectionChange; Index: source/gui/ObjectTypes/CList.cpp =================================================================== --- source/gui/ObjectTypes/CList.cpp +++ source/gui/ObjectTypes/CList.cpp @@ -38,49 +38,25 @@ 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("scrollbar", false, true); - SetSetting("selected", -1, true); - SetSetting("hovered", -1, true); - SetSetting("auto_scroll", false, true); - // Add scroll-bar CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); bar->SetRightAligned(true); @@ -123,14 +99,14 @@ 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 @@ 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 @@ int hovered = GetHoveredItem(); if (hovered == -1) break; - SetSetting("selected", hovered, true); + m_Selected.Set(hovered, true); UpdateAutoScroll(); PlaySound(m_SoundSelected); @@ -240,7 +216,7 @@ if (m_Hovered == -1) break; - SetSetting("hovered", -1, true); + m_Hovered.Set(-1, true); ScriptEvent(EventNameHoverChange); break; } @@ -251,7 +227,7 @@ if (hovered == m_Hovered) break; - SetSetting("hovered", hovered, true); + m_Hovered.Set(hovered, true); ScriptEvent(EventNameHoverChange); break; } @@ -369,7 +345,7 @@ } } - 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::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 @@ void CList::SelectNextElement() { - if (m_Selected != static_cast(m_List.m_Items.size()) - 1) + if (m_Selected != static_cast(m_List->m_Items.size()) - 1) { - SetSetting("selected", m_Selected + 1, true); + m_Selected.Set(m_Selected + 1, true); PlaySound(m_SoundSelected); } } @@ -439,7 +415,7 @@ { if (m_Selected > 0) { - SetSetting("selected", m_Selected - 1, true); + m_Selected.Set(m_Selected - 1, true); PlaySound(m_SoundSelected); } } @@ -447,15 +423,15 @@ void CList::SelectFirstElement() { if (m_Selected >= 0) - SetSetting("selected", 0, true); + m_Selected.Set(0, true); } void CList::SelectLastElement() { - const int index = static_cast(m_List.m_Items.size()) - 1; + const int index = static_cast(m_List->m_Items.size()) - 1; if (m_Selected != index) - SetSetting("selected", index, true); + m_Selected.Set(index, true); } void CList::UpdateAutoScroll() @@ -494,7 +470,7 @@ 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; Index: source/gui/ObjectTypes/CMiniMap.h =================================================================== --- source/gui/ObjectTypes/CMiniMap.h +++ source/gui/ObjectTypes/CMiniMap.h @@ -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 @@ bool m_TerrainDirty; // Whether to draw a black square around and under the minimap. - bool m_Mask; + CGUISimpleSetting m_Mask; ssize_t m_Width, m_Height; Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -109,11 +109,9 @@ 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; Index: source/gui/ObjectTypes/COList.h =================================================================== --- source/gui/ObjectTypes/COList.h +++ source/gui/ObjectTypes/COList.h @@ -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 m_List; + CGUISimpleSetting m_Hidden; }; /** @@ -73,14 +76,13 @@ */ std::vector 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 m_SpriteHeading; + CGUISimpleSetting m_Sortable; + CGUISimpleSetting m_SelectedColumn; + CGUISimpleSetting m_SelectedColumnOrder; + CGUISimpleSetting m_SpriteAsc; + CGUISimpleSetting m_SpriteDesc; + CGUISimpleSetting m_SpriteNotSorted; private: static const CStr EventNameSelectionColumnChange; Index: source/gui/ObjectTypes/COList.cpp =================================================================== --- source/gui/ObjectTypes/COList.cpp +++ source/gui/ObjectTypes/COList.cpp @@ -33,26 +33,19 @@ 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 @@ // 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 @@ 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 @@ 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 @@ mouse.X < leftTopCorner.X + width && mouse.Y < leftTopCorner.Y + m_HeadingHeight) { - if (column.m_Id != m_SelectedColumn) + if (column.m_Id != static_cast(m_SelectedColumn)) { - SetSetting("selected_column_order", -1, true); + m_SelectedColumnOrder.Set(-1, true); CStr selected_column = column.m_Id; - SetSetting("selected_column", selected_column, true); + m_SelectedColumn.Set(selected_column, true); } else - SetSetting("selected_column_order", -m_SelectedColumnOrder, true); + m_SelectedColumnOrder.Set(-m_SelectedColumnOrder, true); ScriptEvent(EventNameSelectionColumnChange); PlaySound(m_SoundSelected); @@ -199,7 +192,14 @@ } 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 @@ if (!CGUI::ParseString(&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(&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 @@ 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 @@ 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 @@ // 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()) Index: source/gui/ObjectTypes/CProgressBar.h =================================================================== --- source/gui/ObjectTypes/CProgressBar.h +++ source/gui/ObjectTypes/CProgressBar.h @@ -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 @@ void HandleMessage(SGUIMessage& Message); // Settings - CGUISpriteInstance m_SpriteBackground; - CGUISpriteInstance m_SpriteBar; - float m_Progress; + CGUISimpleSetting m_SpriteBackground; + CGUISimpleSetting m_SpriteBar; + CGUISimpleSetting m_Progress; }; #endif // INCLUDED_CPROGRESSBAR Index: source/gui/ObjectTypes/CProgressBar.cpp =================================================================== --- source/gui/ObjectTypes/CProgressBar.cpp +++ source/gui/ObjectTypes/CProgressBar.cpp @@ -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 @@ if (Message.value == "progress") { if (m_Progress > 100.f) - SetSetting("progress", 100.f, true); + m_Progress.Set(100.f, true); else if (m_Progress < 0.f) - SetSetting("progress", 0.f, true); + m_Progress.Set(0.f, true); } break; default: Index: source/gui/ObjectTypes/CRadioButton.h =================================================================== --- source/gui/ObjectTypes/CRadioButton.h +++ source/gui/ObjectTypes/CRadioButton.h @@ -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 Index: source/gui/ObjectTypes/CRadioButton.cpp =================================================================== --- source/gui/ObjectTypes/CRadioButton.cpp +++ source/gui/ObjectTypes/CRadioButton.cpp @@ -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 @@ void CRadioButton::HandleMessage(SGUIMessage& Message) { IGUIButtonBehavior::HandleMessage(Message); - switch (Message.type) { case GUIM_PRESSED: @@ -36,10 +35,11 @@ // 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("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("checked", true, true); + m_Checked.Set(true, true); break; default: Index: source/gui/ObjectTypes/CSlider.h =================================================================== --- source/gui/ObjectTypes/CSlider.h +++ source/gui/ObjectTypes/CSlider.h @@ -61,12 +61,12 @@ 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 m_ButtonSide; + CGUISimpleSetting m_MinValue; + CGUISimpleSetting m_MaxValue; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_SpriteBar; + CGUISimpleSetting m_Value; private: CVector2D m_Mouse; Index: source/gui/ObjectTypes/CSlider.cpp =================================================================== --- source/gui/ObjectTypes/CSlider.cpp +++ source/gui/ObjectTypes/CSlider.cpp @@ -27,21 +27,14 @@ CSlider::CSlider(CGUI& pGUI) : IGUIObject(pGUI), IGUIButtonBehavior(*static_cast(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(m_Value, m_MinValue, m_MaxValue), false); } CSlider::~CSlider() @@ -61,7 +54,7 @@ void CSlider::IncrementallyChangeValue(const float difference) { - m_Value = Clamp(m_Value + difference, m_MinValue, m_MaxValue); + m_Value.Set(Clamp(m_Value + difference, m_MinValue, m_MaxValue), true); UpdateValue(); } @@ -72,11 +65,13 @@ switch (Message.type) { + /* case GUIM_SETTINGS_UPDATED: { - m_Value = Clamp(m_Value, m_MinValue, m_MaxValue); + m_Value.Set(Clamp(m_Value, m_MinValue, m_MaxValue), true); break; } + */ case GUIM_MOUSE_WHEEL_DOWN: { if (m_Pressed) @@ -119,7 +114,6 @@ void CSlider::UpdateValue() { - SetSetting("value", m_Value, true); ScriptEvent(EventNameValueChange); } Index: source/gui/ObjectTypes/CText.h =================================================================== --- source/gui/ObjectTypes/CText.h +++ source/gui/ObjectTypes/CText.h @@ -74,20 +74,17 @@ */ 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 m_BufferZone; + CGUISimpleSetting m_Caption; + CGUISimpleSetting m_Clip; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_ScrollBar; + CGUISimpleSetting m_ScrollBarStyle; + CGUISimpleSetting m_ScrollBottom; + CGUISimpleSetting m_ScrollTop; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_TextColor; + CGUISimpleSetting m_TextColorDisabled; }; #endif // INCLUDED_CTEXT Index: source/gui/ObjectTypes/CText.cpp =================================================================== --- source/gui/ObjectTypes/CText.cpp +++ source/gui/ObjectTypes/CText.cpp @@ -27,38 +27,18 @@ : IGUIObject(pGUI), IGUIScrollBarOwner(*static_cast(this)), IGUITextOwner(*static_cast(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("ghost", true, true); - SetSetting("scrollbar", false, true); - SetSetting("clip", true, true); - // Add scroll-bar CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(pGUI); bar->SetRightAligned(true); @@ -82,7 +62,7 @@ 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]); Index: source/gui/ObjectTypes/CTooltip.h =================================================================== --- source/gui/ObjectTypes/CTooltip.h +++ source/gui/ObjectTypes/CTooltip.h @@ -35,6 +35,11 @@ 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 @@ 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 m_BufferZone; + CGUISimpleSetting m_Caption; + CGUISimpleSetting m_Font; + CGUISimpleSetting m_Sprite; + CGUISimpleSetting m_Delay; + CGUISimpleSetting m_TextColor; + CGUISimpleSetting m_MaxWidth; + CGUISimpleSetting m_Offset; + CGUISimpleSetting m_Anchor; + CGUISimpleSetting m_Independent; + CGUISimpleSetting m_MousePos; + CGUISimpleSetting m_UseObject; + CGUISimpleSetting m_HideObject; }; #endif // INCLUDED_CTOOLTIP Index: source/gui/ObjectTypes/CTooltip.cpp =================================================================== --- source/gui/ObjectTypes/CTooltip.cpp +++ source/gui/ObjectTypes/CTooltip.cpp @@ -28,46 +28,24 @@ CTooltip::CTooltip(CGUI& pGUI) : IGUIObject(pGUI), IGUITextOwner(*static_cast(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("delay", 500, true); - SetSetting("anchor", EVAlign::BOTTOM, true); - SetSetting("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 @@ { 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 @@ 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 @@ else if (size.pixel.right > screenw) size.pixel.left -= (size.pixel.right-screenw), size.pixel.right = screenw; - SetSetting("size", size, true); + m_Size.Set(size, true); } void CTooltip::UpdateCachedSize() Index: source/gui/SettingTypes/CGUIHotkey.h =================================================================== --- source/gui/SettingTypes/CGUIHotkey.h +++ source/gui/SettingTypes/CGUIHotkey.h @@ -15,24 +15,26 @@ * along with 0 A.D. If not, see . */ -#include "precompiled.h" +#ifndef INCLUDED_CGUIHOTKEY +#define INCLUDED_CGUIHOTKEY -#include "CImage.h" +#include "gui/CGUISetting.h" +#include "ps/CStr.h" -#include "gui/CGUI.h" - -CImage::CImage(CGUI& pGUI) - : IGUIObject(pGUI), - m_Sprite() +/** + * Manages a hotkey setting for a GUI object. + */ +class CGUIHotkey : public CGUISimpleSetting { - RegisterSetting("sprite", m_Sprite); -} +public: + CGUIHotkey(IGUIObject* pObject, const CStr& Name) : CGUISimpleSetting(pObject, Name) + {} + NONCOPYABLE(CGUIHotkey); + MOVABLE(CGUIHotkey); -CImage::~CImage() -{ -} + bool DoFromString(const CStrW& value) override; + bool DoFromJSVal(const ScriptRequest& rq, JS::HandleValue value) override; + void OnSettingChange(const CStr& setting, bool sendMessage) override; +}; -void CImage::Draw() -{ - m_pGUI.DrawSprite(m_Sprite, GetBufferedZ(), m_CachedActualSize); -} +#endif // INCLUDED_CGUIHOTKEY Index: source/gui/SettingTypes/CGUIHotkey.cpp =================================================================== --- source/gui/SettingTypes/CGUIHotkey.cpp +++ source/gui/SettingTypes/CGUIHotkey.cpp @@ -15,38 +15,32 @@ * along with 0 A.D. If not, see . */ -#ifndef INCLUDED_CIMAGE -#define INCLUDED_CIMAGE +#include "precompiled.h" + +#include "CGUIHotkey.h" -#include "gui/CGUISprite.h" #include "gui/ObjectBases/IGUIObject.h" +#include "scriptinterface/ScriptInterface.h" -/** - * Object just for drawing a sprite. Like CText, without the - * possibility to draw text. - * - * Created, because I've seen the user being indecisive about - * what control to use in these situations. I've seen button - * without functionality used, and that is a lot of unnecessary - * overhead. That's why I thought I'd go with an intuitive - * control. - */ -class CImage : public IGUIObject +bool CGUIHotkey::DoFromString(const CStrW& value) { - GUI_OBJECT(CImage) + m_pObject.GetGUI().UnsetObjectHotkey(&m_pObject, m_Setting); + m_Setting = value.ToUTF8(); + m_pObject.GetGUI().SetObjectHotkey(&m_pObject, m_Setting); + return true; +} -public: - CImage(CGUI& pGUI); - virtual ~CImage(); - -protected: - /** - * Draws the Image - */ - virtual void Draw(); +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; +} - // Settings - CGUISpriteInstance m_Sprite; -}; +void CGUIHotkey::OnSettingChange(const CStr& setting, bool sendMessage) +{ + IGUISetting::OnSettingChange(setting, sendMessage); +} -#endif // INCLUDED_CIMAGE Index: source/scriptinterface/ScriptConversions.h =================================================================== --- source/scriptinterface/ScriptConversions.h +++ source/scriptinterface/ScriptConversions.h @@ -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 @@ 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) {