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