Browse Source

Add history actions: ModuleAdd, ModuleRemove, ModuleMove, ParamChange, WireAdd, WireRemove, WireMove

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
c59b9ba67d
19 changed files with 359 additions and 74 deletions
  1. +1
    -0
      include/app/Knob.hpp
  2. +1
    -0
      include/app/ModuleWidget.hpp
  3. +3
    -2
      include/app/ParamWidget.hpp
  4. +2
    -1
      include/app/RackWidget.hpp
  5. +2
    -2
      include/helpers.hpp
  6. +83
    -2
      include/history.hpp
  7. +23
    -4
      src/app/Knob.cpp
  8. +10
    -2
      src/app/ModuleBrowser.cpp
  9. +25
    -14
      src/app/ModuleWidget.cpp
  10. +4
    -4
      src/app/MomentarySwitch.cpp
  11. +43
    -20
      src/app/ParamWidget.cpp
  12. +38
    -5
      src/app/RackWidget.cpp
  13. +4
    -4
      src/app/SVGKnob.cpp
  14. +2
    -2
      src/app/SVGSlider.cpp
  15. +2
    -2
      src/app/SVGSwitch.cpp
  16. +1
    -1
      src/app/Scene.cpp
  17. +19
    -4
      src/app/ToggleSwitch.cpp
  18. +24
    -5
      src/engine/Engine.cpp
  19. +72
    -0
      src/history.cpp

+ 1
- 0
include/app/Knob.hpp View File

@@ -11,6 +11,7 @@ namespace rack {
struct Knob : ParamWidget {
/** Multiplier for mouse movement to adjust knob value */
float speed = 1.0;
float oldValue = 0.f;

void onButton(const event::Button &e) override;
void onDragStart(const event::DragStart &e) override;


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

@@ -22,6 +22,7 @@ struct ModuleWidget : OpaqueWidget {
std::vector<PortWidget*> outputs;
/** For RackWidget dragging */
math::Vec dragPos;
math::Vec oldPos;

ModuleWidget(Module *module);
~ModuleWidget();


+ 3
- 2
include/app/ParamWidget.hpp View File

@@ -2,14 +2,15 @@
#include "app/common.hpp"
#include "widgets/OpaqueWidget.hpp"
#include "ui/Tooltip.hpp"
#include "ui/Quantity.hpp"
#include "app/ParamQuantity.hpp"
#include "history.hpp"


namespace rack {


struct ParamWidget : OpaqueWidget {
Quantity *quantity = NULL;
ParamQuantity *paramQuantity = NULL;
float dirtyValue = NAN;
Tooltip *tooltip = NULL;



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

@@ -44,12 +44,13 @@ struct RackWidget : OpaqueWidget {
void addModule(ModuleWidget *m);
void addModuleAtMouse(ModuleWidget *m);
/** Removes the module and transfers ownership to the caller */
void deleteModule(ModuleWidget *m);
void removeModule(ModuleWidget *m);
void cloneModule(ModuleWidget *m);
/** Sets a module's box if non-colliding. Returns true if set */
bool requestModuleBox(ModuleWidget *m, math::Rect box);
/** Moves a module to the closest non-colliding position */
bool requestModuleBoxNearest(ModuleWidget *m, math::Rect box);
ModuleWidget *getModule(int moduleId);

void step() override;
void draw(NVGcontext *vg) override;


+ 2
- 2
include/helpers.hpp View File

@@ -60,7 +60,7 @@ TParamWidget *createParam(math::Vec pos, Module *module, int paramId) {
ParamQuantity *q = new ParamQuantity;
q->module = module;
q->paramId = paramId;
o->quantity = q;
o->paramQuantity = q;
return o;
}

@@ -71,7 +71,7 @@ TParamWidget *createParamCentered(math::Vec pos, Module *module, int paramId) {
ParamQuantity *q = new ParamQuantity;
q->module = module;
q->paramId = paramId;
o->quantity = q;
o->paramQuantity = q;
return o;
}



+ 83
- 2
include/history.hpp View File

@@ -3,6 +3,7 @@
#include "math.hpp"
#include "plugin/Model.hpp"
#include <vector>
#include <jansson.h>


namespace rack {
@@ -16,15 +17,95 @@ struct Action {
};


struct ModuleAdd : Action {
Model *model;
/** An action operating on a module
Subclass this to create your own custom actions for your module.
*/
struct ModuleAction : Action {
int moduleId;
};


struct ModuleAdd : ModuleAction {
Model *model;
math::Vec pos;
void undo() override;
void redo() override;
};


struct ModuleRemove : ModuleAction {
Model *model;
math::Vec pos;
json_t *moduleJ;

struct WireInfo {
int wireId;
int outputModuleId;
int outputId;
int inputModuleId;
int inputId;
};
std::vector<WireInfo> wireInfos;

~ModuleRemove();
void undo() override;
void redo() override;
};


struct ModuleMove : ModuleAction {
math::Vec oldPos;
math::Vec newPos;
void undo() override;
void redo() override;
};


struct ParamChange : ModuleAction {
int paramId;
float oldValue;
float newValue;
void undo() override;
void redo() override;
};


struct WireAdd : Action {
int wireId;
int outputModuleId;
int outputId;
int inputModuleId;
int inputId;
void undo() override;
void redo() override;
};


struct WireRemove : Action {
int wireId;
int outputModuleId;
int outputId;
int inputModuleId;
int inputId;
void undo() override;
void redo() override;
};


struct WireMove : Action {
int wireId;
int oldOutputModuleId;
int oldOutputId;
int oldInputModuleId;
int oldInputId;
int newOutputModuleId;
int newOutputId;
int newInputModuleId;
int newInputId;
void undo() override;
void redo() override;
};


struct State {
std::vector<Action*> actions;


+ 23
- 4
src/app/Knob.cpp View File

@@ -1,4 +1,7 @@
#include "app/Knob.hpp"
#include "app.hpp"
#include "app/Scene.hpp"
#include "history.hpp"


namespace rack {
@@ -17,18 +20,34 @@ void Knob::onButton(const event::Button &e) {
}

void Knob::onDragStart(const event::DragStart &e) {
if (paramQuantity)
oldValue = paramQuantity->getValue();

app()->window->cursorLock();
}

void Knob::onDragEnd(const event::DragEnd &e) {
app()->window->cursorUnlock();

if (paramQuantity) {
float newValue = paramQuantity->getValue();
if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramQuantity->module->id;
h->paramId = paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}
}
}

void Knob::onDragMove(const event::DragMove &e) {
if (quantity) {
if (paramQuantity) {
float range;
if (quantity->isBounded()) {
range = quantity->getRange();
if (paramQuantity->isBounded()) {
range = paramQuantity->getRange();
}
else {
// Continuous encoders scale as if their limits are +/-1
@@ -39,7 +58,7 @@ void Knob::onDragMove(const event::DragMove &e) {
// Drag slower if Mod is held
if (app()->window->isModPressed())
delta /= 16.f;
quantity->moveValue(delta);
paramQuantity->moveValue(delta);
}

ParamWidget::onDragMove(e);


+ 10
- 2
src/app/ModuleBrowser.cpp View File

@@ -8,6 +8,7 @@
#include "app/Scene.hpp"
#include "plugin.hpp"
#include "app.hpp"
#include "history.hpp"

#include <set>
#include <algorithm>
@@ -78,12 +79,19 @@ struct ModuleBox : OpaqueWidget {
// Create module
ModuleWidget *moduleWidget = model->createModuleWidget();
assert(moduleWidget);
app()->scene->rackWidget->addModule(moduleWidget);
app()->scene->rackWidget->addModuleAtMouse(moduleWidget);
// This is a bit nonstandard/unsupported usage, but pretend the moduleWidget was clicked so it can be dragged in the RackWidget
e.consume(moduleWidget);
// e.consume(moduleWidget);
// Close Module Browser
ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
moduleBrowser->visible = false;

// Push ModuleAdd history action
history::ModuleAdd *h = new history::ModuleAdd;
h->model = moduleWidget->model;
h->moduleId = moduleWidget->module->id;
h->pos = moduleWidget->box.pos;
app()->history->push(h);
}
OpaqueWidget::onButton(e);
}


+ 25
- 14
src/app/ModuleWidget.cpp View File

@@ -7,6 +7,7 @@
#include "helpers.hpp"
#include "app.hpp"
#include "settings.hpp"
#include "history.hpp"

#include "osdialog.h"

@@ -15,23 +16,12 @@ namespace rack {


ModuleWidget::ModuleWidget(Module *module) {
if (module) {
app()->engine->addModule(module);
}
this->module = module;
}

ModuleWidget::~ModuleWidget() {
// HACK
// If we try to disconnect wires in the Module Browser (e.g. when Rack is closed while the Module Browser is open), app()->scene->rackWidget will be an invalid pointer.
// So only attempt to disconnect if the module is not NULL.
if (module)
disconnect();
// Remove and delete the Module instance
if (module) {
app()->engine->removeModule(module);
delete module;
module = NULL;
}
}

@@ -327,13 +317,26 @@ void ModuleWidget::drawShadow(NVGcontext *vg) {
nvgFill(vg);
}

static void ModuleWidget_removeAction(ModuleWidget *moduleWidget) {
// Push ModuleRemove history action
history::ModuleRemove *h = new history::ModuleRemove;
h->model = moduleWidget->model;
h->moduleId = moduleWidget->module->id;
h->pos = moduleWidget->box.pos;
h->moduleJ = moduleWidget->toJson();
app()->history->push(h);

app()->scene->rackWidget->removeModule(moduleWidget);
delete moduleWidget;
}

void ModuleWidget::onHover(const event::Hover &e) {
OpaqueWidget::onHover(e);

// Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget.
if (glfwGetKey(app()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(app()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
if (!app()->window->isModPressed() && !app()->window->isShiftPressed()) {
requestedDelete = true;
ModuleWidget_removeAction(this);
return;
}
}
@@ -401,10 +404,19 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) {
}

void ModuleWidget::onDragStart(const event::DragStart &e) {
oldPos = box.pos;
dragPos = app()->scene->rackWidget->lastMousePos.minus(box.pos);
}

void ModuleWidget::onDragEnd(const event::DragEnd &e) {
if (!box.pos.isEqual(oldPos)) {
// Push ModuleMove history action
history::ModuleMove *h = new history::ModuleMove;
h->moduleId = module->id;
h->oldPos = oldPos;
h->newPos = box.pos;
app()->history->push(h);
}
}

void ModuleWidget::onDragMove(const event::DragMove &e) {
@@ -526,8 +538,7 @@ struct ModuleDeleteItem : MenuItem {
rightText = "Backspace/Delete";
}
void onAction(const event::Action &e) override {
app()->scene->rackWidget->deleteModule(moduleWidget);
delete moduleWidget;
ModuleWidget_removeAction(moduleWidget);
}
};



+ 4
- 4
src/app/MomentarySwitch.cpp View File

@@ -5,14 +5,14 @@ namespace rack {


void MomentarySwitch::onDragStart(const event::DragStart &e) {
if (quantity) {
quantity->setMax();
if (paramQuantity) {
paramQuantity->setMax();
}
}

void MomentarySwitch::onDragEnd(const event::DragEnd &e) {
if (quantity) {
quantity->setMin();
if (paramQuantity) {
paramQuantity->setMin();
}
}



+ 43
- 20
src/app/ParamWidget.cpp View File

@@ -6,6 +6,7 @@
#include "app.hpp"
#include "settings.hpp"
#include "random.hpp"
#include "history.hpp"


namespace rack {
@@ -21,15 +22,27 @@ struct ParamField : TextField {

void setParamWidget(ParamWidget *paramWidget) {
this->paramWidget = paramWidget;
if (paramWidget->quantity)
text = paramWidget->quantity->getDisplayValueString();
if (paramWidget->paramQuantity)
text = paramWidget->paramQuantity->getDisplayValueString();
selectAll();
}

void onSelectKey(const event::SelectKey &e) override {
if (e.action == GLFW_PRESS && (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER)) {
if (paramWidget->quantity)
paramWidget->quantity->setDisplayValueString(text);
float oldValue = paramWidget->paramQuantity->getValue();
if (paramWidget->paramQuantity)
paramWidget->paramQuantity->setDisplayValueString(text);
float newValue = paramWidget->paramQuantity->getValue();

if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramWidget->paramQuantity->module->id;
h->paramId = paramWidget->paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}

MenuOverlay *overlay = getAncestorOfType<MenuOverlay>();
overlay->requestedDelete = true;
@@ -49,14 +62,14 @@ struct ParamField : TextField {


ParamWidget::~ParamWidget() {
if (quantity)
delete quantity;
if (paramQuantity)
delete paramQuantity;
}

void ParamWidget::step() {
if (quantity) {
float value = quantity->getValue();
// Trigger change event when quantity value changes
if (paramQuantity) {
float value = paramQuantity->getValue();
// Trigger change event when paramQuantity value changes
if (value != dirtyValue) {
dirtyValue = value;
event::Change eChange;
@@ -65,13 +78,10 @@ void ParamWidget::step() {
}

if (tooltip) {
// Quantity string
if (quantity) {
tooltip->text = quantity->getString();
}
// Param description
ParamQuantity *paramQuantity = dynamic_cast<ParamQuantity*>(quantity);
if (paramQuantity) {
// Quantity string
tooltip->text = paramQuantity->getString();
// Param description
std::string description = paramQuantity->getParam()->description;
if (!description.empty())
tooltip->text += "\n" + description;
@@ -86,18 +96,31 @@ void ParamWidget::step() {
void ParamWidget::fromJson(json_t *rootJ) {
json_t *valueJ = json_object_get(rootJ, "value");
if (valueJ) {
if (quantity)
quantity->setValue(json_number_value(valueJ));
if (paramQuantity)
paramQuantity->setValue(json_number_value(valueJ));
}
}

void ParamWidget::onButton(const event::Button &e) {
// Right click to reset
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && !(e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) {
if (quantity)
quantity->reset();
if (paramQuantity) {
float oldValue = paramQuantity->getValue();
paramQuantity->reset();
float newValue = paramQuantity->getValue();

if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramQuantity->module->id;
h->paramId = paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}
}
// Here's another way of doing it, but either works.
// dynamic_cast<ParamQuantity*>(quantity)->getParam()->reset();
// paramQuantity->getParam()->reset();
e.consume(this);
}



+ 38
- 5
src/app/RackWidget.cpp View File

@@ -9,6 +9,7 @@
#include "asset.hpp"
#include "system.hpp"
#include "plugin.hpp"
#include "engine/Engine.hpp"
#include "app.hpp"


@@ -53,12 +54,19 @@ RackWidget::RackWidget() {
}

RackWidget::~RackWidget() {
clear();
}

void RackWidget::clear() {
wireContainer->activeWire = NULL;
wireContainer->clearChildren();
moduleContainer->clearChildren();
// Remove ModuleWidgets
std::list<Widget*> widgets = moduleContainer->children;
for (Widget *w : widgets) {
ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
assert(moduleWidget);
removeModule(moduleWidget);
}

app()->scene->scrollWidget->offset = math::Vec(0, 0);
}
@@ -455,17 +463,32 @@ void RackWidget::pastePresetClipboard() {
}

void RackWidget::addModule(ModuleWidget *m) {
// Add module to ModuleContainer
assert(m);
assert(m->module);
moduleContainer->addChild(m);

// Add module to Engine
app()->engine->addModule(m->module);
}

void RackWidget::addModuleAtMouse(ModuleWidget *m) {
addModule(m);
assert(m);
// Move module nearest to the mouse position
m->box.pos = lastMousePos.minus(m->box.size.div(2));
requestModuleBoxNearest(m, m->box);
addModule(m);
}

void RackWidget::deleteModule(ModuleWidget *m) {
void RackWidget::removeModule(ModuleWidget *m) {
// Disconnect wires
m->disconnect();

// Remove module from Engine
assert(m->module);
app()->engine->removeModule(m->module);

// Remove module from ModuleContainer
moduleContainer->removeChild(m);
}

@@ -496,8 +519,8 @@ bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect box) {

bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, math::Rect box) {
// Create possible positions
int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
int x0 = std::round(box.pos.x / RACK_GRID_WIDTH);
int y0 = std::round(box.pos.y / RACK_GRID_HEIGHT);
std::vector<math::Vec> positions;
for (int y = std::max(0, y0 - 8); y < y0 + 8; y++) {
for (int x = std::max(0, x0 - 400); x < x0 + 400; x++) {
@@ -520,6 +543,16 @@ bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, math::Rect box) {
return false;
}

ModuleWidget *RackWidget::getModule(int moduleId) {
for (Widget *w : moduleContainer->children) {
ModuleWidget *moduleWidget = dynamic_cast<ModuleWidget*>(w);
assert(moduleWidget);
if (moduleWidget->module->id == moduleId)
return moduleWidget;
}
return NULL;
}

void RackWidget::step() {
// Expand size to fit modules
math::Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();


+ 4
- 4
src/app/SVGKnob.cpp View File

@@ -32,14 +32,14 @@ void SVGKnob::step() {

void SVGKnob::onChange(const event::Change &e) {
// Re-transform the TransformWidget
if (quantity) {
if (paramQuantity) {
float angle;
if (quantity->isBounded()) {
angle = math::rescale(quantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle);
if (paramQuantity->isBounded()) {
angle = math::rescale(paramQuantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle);
angle = std::fmod(angle, 2*M_PI);
}
else {
angle = math::rescale(quantity->getValue(), 0.f, 1.f, minAngle, maxAngle);
angle = math::rescale(paramQuantity->getValue(), 0.f, 1.f, minAngle, maxAngle);
}
tw->identity();
// Rotate SVG


+ 2
- 2
src/app/SVGSlider.cpp View File

@@ -28,9 +28,9 @@ void SVGSlider::step() {
}

void SVGSlider::onChange(const event::Change &e) {
if (quantity) {
if (paramQuantity) {
// Interpolate handle position
float v = quantity->getScaledValue();
float v = paramQuantity->getScaledValue();
handle->box.pos = math::Vec(
math::rescale(v, 0.f, 1.f, minHandlePos.x, maxHandlePos.x),
math::rescale(v, 0.f, 1.f, minHandlePos.y, maxHandlePos.y));


+ 2
- 2
src/app/SVGSwitch.cpp View File

@@ -25,8 +25,8 @@ void SVGSwitch::addFrame(std::shared_ptr<SVG> svg) {

void SVGSwitch::onChange(const event::Change &e) {
assert(frames.size() > 0);
if (quantity) {
int index = quantity->getScaledValue() * (frames.size() - 1);
if (paramQuantity) {
int index = paramQuantity->getScaledValue() * (frames.size() - 1);
index = math::clamp(index, 0, (int) frames.size() - 1);
sw->setSVG(frames[index]);
dirty = true;


+ 1
- 1
src/app/Scene.cpp View File

@@ -76,7 +76,7 @@ void Scene::draw(NVGcontext *vg) {
}

void Scene::onHoverKey(const event::HoverKey &e) {
if (e.action == GLFW_PRESS) {
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
switch (e.key) {
case GLFW_KEY_N: {
if ((e.mods & WINDOW_MOD) && !(e.mods & GLFW_MOD_SHIFT)) {


+ 19
- 4
src/app/ToggleSwitch.cpp View File

@@ -1,4 +1,7 @@
#include "app/ToggleSwitch.hpp"
#include "app.hpp"
#include "app/Scene.hpp"
#include "history.hpp"


namespace rack {
@@ -7,12 +10,24 @@ namespace rack {
void ToggleSwitch::onDragStart(const event::DragStart &e) {
// Cycle through values
// e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3.
if (quantity) {
if (quantity->isMax()) {
quantity->setMin();
if (paramQuantity) {
float oldValue = paramQuantity->getValue();
if (paramQuantity->isMax()) {
paramQuantity->setMin();
}
else {
quantity->setValue(std::floor(quantity->getValue() + 1));
paramQuantity->setValue(std::floor(paramQuantity->getValue() + 1));
}
float newValue = paramQuantity->getValue();

if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramQuantity->module->id;
h->paramId = paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}
}
}


+ 24
- 5
src/engine/Engine.cpp View File

@@ -230,12 +230,22 @@ void Engine::addModule(Module *module) {
assert(module);
VIPLock vipLock(internal->vipMutex);
std::lock_guard<std::mutex> lock(internal->mutex);
// Set ID
assert(module->id == 0);
module->id = internal->nextModuleId++;
// Check that the module is not already added
auto it = std::find(modules.begin(), modules.end(), module);
assert(it == modules.end());
// Set ID
if (module->id == 0) {
// Automatically assign ID
module->id = internal->nextModuleId++;
}
else {
// Manual ID
// Check that the ID is not already taken
for (Module *m : modules) {
assert(module->id != m->id);
}
}
// Add module
modules.push_back(module);
}

@@ -299,8 +309,17 @@ void Engine::addWire(Wire *wire) {
assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
}
// Set ID
assert(wire->id == 0);
wire->id = internal->nextWireId++;
if (wire->id == 0) {
// Automatically assign ID
wire->id = internal->nextWireId++;
}
else {
// Manual ID
// Check that the ID is not already taken
for (Wire *w : wires) {
assert(wire->id != w->id);
}
}
// Add the wire
wires.push_back(wire);
Engine_updateActive(this);


+ 72
- 0
src/history.cpp View File

@@ -1,10 +1,82 @@
#include "history.hpp"
#include "app.hpp"
#include "app/Scene.hpp"


namespace rack {
namespace history {


void ModuleAdd::undo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
app()->scene->rackWidget->removeModule(moduleWidget);
delete moduleWidget;
}

void ModuleAdd::redo() {
ModuleWidget *moduleWidget = model->createModuleWidget();
assert(moduleWidget);
assert(moduleWidget->module);
moduleWidget->module->id = moduleId;
moduleWidget->box.pos = pos;
app()->scene->rackWidget->addModule(moduleWidget);
}


ModuleRemove::~ModuleRemove() {
json_decref(moduleJ);
}

void ModuleRemove::undo() {
ModuleWidget *moduleWidget = model->createModuleWidget();
assert(moduleWidget);
assert(moduleWidget->module);
moduleWidget->module->id = moduleId;
moduleWidget->box.pos = pos;
moduleWidget->fromJson(moduleJ);
app()->scene->rackWidget->addModule(moduleWidget);

// Add wires
for (WireInfo &wireInfo : wireInfos) {
// TODO Add wire
}
}

void ModuleRemove::redo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
app()->scene->rackWidget->removeModule(moduleWidget);
delete moduleWidget;
}


void ModuleMove::undo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
moduleWidget->box.pos = oldPos;
}

void ModuleMove::redo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
moduleWidget->box.pos = newPos;
}


void ParamChange::undo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
moduleWidget->module->params[paramId].value = oldValue;
}

void ParamChange::redo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
moduleWidget->module->params[paramId].value = newValue;
}


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


Loading…
Cancel
Save