| @@ -4,6 +4,7 @@ | |||
| #include <color.hpp> | |||
| #include <vector> | |||
| #include <map> | |||
| #include <list> | |||
| #include <tuple> | |||
| #include <jansson.h> | |||
| @@ -45,6 +46,7 @@ extern int frameSwapInterval; | |||
| extern float autosavePeriod; | |||
| extern bool skipLoadOnLaunch; | |||
| extern std::string patchPath; | |||
| extern std::list<std::string> recentPatchPaths; | |||
| extern std::vector<NVGcolor> cableColors; | |||
| // pluginSlug -> moduleSlugs | |||
| extern std::map<std::string, std::vector<std::string>> moduleWhitelist; | |||
| @@ -90,6 +90,28 @@ struct OpenItem : ui::MenuItem { | |||
| } | |||
| }; | |||
| struct OpenPathItem : ui::MenuItem { | |||
| std::string path; | |||
| void onAction(const event::Action& e) override { | |||
| APP->patch->loadPathDialog(path); | |||
| } | |||
| }; | |||
| struct OpenRecentItem : ui::MenuItem { | |||
| ui::Menu* createChildMenu() override { | |||
| ui::Menu* menu = new ui::Menu; | |||
| for (const std::string& path : settings::recentPatchPaths) { | |||
| OpenPathItem* item = new OpenPathItem; | |||
| item->text = string::filename(path); | |||
| item->path = path; | |||
| menu->addChild(item); | |||
| } | |||
| return menu; | |||
| } | |||
| }; | |||
| struct SaveItem : ui::MenuItem { | |||
| void onAction(const event::Action& e) override { | |||
| APP->patch->saveDialog(); | |||
| @@ -136,6 +158,11 @@ struct FileButton : MenuButton { | |||
| openItem->rightText = RACK_MOD_CTRL_NAME "+O"; | |||
| menu->addChild(openItem); | |||
| OpenRecentItem* openRecentItem = new OpenRecentItem; | |||
| openRecentItem->text = "Open recent"; | |||
| openRecentItem->rightText = RIGHT_ARROW; | |||
| menu->addChild(openRecentItem); | |||
| SaveItem* saveItem = new SaveItem; | |||
| saveItem->text = "Save"; | |||
| saveItem->rightText = RACK_MOD_CTRL_NAME "+S"; | |||
| @@ -8,6 +8,7 @@ | |||
| #include <app/RackWidget.hpp> | |||
| #include <history.hpp> | |||
| #include <settings.hpp> | |||
| #include <algorithm> | |||
| #include <osdialog.h> | |||
| @@ -47,7 +48,7 @@ void PatchManager::init(std::string path) { | |||
| } | |||
| // Load autosave | |||
| if (load(asset::autosavePath)) { | |||
| if (load("")) { | |||
| return; | |||
| } | |||
| @@ -164,8 +165,10 @@ void PatchManager::saveTemplateDialog() { | |||
| } | |||
| bool PatchManager::load(std::string path) { | |||
| INFO("Loading patch %s", path.c_str()); | |||
| FILE* file = std::fopen(path.c_str(), "r"); | |||
| std::string actualPath = (path != "") ? path : asset::autosavePath; | |||
| INFO("Loading patch %s", actualPath.c_str()); | |||
| FILE* file = std::fopen(actualPath.c_str(), "r"); | |||
| if (!file) { | |||
| // Exit silently | |||
| return false; | |||
| @@ -192,6 +195,18 @@ bool PatchManager::load(std::string path) { | |||
| } | |||
| APP->engine->clear(); | |||
| fromJson(rootJ); | |||
| // Update recent patches | |||
| if (path != "") { | |||
| auto& recent = settings::recentPatchPaths; | |||
| // Remove path from recent patches (if exists) | |||
| recent.erase(std::remove(recent.begin(), recent.end(), path), recent.end()); | |||
| // Add path to top of recent patches | |||
| recent.push_front(path); | |||
| // Limit recent patches size | |||
| recent.resize(std::min((int) recent.size(), 10)); | |||
| } | |||
| return true; | |||
| } | |||
| @@ -39,6 +39,7 @@ bool lockModules = false; | |||
| float autosavePeriod = 15.0; | |||
| bool skipLoadOnLaunch = false; | |||
| std::string patchPath; | |||
| std::list<std::string> recentPatchPaths; | |||
| std::vector<NVGcolor> cableColors = { | |||
| nvgRGB(0xc9, 0xb7, 0x0e), // yellow | |||
| nvgRGB(0x0c, 0x8e, 0x15), // green | |||
| @@ -92,6 +93,12 @@ json_t* toJson() { | |||
| json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str())); | |||
| json_t* recentPatchPathsJ = json_array(); | |||
| for (const std::string& path : recentPatchPaths) { | |||
| json_array_append_new(recentPatchPathsJ, json_string(path.c_str())); | |||
| } | |||
| json_object_set_new(rootJ, "recentPatchPaths", recentPatchPathsJ); | |||
| json_t* cableColorsJ = json_array(); | |||
| for (NVGcolor cableColor : cableColors) { | |||
| std::string colorStr = color::toHexString(cableColor); | |||
| @@ -195,6 +202,17 @@ void fromJson(json_t* rootJ) { | |||
| if (patchPathJ) | |||
| patchPath = json_string_value(patchPathJ); | |||
| recentPatchPaths.clear(); | |||
| json_t* recentPatchPathsJ = json_object_get(rootJ, "recentPatchPaths"); | |||
| if (recentPatchPathsJ) { | |||
| size_t i; | |||
| json_t* pathJ; | |||
| json_array_foreach(recentPatchPathsJ, i, pathJ) { | |||
| std::string path = json_string_value(pathJ); | |||
| recentPatchPaths.push_back(path); | |||
| } | |||
| } | |||
| cableColors.clear(); | |||
| json_t* cableColorsJ = json_object_get(rootJ, "cableColors"); | |||
| if (cableColorsJ) { | |||