Browse Source

Implement the "modules" half of RackWidget::pasteJsonAction().

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
76331f350c
4 changed files with 192 additions and 80 deletions
  1. +1
    -1
      include/app/ModuleWidget.hpp
  2. +2
    -1
      include/app/RackWidget.hpp
  3. +27
    -23
      src/app/ModuleWidget.cpp
  4. +162
    -55
      src/app/RackWidget.cpp

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

@@ -80,7 +80,7 @@ struct ModuleWidget : widget::OpaqueWidget {

json_t* toJson();
void fromJson(json_t* rootJ);
void fromJsonAction(json_t* rootJ);
void pasteJsonAction(json_t* rootJ);
void copyClipboard();
void pasteClipboardAction();
void load(std::string filename);


+ 2
- 1
include/app/RackWidget.hpp View File

@@ -47,7 +47,8 @@ struct RackWidget : widget::OpaqueWidget {
void clear();
void mergeJson(json_t* rootJ);
void fromJson(json_t* rootJ);
void fromJsonAction(json_t* rootJ);
void pasteJsonAction(json_t* rootJ);
void pasteModuleJsonAction(json_t* moduleJ);
void pasteClipboardAction();

// Module methods


+ 27
- 23
src/app/ModuleWidget.cpp View File

@@ -471,25 +471,28 @@ void ModuleWidget::onDragHover(const DragHoverEvent& e) {
OpaqueWidget::onDragHover(e);
}

static void cleanupModuleJson(json_t* moduleJ) {
json_object_del(moduleJ, "id");
json_object_del(moduleJ, "leftModuleId");
json_object_del(moduleJ, "rightModuleId");
}

json_t* ModuleWidget::toJson() {
json_t* rootJ = APP->engine->moduleToJson(module);
return rootJ;
json_t* moduleJ = APP->engine->moduleToJson(module);
return moduleJ;
}

void ModuleWidget::fromJson(json_t* rootJ) {
APP->engine->moduleFromJson(module, rootJ);
void ModuleWidget::fromJson(json_t* moduleJ) {
APP->engine->moduleFromJson(module, moduleJ);
}

void ModuleWidget::fromJsonAction(json_t* rootJ) {
// Don't use IDs from JSON
json_object_del(rootJ, "id");
json_object_del(rootJ, "leftModuleId");
json_object_del(rootJ, "rightModuleId");
void ModuleWidget::pasteJsonAction(json_t* moduleJ) {
cleanupModuleJson(moduleJ);

json_t* oldModuleJ = toJson();

try {
fromJson(rootJ);
fromJson(moduleJ);
}
catch (Exception& e) {
WARN("%s", e.what());
@@ -502,34 +505,36 @@ void ModuleWidget::fromJsonAction(json_t* rootJ) {
h->name = "paste module preset";
h->moduleId = module->id;
h->oldModuleJ = oldModuleJ;
h->newModuleJ = toJson();
h->newModuleJ = moduleJ;
APP->history->push(h);
}

void ModuleWidget::copyClipboard() {
json_t* moduleJ = toJson();
cleanupModuleJson(moduleJ);

DEFER({json_decref(moduleJ);});
char* moduleJson = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
DEFER({std::free(moduleJson);});
glfwSetClipboardString(APP->window->win, moduleJson);
char* json = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
DEFER({std::free(json);});
glfwSetClipboardString(APP->window->win, json);
}

void ModuleWidget::pasteClipboardAction() {
const char* moduleJson = glfwGetClipboardString(APP->window->win);
if (!moduleJson) {
const char* json = glfwGetClipboardString(APP->window->win);
if (!json) {
WARN("Could not get text from clipboard.");
return;
}

json_error_t error;
json_t* moduleJ = json_loads(moduleJson, 0, &error);
json_t* moduleJ = json_loads(json, 0, &error);
if (!moduleJ) {
WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
return;
}
DEFER({json_decref(moduleJ);});

fromJsonAction(moduleJ);
pasteJsonAction(moduleJ);
}

void ModuleWidget::load(std::string filename) {
@@ -546,11 +551,7 @@ void ModuleWidget::load(std::string filename) {
throw Exception("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);});

// Don't use IDs from JSON
json_object_del(moduleJ, "id");
json_object_del(moduleJ, "leftModuleId");
json_object_del(moduleJ, "rightModuleId");

cleanupModuleJson(moduleJ);
fromJson(moduleJ);
}

@@ -569,6 +570,7 @@ void ModuleWidget::loadAction(std::string filename) {
throw;
}

// TODO We can use `moduleJ` here instead to save a toJson() call.
h->newModuleJ = toJson();
APP->history->push(h);
}
@@ -623,6 +625,8 @@ void ModuleWidget::save(std::string filename) {
assert(moduleJ);
DEFER({json_decref(moduleJ);});

cleanupModuleJson(moduleJ);

FILE* file = std::fopen(filename.c_str(), "w");
if (!file) {
std::string message = string::f("Could not save preset to file %s", filename.c_str());


+ 162
- 55
src/app/RackWidget.cpp View File

@@ -205,13 +205,42 @@ void RackWidget::clear() {
}
}

static void RackWidget_updateExpanders(RackWidget* that) {
for (widget::Widget* w : that->internal->moduleContainer->children) {
math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
ModuleWidget* mwLeft = NULL;
ModuleWidget* mwRight = NULL;

// Find adjacent modules
for (widget::Widget* w2 : that->internal->moduleContainer->children) {
if (w2 == w)
continue;

math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();

// Check if this is a left module
if (p2Right.equals(pLeft)) {
mwLeft = dynamic_cast<ModuleWidget*>(w2);
}

// Check if this is a right module
if (p2Left.equals(pRight)) {
mwRight = dynamic_cast<ModuleWidget*>(w2);
}
}

ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
mw->module->leftExpander.moduleId = mwLeft ? mwLeft->module->id : -1;
mw->module->rightExpander.moduleId = mwRight ? mwRight->module->id : -1;
}
}

void RackWidget::mergeJson(json_t* rootJ) {
// Get module offset so modules are aligned to (0, 0) when the patch is loaded.
math::Vec moduleOffset = math::Vec(INFINITY, INFINITY);
for (widget::Widget* w : internal->moduleContainer->children) {
moduleOffset = moduleOffset.min(w->box.pos);
}
if (internal->moduleContainer->children.empty()) {
math::Vec moduleOffset = internal->moduleContainer->getChildrenBoundingBox().pos;
if (!moduleOffset.isFinite()) {
moduleOffset = RACK_OFFSET;
}

@@ -228,14 +257,14 @@ void RackWidget::mergeJson(json_t* rootJ) {
continue;
int64_t id = json_integer_value(idJ);
// TODO Legacy v0.6?
ModuleWidget* moduleWidget = getModule(id);
if (!moduleWidget) {
ModuleWidget* mw = getModule(id);
if (!mw) {
WARN("Cannot find ModuleWidget %" PRId64, id);
continue;
}

// pos
math::Vec pos = moduleWidget->box.pos.minus(moduleOffset);
math::Vec pos = mw->box.pos.minus(moduleOffset);
pos = pos.div(RACK_GRID_SIZE).round();
json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
json_object_set_new(moduleJ, "pos", posJ);
@@ -299,7 +328,7 @@ void RackWidget::fromJson(json_t* rootJ) {
}

// Create ModuleWidget
ModuleWidget* moduleWidget = module->model->createModuleWidget(module);
ModuleWidget* mw = module->model->createModuleWidget(module);

// pos
json_t* posJ = json_object_get(moduleJ, "pos");
@@ -308,16 +337,17 @@ void RackWidget::fromJson(json_t* rootJ) {
math::Vec pos = math::Vec(x, y);
if (legacyV05) {
// In <=v0.5, positions were in pixel units
moduleWidget->box.pos = pos;
}
else {
moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
pos = pos.mult(RACK_GRID_SIZE);
}
moduleWidget->box.pos = moduleWidget->box.pos.plus(RACK_OFFSET);
mw->box.pos = pos.plus(RACK_OFFSET);

addModule(moduleWidget);
internal->moduleContainer->addChild(mw);
}

RackWidget_updateExpanders(this);

// cables
json_t* cablesJ = json_object_get(rootJ, "cables");
// In <=v0.6, cables were called wires
@@ -355,13 +385,107 @@ void RackWidget::fromJson(json_t* rootJ) {
}
}

void RackWidget::fromJsonAction(json_t* rootJ) {
json_t* moduleJ = rootJ;

// Because we are creating a new module, we don't want to use the IDs from the JSON.
static void cleanupModuleJson(json_t* moduleJ) {
json_object_del(moduleJ, "id");
json_object_del(moduleJ, "leftModuleId");
json_object_del(moduleJ, "rightModuleId");
}

void RackWidget::pasteJsonAction(json_t* rootJ) {
deselectModules();

history::ComplexAction* complexAction = new history::ComplexAction;
complexAction->name = "paste modules";
DEFER({
if (!complexAction->isEmpty())
APP->history->push(complexAction);
else
delete complexAction;
});

// modules
json_t* modulesJ = json_object_get(rootJ, "modules");
if (!modulesJ)
return;

size_t moduleIndex;
json_t* moduleJ;
json_array_foreach(modulesJ, moduleIndex, moduleJ) {
cleanupModuleJson(moduleJ);

ModuleWidget* mw;
try {
mw = moduleWidgetFromJson(moduleJ);
}
catch (Exception& e) {
WARN("%s", e.what());
continue;
}
assert(mw);
assert(mw->module);

APP->engine->addModule(mw->module);

// pos
json_t* posJ = json_object_get(moduleJ, "pos");
double x = 0.0, y = 0.0;
json_unpack(posJ, "[F, F]", &x, &y);
math::Vec pos = math::Vec(x, y);
pos = pos.mult(RACK_GRID_SIZE);
mw->box.pos = pos.plus(RACK_OFFSET);

internal->moduleContainer->addChild(mw);
mw->selected() = true;

// history::ModuleAdd
history::ModuleAdd* h = new history::ModuleAdd;
h->setModule(mw);
complexAction->push(h);
}

// This calls RackWidget_updateExpanders()
setSelectedModulesPosNearest(math::Vec(0, 0));

// TODO
// // cables
// json_t* cablesJ = json_object_get(rootJ, "cables");
// // In <=v0.6, cables were called wires
// if (!cablesJ)
// cablesJ = json_object_get(rootJ, "wires");
// if (!cablesJ)
// return;
// size_t cableIndex;
// json_t* cableJ;
// json_array_foreach(cablesJ, cableIndex, cableJ) {
// // Get cable ID
// json_t* idJ = json_object_get(cableJ, "id");
// int64_t id;
// if (idJ)
// id = json_integer_value(idJ);
// else
// id = cableIndex;

// // Get Cable
// engine::Cable* cable = APP->engine->getCable(id);
// if (!cable) {
// WARN("Cannot find Cable %" PRId64, id);
// continue;
// }

// // Create CableWidget
// CableWidget* cw = new CableWidget;
// cw->setCable(cable);
// cw->fromJson(cableJ);
// // In <=v1, cable colors were not serialized, so choose one from the available colors.
// if (cw->color.a == 0.f) {
// cw->setNextCableColor();
// }
// addCable(cw);
// }
}

void RackWidget::pasteModuleJsonAction(json_t* moduleJ) {
cleanupModuleJson(moduleJ);

ModuleWidget* mw;
try {
@@ -379,57 +503,34 @@ void RackWidget::fromJsonAction(json_t* rootJ) {

// history::ModuleAdd
history::ModuleAdd* h = new history::ModuleAdd;
h->name = "paste module";
h->setModule(mw);
APP->history->push(h);
}

void RackWidget::pasteClipboardAction() {
const char* moduleJson = glfwGetClipboardString(APP->window->win);
if (!moduleJson) {
const char* json = glfwGetClipboardString(APP->window->win);
if (!json) {
WARN("Could not get text from clipboard.");
return;
}

json_error_t error;
json_t* moduleJ = json_loads(moduleJson, 0, &error);
if (!moduleJ) {
json_t* rootJ = json_loads(json, 0, &error);
if (!rootJ) {
WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
return;
}
DEFER({json_decref(moduleJ);});

fromJsonAction(moduleJ);
}

static void RackWidget_updateExpanders(RackWidget* that) {
for (widget::Widget* w : that->internal->moduleContainer->children) {
math::Vec pLeft = w->box.pos.div(RACK_GRID_SIZE).round();
math::Vec pRight = w->box.getTopRight().div(RACK_GRID_SIZE).round();
ModuleWidget* mwLeft = NULL;
ModuleWidget* mwRight = NULL;

// Find adjacent modules
for (widget::Widget* w2 : that->internal->moduleContainer->children) {
if (w2 == w)
continue;

math::Vec p2Left = w2->box.pos.div(RACK_GRID_SIZE).round();
math::Vec p2Right = w2->box.getTopRight().div(RACK_GRID_SIZE).round();

// Check if this is a left module
if (p2Right.equals(pLeft)) {
mwLeft = dynamic_cast<ModuleWidget*>(w2);
}

// Check if this is a right module
if (p2Left.equals(pRight)) {
mwRight = dynamic_cast<ModuleWidget*>(w2);
}
}
DEFER({json_decref(rootJ);});

ModuleWidget* mw = dynamic_cast<ModuleWidget*>(w);
mw->module->leftExpander.moduleId = mwLeft ? mwLeft->module->id : -1;
mw->module->rightExpander.moduleId = mwRight ? mwRight->module->id : -1;
json_t* modulesJ = json_object_get(rootJ, "modules");
if (modulesJ) {
// JSON is a selection of modules
pasteJsonAction(rootJ);
}
else {
// JSON is a single module
pasteModuleJsonAction(rootJ);
}
}

@@ -707,8 +808,14 @@ json_t* RackWidget::selectedModulesToJson() {
json_t* modulesJ = json_array();
for (ModuleWidget* mw : getSelectedModules()) {
json_t* moduleJ = mw->toJson();
json_array_append_new(modulesJ, moduleJ);

// pos
math::Vec pos = mw->box.pos.minus(RACK_OFFSET);
pos = pos.div(RACK_GRID_SIZE).round();
json_t* posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
json_object_set_new(moduleJ, "pos", posJ);

json_array_append_new(modulesJ, moduleJ);
modules.insert(mw->getModule());
}
json_object_set_new(rootJ, "modules", modulesJ);


Loading…
Cancel
Save