127 lines
No EOL
4.6 KiB
C++
127 lines
No EOL
4.6 KiB
C++
#pragma once
|
|
#include "thirdparty/toml.hpp"
|
|
#include "log.hpp"
|
|
#include <string>
|
|
#include <vector>
|
|
#include <typeinfo>
|
|
#include <typeindex>
|
|
#include <optional>
|
|
#define OPTIONS (*Looper::Options::options)
|
|
namespace Looper::Options {
|
|
extern toml::table *options;
|
|
void save_options();
|
|
void load_options();
|
|
|
|
std::string get_options_path();
|
|
inline bool option_set(std::string name) {
|
|
DEBUG.writefln("Checking if option '%s' is set...", name.c_str());
|
|
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;
|
|
DEBUG.writef(".%s", component.c_str());
|
|
if (cur_tmp.contains(component)) {
|
|
if (!cur_tmp[component].is_table()) {
|
|
DEBUG.writefln("[invalid]");
|
|
return false;
|
|
} else {
|
|
tmp = cur_tmp[component].as_table();
|
|
}
|
|
} else {
|
|
DEBUG.writefln("[Not found, parent]");
|
|
return false;
|
|
}
|
|
}
|
|
DEBUG.writef(".%s", last_component.c_str());
|
|
if (tmp->contains(last_component)) {
|
|
DEBUG.writefln("[OK]");
|
|
return true;
|
|
} else {
|
|
DEBUG.writefln("[Not found, last component]");
|
|
return false;
|
|
}
|
|
}
|
|
inline void delete_option(std::string name) {
|
|
DEBUG.writefln("Deleting option '%s'...", name.c_str());
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
template<class T>
|
|
void set_option(std::string name, T value) {
|
|
DEBUG.writefln("Setting option '%s'...", name.c_str());
|
|
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();
|
|
DEBUG.writef(".%s", component.c_str());
|
|
} else {
|
|
DEBUG.writefln("[invalid]");
|
|
return;
|
|
}
|
|
} else {
|
|
tmp->insert_or_assign(component, toml::table());
|
|
tmp = cur_tmp[component].as_table();
|
|
DEBUG.writef(".%s[new]", component.c_str());
|
|
}
|
|
}
|
|
DEBUG.writefln(".%s%s", last_component.c_str(), tmp->contains(last_component) ? "[set]" : "[new]");
|
|
tmp->insert_or_assign(last_component, value);
|
|
}
|
|
template<class T>
|
|
inline void init_option(std::string name, T value) {
|
|
if (!option_set(name)) {
|
|
DEBUG.writefln("Initializing option '%s'...", name.c_str());
|
|
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")) |