From 6c817f8d4cc01aa02780f77041a54873963786fd Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 30 Jun 2018 05:40:20 -0400 Subject: [PATCH] Add module preset copy, paste, load, and save --- include/app.hpp | 17 ++- src/app/ModuleWidget.cpp | 228 ++++++++++++++++++++++++++++++++++----- src/app/RackScene.cpp | 12 ++- src/app/RackWidget.cpp | 130 +++++++++++++++------- src/app/Toolbar.cpp | 2 +- src/engine.cpp | 2 +- src/main.cpp | 6 +- 7 files changed, 321 insertions(+), 76 deletions(-) diff --git a/include/app.hpp b/include/app.hpp index 2e59e654..8b9d09f4 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -46,6 +46,8 @@ struct SVGPanel; static const float RACK_GRID_WIDTH = 15; static const float RACK_GRID_HEIGHT = 380; static const Vec RACK_GRID_SIZE = Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); +static const std::string PRESET_FILTERS = "VCV Rack module preset (.vcvm):vcvm"; +static const std::string PATCH_FILTERS = "VCV Rack patch (.vcv):vcv"; struct ModuleWidget : OpaqueWidget { @@ -68,6 +70,12 @@ struct ModuleWidget : OpaqueWidget { virtual json_t *toJson(); virtual void fromJson(json_t *rootJ); + void copyClipboard(); + void pasteClipboard(); + void save(std::string filename); + void load(std::string filename); + void loadDialog(); + void saveDialog(); virtual void create(); virtual void _delete(); @@ -154,17 +162,20 @@ struct RackWidget : OpaqueWidget { void clear(); /** Clears the rack and loads the template patch */ void reset(); - void openDialog(); + void loadDialog(); void saveDialog(); void saveAsDialog(); /** If `lastPath` is defined, ask the user to reload it */ void revert(); /** Disconnects all wires */ void disconnect(); - void savePatch(std::string filename); - void loadPatch(std::string filename); + void save(std::string filename); + void load(std::string filename); json_t *toJson(); void fromJson(json_t *rootJ); + /** Creates a module and adds it to the rack */ + ModuleWidget *moduleFromJson(json_t *moduleJ); + void pastePresetClipboard(); void addModule(ModuleWidget *m); /** Removes the module and transfers ownership to the caller */ diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 2d869e5e..2f81c844 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -2,6 +2,8 @@ #include "engine.hpp" #include "plugin.hpp" #include "window.hpp" +#include "asset.hpp" +#include "osdialog.h" namespace rack { @@ -68,10 +70,6 @@ json_t *ModuleWidget::toJson() { json_object_set_new(rootJ, "version", json_string(model->plugin->version.c_str())); // model json_object_set_new(rootJ, "model", json_string(model->slug.c_str())); - // pos - Vec pos = box.pos.div(RACK_GRID_SIZE).round(); - json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y); - json_object_set_new(rootJ, "pos", posJ); // params json_t *paramsJ = json_array(); for (ParamWidget *paramWidget : params) { @@ -91,24 +89,42 @@ json_t *ModuleWidget::toJson() { } void ModuleWidget::fromJson(json_t *rootJ) { + // Check if plugin and model are incorrect + json_t *pluginJ = json_object_get(rootJ, "plugin"); + std::string pluginSlug; + if (pluginJ) { + pluginSlug = json_string_value(pluginJ); + if (pluginSlug != model->plugin->slug) { + warn("Plugin %s does not match ModuleWidget's plugin %s.", pluginSlug.c_str(), model->plugin->slug.c_str()); + return; + } + } + + json_t *modelJ = json_object_get(rootJ, "model"); + std::string modelSlug; + if (modelJ) { + modelSlug = json_string_value(modelJ); + if (modelSlug != model->slug) { + warn("Model %s does not match ModuleWidget's model %s.", modelSlug.c_str(), model->slug.c_str()); + return; + } + } + + // Check plugin version + json_t *versionJ = json_object_get(rootJ, "version"); + if (versionJ) { + std::string version = json_string_value(versionJ); + if (version != model->plugin->version) { + info("Patch created with %s version %s, using version %s.", pluginSlug.c_str(), version.c_str(), model->plugin->version.c_str()); + } + } + // legacy int legacy = 0; json_t *legacyJ = json_object_get(rootJ, "legacy"); if (legacyJ) legacy = json_integer_value(legacyJ); - // pos - json_t *posJ = json_object_get(rootJ, "pos"); - double x, y; - json_unpack(posJ, "[F, F]", &x, &y); - Vec pos = Vec(x, y); - if (legacy && legacy <= 1) { - box.pos = pos; - } - else { - box.pos = pos.mult(RACK_GRID_SIZE); - } - // params json_t *paramsJ = json_object_get(rootJ, "params"); size_t i; @@ -146,6 +162,102 @@ void ModuleWidget::fromJson(json_t *rootJ) { } } +void ModuleWidget::copyClipboard() { + json_t *moduleJ = toJson(); + char *moduleJson = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); + glfwSetClipboardString(gWindow, moduleJson); + free(moduleJson); + json_decref(moduleJ); +} + +void ModuleWidget::pasteClipboard() { + const char *moduleJson = glfwGetClipboardString(gWindow); + if (!moduleJson) { + warn("Could not get text from clipboard."); + return; + } + + json_error_t error; + json_t *moduleJ = json_loads(moduleJson, 0, &error); + if (moduleJ) { + fromJson(moduleJ); + json_decref(moduleJ); + } + else { + warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + } +} + +void ModuleWidget::load(std::string filename) { + info("Loading preset %s", filename.c_str()); + FILE *file = fopen(filename.c_str(), "r"); + if (!file) { + // Exit silently + return; + } + + json_error_t error; + json_t *moduleJ = json_loadf(file, 0, &error); + if (moduleJ) { + fromJson(moduleJ); + json_decref(moduleJ); + } + else { + std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); + } + + fclose(file); +} + +void ModuleWidget::save(std::string filename) { + info("Saving preset %s", filename.c_str()); + json_t *moduleJ = toJson(); + if (!moduleJ) + return; + + FILE *file = fopen(filename.c_str(), "w"); + if (file) { + json_dumpf(moduleJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); + fclose(file); + } + + json_decref(moduleJ); +} + +void ModuleWidget::loadDialog() { + std::string dir = assetLocal("presets"); + systemCreateDirectory(dir); + + osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); + char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters); + if (path) { + load(path); + free(path); + } + osdialog_filters_free(filters); +} + +void ModuleWidget::saveDialog() { + std::string dir = assetLocal("presets"); + systemCreateDirectory(dir); + + osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); + char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), "Untitled.vcvm", filters); + + if (path) { + std::string pathStr = path; + free(path); + std::string extension = stringExtension(pathStr); + if (extension.empty()) { + pathStr += ".vcvm"; + } + + save(pathStr); + } + osdialog_filters_free(filters); +} + void ModuleWidget::disconnect() { for (Port *input : inputs) { gRackWidget->wireContainer->removeAllWires(input); @@ -268,6 +380,20 @@ void ModuleWidget::onHoverKey(EventHoverKey &e) { return; } } break; + case GLFW_KEY_C: { + if (windowIsModPressed() && !windowIsShiftPressed()) { + copyClipboard(); + e.consumed = true; + return; + } + } break; + case GLFW_KEY_V: { + if (windowIsModPressed() && !windowIsShiftPressed()) { + pasteClipboard(); + e.consumed = true; + return; + } + } break; case GLFW_KEY_D: { if (windowIsModPressed() && !windowIsShiftPressed()) { gRackWidget->cloneModule(this); @@ -303,35 +429,63 @@ void ModuleWidget::onDragMove(EventDragMove &e) { } -struct DisconnectMenuItem : MenuItem { +struct ModuleDisconnectItem : MenuItem { ModuleWidget *moduleWidget; void onAction(EventAction &e) override { moduleWidget->disconnect(); } }; -struct ResetMenuItem : MenuItem { +struct ModuleResetItem : MenuItem { ModuleWidget *moduleWidget; void onAction(EventAction &e) override { moduleWidget->reset(); } }; -struct RandomizeMenuItem : MenuItem { +struct ModuleRandomizeItem : MenuItem { ModuleWidget *moduleWidget; void onAction(EventAction &e) override { moduleWidget->randomize(); } }; -struct CloneMenuItem : MenuItem { +struct ModuleCopyItem : MenuItem { + ModuleWidget *moduleWidget; + void onAction(EventAction &e) override { + moduleWidget->copyClipboard(); + } +}; + +struct ModulePasteItem : MenuItem { + ModuleWidget *moduleWidget; + void onAction(EventAction &e) override { + moduleWidget->pasteClipboard(); + } +}; + +struct ModuleSaveItem : MenuItem { + ModuleWidget *moduleWidget; + void onAction(EventAction &e) override { + moduleWidget->saveDialog(); + } +}; + +struct ModuleLoadItem : MenuItem { + ModuleWidget *moduleWidget; + void onAction(EventAction &e) override { + moduleWidget->loadDialog(); + } +}; + +struct ModuleCloneItem : MenuItem { ModuleWidget *moduleWidget; void onAction(EventAction &e) override { gRackWidget->cloneModule(moduleWidget); } }; -struct DeleteMenuItem : MenuItem { +struct ModuleDeleteItem : MenuItem { ModuleWidget *moduleWidget; void onAction(EventAction &e) override { gRackWidget->deleteModule(moduleWidget); @@ -347,31 +501,53 @@ Menu *ModuleWidget::createContextMenu() { menuLabel->text = model->author + " " + model->name + " " + model->plugin->version; menu->addChild(menuLabel); - ResetMenuItem *resetItem = new ResetMenuItem(); + ModuleResetItem *resetItem = new ModuleResetItem(); resetItem->text = "Initialize"; resetItem->rightText = WINDOW_MOD_KEY_NAME "+I"; resetItem->moduleWidget = this; menu->addChild(resetItem); - RandomizeMenuItem *randomizeItem = new RandomizeMenuItem(); + ModuleRandomizeItem *randomizeItem = new ModuleRandomizeItem(); randomizeItem->text = "Randomize"; randomizeItem->rightText = WINDOW_MOD_KEY_NAME "+R"; randomizeItem->moduleWidget = this; menu->addChild(randomizeItem); - DisconnectMenuItem *disconnectItem = new DisconnectMenuItem(); + ModuleDisconnectItem *disconnectItem = new ModuleDisconnectItem(); disconnectItem->text = "Disconnect cables"; disconnectItem->rightText = WINDOW_MOD_KEY_NAME "+U"; disconnectItem->moduleWidget = this; menu->addChild(disconnectItem); - CloneMenuItem *cloneItem = new CloneMenuItem(); + ModuleCloneItem *cloneItem = new ModuleCloneItem(); cloneItem->text = "Duplicate"; cloneItem->rightText = WINDOW_MOD_KEY_NAME "+D"; cloneItem->moduleWidget = this; menu->addChild(cloneItem); - DeleteMenuItem *deleteItem = new DeleteMenuItem(); + ModuleCopyItem *copyItem = new ModuleCopyItem(); + copyItem->text = "Copy preset"; + copyItem->rightText = WINDOW_MOD_KEY_NAME "+C"; + copyItem->moduleWidget = this; + menu->addChild(copyItem); + + ModulePasteItem *pasteItem = new ModulePasteItem(); + pasteItem->text = "Paste preset"; + pasteItem->rightText = WINDOW_MOD_KEY_NAME "+V"; + pasteItem->moduleWidget = this; + menu->addChild(pasteItem); + + ModuleLoadItem *loadItem = new ModuleLoadItem(); + loadItem->text = "Load preset"; + loadItem->moduleWidget = this; + menu->addChild(loadItem); + + ModuleSaveItem *saveItem = new ModuleSaveItem(); + saveItem->text = "Save preset"; + saveItem->moduleWidget = this; + menu->addChild(saveItem); + + ModuleDeleteItem *deleteItem = new ModuleDeleteItem(); deleteItem->text = "Delete"; deleteItem->rightText = "Backspace/Delete"; deleteItem->moduleWidget = this; diff --git a/src/app/RackScene.cpp b/src/app/RackScene.cpp index faa1a26a..d74f09d1 100644 --- a/src/app/RackScene.cpp +++ b/src/app/RackScene.cpp @@ -77,7 +77,7 @@ void RackScene::onHoverKey(EventHoverKey &e) { } break; case GLFW_KEY_O: { if (windowIsModPressed() && !windowIsShiftPressed()) { - gRackWidget->openDialog(); + gRackWidget->loadDialog(); e.consumed = true; } if (windowIsModPressed() && windowIsShiftPressed()) { @@ -95,6 +95,12 @@ void RackScene::onHoverKey(EventHoverKey &e) { e.consumed = true; } } break; + case GLFW_KEY_V: { + if (windowIsModPressed() && !windowIsShiftPressed()) { + gRackWidget->pastePresetClipboard(); + e.consumed = true; + } + } break; case GLFW_KEY_ENTER: case GLFW_KEY_KP_ENTER: { appModuleBrowserCreate(); @@ -109,9 +115,9 @@ void RackScene::onHoverKey(EventHoverKey &e) { void RackScene::onPathDrop(EventPathDrop &e) { if (e.paths.size() >= 1) { - const std::string& firstPath = e.paths.front(); + const std::string &firstPath = e.paths.front(); if (stringExtension(firstPath) == "vcv") { - gRackWidget->loadPatch(firstPath); + gRackWidget->load(firstPath); e.consumed = true; } } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 26fc7528..e7d5c065 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -12,9 +12,6 @@ namespace rack { -static const char *FILTERS = "VCV Rack patch (.vcv):vcv"; - - struct ModuleContainer : Widget { void draw(NVGcontext *vg) override { // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front. @@ -66,12 +63,12 @@ void RackWidget::reset() { if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Clear patch and start over?")) { clear(); // Fails silently if file does not exist - loadPatch(assetLocal("template.vcv")); + load(assetLocal("template.vcv")); lastPath = ""; } } -void RackWidget::openDialog() { +void RackWidget::loadDialog() { std::string dir; if (lastPath.empty()) { dir = assetLocal("patches"); @@ -80,10 +77,10 @@ void RackWidget::openDialog() { else { dir = stringDirectory(lastPath); } - osdialog_filters *filters = osdialog_filters_parse(FILTERS); + osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str()); char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters); if (path) { - loadPatch(path); + load(path); lastPath = path; free(path); } @@ -92,7 +89,7 @@ void RackWidget::openDialog() { void RackWidget::saveDialog() { if (!lastPath.empty()) { - savePatch(lastPath); + save(lastPath); } else { saveAsDialog(); @@ -110,7 +107,7 @@ void RackWidget::saveAsDialog() { dir = stringDirectory(lastPath); filename = stringFilename(lastPath); } - osdialog_filters *filters = osdialog_filters_parse(FILTERS); + osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str()); char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters); if (path) { @@ -121,19 +118,19 @@ void RackWidget::saveAsDialog() { pathStr += ".vcv"; } - savePatch(pathStr); + save(pathStr); lastPath = pathStr; } osdialog_filters_free(filters); } -void RackWidget::savePatch(std::string path) { - info("Saving patch %s", path.c_str()); +void RackWidget::save(std::string filename) { + info("Saving patch %s", filename.c_str()); json_t *rootJ = toJson(); if (!rootJ) return; - FILE *file = fopen(path.c_str(), "w"); + FILE *file = fopen(filename.c_str(), "w"); if (file) { json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); fclose(file); @@ -142,9 +139,9 @@ void RackWidget::savePatch(std::string path) { json_decref(rootJ); } -void RackWidget::loadPatch(std::string path) { - info("Loading patch %s", path.c_str()); - FILE *file = fopen(path.c_str(), "r"); +void RackWidget::load(std::string filename) { + info("Loading patch %s", filename.c_str()); + FILE *file = fopen(filename.c_str(), "r"); if (!file) { // Exit silently return; @@ -158,7 +155,7 @@ void RackWidget::loadPatch(std::string path) { json_decref(rootJ); } else { - std::string message = stringf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text); + std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); } @@ -169,7 +166,7 @@ void RackWidget::revert() { if (lastPath.empty()) return; if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Revert patch to the last saved state?")) { - loadPatch(lastPath); + load(lastPath); } } @@ -203,6 +200,12 @@ json_t *RackWidget::toJson() { moduleId++; // module json_t *moduleJ = moduleWidget->toJson(); + { + // pos + Vec pos = moduleWidget->box.pos.div(RACK_GRID_SIZE).round(); + json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y); + json_object_set_new(moduleJ, "pos", posJ); + } json_array_append_new(modulesJ, moduleJ); } json_object_set_new(rootJ, "modules", modulesJ); @@ -275,25 +278,30 @@ void RackWidget::fromJson(json_t *rootJ) { json_object_set(moduleJ, "legacy", json_integer(legacy)); } - json_t *pluginSlugJ = json_object_get(moduleJ, "plugin"); - if (!pluginSlugJ) continue; - json_t *modelSlugJ = json_object_get(moduleJ, "model"); - if (!modelSlugJ) continue; - std::string pluginSlug = json_string_value(pluginSlugJ); - std::string modelSlug = json_string_value(modelSlugJ); + ModuleWidget *moduleWidget = moduleFromJson(moduleJ); + + if (moduleWidget) { + // pos + json_t *posJ = json_object_get(moduleJ, "pos"); + double x, y; + json_unpack(posJ, "[F, F]", &x, &y); + Vec pos = Vec(x, y); + if (legacy && legacy <= 1) { + moduleWidget->box.pos = pos; + } + else { + moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE); + } - Model *model = pluginGetModel(pluginSlug, modelSlug); - if (!model) { + moduleWidgets[moduleId] = moduleWidget; + } + else { + json_t *pluginSlugJ = json_object_get(moduleJ, "plugin"); + json_t *modelSlugJ = json_object_get(moduleJ, "model"); + std::string pluginSlug = json_string_value(pluginSlugJ); + std::string modelSlug = json_string_value(modelSlugJ); message += stringf("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str()); - continue; } - - // Create ModuleWidget - ModuleWidget *moduleWidget = model->createModuleWidget(); - assert(moduleWidget); - moduleWidget->fromJson(moduleJ); - moduleContainer->addChild(moduleWidget); - moduleWidgets[moduleId] = moduleWidget; } // wires @@ -355,6 +363,53 @@ void RackWidget::fromJson(json_t *rootJ) { } } +ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) { + // Get slugs + json_t *pluginSlugJ = json_object_get(moduleJ, "plugin"); + if (!pluginSlugJ) + return NULL; + json_t *modelSlugJ = json_object_get(moduleJ, "model"); + if (!modelSlugJ) + return NULL; + std::string pluginSlug = json_string_value(pluginSlugJ); + std::string modelSlug = json_string_value(modelSlugJ); + + // Get Model + Model *model = pluginGetModel(pluginSlug, modelSlug); + if (!model) + return NULL; + + // Create ModuleWidget + ModuleWidget *moduleWidget = model->createModuleWidget(); + assert(moduleWidget); + moduleWidget->fromJson(moduleJ); + moduleContainer->addChild(moduleWidget); + return moduleWidget; +} + +void RackWidget::pastePresetClipboard() { + const char *moduleJson = glfwGetClipboardString(gWindow); + if (!moduleJson) { + warn("Could not get text from clipboard."); + return; + } + + json_error_t error; + json_t *moduleJ = json_loads(moduleJson, 0, &error); + if (moduleJ) { + ModuleWidget *moduleWidget = moduleFromJson(moduleJ); + // Set moduleWidget position + Rect newBox = moduleWidget->box; + newBox.pos = lastMousePos.minus(newBox.size.div(2)); + requestModuleBoxNearest(moduleWidget, newBox); + + json_decref(moduleJ); + } + else { + warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + } +} + void RackWidget::addModule(ModuleWidget *m) { moduleContainer->addChild(m); m->create(); @@ -366,16 +421,13 @@ void RackWidget::deleteModule(ModuleWidget *m) { } void RackWidget::cloneModule(ModuleWidget *m) { - // Create new module from model - ModuleWidget *clonedModuleWidget = m->model->createModuleWidget(); // JSON serialization is the most straightforward way to do this json_t *moduleJ = m->toJson(); - clonedModuleWidget->fromJson(moduleJ); + ModuleWidget *clonedModuleWidget = moduleFromJson(moduleJ); json_decref(moduleJ); Rect clonedBox = clonedModuleWidget->box; clonedBox.pos = m->box.pos; requestModuleBoxNearest(clonedModuleWidget, clonedBox); - addModule(clonedModuleWidget); } bool RackWidget::requestModuleBox(ModuleWidget *m, Rect box) { @@ -438,7 +490,7 @@ void RackWidget::step() { // Autosave every 15 seconds if (gGuiFrame % (60 * 15) == 0) { - savePatch(assetLocal("autosave.vcv")); + save(assetLocal("autosave.vcv")); settingsSave(assetLocal("settings.json")); } diff --git a/src/app/Toolbar.cpp b/src/app/Toolbar.cpp index c16208f8..ea3bb4b8 100644 --- a/src/app/Toolbar.cpp +++ b/src/app/Toolbar.cpp @@ -45,7 +45,7 @@ struct OpenButton : TooltipIconButton { tooltipText = "Open (" WINDOW_MOD_KEY_NAME "+O)"; } void onAction(EventAction &e) override { - gRackWidget->openDialog(); + gRackWidget->loadDialog(); } }; diff --git a/src/engine.cpp b/src/engine.cpp index 8a557256..ac26871b 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -295,9 +295,9 @@ void engineSetParamSmooth(Module *module, int paramId, float value) { if (smoothModule && !(smoothModule == module && smoothParamId == paramId)) { smoothModule->params[smoothParamId].value = smoothValue; } - smoothModule = module; smoothParamId = paramId; smoothValue = value; + smoothModule = module; } void engineSetSampleRate(float newSampleRate) { diff --git a/src/main.cpp b/src/main.cpp index 336f4d52..964525af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,13 +73,13 @@ int main(int argc, char* argv[]) { else { // Load autosave std::string oldLastPath = gRackWidget->lastPath; - gRackWidget->loadPatch(assetLocal("autosave.vcv")); + gRackWidget->load(assetLocal("autosave.vcv")); gRackWidget->lastPath = oldLastPath; } } else { // Load patch - gRackWidget->loadPatch(patchFile); + gRackWidget->load(patchFile); } engineStart(); @@ -87,7 +87,7 @@ int main(int argc, char* argv[]) { engineStop(); // Destroy namespaces - gRackWidget->savePatch(assetLocal("autosave.vcv")); + gRackWidget->save(assetLocal("autosave.vcv")); settingsSave(assetLocal("settings.json")); appDestroy(); windowDestroy();