| @@ -4,6 +4,7 @@ | |||||
| #include <color.hpp> | #include <color.hpp> | ||||
| #include <vector> | #include <vector> | ||||
| #include <map> | #include <map> | ||||
| #include <list> | |||||
| #include <tuple> | #include <tuple> | ||||
| #include <jansson.h> | #include <jansson.h> | ||||
| @@ -45,6 +46,7 @@ extern int frameSwapInterval; | |||||
| extern float autosavePeriod; | extern float autosavePeriod; | ||||
| extern bool skipLoadOnLaunch; | extern bool skipLoadOnLaunch; | ||||
| extern std::string patchPath; | extern std::string patchPath; | ||||
| extern std::list<std::string> recentPatchPaths; | |||||
| extern std::vector<NVGcolor> cableColors; | extern std::vector<NVGcolor> cableColors; | ||||
| // pluginSlug -> moduleSlugs | // pluginSlug -> moduleSlugs | ||||
| extern std::map<std::string, std::vector<std::string>> moduleWhitelist; | 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 { | struct SaveItem : ui::MenuItem { | ||||
| void onAction(const event::Action& e) override { | void onAction(const event::Action& e) override { | ||||
| APP->patch->saveDialog(); | APP->patch->saveDialog(); | ||||
| @@ -136,6 +158,11 @@ struct FileButton : MenuButton { | |||||
| openItem->rightText = RACK_MOD_CTRL_NAME "+O"; | openItem->rightText = RACK_MOD_CTRL_NAME "+O"; | ||||
| menu->addChild(openItem); | menu->addChild(openItem); | ||||
| OpenRecentItem* openRecentItem = new OpenRecentItem; | |||||
| openRecentItem->text = "Open recent"; | |||||
| openRecentItem->rightText = RIGHT_ARROW; | |||||
| menu->addChild(openRecentItem); | |||||
| SaveItem* saveItem = new SaveItem; | SaveItem* saveItem = new SaveItem; | ||||
| saveItem->text = "Save"; | saveItem->text = "Save"; | ||||
| saveItem->rightText = RACK_MOD_CTRL_NAME "+S"; | saveItem->rightText = RACK_MOD_CTRL_NAME "+S"; | ||||
| @@ -8,6 +8,7 @@ | |||||
| #include <app/RackWidget.hpp> | #include <app/RackWidget.hpp> | ||||
| #include <history.hpp> | #include <history.hpp> | ||||
| #include <settings.hpp> | #include <settings.hpp> | ||||
| #include <algorithm> | |||||
| #include <osdialog.h> | #include <osdialog.h> | ||||
| @@ -47,7 +48,7 @@ void PatchManager::init(std::string path) { | |||||
| } | } | ||||
| // Load autosave | // Load autosave | ||||
| if (load(asset::autosavePath)) { | |||||
| if (load("")) { | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -164,8 +165,10 @@ void PatchManager::saveTemplateDialog() { | |||||
| } | } | ||||
| bool PatchManager::load(std::string path) { | 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) { | if (!file) { | ||||
| // Exit silently | // Exit silently | ||||
| return false; | return false; | ||||
| @@ -192,6 +195,18 @@ bool PatchManager::load(std::string path) { | |||||
| } | } | ||||
| APP->engine->clear(); | APP->engine->clear(); | ||||
| fromJson(rootJ); | 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; | return true; | ||||
| } | } | ||||
| @@ -39,6 +39,7 @@ bool lockModules = false; | |||||
| float autosavePeriod = 15.0; | float autosavePeriod = 15.0; | ||||
| bool skipLoadOnLaunch = false; | bool skipLoadOnLaunch = false; | ||||
| std::string patchPath; | std::string patchPath; | ||||
| std::list<std::string> recentPatchPaths; | |||||
| std::vector<NVGcolor> cableColors = { | std::vector<NVGcolor> cableColors = { | ||||
| nvgRGB(0xc9, 0xb7, 0x0e), // yellow | nvgRGB(0xc9, 0xb7, 0x0e), // yellow | ||||
| nvgRGB(0x0c, 0x8e, 0x15), // green | nvgRGB(0x0c, 0x8e, 0x15), // green | ||||
| @@ -92,6 +93,12 @@ json_t* toJson() { | |||||
| json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str())); | 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(); | json_t* cableColorsJ = json_array(); | ||||
| for (NVGcolor cableColor : cableColors) { | for (NVGcolor cableColor : cableColors) { | ||||
| std::string colorStr = color::toHexString(cableColor); | std::string colorStr = color::toHexString(cableColor); | ||||
| @@ -195,6 +202,17 @@ void fromJson(json_t* rootJ) { | |||||
| if (patchPathJ) | if (patchPathJ) | ||||
| patchPath = json_string_value(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(); | cableColors.clear(); | ||||
| json_t* cableColorsJ = json_object_get(rootJ, "cableColors"); | json_t* cableColorsJ = json_object_get(rootJ, "cableColors"); | ||||
| if (cableColorsJ) { | if (cableColorsJ) { | ||||