Browse Source

Use cable history actions when interacting with cables

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
94c33c5e77
10 changed files with 158 additions and 47 deletions
  1. +3
    -1
      include/app/CableContainer.hpp
  2. +2
    -2
      include/app/CableWidget.hpp
  3. +7
    -4
      include/app/ModuleWidget.hpp
  4. +1
    -1
      include/engine/Module.hpp
  5. +20
    -9
      include/history.hpp
  6. +10
    -0
      src/app/CableContainer.cpp
  7. +7
    -7
      src/app/CableWidget.cpp
  8. +44
    -17
      src/app/ModuleWidget.cpp
  9. +22
    -6
      src/app/PortWidget.cpp
  10. +42
    -0
      src/history.cpp

+ 3
- 1
include/app/CableContainer.hpp View File

@@ -24,8 +24,10 @@ struct CableContainer : TransparentWidget {
/** Takes ownership of `w` and adds it as a child if it isn't already */
void setIncompleteCable(CableWidget *w);
CableWidget *releaseIncompleteCable();
/** Returns the most recently added cable connected to the given Port, i.e. the top of the stack */
/** Returns the most recently added complete cable connected to the given Port, i.e. the top of the stack */
CableWidget *getTopCable(PortWidget *port);
CableWidget *getCable(int cableId);

json_t *toJson();
void fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &moduleWidgets);
void draw(NVGcontext *vg) override;


+ 2
- 2
include/app/CableWidget.hpp View File

@@ -21,8 +21,8 @@ struct CableWidget : OpaqueWidget {
CableWidget();
~CableWidget();
bool isComplete();
void setOutputPort(PortWidget *outputPort);
void setInputPort(PortWidget *inputPort);
void setOutput(PortWidget *outputPort);
void setInput(PortWidget *inputPort);
math::Vec getOutputPos();
math::Vec getInputPos();
json_t *toJson();


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

@@ -18,8 +18,8 @@ struct ModuleWidget : OpaqueWidget {

Widget *panel = NULL;
std::vector<ParamWidget*> params;
std::vector<PortWidget*> inputs;
std::vector<PortWidget*> outputs;
std::vector<PortWidget*> inputs;
/** For RackWidget dragging */
math::Vec dragPos;
math::Vec oldPos;
@@ -44,12 +44,15 @@ struct ModuleWidget : OpaqueWidget {
Transfers ownership
*/
void setModule(Module *module);
void setPanel(std::shared_ptr<SVG> svg);

/** Convenience functions for adding special widgets (calls addChild()) */
void addInput(PortWidget *input);
void addOutput(PortWidget *output);
void addParam(ParamWidget *param);
void setPanel(std::shared_ptr<SVG> svg);
void addOutput(PortWidget *output);
void addInput(PortWidget *input);
ParamWidget *getParam(int paramId);
PortWidget *getOutput(int outputId);
PortWidget *getInput(int inputId);

/** Overriding these is deprecated.
Use Module::dataToJson() and dataFromJson() instead


+ 1
- 1
include/engine/Module.hpp View File

@@ -15,8 +15,8 @@ namespace rack {
struct Module {
int id = 0;
std::vector<Param> params;
std::vector<Input> inputs;
std::vector<Output> outputs;
std::vector<Input> inputs;
std::vector<Light> lights;
/** For power meter */
float cpuTime = 0.f;


+ 20
- 9
include/history.hpp View File

@@ -1,12 +1,18 @@
#pragma once
#include "common.hpp"
#include "math.hpp"
#include "color.hpp"
#include "plugin/Model.hpp"
#include <vector>
#include <jansson.h>


namespace rack {


struct CableWidget;


namespace history {


@@ -17,6 +23,17 @@ struct Action {
};


template <class TAction>
struct InverseAction : TAction {
void undo() override {
TAction::redo();
}
void redo() override {
TAction::undo();
}
};


/** Batches multiple actions into one */
struct ComplexAction : Action {
/** Ordered by time occurred. Undoing will replay them backwards. */
@@ -84,20 +101,14 @@ struct CableAdd : Action {
int outputId;
int inputModuleId;
int inputId;
NVGcolor color;
void setCable(CableWidget *cw);
void undo() override;
void redo() override;
};


struct CableRemove : Action {
int cableId;
int outputModuleId;
int outputId;
int inputModuleId;
int inputId;
void undo() override;
void redo() override;
};
struct CableRemove : InverseAction<CableAdd> {};


struct State {


+ 10
- 0
src/app/CableContainer.cpp View File

@@ -86,6 +86,16 @@ CableWidget *CableContainer::getTopCable(PortWidget *port) {
return NULL;
}

CableWidget *CableContainer::getCable(int cableId) {
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
if (cw->cable->id == cableId)
return cw;
}
return NULL;
}

json_t *CableContainer::toJson() {
json_t *rootJ = json_array();
for (Widget *w : children) {


+ 7
- 7
src/app/CableWidget.cpp View File

@@ -99,7 +99,7 @@ bool CableWidget::isComplete() {
return outputPort && inputPort;
}

void CableWidget::setOutputPort(PortWidget *outputPort) {
void CableWidget::setOutput(PortWidget *outputPort) {
this->outputPort = outputPort;
if (outputPort) {
assert(outputPort->type == PortWidget::OUTPUT);
@@ -108,7 +108,7 @@ void CableWidget::setOutputPort(PortWidget *outputPort) {
}
}

void CableWidget::setInputPort(PortWidget *inputPort) {
void CableWidget::setInput(PortWidget *inputPort) {
this->inputPort = inputPort;
if (inputPort) {
assert(inputPort->type == PortWidget::INPUT);
@@ -145,7 +145,7 @@ json_t *CableWidget::toJson() {
assert(isComplete());
json_t *rootJ = json_object();

// This is just here for fun. It is not used in fromJson()
// This is just here for fun. It is not used in fromJson(), since cableIds are not preserved across multiple launches of Rack.
json_object_set_new(rootJ, "id", json_integer(cable->id));

json_object_set_new(rootJ, "outputModuleId", json_integer(cable->outputModule->id));
@@ -177,19 +177,19 @@ void CableWidget::fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &mo
// Set ports
if (app()->patch->isLegacy(1)) {
// Before 0.6, the index of the "ports" array was the index of the PortWidget in the `outputs` and `inputs` vector.
setOutputPort(outputModule->outputs[outputId]);
setInputPort(inputModule->inputs[inputId]);
setOutput(outputModule->outputs[outputId]);
setInput(inputModule->inputs[inputId]);
}
else {
for (PortWidget *port : outputModule->outputs) {
if (port->portId == outputId) {
setOutputPort(port);
setOutput(port);
break;
}
}
for (PortWidget *port : inputModule->inputs) {
if (port->portId == inputId) {
setInputPort(port);
setInput(port);
break;
}
}


+ 44
- 17
src/app/ModuleWidget.cpp View File

@@ -162,6 +162,16 @@ void ModuleWidget::draw(NVGcontext *vg) {
nvgFill(vg);
}

// if (module) {
// nvgBeginPath(vg);
// nvgRect(vg, 0, 0, 20, 20);
// nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75));
// nvgFill(vg);

// std::string debugText = string::f("%d", module->id);
// bndLabel(vg, 0, 0, INFINITY, INFINITY, -1, debugText.c_str());
// }

// nvgResetScissor(vg);
}

@@ -282,23 +292,6 @@ void ModuleWidget::setModule(Module *module) {
this->module = module;
}

void ModuleWidget::addInput(PortWidget *input) {
assert(input->type == PortWidget::INPUT);
inputs.push_back(input);
addChild(input);
}

void ModuleWidget::addOutput(PortWidget *output) {
assert(output->type == PortWidget::OUTPUT);
outputs.push_back(output);
addChild(output);
}

void ModuleWidget::addParam(ParamWidget *param) {
params.push_back(param);
addChild(param);
}

void ModuleWidget::setPanel(std::shared_ptr<SVG> svg) {
// Remove old panel
if (panel) {
@@ -316,6 +309,40 @@ void ModuleWidget::setPanel(std::shared_ptr<SVG> svg) {
}
}

void ModuleWidget::addParam(ParamWidget *param) {
params.push_back(param);
addChild(param);
}

void ModuleWidget::addOutput(PortWidget *output) {
assert(output->type == PortWidget::OUTPUT);
outputs.push_back(output);
addChild(output);
}

void ModuleWidget::addInput(PortWidget *input) {
assert(input->type == PortWidget::INPUT);
inputs.push_back(input);
addChild(input);
}

ParamWidget *ModuleWidget::getParam(int paramId) {
if (0 <= paramId && paramId < (int) params.size())
return params[paramId];
return NULL;
}

PortWidget *ModuleWidget::getOutput(int outputId) {
if (0 <= outputId && outputId < (int) outputs.size())
return outputs[outputId];
return NULL;
}

PortWidget *ModuleWidget::getInput(int inputId) {
if (0 <= inputId && inputId < (int) inputs.size())
return inputs[inputId];
return NULL;
}

json_t *ModuleWidget::toJson() {
json_t *rootJ = json_object();


+ 22
- 6
src/app/PortWidget.cpp View File

@@ -2,6 +2,7 @@
#include "app/Scene.hpp"
#include "window.hpp"
#include "app.hpp"
#include "history.hpp"
#include "componentlibrary.hpp"


@@ -60,6 +61,11 @@ void PortWidget::onButton(const event::Button &e) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
CableWidget *cw = app()->scene->rackWidget->cableContainer->getTopCable(this);
if (cw) {
// history::CableRemove
history::CableRemove *h = new history::CableRemove;
h->setCable(cw);
app()->history->push(h);

app()->scene->rackWidget->cableContainer->removeCable(cw);
delete cw;
}
@@ -78,20 +84,25 @@ void PortWidget::onDragStart(const event::DragStart &e) {
}

if (cw) {
// history::CableRemove
history::CableRemove *h = new history::CableRemove;
h->setCable(cw);
app()->history->push(h);

// Disconnect and reuse existing cable
app()->scene->rackWidget->cableContainer->removeCable(cw);
if (type == OUTPUT)
cw->setOutputPort(NULL);
cw->setOutput(NULL);
else
cw->setInputPort(NULL);
cw->setInput(NULL);
}
else {
// Create a new cable
cw = new CableWidget;
if (type == OUTPUT)
cw->setOutputPort(this);
cw->setOutput(this);
else
cw->setInputPort(this);
cw->setInput(this);
}
app()->scene->rackWidget->cableContainer->setIncompleteCable(cw);
}
@@ -102,6 +113,11 @@ void PortWidget::onDragEnd(const event::DragEnd &e) {
CableWidget *cw = app()->scene->rackWidget->cableContainer->releaseIncompleteCable();
if (cw->isComplete()) {
app()->scene->rackWidget->cableContainer->addCable(cw);

// history::CableAdd
history::CableAdd *h = new history::CableAdd;
h->setCable(cw);
app()->history->push(h);
}
else {
delete cw;
@@ -119,9 +135,9 @@ void PortWidget::onDragDrop(const event::DragDrop &e) {
if (cw) {
cw->hoveredOutputPort = cw->hoveredInputPort = NULL;
if (type == OUTPUT)
cw->setOutputPort(this);
cw->setOutput(this);
else
cw->setInputPort(this);
cw->setInput(this);
}
}



+ 42
- 0
src/history.cpp View File

@@ -1,6 +1,7 @@
#include "history.hpp"
#include "app.hpp"
#include "app/Scene.hpp"
#include "engine/Cable.hpp"


namespace rack {
@@ -109,6 +110,47 @@ void ParamChange::redo() {
}


void CableAdd::setCable(CableWidget *cw) {
assert(cw->cable);
assert(cw->cable->id > 0);
cableId = cw->cable->id;
assert(cw->cable->outputModule);
outputModuleId = cw->cable->outputModule->id;
outputId = cw->cable->outputId;
assert(cw->cable->inputModule);
inputModuleId = cw->cable->inputModule->id;
inputId = cw->cable->inputId;
color = cw->color;
}

void CableAdd::undo() {
CableWidget *cw = app()->scene->rackWidget->cableContainer->getCable(cableId);
app()->scene->rackWidget->cableContainer->removeCable(cw);
delete cw;
}

void CableAdd::redo() {
CableWidget *cw = new CableWidget;
cw->cable->id = cableId;

ModuleWidget *outputModule = app()->scene->rackWidget->getModule(outputModuleId);
assert(outputModule);
PortWidget *outputPort = outputModule->getOutput(outputId);
assert(outputPort);
cw->setOutput(outputPort);

ModuleWidget *inputModule = app()->scene->rackWidget->getModule(inputModuleId);
assert(inputModule);
PortWidget *inputPort = inputModule->getInput(inputId);
assert(inputPort);
cw->setInput(inputPort);

cw->color = color;

app()->scene->rackWidget->cableContainer->addCable(cw);
}


State::~State() {
for (Action *action : actions) {
delete action;


Loading…
Cancel
Save