Skip to content

Instantly share code, notes, and snippets.

@nariakiiwatani
Last active March 10, 2020 07:16
Show Gist options
  • Save nariakiiwatani/ac5ea80f979fe889040e43cdfb3cecae to your computer and use it in GitHub Desktop.
Save nariakiiwatani/ac5ea80f979fe889040e43cdfb3cecae to your computer and use it in GitHub Desktop.
#pragma once
#include "ofxWatchFile.h"
#include "ofxJsonUtils.h"
#define KVCS1(name) kv(name)
#define KVCS2(name, ...) KVCS1(name), KVCS1(__VA_ARGS__)
#define KVCS3(name, ...) KVCS1(name), KVCS2(__VA_ARGS__)
#define KVCS4(name, ...) KVCS1(name), KVCS3(__VA_ARGS__)
#define KVCS5(name, ...) KVCS1(name), KVCS4(__VA_ARGS__)
#define KVCS6(name, ...) KVCS1(name), KVCS5(__VA_ARGS__)
#define KVCS7(name, ...) KVCS1(name), KVCS6(__VA_ARGS__)
#define KVCS8(name, ...) KVCS1(name), KVCS7(__VA_ARGS__)
#define KVCS9(name, ...) KVCS1(name), KVCS8(__VA_ARGS__)
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME
#define KV_COMMA_SEPARATION(...) GET_MACRO(__VA_ARGS__, KVCS9, KVCS8, KVCS7, KVCS6, KVCS5, KVCS4, KVCS3, KVCS2, KVCS1)(__VA_ARGS__)
#define JSON_FUNCS(...) \
void loadJson(const ofJson &json) {ofxJsonUtils::load(json, KV_COMMA_SEPARATION(__VA_ARGS__));}\
ofJson toJson() const { return ofxJsonUtils::create(KV_COMMA_SEPARATION(__VA_ARGS__));}
namespace ofx { namespace JsonUtils {
static inline const ofJson &convert(const ofJson &json) {
return json;
}
static const inline void parse(const ofJson &src, ofJson &dst) {
dst = src;
}
}}
template<typename ConvertType, bool NDJson=false>
class AutoJson_ : public ConvertType
{
public:
using Type = ConvertType;
using Json = typename std::conditional<NDJson, std::vector<ofJson>, ofJson>::type;
AutoJson_() {
watcher_.addListener(this, &AutoJson_::reload);
}
bool load(const std::string &filepath, std::vector<std::string> hierarchy={}) {
hierarchy_ = hierarchy;
filepath_ = filepath;
return watcher_.setTargetPath(filepath);
}
void setTargetPath(const std::string &filepath) {
filepath_ = filepath;
watcher_.setTargetPath(filepath, false);
}
void setWillSaveListener(std::function<void(const Type&, Json&)> callback) {
save_callback_ = callback;
}
void setDidLoadListener(std::function<void(Type&, const Json&)> callback) {
loaded_callback_ = callback;
}
bool reload() {
return watcher_.load();
}
bool overwrite(int indent=-1) const {
return writeToFile(filepath_, indent);
}
bool writeToFile(const std::string &filepath, int indent=-1) const {
if(filepath == "") {
return false;
}
Json json = loadFunc(filepath);
Json local = ofxJsonUtils::convert(*(Type*)this);
if(save_callback_) {
save_callback_(*this, local);
}
hierarchySet(local, json);
return saveFunc(filepath, json, true, indent);
}
void loadJson(const ofJson &json) {
ofxJsonUtils::parse(json, *(Type*)this);
}
ofJson toJson() const {
return ofxJsonUtils::convert(*(Type*)this);
}
template<typename ReturnType, typename ...ArgTypes>
ReturnType userFunc(ArgTypes...);
private:
void reload(ofFile &file) {
Json json = loadFunc(file.path());
json = hierarchyGet(json);
ofxJsonUtils::parse(json, *this);
if(loaded_callback_) {
loaded_callback_(*this, json);
}
}
ofxWatchFile watcher_;
std::string filepath_="";
std::vector<std::string> hierarchy_={};
std::function<void(const Type&, Json&)> save_callback_ = nullptr;
std::function<void(Type&, const Json&)> loaded_callback_ = nullptr;
template<typename T = Json>
auto loadFunc(const std::string &filepath) const
-> typename std::enable_if<NDJson, T>::type {
return ofxJsonUtils::loadNDJsonFromFile(filepath);
}
template<typename T = Json>
auto loadFunc(const std::string &filepath) const
-> typename std::enable_if<!NDJson, T>::type {
return ofxJsonUtils::loadFromFile(filepath);
}
template<typename T = bool>
auto saveFunc(const std::string &filepath, const Json &json, bool isInDataDir = true, int indent = -1) const
-> typename std::enable_if<NDJson, T>::type {
return ofxJsonUtils::writeToNDJsonFile(filepath, json, isInDataDir, -1);
}
template<typename T = bool>
auto saveFunc(const std::string &filepath, const Json &json, bool isInDataDir = true, int indent = -1) const
-> typename std::enable_if<!NDJson, T>::type {
return ofxJsonUtils::writeToFile(filepath, json, isInDataDir, indent);
}
std::vector<ofJson> hierarchyGet(const std::vector<ofJson> &json) const {
auto ret = json;
for(auto &j : ret) {
for(auto &h : hierarchy_) {
j = j[h];
}
}
return ret;
}
ofJson hierarchyGet(const ofJson &json) const {
auto ret = json;
for(auto &h : hierarchy_) {
ret = ret[h];
}
return ret;
}
void hierarchySet(const std::vector<ofJson> &json, std::vector<ofJson> &root) const {
root.resize(json.size());
for(int i = 0, num = json.size(); i < num; ++i) {
auto *dst = &root[i];
for(auto &h : hierarchy_) {
dst = &(*dst)[h];
}
*dst = json[i];
}
}
void hierarchySet(const ofJson &json, ofJson &root) const {
auto *dst = &root;
for(auto &h : hierarchy_) {
dst = &(*dst)[h];
}
*dst = json;
}
};
using AutoJson = AutoJson_<ofJson>;
#pragma once
#include "imgui.h"
namespace AutoJsonUtils_ImGui {
namespace IO {
template<typename Json>
bool Save(Json &json, const std::string &default_filename="", int indent=4) {
bool success = false;
bool tried = false;
if(ImGui::Button("Save")) {
tried = true;
success = json.overwrite(indent);
}
ImGui::SameLine();
if(ImGui::Button("Save As") || (tried && !success)) {
auto result = ofSystemSaveDialog(default_filename, "Save As...");
if(result.bSuccess) {
if(json.writeToFile(result.getPath(), indent)) {
json.setTargetPath(result.getPath());
success = true;
}
}
}
return success;
}
template<typename Json>
bool Load(Json &json) {
bool success = false;
bool tried = false;
if(ImGui::Button("Reload")) {
tried = true;
success = json.reload();
}
ImGui::SameLine();
if(ImGui::Button("Load From") || (tried && !success)) {
auto result = ofSystemLoadDialog("Load From...");
if(result.bSuccess) {
if(json.load(result.getPath())) {
json.setTargetPath(result.getPath());
success = true;
}
}
}
return success;
}
template<typename Json>
void SaveLoad(Json &json, bool &saved, bool &loaded, const std::string &default_filename="", int indent=4) {
saved = Save(json, default_filename, indent);
ImGui::SameLine();
loaded = Load(json);
}
template<typename Json>
void SaveLoad(Json &json, const std::string &default_filename="", int indent=4) {
Save(json, default_filename, indent);
ImGui::SameLine();
Load(json);
}
}}
@nariakiiwatani
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment