Browse Source

Duplicate cables attached to inputs in RackWidget::cloneSelectionAction().

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
b63c9406eb
3 changed files with 124 additions and 75 deletions
  1. +4
    -5
      include/app/ModuleWidget.hpp
  2. +8
    -9
      src/app/ModuleWidget.cpp
  3. +112
    -61
      src/app/RackWidget.cpp

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

@@ -7,7 +7,6 @@
#include <plugin/Model.hpp> #include <plugin/Model.hpp>
#include <engine/Module.hpp> #include <engine/Module.hpp>
#include <history.hpp> #include <history.hpp>
#include <list>




namespace rack { namespace rack {
@@ -57,10 +56,10 @@ struct ModuleWidget : widget::OpaqueWidget {
PortWidget* getInput(int portId); PortWidget* getInput(int portId);
PortWidget* getOutput(int portId); PortWidget* getOutput(int portId);
/** Scans children widgets recursively for all ParamWidgets. */ /** Scans children widgets recursively for all ParamWidgets. */
std::list<ParamWidget*> getParams();
std::list<PortWidget*> getPorts();
std::list<PortWidget*> getInputs();
std::list<PortWidget*> getOutputs();
std::vector<ParamWidget*> getParams();
std::vector<PortWidget*> getPorts();
std::vector<PortWidget*> getInputs();
std::vector<PortWidget*> getOutputs();


void draw(const DrawArgs& args) override; void draw(const DrawArgs& args) override;
void drawShadow(const DrawArgs& args); void drawShadow(const DrawArgs& args);


+ 8
- 9
src/app/ModuleWidget.cpp View File

@@ -174,24 +174,24 @@ void doIfTypeRecursive(widget::Widget* w, F f) {
} }
} }


std::list<ParamWidget*> ModuleWidget::getParams() {
std::list<ParamWidget*> pws;
std::vector<ParamWidget*> ModuleWidget::getParams() {
std::vector<ParamWidget*> pws;
doIfTypeRecursive<ParamWidget>(this, [&](ParamWidget* pw) { doIfTypeRecursive<ParamWidget>(this, [&](ParamWidget* pw) {
pws.push_back(pw); pws.push_back(pw);
}); });
return pws; return pws;
} }


std::list<PortWidget*> ModuleWidget::getPorts() {
std::list<PortWidget*> pws;
std::vector<PortWidget*> ModuleWidget::getPorts() {
std::vector<PortWidget*> pws;
doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) { doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) {
pws.push_back(pw); pws.push_back(pw);
}); });
return pws; return pws;
} }


std::list<PortWidget*> ModuleWidget::getInputs() {
std::list<PortWidget*> pws;
std::vector<PortWidget*> ModuleWidget::getInputs() {
std::vector<PortWidget*> pws;
doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) { doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) {
if (pw->type == engine::Port::INPUT) if (pw->type == engine::Port::INPUT)
pws.push_back(pw); pws.push_back(pw);
@@ -199,8 +199,8 @@ std::list<PortWidget*> ModuleWidget::getInputs() {
return pws; return pws;
} }


std::list<PortWidget*> ModuleWidget::getOutputs() {
std::list<PortWidget*> pws;
std::vector<PortWidget*> ModuleWidget::getOutputs() {
std::vector<PortWidget*> pws;
doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) { doIfTypeRecursive<PortWidget>(this, [&](PortWidget* pw) {
if (pw->type == engine::Port::OUTPUT) if (pw->type == engine::Port::OUTPUT)
pws.push_back(pw); pws.push_back(pw);
@@ -802,7 +802,6 @@ void ModuleWidget::cloneAction() {
for (CableWidget* cw : APP->scene->rack->getCablesOnPort(pw)) { for (CableWidget* cw : APP->scene->rack->getCablesOnPort(pw)) {
// Create cable attached to cloned ModuleWidget's input // Create cable attached to cloned ModuleWidget's input
engine::Cable* clonedCable = new engine::Cable; engine::Cable* clonedCable = new engine::Cable;
clonedCable->id = -1;
clonedCable->inputModule = clonedModule; clonedCable->inputModule = clonedModule;
clonedCable->inputId = cw->cable->inputId; clonedCable->inputId = cw->cable->inputId;
// If cable is self-patched, attach to cloned module instead // If cable is self-patched, attach to cloned module instead


+ 112
- 61
src/app/RackWidget.cpp View File

@@ -393,24 +393,19 @@ static void cleanupModuleJson(json_t* moduleJ) {
json_object_del(moduleJ, "rightModuleId"); json_object_del(moduleJ, "rightModuleId");
} }


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


history::ComplexAction* complexAction = new history::ComplexAction;
complexAction->name = "paste modules";
DEFER({
if (!complexAction->isEmpty())
APP->history->push(complexAction);
else
delete complexAction;
});
struct PasteJsonReturn {
std::map<int64_t, int64_t> newModuleIds;
};
static PasteJsonReturn RackWidget_pasteJson(RackWidget* that, json_t* rootJ, history::ComplexAction* complexAction) {
that->deselect();


std::map<int64_t, int64_t> oldIdMap;
std::map<int64_t, int64_t> newModuleIds;


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


size_t moduleIndex; size_t moduleIndex;
json_t* moduleJ; json_t* moduleJ;
@@ -443,17 +438,17 @@ void RackWidget::pasteJsonAction(json_t* rootJ) {
pos = pos.mult(RACK_GRID_SIZE); pos = pos.mult(RACK_GRID_SIZE);
mw->box.pos = pos.plus(RACK_OFFSET); mw->box.pos = pos.plus(RACK_OFFSET);


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


oldIdMap[id] = mw->module->id;
newModuleIds[id] = mw->module->id;
} }


// This calls RackWidget_updateExpanders() // This calls RackWidget_updateExpanders()
setSelectionPosNearest(math::Vec(0, 0));
that->setSelectionPosNearest(math::Vec(0, 0));


// Add positioned selected modules to history // Add positioned selected modules to history
for (ModuleWidget* mw : getSelectedModules()) {
for (ModuleWidget* mw : that->getSelectedModules()) {
// history::ModuleAdd // history::ModuleAdd
history::ModuleAdd* h = new history::ModuleAdd; history::ModuleAdd* h = new history::ModuleAdd;
h->setModule(mw); h->setModule(mw);
@@ -462,55 +457,70 @@ void RackWidget::pasteJsonAction(json_t* rootJ) {


// cables // cables
json_t* cablesJ = json_object_get(rootJ, "cables"); json_t* cablesJ = json_object_get(rootJ, "cables");
if (!cablesJ)
return;
size_t cableIndex;
json_t* cableJ;
json_array_foreach(cablesJ, cableIndex, cableJ) {
json_object_del(cableJ, "id");
if (cablesJ) {
size_t cableIndex;
json_t* cableJ;
json_array_foreach(cablesJ, cableIndex, cableJ) {
json_object_del(cableJ, "id");

// Remap old module IDs to new IDs
json_t* inputModuleIdJ = json_object_get(cableJ, "inputModuleId");
if (!inputModuleIdJ)
continue;
int64_t inputModuleId = json_integer_value(inputModuleIdJ);
inputModuleId = get(newModuleIds, inputModuleId, -1);
if (inputModuleId < 0)
continue;
json_object_set(cableJ, "inputModuleId", json_integer(inputModuleId));


// Remap old module IDs to new IDs
json_t* inputModuleIdJ = json_object_get(cableJ, "inputModuleId");
if (!inputModuleIdJ)
continue;
int64_t inputModuleId = json_integer_value(inputModuleIdJ);
inputModuleId = get(oldIdMap, inputModuleId, -1);
if (inputModuleId < 0)
continue;
json_object_set(cableJ, "inputModuleId", json_integer(inputModuleId));
json_t* outputModuleIdJ = json_object_get(cableJ, "outputModuleId");
if (!outputModuleIdJ)
continue;
int64_t outputModuleId = json_integer_value(outputModuleIdJ);
outputModuleId = get(newModuleIds, outputModuleId, -1);
if (outputModuleId < 0)
continue;
json_object_set(cableJ, "outputModuleId", json_integer(outputModuleId));


json_t* outputModuleIdJ = json_object_get(cableJ, "outputModuleId");
if (!outputModuleIdJ)
continue;
int64_t outputModuleId = json_integer_value(outputModuleIdJ);
outputModuleId = get(oldIdMap, outputModuleId, -1);
if (outputModuleId < 0)
continue;
json_object_set(cableJ, "outputModuleId", json_integer(outputModuleId));
// Create Cable
engine::Cable* cable = new engine::Cable;
try {
cable->fromJson(cableJ);
APP->engine->addCable(cable);
}
catch (Exception& e) {
WARN("Cannot paste cable: %s", e.what());
delete cable;
continue;
}


// Create Cable
engine::Cable* cable = new engine::Cable;
try {
cable->fromJson(cableJ);
APP->engine->addCable(cable);
}
catch (Exception& e) {
WARN("Cannot paste cable: %s", e.what());
delete cable;
continue;
// Create CableWidget
app::CableWidget* cw = new app::CableWidget;
cw->setCable(cable);
cw->fromJson(cableJ);
that->addCable(cw);
// history::CableAdd
history::CableAdd* h = new history::CableAdd;
h->setCable(cw);
complexAction->push(h);
} }
}


// Create CableWidget
app::CableWidget* cw = new app::CableWidget;
cw->setCable(cable);
cw->fromJson(cableJ);
addCable(cw);
return {newModuleIds};
}


// history::CableAdd
history::CableAdd* h = new history::CableAdd;
h->setCable(cw);
complexAction->push(h);
}
void RackWidget::pasteJsonAction(json_t* rootJ) {
history::ComplexAction* complexAction = new history::ComplexAction;
complexAction->name = "paste modules";
DEFER({
if (!complexAction->isEmpty())
APP->history->push(complexAction);
else
delete complexAction;
});

RackWidget_pasteJson(this, rootJ, complexAction);
} }


void RackWidget::pasteModuleJsonAction(json_t* moduleJ) { void RackWidget::pasteModuleJsonAction(json_t* moduleJ) {
@@ -1028,8 +1038,49 @@ void RackWidget::disconnectSelectionAction() {
void RackWidget::cloneSelectionAction() { void RackWidget::cloneSelectionAction() {
json_t* rootJ = selectionToJson(); json_t* rootJ = selectionToJson();
DEFER({json_decref(rootJ);}); DEFER({json_decref(rootJ);});
// TODO The Action name is incorrect here.
pasteJsonAction(rootJ);

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

auto p = RackWidget_pasteJson(this, rootJ, complexAction);

// Clone cables attached to inputs of selected modules but outputs of non-selected modules
for (CableWidget* cw : getCompleteCables()) {
auto inputIt = p.newModuleIds.find(cw->getCable()->inputModule->id);
if (inputIt == p.newModuleIds.end())
continue;

auto outputIt = p.newModuleIds.find(cw->getCable()->outputModule->id);
if (outputIt != p.newModuleIds.end())
continue;

int64_t clonedInputModuleId = inputIt->second;
engine::Module* clonedInputModule = APP->engine->getModule(clonedInputModuleId);

// Create cable attached to cloned ModuleWidget's input
engine::Cable* clonedCable = new engine::Cable;
clonedCable->inputModule = clonedInputModule;
clonedCable->inputId = cw->cable->inputId;
clonedCable->outputModule = cw->cable->outputModule;
clonedCable->outputId = cw->cable->outputId;
APP->engine->addCable(clonedCable);

app::CableWidget* clonedCw = new app::CableWidget;
clonedCw->setCable(clonedCable);
clonedCw->color = cw->color;
APP->scene->rack->addCable(clonedCw);

// history::CableAdd
history::CableAdd* hca = new history::CableAdd;
hca->setCable(clonedCw);
complexAction->push(hca);
}
} }


void RackWidget::bypassSelectionAction(bool bypassed) { void RackWidget::bypassSelectionAction(bool bypassed) {


Loading…
Cancel
Save