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
+