diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index b2865392..cf1d8f77 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -69,6 +69,10 @@ struct ModuleWidget : widget::OpaqueWidget { void loadDialog(); void save(std::string filename); void saveTemplate(); + void saveTemplateDialog(); + bool hasTemplate(); + void clearTemplate(); + void clearTemplateDialog(); void saveDialog(); /** Disconnects cables from all ports diff --git a/include/system.hpp b/include/system.hpp index 3128be43..c1e88758 100644 --- a/include/system.hpp +++ b/include/system.hpp @@ -27,7 +27,7 @@ std::string join(const std::string& path1, const std::string& path2, Paths... pa `depth` is the number of directories to recurse. 0 depth does not recurse. -1 depth recurses infinitely. */ std::list getEntries(const std::string& dirPath, int depth = 0); -bool doesExist(const std::string& path); +bool exists(const std::string& path); /** Returns whether the given path is a file. */ bool isFile(const std::string& path); /** Returns whether the given path is a directory. */ diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 46395f37..6c5bb08d 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -223,7 +223,17 @@ struct ModuleSaveTemplateItem : ui::MenuItem { void onAction(const event::Action& e) override { if (!moduleWidget) return; - moduleWidget->saveTemplate(); + moduleWidget->saveTemplateDialog(); + } +}; + + +struct ModuleClearTemplateItem : ui::MenuItem { + WeakPtr moduleWidget; + void onAction(const event::Action& e) override { + if (!moduleWidget) + return; + moduleWidget->clearTemplateDialog(); } }; @@ -288,6 +298,12 @@ struct ModulePresetItem : ui::MenuItem { saveTemplateItem->moduleWidget = moduleWidget; menu->addChild(saveTemplateItem); + ModuleClearTemplateItem* clearTemplateItem = new ModuleClearTemplateItem; + clearTemplateItem->text = "Clear template"; + clearTemplateItem->moduleWidget = moduleWidget; + clearTemplateItem->disabled = !moduleWidget->hasTemplate(); + menu->addChild(clearTemplateItem); + // Create ModulePresetPathItems for each patch in a directory. auto createPresetItems = [&](std::string presetDir) { bool hasPresets = false; @@ -791,8 +807,13 @@ void ModuleWidget::loadDialog() { // Delete directories if empty DEFER({ - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } }); osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); @@ -822,7 +843,9 @@ void ModuleWidget::save(std::string filename) { FILE* file = std::fopen(filename.c_str(), "w"); if (!file) { - WARN("Could not write to patch file %s", filename.c_str()); + std::string message = string::f("Could not save preset to file %s", filename.c_str()); + osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); + return; } DEFER({std::fclose(file);}); @@ -832,20 +855,51 @@ void ModuleWidget::save(std::string filename) { void ModuleWidget::saveTemplate() { std::string presetDir = model->getUserPresetDir(); system::createDirectories(presetDir); - std::string templatePath = system::join(presetDir, "template.vcvm"); save(templatePath); } +void ModuleWidget::saveTemplateDialog() { + if (hasTemplate()) { + std::string message = string::f("Overwrite template preset for %s?", model->getFullName().c_str()); + if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) + return; + } + saveTemplate(); +} + +bool ModuleWidget::hasTemplate() { + std::string presetDir = model->getUserPresetDir(); + std::string templatePath = system::join(presetDir, "template.vcvm"); + return system::exists(templatePath);; +} + +void ModuleWidget::clearTemplate() { + std::string presetDir = model->getUserPresetDir(); + std::string templatePath = system::join(presetDir, "template.vcvm"); + system::remove(templatePath); +} + +void ModuleWidget::clearTemplateDialog() { + std::string message = string::f("Delete template preset for %s?", model->getFullName().c_str()); + if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) + return; + clearTemplate(); +} + void ModuleWidget::saveDialog() { std::string presetDir = model->getUserPresetDir(); system::createDirectories(presetDir); // Delete directories if empty DEFER({ - // These fail silently if the directories are not empty - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } }); osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 7d193459..6dfce2bb 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -239,9 +239,10 @@ struct AudioInterface : Module, audio::Port { if (audioJ) audio::Port::fromJson(audioJ); - json_t* primaryJ = json_object_get(rootJ, "primary"); - if (primaryJ) - setPrimary(); + // For not, don't deserialize primary module state. + // json_t* primaryJ = json_object_get(rootJ, "primary"); + // if (primaryJ) + // setPrimary(); json_t* dcFilterJ = json_object_get(rootJ, "dcFilter"); if (dcFilterJ) diff --git a/src/system.cpp b/src/system.cpp index b70f54b7..0f7f5f67 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -80,7 +80,7 @@ std::list getEntries(const std::string& dirPath, int depth) { } -bool doesExist(const std::string& path) { +bool exists(const std::string& path) { try { return fs::exists(fs::u8path(path)); }