@@ -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) { | ||||