[nostalgia] Cleanup config IO
This commit is contained in:
parent
6cbafc75bf
commit
3635702ede
@ -15,16 +15,6 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
namespace ig = studio::ig;
|
namespace ig = studio::ig;
|
||||||
|
|
||||||
static ox::String configName(ox::StringView str) noexcept {
|
|
||||||
auto out = ox::String{str};
|
|
||||||
for (auto &c : out) {
|
|
||||||
if (c == '/' || c == '\\') {
|
|
||||||
c = '%';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TileSheetEditorConfig {
|
struct TileSheetEditorConfig {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetEditorConfig";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetEditorConfig";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
@ -35,16 +25,6 @@ oxModelBegin(TileSheetEditorConfig)
|
|||||||
oxModelFieldRename(activeSubsheet, active_subsheet)
|
oxModelFieldRename(activeSubsheet, active_subsheet)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
struct TileSheetEditorConfigs {
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetEditorConfigs";
|
|
||||||
static constexpr auto TypeVersion = 1;
|
|
||||||
ox::HashMap<ox::String, TileSheetEditorConfig> configs;
|
|
||||||
};
|
|
||||||
|
|
||||||
oxModelBegin(TileSheetEditorConfigs)
|
|
||||||
oxModelField(configs)
|
|
||||||
oxModelEnd()
|
|
||||||
|
|
||||||
static ox::Vector<uint32_t> normalizePixelSizes(
|
static ox::Vector<uint32_t> normalizePixelSizes(
|
||||||
ox::Vector<uint8_t> const&inPixels,
|
ox::Vector<uint8_t> const&inPixels,
|
||||||
int const bpp) noexcept {
|
int const bpp) noexcept {
|
||||||
@ -120,7 +100,7 @@ TileSheetEditorImGui::TileSheetEditorImGui(studio::StudioContext &sctx, ox::Stri
|
|||||||
m_model.paletteChanged.connect(this, &TileSheetEditorImGui::setPaletteSelection);
|
m_model.paletteChanged.connect(this, &TileSheetEditorImGui::setPaletteSelection);
|
||||||
// load config
|
// load config
|
||||||
auto const&config = studio::readConfig<TileSheetEditorConfig>(
|
auto const&config = studio::readConfig<TileSheetEditorConfig>(
|
||||||
keelCtx(m_sctx), configName(itemPath()));
|
keelCtx(m_sctx), itemPath());
|
||||||
if (config.ok()) {
|
if (config.ok()) {
|
||||||
m_model.setActiveSubsheet(validateSubSheetIdx(m_model.img(), config.value.activeSubsheet));
|
m_model.setActiveSubsheet(validateSubSheetIdx(m_model.img(), config.value.activeSubsheet));
|
||||||
}
|
}
|
||||||
@ -537,9 +517,9 @@ ox::Error TileSheetEditorImGui::setPaletteSelection() noexcept {
|
|||||||
|
|
||||||
void TileSheetEditorImGui::setActiveSubsheet(TileSheet::SubSheetIdx path) noexcept {
|
void TileSheetEditorImGui::setActiveSubsheet(TileSheet::SubSheetIdx path) noexcept {
|
||||||
m_model.setActiveSubsheet(path);
|
m_model.setActiveSubsheet(path);
|
||||||
studio::editConfig<TileSheetEditorConfig>(keelCtx(m_sctx), configName(itemPath()),
|
studio::editConfig<TileSheetEditorConfig>(keelCtx(m_sctx), itemPath(),
|
||||||
[&path](TileSheetEditorConfig *config) {
|
[&path](TileSheetEditorConfig &config) {
|
||||||
config->activeSubsheet = std::move(path);
|
config.activeSubsheet = std::move(path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ void StudioUI::drawTabs() noexcept {
|
|||||||
if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
|
if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
|
||||||
if (m_activeEditor != e.get()) {
|
if (m_activeEditor != e.get()) {
|
||||||
m_activeEditor = e.get();
|
m_activeEditor = e.get();
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
||||||
config->activeTabItemName = m_activeEditor->itemPath();
|
config.activeTabItemName = m_activeEditor->itemPath();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (m_activeEditorUpdatePending == e.get()) {
|
if (m_activeEditorUpdatePending == e.get()) {
|
||||||
@ -258,8 +258,8 @@ void StudioUI::loadModules() noexcept {
|
|||||||
|
|
||||||
void StudioUI::toggleProjectExplorer() noexcept {
|
void StudioUI::toggleProjectExplorer() noexcept {
|
||||||
m_showProjectExplorer = !m_showProjectExplorer;
|
m_showProjectExplorer = !m_showProjectExplorer;
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
||||||
config->showProjectExplorer = m_showProjectExplorer;
|
config.showProjectExplorer = m_showProjectExplorer;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,9 +342,9 @@ ox::Error StudioUI::openProjectPath(ox::CRStringView path) noexcept {
|
|||||||
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
||||||
m_openFiles.clear();
|
m_openFiles.clear();
|
||||||
m_editors.clear();
|
m_editors.clear();
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
||||||
config->projectPath = ox::String(m_project->projectPath());
|
config.projectPath = ox::String(m_project->projectPath());
|
||||||
config->openFiles.clear();
|
config.openFiles.clear();
|
||||||
});
|
});
|
||||||
return m_projectExplorer.refreshProjectTreeModel();
|
return m_projectExplorer.refreshProjectTreeModel();
|
||||||
}
|
}
|
||||||
@ -395,9 +395,9 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
|
|||||||
m_activeEditorUpdatePending = editor;
|
m_activeEditorUpdatePending = editor;
|
||||||
}
|
}
|
||||||
// save to config
|
// save to config
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
||||||
if (!config->openFiles.contains(path)) {
|
if (!config.openFiles.contains(path)) {
|
||||||
config->openFiles.emplace_back(path);
|
config.openFiles.emplace_back(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {};
|
return {};
|
||||||
@ -409,8 +409,8 @@ ox::Error StudioUI::closeFile(ox::CRStringView path) noexcept {
|
|||||||
}
|
}
|
||||||
std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
|
std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
|
||||||
// save to config
|
// save to config
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
||||||
std::ignore = config->openFiles.erase(std::remove(config->openFiles.begin(), config->openFiles.end(), path));
|
std::ignore = config.openFiles.erase(std::remove(config.openFiles.begin(), config.openFiles.end(), path));
|
||||||
});
|
});
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,25 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
inline ox::String slashesToPct(ox::StringView str) noexcept {
|
||||||
|
auto out = ox::String{str};
|
||||||
|
for (auto&c: out) {
|
||||||
|
if (c == '/' || c == '\\') {
|
||||||
|
c = '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::String configPath(keel::Context const&ctx) noexcept;
|
ox::String configPath(keel::Context const&ctx) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> readConfig(keel::Context &ctx, ox::CRStringView name) noexcept {
|
ox::Result<T> readConfig(keel::Context &ctx, ox::CRStringView name) noexcept {
|
||||||
oxAssert(name != "", "Config type has no TypeName");
|
oxAssert(name != "", "Config type has no TypeName");
|
||||||
auto const path = ox::sfmt("/{}.json", name);
|
auto const path = ox::sfmt("/{}.json", detail::slashesToPct(name));
|
||||||
ox::PassThroughFS fs(configPath(ctx));
|
ox::PassThroughFS fs(configPath(ctx));
|
||||||
auto const [buff, err] = fs.read(path);
|
auto const [buff, err] = fs.read(path);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -40,15 +52,15 @@ ox::Result<T> readConfig(keel::Context &ctx) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Error writeConfig(keel::Context &ctx, ox::CRStringView name, T *data) noexcept {
|
ox::Error writeConfig(keel::Context &ctx, ox::CRStringView name, T const&data) noexcept {
|
||||||
oxAssert(name != "", "Config type has no TypeName");
|
oxAssert(name != "", "Config type has no TypeName");
|
||||||
auto const path = ox::sfmt("/{}.json", name);
|
auto const path = ox::sfmt("/{}.json", detail::slashesToPct(name));
|
||||||
ox::PassThroughFS fs(configPath(ctx));
|
ox::PassThroughFS fs(configPath(ctx));
|
||||||
if (auto const err = fs.mkdir("/", true)) {
|
if (auto const err = fs.mkdir("/", true)) {
|
||||||
oxErrf("Could not create config directory: {}\n", toStr(err));
|
oxErrf("Could not create config directory: {}\n", toStr(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
oxRequireM(buff, ox::writeOC(*data));
|
oxRequireM(buff, ox::writeOC(data));
|
||||||
*buff.back().value = '\n';
|
*buff.back().value = '\n';
|
||||||
if (auto const err = fs.write(path, buff.data(), buff.size())) {
|
if (auto const err = fs.write(path, buff.data(), buff.size())) {
|
||||||
oxErrf("Could not read config file: {}\n", toStr(err));
|
oxErrf("Could not read config file: {}\n", toStr(err));
|
||||||
@ -58,7 +70,7 @@ ox::Error writeConfig(keel::Context &ctx, ox::CRStringView name, T *data) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Error writeConfig(keel::Context &ctx, T *data) noexcept {
|
ox::Error writeConfig(keel::Context &ctx, T const&data) noexcept {
|
||||||
constexpr auto TypeName = ox::requireModelTypeName<T>();
|
constexpr auto TypeName = ox::requireModelTypeName<T>();
|
||||||
return writeConfig(ctx, TypeName, data);
|
return writeConfig(ctx, TypeName, data);
|
||||||
}
|
}
|
||||||
@ -68,7 +80,7 @@ void openConfig(keel::Context &ctx, ox::CRStringView name, Func f) noexcept {
|
|||||||
oxAssert(name != "", "Config type has no TypeName");
|
oxAssert(name != "", "Config type has no TypeName");
|
||||||
auto const [c, err] = readConfig<T>(ctx, name);
|
auto const [c, err] = readConfig<T>(ctx, name);
|
||||||
oxLogError(err);
|
oxLogError(err);
|
||||||
f(&c);
|
f(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Func>
|
template<typename T, typename Func>
|
||||||
@ -82,8 +94,8 @@ void editConfig(keel::Context &ctx, ox::CRStringView name, Func f) noexcept {
|
|||||||
oxAssert(name != "", "Config type has no TypeName");
|
oxAssert(name != "", "Config type has no TypeName");
|
||||||
auto [c, err] = readConfig<T>(ctx, name);
|
auto [c, err] = readConfig<T>(ctx, name);
|
||||||
oxLogError(err);
|
oxLogError(err);
|
||||||
f(&c);
|
f(c);
|
||||||
oxLogError(writeConfig(ctx, name, &c));
|
oxLogError(writeConfig(ctx, name, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Func>
|
template<typename T, typename Func>
|
||||||
|
Loading…
Reference in New Issue
Block a user