2024-03-23 18:41:26 -07:00
|
|
|
#pragma once
|
|
|
|
#include "thirdparty/toml.hpp"
|
|
|
|
#include "log.hpp"
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <typeinfo>
|
|
|
|
#include <typeindex>
|
2024-04-28 12:31:40 -07:00
|
|
|
#include <optional>
|
2024-03-23 18:41:26 -07:00
|
|
|
#define OPTIONS (*Looper::Options::options)
|
|
|
|
namespace Looper::Options {
|
|
|
|
extern toml::table *options;
|
|
|
|
void save_options();
|
|
|
|
void load_options();
|
2024-05-02 14:52:11 -07:00
|
|
|
extern std::optional<const char *> options_path_override;
|
2024-03-23 18:41:26 -07:00
|
|
|
std::string get_options_path();
|
|
|
|
inline bool option_set(std::string name) {
|
|
|
|
toml::path path(name);
|
|
|
|
auto *tmp = options;
|
|
|
|
std::vector<std::string> components;
|
|
|
|
for (auto component : path) {
|
|
|
|
components.push_back((std::string)component);
|
|
|
|
}
|
|
|
|
std::string last_component = components[components.size() - 1];
|
|
|
|
components.pop_back();
|
|
|
|
for (auto component : components) {
|
|
|
|
auto &cur_tmp = *tmp;
|
|
|
|
if (cur_tmp.contains(component)) {
|
|
|
|
if (!cur_tmp[component].is_table()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
tmp = cur_tmp[component].as_table();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tmp->contains(last_component)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2024-04-28 12:31:40 -07:00
|
|
|
inline void delete_option(std::string name) {
|
|
|
|
toml::path path(name);
|
|
|
|
auto *tmp = &OPTIONS;
|
|
|
|
std::vector<std::string> components;
|
|
|
|
for (auto component : path) {
|
|
|
|
std::string component_str = (std::string)component;
|
|
|
|
components.push_back(component_str);
|
|
|
|
}
|
|
|
|
while (!path.empty()) {
|
|
|
|
if (option_set(path.str())) {
|
|
|
|
toml::path parent_path = path.parent();
|
|
|
|
auto &parent = OPTIONS.at(parent_path.str());
|
|
|
|
auto last_component = path[path.size() - 1];
|
|
|
|
if (parent.is_table()) {
|
|
|
|
auto &table = *parent.as_table();
|
|
|
|
table.erase((std::string)last_component);
|
|
|
|
if (!table.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (parent.is_array()) {
|
|
|
|
auto &array = *parent.as_array();
|
|
|
|
array.erase(array.begin() + last_component.index());
|
|
|
|
if (!array.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path = parent_path;
|
|
|
|
}
|
|
|
|
}
|
2024-05-01 09:07:08 -07:00
|
|
|
save_options();
|
2024-04-28 12:31:40 -07:00
|
|
|
}
|
2024-03-23 18:41:26 -07:00
|
|
|
template<class T>
|
|
|
|
void set_option(std::string name, T value) {
|
|
|
|
toml::path path(name);
|
|
|
|
auto *tmp = &OPTIONS;
|
|
|
|
std::vector<std::string> components;
|
|
|
|
for (auto component : path) {
|
|
|
|
std::string component_str = (std::string)component;
|
|
|
|
components.push_back(component_str);
|
|
|
|
}
|
|
|
|
auto last_component = components[components.size() - 1];
|
|
|
|
components.pop_back();
|
|
|
|
for (auto component : components) {
|
|
|
|
auto &cur_tmp = *tmp;
|
|
|
|
if (cur_tmp.contains(component)) {
|
|
|
|
if (cur_tmp[component].is_table()) {
|
|
|
|
tmp = cur_tmp[component].as_table();
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tmp->insert_or_assign(component, toml::table());
|
|
|
|
tmp = cur_tmp[component].as_table();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp->insert_or_assign(last_component, value);
|
2024-05-01 09:07:08 -07:00
|
|
|
save_options();
|
2024-03-23 18:41:26 -07:00
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
inline void init_option(std::string name, T value) {
|
|
|
|
if (!option_set(name)) {
|
|
|
|
set_option<T>(name, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
T get_option(std::string name, std::optional<T> initial_value = {}) {
|
|
|
|
if (initial_value.has_value()) {
|
|
|
|
init_option<T>(name, initial_value.value());
|
|
|
|
}
|
|
|
|
return (**(OPTIONS.at_path(name).as<T>()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#define UI_BACKEND() (Looper::Options::get_option<std::string>("ui.frontend", "imgui"))
|