Browse Source

Add template preset for modules, which are loaded when created from the Module Browser.

tags/v2.0.0
Andrew Belt 4 years ago
parent
commit
8423ce87aa
7 changed files with 141 additions and 50 deletions
  1. +4
    -1
      include/app/ModuleWidget.hpp
  2. +3
    -0
      include/plugin/Model.hpp
  3. +4
    -0
      include/system.hpp
  4. +5
    -1
      src/app/ModuleBrowser.cpp
  5. +93
    -48
      src/app/ModuleWidget.cpp
  6. +12
    -0
      src/plugin/Model.cpp
  7. +20
    -0
      src/system.cpp

+ 4
- 1
include/app/ModuleWidget.hpp View File

@@ -66,9 +66,12 @@ struct ModuleWidget : widget::OpaqueWidget {
void fromJson(json_t* rootJ);
void copyClipboard();
void pasteClipboardAction();
void load(std::string filename);
void loadAction(std::string filename);
void save(std::string filename);
void loadTemplate();
void loadDialog();
void save(std::string filename);
void saveTemplate();
void saveDialog();

/** Disconnects cables from all ports


+ 3
- 0
include/plugin/Model.hpp View File

@@ -53,7 +53,10 @@ struct Model {
}

void fromJson(json_t* rootJ);
/** Returns the branded name of the model, e.g. VCV VCO-1. */
std::string getFullName();
std::string getFactoryPresetDir();
std::string getUserPresetDir();
};




+ 4
- 0
include/system.hpp View File

@@ -26,10 +26,14 @@ void copyFile(const std::string& srcPath, const std::string& destPath);
The parent directory must exist.
*/
void createDirectory(const std::string& path);
/** Creates all directories up to the path.
*/
void createDirectories(const std::string& path);
/** Deletes a directory.
The directory must be empty. Fails silently.
*/
void removeDirectory(const std::string& path);
void removeDirectories(const std::string& path);
/** Returns the number of logical simultaneous multithreading (SMT) (e.g. Intel Hyperthreaded) threads on the CPU. */
int getLogicalCoreCount();
/** Sets a name of the current thread for debuggers and OS-specific process viewers. */


+ 5
- 1
src/app/ModuleBrowser.cpp View File

@@ -90,9 +90,13 @@ static ModuleWidget* chooseModel(plugin::Model* model) {
ModuleWidget* moduleWidget = model->createModuleWidget(module);
APP->scene->rack->addModuleAtMouse(moduleWidget);

// Push ModuleAdd history action
// Load template preset
moduleWidget->loadTemplate();

// history::ModuleAdd
history::ModuleAdd* h = new history::ModuleAdd;
h->name = "create module";
// This serializes the module so redoing returns to the current state.
h->setModule(moduleWidget);
APP->history->push(h);



+ 93
- 48
src/app/ModuleWidget.cpp View File

@@ -170,6 +170,14 @@ struct ModuleSaveItem : ui::MenuItem {
};


struct ModuleSaveTemplateItem : ui::MenuItem {
ModuleWidget* moduleWidget;
void onAction(const event::Action& e) override {
moduleWidget->saveTemplate();
}
};


struct ModuleLoadItem : ui::MenuItem {
ModuleWidget* moduleWidget;
void onAction(const event::Action& e) override {
@@ -182,7 +190,12 @@ struct ModulePresetPathItem : ui::MenuItem {
ModuleWidget* moduleWidget;
std::string presetPath;
void onAction(const event::Action& e) override {
moduleWidget->loadAction(presetPath);
try {
moduleWidget->loadAction(presetPath);
}
catch (Exception& e) {
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what());
}
}
};

@@ -214,6 +227,11 @@ struct ModulePresetItem : ui::MenuItem {
saveItem->moduleWidget = moduleWidget;
menu->addChild(saveItem);

ModuleSaveTemplateItem* saveTemplateItem = new ModuleSaveTemplateItem;
saveTemplateItem->text = "Save template";
saveTemplateItem->moduleWidget = moduleWidget;
menu->addChild(saveTemplateItem);

// Create ModulePresetPathItems for each patch in a directory.
auto createPresetItems = [&](std::string presetDir) {
bool hasPresets = false;
@@ -238,12 +256,12 @@ struct ModulePresetItem : ui::MenuItem {
// Scan `<user dir>/presets/<plugin slug>/<module slug>` for presets.
menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("User presets"));
createPresetItems(asset::user("presets/" + moduleWidget->model->plugin->slug + "/" + moduleWidget->model->slug));
createPresetItems(moduleWidget->model->getUserPresetDir());

// Scan `<plugin dir>/presets/<module slug>` for presets.
menu->addChild(new ui::MenuSeparator);
menu->addChild(createMenuLabel("Factory presets"));
createPresetItems(asset::plugin(moduleWidget->model->plugin, "presets/" + moduleWidget->model->slug));
createPresetItems(moduleWidget->model->getFactoryPresetDir());

return menu;
}
@@ -599,41 +617,87 @@ void ModuleWidget::pasteClipboardAction() {
APP->history->push(h);
}

void ModuleWidget::loadAction(std::string filename) {
INFO("Loading preset %s", filename.c_str());

FILE* file = fopen(filename.c_str(), "r");
if (!file) {
WARN("Could not load patch file %s", filename.c_str());
return;
}
void ModuleWidget::load(std::string filename) {
FILE* file = std::fopen(filename.c_str(), "r");
if (!file)
throw Exception(string::f("Could not load patch file %s", filename.c_str()));
DEFER({
fclose(file);
std::fclose(file);
});

INFO("Loading preset %s", filename.c_str());

json_error_t error;
json_t* moduleJ = json_loadf(file, 0, &error);
if (!moduleJ) {
std::string message = string::f("File is not a valid patch file. 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());
return;
}
if (!moduleJ)
throw Exception(string::f("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text));
DEFER({
json_decref(moduleJ);
});

fromJson(moduleJ);
}

void ModuleWidget::loadAction(std::string filename) {
// history::ModuleChange
history::ModuleChange* h = new history::ModuleChange;
h->name = "load module preset";
h->moduleId = module->id;
h->oldModuleJ = toJson();

fromJson(moduleJ);
try {
load(filename);
}
catch (Exception& e) {
delete h;
throw;
}

h->newModuleJ = toJson();
APP->history->push(h);
}

void ModuleWidget::loadTemplate() {
std::string templatePath = model->getUserPresetDir() + "/" + "template.vcvm";
try {
load(templatePath);
}
catch (Exception& e) {
// Do nothing
}
}

void ModuleWidget::loadDialog() {
std::string presetDir = model->getUserPresetDir();
system::createDirectories(presetDir);

// Delete directories if empty
DEFER({
system::removeDirectories(presetDir);
});

osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS);
DEFER({
osdialog_filters_free(filters);
});

char* path = osdialog_file(OSDIALOG_OPEN, presetDir.c_str(), NULL, filters);
if (!path) {
// No path selected
return;
}
DEFER({
free(path);
});

try {
loadAction(path);
}
catch (Exception& e) {
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what());
}
}

void ModuleWidget::save(std::string filename) {
INFO("Saving preset %s", filename.c_str());

@@ -654,40 +718,21 @@ void ModuleWidget::save(std::string filename) {
json_dumpf(moduleJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
}

void ModuleWidget::loadDialog() {
std::string presetDir = asset::user("presets");
std::string pluginPresetDir = presetDir + "/" + model->plugin->slug;
std::string modulePresetDir = pluginPresetDir + "/" + model->slug;
system::createDirectory(modulePresetDir);
void ModuleWidget::saveTemplate() {
std::string presetDir = model->getUserPresetDir();
system::createDirectories(presetDir);

osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS);
DEFER({
osdialog_filters_free(filters);
});

char* path = osdialog_file(OSDIALOG_OPEN, modulePresetDir.c_str(), NULL, filters);
if (!path) {
// No path selected
return;
}
DEFER({
free(path);
});

loadAction(path);
std::string templatePath = presetDir + "/" + "template.vcvm";
save(templatePath);
}

void ModuleWidget::saveDialog() {
std::string presetDir = asset::user("presets");
system::createDirectory(presetDir);
std::string pluginPresetDir = presetDir + "/" + model->plugin->slug;
system::createDirectory(pluginPresetDir);
std::string modulePresetDir = pluginPresetDir + "/" + model->slug;
system::createDirectory(modulePresetDir);
// Delete directory if empty
std::string presetDir = model->getUserPresetDir();
system::createDirectories(presetDir);

// Delete directories if empty
DEFER({
system::removeDirectory(modulePresetDir);
system::removeDirectory(pluginPresetDir);
system::removeDirectories(presetDir);
});

osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS);
@@ -695,7 +740,7 @@ void ModuleWidget::saveDialog() {
osdialog_filters_free(filters);
});

char* path = osdialog_file(OSDIALOG_SAVE, modulePresetDir.c_str(), "Untitled.vcvm", filters);
char* path = osdialog_file(OSDIALOG_SAVE, presetDir.c_str(), "Untitled.vcvm", filters);
if (!path) {
// No path selected
return;


+ 12
- 0
src/plugin/Model.cpp View File

@@ -50,5 +50,17 @@ std::string Model::getFullName() {
}


std::string Model::getFactoryPresetDir() {
return asset::plugin(plugin, "presets/" + slug);
}


std::string Model::getUserPresetDir() {
return asset::user("presets/" + plugin->slug + "/" + slug);
}




} // namespace plugin
} // namespace rack

+ 20
- 0
src/system.cpp View File

@@ -137,11 +137,31 @@ void createDirectory(const std::string& path) {
}


void createDirectories(const std::string& path) {
for (size_t i = 1; i < path.size(); i++) {
char c = path[i];
if (c == '/' || c == '\\')
createDirectory(path.substr(0, i));
}
createDirectory(path);
}


void removeDirectory(const std::string& path) {
rmdir(path.c_str());
}


void removeDirectories(const std::string& path) {
removeDirectory(path);
for (size_t i = path.size() - 1; i >= 1; i--) {
char c = path[i];
if (c == '/' || c == '\\')
removeDirectory(path.substr(0, i));
}
}


int getLogicalCoreCount() {
return std::thread::hardware_concurrency();
}


Loading…
Cancel
Save