looper/options.hpp

127 lines
4.6 KiB
C++
Raw Normal View History

#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"))