From 6fa82da1f1967c877e70e7bf05b910a0bdadb8fe Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 22 Sep 2021 17:39:01 +1000 Subject: [PATCH] Common: Add SettingsInterface and SettingsWrapper --- common/CMakeLists.txt | 3 + common/SettingsInterface.h | 89 +++++++++++++++++ common/SettingsWrapper.cpp | 180 ++++++++++++++++++++++++++++++++++ common/SettingsWrapper.h | 109 ++++++++++++++++++++ common/common.vcxproj | 3 + common/common.vcxproj.filters | 9 ++ 6 files changed, 393 insertions(+) create mode 100644 common/SettingsInterface.h create mode 100644 common/SettingsWrapper.cpp create mode 100644 common/SettingsWrapper.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 7797e8a611..0c55676185 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -29,6 +29,7 @@ target_sources(common PRIVATE pxWindowTextWriter.cpp RwMutex.cpp Semaphore.cpp + SettingsWrapper.cpp StringHelpers.cpp StringUtil.cpp ThreadTools.cpp @@ -80,6 +81,8 @@ target_sources(common PRIVATE SafeArray.h ScopedAlloc.h ScopedPtrMT.h + SettingsInterface.h + SettingsWrapper.h StringHelpers.h StringUtil.h Threading.h diff --git a/common/SettingsInterface.h b/common/SettingsInterface.h new file mode 100644 index 0000000000..f19b76b822 --- /dev/null +++ b/common/SettingsInterface.h @@ -0,0 +1,89 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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 PCSX2. + * If not, see . + */ + +#pragma once + +#include "Pcsx2Defs.h" +#include +#include + +class SettingsInterface +{ +public: + virtual ~SettingsInterface() = default; + + virtual bool Save() = 0; + virtual void Clear() = 0; + + virtual bool GetIntValue(const char* section, const char* key, int* value) const = 0; + virtual bool GetUIntValue(const char* section, const char* key, uint* value) const = 0; + virtual bool GetFloatValue(const char* section, const char* key, float* value) const = 0; + virtual bool GetDoubleValue(const char* section, const char* key, double* value) const = 0; + virtual bool GetBoolValue(const char* section, const char* key, bool* value) const = 0; + virtual bool GetStringValue(const char* section, const char* key, std::string* value) const = 0; + + virtual void SetIntValue(const char* section, const char* key, int value) = 0; + virtual void SetUIntValue(const char* section, const char* key, uint value) = 0; + virtual void SetFloatValue(const char* section, const char* key, float value) = 0; + virtual void SetDoubleValue(const char* section, const char* key, double value) = 0; + virtual void SetBoolValue(const char* section, const char* key, bool value) = 0; + virtual void SetStringValue(const char* section, const char* key, const char* value) = 0; + + virtual std::vector GetStringList(const char* section, const char* key) = 0; + virtual void SetStringList(const char* section, const char* key, const std::vector& items) = 0; + virtual bool RemoveFromStringList(const char* section, const char* key, const char* item) = 0; + virtual bool AddToStringList(const char* section, const char* key, const char* item) = 0; + + virtual void DeleteValue(const char* section, const char* key) = 0; + virtual void ClearSection(const char* section) = 0; + + __fi int GetIntValue(const char* section, const char* key, int default_value = 0) const + { + int value; + return GetIntValue(section, key, &value) ? value : default_value; + } + + __fi uint GetUIntValue(const char* section, const char* key, uint default_value = 0) const + { + uint value; + return GetUIntValue(section, key, &value) ? value : default_value; + } + + __fi float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) const + { + float value; + return GetFloatValue(section, key, &value) ? value : default_value; + } + + __fi float GetDoubleValue(const char* section, const char* key, double default_value = 0.0) const + { + double value; + return GetDoubleValue(section, key, &value) ? value : default_value; + } + + __fi bool GetBoolValue(const char* section, const char* key, bool default_value = false) const + { + bool value; + return GetBoolValue(section, key, &value) ? value : default_value; + } + + __fi std::string GetStringValue(const char* section, const char* key, const char* default_value = "") const + { + std::string value; + if (!GetStringValue(section, key, &value)) + value.assign(default_value); + return value; + } +}; diff --git a/common/SettingsWrapper.cpp b/common/SettingsWrapper.cpp new file mode 100644 index 0000000000..3f4ca58e85 --- /dev/null +++ b/common/SettingsWrapper.cpp @@ -0,0 +1,180 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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 PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#include + +#include "SettingsWrapper.h" +#include "Console.h" + +static int _calcEnumLength(const char* const* enumArray) +{ + int cnt = 0; + while (*enumArray != nullptr) + { + enumArray++; + cnt++; + } + + return cnt; +} + +SettingsWrapper::SettingsWrapper(SettingsInterface& si) + : m_si(si) +{ +} + +SettingsLoadWrapper::SettingsLoadWrapper(SettingsInterface& si) + : SettingsWrapper(si) +{ +} + +bool SettingsLoadWrapper::IsLoading() const +{ + return true; +} + +bool SettingsLoadWrapper::IsSaving() const +{ + return false; +} + +void SettingsLoadWrapper::Entry(const char* section, const char* var, int& value, const int defvalue /*= 0*/) +{ + value = m_si.GetIntValue(section, var, defvalue); +} + +void SettingsLoadWrapper::Entry(const char* section, const char* var, uint& value, const uint defvalue /*= 0*/) +{ + value = m_si.GetUIntValue(section, var, defvalue); +} + +void SettingsLoadWrapper::Entry(const char* section, const char* var, bool& value, const bool defvalue /*= false*/) +{ + value = m_si.GetBoolValue(section, var, defvalue); +} + +void SettingsLoadWrapper::Entry(const char* section, const char* var, double& value, const double defvalue /*= 0.0*/) +{ + value = m_si.GetDoubleValue(section, var, defvalue); +} + +void SettingsLoadWrapper::Entry(const char* section, const char* var, std::string& value, const std::string& default_value /*= std::string()*/) +{ + if (!m_si.GetStringValue(section, var, &value) && &value != &default_value) + value = default_value; +} + +void SettingsLoadWrapper::_EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) +{ + const int cnt = _calcEnumLength(enumArray); + defvalue = std::clamp(defvalue, 0, cnt); + + const std::string retval(m_si.GetStringValue(section, var, enumArray[defvalue])); + + int i = 0; + while (enumArray[i] != nullptr && (retval != enumArray[i])) + i++; + + if (enumArray[i] == nullptr) + { + Console.Warning("(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.", + retval.c_str(), var, enumArray[defvalue]); + value = defvalue; + } + else + { + value = i; + } +} + +bool SettingsLoadWrapper::EntryBitBool(const char* section, const char* var, bool value, const bool defvalue /*= false*/) +{ + return m_si.GetBoolValue(section, var, defvalue); +} + +int SettingsLoadWrapper::EntryBitfield(const char* section, const char* var, int value, const int defvalue /*= 0*/) +{ + return m_si.GetIntValue(section, var, defvalue); +} + +SettingsSaveWrapper::SettingsSaveWrapper(SettingsInterface& si) + : SettingsWrapper(si) +{ +} + +bool SettingsSaveWrapper::IsLoading() const +{ + return false; +} + +bool SettingsSaveWrapper::IsSaving() const +{ + return true; +} + +void SettingsSaveWrapper::Entry(const char* section, const char* var, int& value, const int defvalue /*= 0*/) +{ + m_si.SetIntValue(section, var, value); +} + +void SettingsSaveWrapper::Entry(const char* section, const char* var, uint& value, const uint defvalue /*= 0*/) +{ + m_si.SetUIntValue(section, var, value); +} + +void SettingsSaveWrapper::Entry(const char* section, const char* var, bool& value, const bool defvalue /*= false*/) +{ + m_si.SetBoolValue(section, var, value); +} + +void SettingsSaveWrapper::Entry(const char* section, const char* var, double& value, const double defvalue /*= 0.0*/) +{ + m_si.SetDoubleValue(section, var, value); +} + +void SettingsSaveWrapper::Entry(const char* section, const char* var, std::string& value, const std::string& default_value /*= std::string()*/) +{ + m_si.SetStringValue(section, var, value.c_str()); +} + +bool SettingsSaveWrapper::EntryBitBool(const char* section, const char* var, bool value, const bool defvalue /*= false*/) +{ + m_si.SetBoolValue(section, var, value); + return value; +} + +int SettingsSaveWrapper::EntryBitfield(const char* section, const char* var, int value, const int defvalue /*= 0*/) +{ + m_si.SetIntValue(section, var, value); + return value; +} + +void SettingsSaveWrapper::_EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) +{ + const int cnt = _calcEnumLength(enumArray); + if (value >= cnt) + { + Console.Warning("(SaveSettings) An illegal enumerated index was detected when saving '%s'", var); + Console.Indent().Warning( + "Illegal Value: %d\n" + "Using Default: %d (%s)\n", + value, defvalue, enumArray[defvalue]); + value = defvalue; + } + + m_si.SetIntValue(section, var, value); +} diff --git a/common/SettingsWrapper.h b/common/SettingsWrapper.h new file mode 100644 index 0000000000..9dcb5ba70b --- /dev/null +++ b/common/SettingsWrapper.h @@ -0,0 +1,109 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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 PCSX2. + * If not, see . + */ + +#pragma once + +#include "SettingsInterface.h" + +// TODO(Stenzek): Remove when wx goes bye bye. +#include +#include "Path.h" + + +// Helper class which loads or saves depending on the derived class. +class SettingsWrapper +{ +public: + SettingsWrapper(SettingsInterface& si); + + virtual bool IsLoading() const = 0; + virtual bool IsSaving() const = 0; + + virtual void Entry(const char* section, const char* var, int& value, const int defvalue = 0) = 0; + virtual void Entry(const char* section, const char* var, uint& value, const uint defvalue = 0) = 0; + virtual void Entry(const char* section, const char* var, bool& value, const bool defvalue = false) = 0; + virtual void Entry(const char* section, const char* var, double& value, const double defvalue = 0.0) = 0; + virtual void Entry(const char* section, const char* var, std::string& value, const std::string& default_value = std::string()) = 0; + + // This special form of Entry is provided for bitfields, which cannot be passed by reference. + virtual bool EntryBitBool(const char* section, const char* var, bool value, const bool defvalue = false) = 0; + virtual int EntryBitfield(const char* section, const char* var, int value, const int defvalue = 0) = 0; + + template + void EnumEntry(const char* section, const char* var, T& value, const char* const* enumArray = nullptr, const T defvalue = (T)0) + { + int tstore = (int)value; + auto defaultvalue = enum_cast(defvalue); + if (enumArray == NULL) + Entry(section, var, tstore, defaultvalue); + else + _EnumEntry(section, var, tstore, enumArray, defaultvalue); + value = (T)tstore; + } + +protected: + virtual void _EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) = 0; + + SettingsInterface& m_si; +}; + +class SettingsLoadWrapper final : public SettingsWrapper +{ +public: + SettingsLoadWrapper(SettingsInterface& si); + + bool IsLoading() const override; + bool IsSaving() const override; + + void Entry(const char* section, const char* var, int& value, const int defvalue = 0) override; + void Entry(const char* section, const char* var, uint& value, const uint defvalue = 0) override; + void Entry(const char* section, const char* var, bool& value, const bool defvalue = false) override; + void Entry(const char* section, const char* var, double& value, const double defvalue = 0.0) override; + + void Entry(const char* section, const char* var, std::string& value, const std::string& default_value = std::string()) override; + bool EntryBitBool(const char* section, const char* var, bool value, const bool defvalue = false) override; + int EntryBitfield(const char* section, const char* var, int value, const int defvalue = 0) override; + +protected: + void _EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) override; +}; + +class SettingsSaveWrapper final : public SettingsWrapper +{ +public: + SettingsSaveWrapper(SettingsInterface& si); + + bool IsLoading() const override; + bool IsSaving() const override; + + void Entry(const char* section, const char* var, int& value, const int defvalue = 0) override; + void Entry(const char* section, const char* var, uint& value, const uint defvalue = 0) override; + void Entry(const char* section, const char* var, bool& value, const bool defvalue = false) override; + void Entry(const char* section, const char* var, double& value, const double defvalue = 0.0) override; + + void Entry(const char* section, const char* var, std::string& value, const std::string& default_value = std::string()) override; + bool EntryBitBool(const char* section, const char* var, bool value, const bool defvalue = false) override; + int EntryBitfield(const char* section, const char* var, int value, const int defvalue = 0) override; + +protected: + void _EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) override; +}; + +#define SettingsWrapSection(section) const char* CURRENT_SETTINGS_SECTION = section; +#define SettingsWrapEntry(var) wrap.Entry(CURRENT_SETTINGS_SECTION, #var, var, var) +#define SettingsWrapBitfield(var) wrap.EntryBitfield(CURRENT_SETTINGS_SECTION, #var, var, var) +#define SettingsWrapBitBool(varname) varname = wrap.EntryBitBool(CURRENT_SETTINGS_SECTION, #varname, !!varname, varname) +#define SettingsWrapBitfieldEx(varname, textname) varname = wrap.EntryBitfield(CURRENT_SETTINGS_SECTION, textname, varname, varname) +#define SettingsWrapBitBoolEx(varname, textname) varname = wrap.EntryBitBool(CURRENT_SETTINGS_SECTION, textname, !!varname, varname) diff --git a/common/common.vcxproj b/common/common.vcxproj index 0b05771ffe..2dcce1a3e6 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -53,6 +53,7 @@ + @@ -101,6 +102,8 @@ + + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 9396415780..163c6d5d76 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -124,6 +124,9 @@ Source Files + + Source Files + @@ -276,6 +279,12 @@ Header Files + + Header Files + + + Header Files +