mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-02 19:32:11 +01:00
5978550b2f
EmulationActivity has an instance of Settings. If you go to SettingsActivity from EmulationActivity and change some settings, the changes get saved to disk, but EmulationActivity's Settings instance still contains the old settings in its map of all settings (assuming the EmulationActivity was not killed by the system to save memory). Then, once you're done playing your game and exit EmulationActivity, EmulationActivity calls Settings.saveSettings. This call to saveSettings first overwrites the entire INI file with its map of all settings (which is outdated) in order to save any legacy settings that have changed (which they haven't, since the GUI doesn't let you change legacy settings while a game is running). Then, it asks the new config system to write the most up-to-date values available for non-legacy settings, which should make all the settings be up-to-date again. The problem here is that the new config system would skip writing to disk if no settings changes had been made since the last time we asked it to write to disk (i.e. since SettingsActivity exited). NB: Calling Settings.loadSettings in EmulationActivity.onResume is not a working solution. I assume this is because SettingsActivity saves its settings in onStop and not onPause.
160 lines
3.6 KiB
C++
160 lines
3.6 KiB
C++
// Copyright 2016 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "Common/Config/ConfigInfo.h"
|
|
#include "Common/Config/Enums.h"
|
|
#include "Common/StringUtil.h"
|
|
|
|
namespace Config
|
|
{
|
|
namespace detail
|
|
{
|
|
template <typename T, std::enable_if_t<!std::is_enum<T>::value>* = nullptr>
|
|
std::optional<T> TryParse(const std::string& str_value)
|
|
{
|
|
T value;
|
|
if (!::TryParse(str_value, &value))
|
|
return std::nullopt;
|
|
return value;
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<std::is_enum<T>::value>* = nullptr>
|
|
std::optional<T> TryParse(const std::string& str_value)
|
|
{
|
|
const auto result = TryParse<std::underlying_type_t<T>>(str_value);
|
|
if (result)
|
|
return static_cast<T>(*result);
|
|
return {};
|
|
}
|
|
|
|
template <>
|
|
inline std::optional<std::string> TryParse(const std::string& str_value)
|
|
{
|
|
return str_value;
|
|
}
|
|
} // namespace detail
|
|
|
|
template <typename T>
|
|
class Info;
|
|
|
|
class Layer;
|
|
using LayerMap = std::map<Location, std::optional<std::string>>;
|
|
|
|
class ConfigLayerLoader
|
|
{
|
|
public:
|
|
explicit ConfigLayerLoader(LayerType layer);
|
|
virtual ~ConfigLayerLoader();
|
|
virtual void Load(Layer* config_layer) = 0;
|
|
virtual void Save(Layer* config_layer) = 0;
|
|
|
|
LayerType GetLayer() const;
|
|
|
|
private:
|
|
const LayerType m_layer;
|
|
};
|
|
|
|
class Section
|
|
{
|
|
public:
|
|
using iterator = LayerMap::iterator;
|
|
Section(iterator begin_, iterator end_) : m_begin(begin_), m_end(end_) {}
|
|
iterator begin() const { return m_begin; }
|
|
iterator end() const { return m_end; }
|
|
|
|
private:
|
|
iterator m_begin;
|
|
iterator m_end;
|
|
};
|
|
|
|
class ConstSection
|
|
{
|
|
public:
|
|
using iterator = LayerMap::const_iterator;
|
|
ConstSection(iterator begin_, iterator end_) : m_begin(begin_), m_end(end_) {}
|
|
iterator begin() const { return m_begin; }
|
|
iterator end() const { return m_end; }
|
|
|
|
private:
|
|
iterator m_begin;
|
|
iterator m_end;
|
|
};
|
|
|
|
class Layer
|
|
{
|
|
public:
|
|
explicit Layer(LayerType layer);
|
|
explicit Layer(std::unique_ptr<ConfigLayerLoader> loader);
|
|
virtual ~Layer();
|
|
|
|
// Convenience functions
|
|
bool Exists(const Location& location) const;
|
|
bool DeleteKey(const Location& location);
|
|
void DeleteAllKeys();
|
|
|
|
template <typename T>
|
|
T Get(const Info<T>& config_info) const
|
|
{
|
|
return Get<T>(config_info.GetLocation()).value_or(config_info.GetDefaultValue());
|
|
}
|
|
|
|
template <typename T>
|
|
std::optional<T> Get(const Location& location) const
|
|
{
|
|
const auto iter = m_map.find(location);
|
|
if (iter == m_map.end() || !iter->second.has_value())
|
|
return std::nullopt;
|
|
return detail::TryParse<T>(*iter->second);
|
|
}
|
|
|
|
template <typename T>
|
|
void Set(const Info<T>& config_info, const std::common_type_t<T>& value)
|
|
{
|
|
Set(config_info.GetLocation(), value);
|
|
}
|
|
|
|
template <typename T>
|
|
void Set(const Location& location, const T& value)
|
|
{
|
|
Set(location, ValueToString(value));
|
|
}
|
|
|
|
void Set(const Location& location, std::string new_value)
|
|
{
|
|
const auto iter = m_map.find(location);
|
|
if (iter != m_map.end() && iter->second == new_value)
|
|
return;
|
|
m_is_dirty = true;
|
|
m_map.insert_or_assign(location, std::move(new_value));
|
|
}
|
|
|
|
void MarkAsDirty() { m_is_dirty = true; }
|
|
|
|
Section GetSection(System system, const std::string& section);
|
|
ConstSection GetSection(System system, const std::string& section) const;
|
|
|
|
// Explicit load and save of layers
|
|
void Load();
|
|
void Save();
|
|
|
|
LayerType GetLayer() const;
|
|
const LayerMap& GetLayerMap() const;
|
|
|
|
protected:
|
|
bool m_is_dirty = false;
|
|
LayerMap m_map;
|
|
const LayerType m_layer;
|
|
std::unique_ptr<ConfigLayerLoader> m_loader;
|
|
};
|
|
} // namespace Config
|