@@ -62,8 +62,8 @@ struct ModuleWidget : OpaqueWidget { | |||||
/** Serializes/unserializes the module state */ | /** Serializes/unserializes the module state */ | ||||
void copyClipboard(); | void copyClipboard(); | ||||
void pasteClipboard(); | |||||
void load(std::string filename); | |||||
void pasteClipboardAction(); | |||||
void loadAction(std::string filename); | |||||
void save(std::string filename); | void save(std::string filename); | ||||
void loadDialog(); | void loadDialog(); | ||||
void saveDialog(); | void saveDialog(); | ||||
@@ -72,18 +72,20 @@ struct ModuleWidget : OpaqueWidget { | |||||
Called when the user clicks Disconnect Cables in the context menu. | Called when the user clicks Disconnect Cables in the context menu. | ||||
*/ | */ | ||||
void disconnect(); | void disconnect(); | ||||
/** Resets the parameters of the module and calls the Module's randomize(). | /** Resets the parameters of the module and calls the Module's randomize(). | ||||
Called when the user clicks Initialize in the context menu. | Called when the user clicks Initialize in the context menu. | ||||
*/ | */ | ||||
void reset(); | |||||
void resetAction(); | |||||
/** Randomizes the parameters of the module and calls the Module's randomize(). | /** Randomizes the parameters of the module and calls the Module's randomize(). | ||||
Called when the user clicks Randomize in the context menu. | Called when the user clicks Randomize in the context menu. | ||||
*/ | */ | ||||
void randomize(); | |||||
void removeAction(); | |||||
void bypassAction(); | |||||
void randomizeAction(); | |||||
void disconnectAction(); | |||||
void cloneAction(); | void cloneAction(); | ||||
void bypassAction(); | |||||
/** Deletes `this` */ | |||||
void removeAction(); | |||||
void createContextMenu(); | void createContextMenu(); | ||||
/** Override to add context menu entries to your subclass. | /** Override to add context menu entries to your subclass. | ||||
It is recommended to add a blank MenuEntry first for spacing. | It is recommended to add a blank MenuEntry first for spacing. | ||||
@@ -21,8 +21,10 @@ struct PortWidget : OpaqueWidget { | |||||
PortWidget(); | PortWidget(); | ||||
~PortWidget(); | ~PortWidget(); | ||||
void step() override; | void step() override; | ||||
void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
void onButton(const event::Button &e) override; | void onButton(const event::Button &e) override; | ||||
void onDragStart(const event::DragStart &e) override; | void onDragStart(const event::DragStart &e) override; | ||||
void onDragEnd(const event::DragEnd &e) override; | void onDragEnd(const event::DragEnd &e) override; | ||||
@@ -25,6 +25,7 @@ struct RackWidget : OpaqueWidget { | |||||
void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
void onHover(const event::Hover &e) override; | void onHover(const event::Hover &e) override; | ||||
void onHoverKey(const event::HoverKey &e) override; | |||||
void onDragHover(const event::DragHover &e) override; | void onDragHover(const event::DragHover &e) override; | ||||
void onButton(const event::Button &e) override; | void onButton(const event::Button &e) override; | ||||
void onZoom(const event::Zoom &e) override; | void onZoom(const event::Zoom &e) override; | ||||
@@ -33,7 +34,7 @@ struct RackWidget : OpaqueWidget { | |||||
void clear(); | void clear(); | ||||
json_t *toJson(); | json_t *toJson(); | ||||
void fromJson(json_t *rootJ); | void fromJson(json_t *rootJ); | ||||
void pastePresetClipboard(); | |||||
void pastePresetClipboardAction(); | |||||
// Module methods | // Module methods | ||||
@@ -67,6 +68,8 @@ struct RackWidget : OpaqueWidget { | |||||
/** Returns the most recently added complete 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 *getTopCable(PortWidget *port); | ||||
CableWidget *getCable(int cableId); | CableWidget *getCable(int cableId); | ||||
/** Returns all cables attached to port, complete or not */ | |||||
std::list<CableWidget*> getCablesOnPort(PortWidget *port); | |||||
}; | }; | ||||
@@ -83,6 +83,15 @@ struct ModuleBypass : ModuleAction { | |||||
}; | }; | ||||
struct ModuleChange : ModuleAction { | |||||
json_t *oldModuleJ; | |||||
json_t *newModuleJ; | |||||
~ModuleChange(); | |||||
void undo() override; | |||||
void redo() override; | |||||
}; | |||||
struct ParamChange : ModuleAction { | struct ParamChange : ModuleAction { | ||||
int paramId; | int paramId; | ||||
float oldValue; | float oldValue; | ||||
@@ -22,7 +22,7 @@ struct ModuleDisconnectItem : MenuItem { | |||||
rightText = WINDOW_MOD_CTRL_NAME "+U"; | rightText = WINDOW_MOD_CTRL_NAME "+U"; | ||||
} | } | ||||
void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
moduleWidget->disconnect(); | |||||
moduleWidget->disconnectAction(); | |||||
} | } | ||||
}; | }; | ||||
@@ -33,7 +33,7 @@ struct ModuleResetItem : MenuItem { | |||||
rightText = WINDOW_MOD_CTRL_NAME "+I"; | rightText = WINDOW_MOD_CTRL_NAME "+I"; | ||||
} | } | ||||
void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
moduleWidget->reset(); | |||||
moduleWidget->resetAction(); | |||||
} | } | ||||
}; | }; | ||||
@@ -44,7 +44,7 @@ struct ModuleRandomizeItem : MenuItem { | |||||
rightText = WINDOW_MOD_CTRL_NAME "+R"; | rightText = WINDOW_MOD_CTRL_NAME "+R"; | ||||
} | } | ||||
void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
moduleWidget->randomize(); | |||||
moduleWidget->randomizeAction(); | |||||
} | } | ||||
}; | }; | ||||
@@ -66,7 +66,7 @@ struct ModulePasteItem : MenuItem { | |||||
rightText = WINDOW_MOD_CTRL_NAME "+V"; | rightText = WINDOW_MOD_CTRL_NAME "+V"; | ||||
} | } | ||||
void onAction(const event::Action &e) override { | void onAction(const event::Action &e) override { | ||||
moduleWidget->pasteClipboard(); | |||||
moduleWidget->pasteClipboardAction(); | |||||
} | } | ||||
}; | }; | ||||
@@ -214,13 +214,13 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { | |||||
switch (e.key) { | switch (e.key) { | ||||
case GLFW_KEY_I: { | case GLFW_KEY_I: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
reset(); | |||||
resetAction(); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
} break; | } break; | ||||
case GLFW_KEY_R: { | case GLFW_KEY_R: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
randomize(); | |||||
randomizeAction(); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
} break; | } break; | ||||
@@ -232,18 +232,19 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { | |||||
} break; | } break; | ||||
case GLFW_KEY_V: { | case GLFW_KEY_V: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
pasteClipboard(); | |||||
pasteClipboardAction(); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
} break; | } break; | ||||
case GLFW_KEY_D: { | case GLFW_KEY_D: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
cloneAction(); | cloneAction(); | ||||
e.consume(this); | |||||
} | } | ||||
} break; | } break; | ||||
case GLFW_KEY_U: { | case GLFW_KEY_U: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
disconnect(); | |||||
disconnectAction(); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
} break; | } break; | ||||
@@ -267,7 +268,7 @@ void ModuleWidget::onDragStart(const event::DragStart &e) { | |||||
void ModuleWidget::onDragEnd(const event::DragEnd &e) { | void ModuleWidget::onDragEnd(const event::DragEnd &e) { | ||||
if (!box.pos.isEqual(oldPos)) { | if (!box.pos.isEqual(oldPos)) { | ||||
// Push ModuleMove history action | |||||
// history::ModuleMove | |||||
history::ModuleMove *h = new history::ModuleMove; | history::ModuleMove *h = new history::ModuleMove; | ||||
h->moduleId = module->id; | h->moduleId = module->id; | ||||
h->oldPos = oldPos; | h->oldPos = oldPos; | ||||
@@ -412,7 +413,7 @@ void ModuleWidget::copyClipboard() { | |||||
glfwSetClipboardString(app()->window->win, moduleJson); | glfwSetClipboardString(app()->window->win, moduleJson); | ||||
} | } | ||||
void ModuleWidget::pasteClipboard() { | |||||
void ModuleWidget::pasteClipboardAction() { | |||||
const char *moduleJson = glfwGetClipboardString(app()->window->win); | const char *moduleJson = glfwGetClipboardString(app()->window->win); | ||||
if (!moduleJson) { | if (!moduleJson) { | ||||
WARN("Could not get text from clipboard."); | WARN("Could not get text from clipboard."); | ||||
@@ -429,10 +430,18 @@ void ModuleWidget::pasteClipboard() { | |||||
json_decref(moduleJ); | json_decref(moduleJ); | ||||
}); | }); | ||||
// history::ModuleChange | |||||
history::ModuleChange *h = new history::ModuleChange; | |||||
h->moduleId = module->id; | |||||
h->oldModuleJ = toJson(); | |||||
fromJson(moduleJ); | fromJson(moduleJ); | ||||
h->newModuleJ = toJson(); | |||||
app()->history->push(h); | |||||
} | } | ||||
void ModuleWidget::load(std::string filename) { | |||||
void ModuleWidget::loadAction(std::string filename) { | |||||
INFO("Loading preset %s", filename.c_str()); | INFO("Loading preset %s", filename.c_str()); | ||||
FILE *file = fopen(filename.c_str(), "r"); | FILE *file = fopen(filename.c_str(), "r"); | ||||
@@ -455,7 +464,15 @@ void ModuleWidget::load(std::string filename) { | |||||
json_decref(moduleJ); | json_decref(moduleJ); | ||||
}); | }); | ||||
// history::ModuleChange | |||||
history::ModuleChange *h = new history::ModuleChange; | |||||
h->moduleId = module->id; | |||||
h->oldModuleJ = toJson(); | |||||
fromJson(moduleJ); | fromJson(moduleJ); | ||||
h->newModuleJ = toJson(); | |||||
app()->history->push(h); | |||||
} | } | ||||
void ModuleWidget::save(std::string filename) { | void ModuleWidget::save(std::string filename) { | ||||
@@ -496,7 +513,7 @@ void ModuleWidget::loadDialog() { | |||||
free(path); | free(path); | ||||
}); | }); | ||||
load(path); | |||||
loadAction(path); | |||||
} | } | ||||
void ModuleWidget::saveDialog() { | void ModuleWidget::saveDialog() { | ||||
@@ -535,39 +552,68 @@ void ModuleWidget::disconnect() { | |||||
} | } | ||||
} | } | ||||
void ModuleWidget::reset() { | |||||
if (module) { | |||||
app()->engine->resetModule(module); | |||||
} | |||||
} | |||||
void ModuleWidget::resetAction() { | |||||
assert(module); | |||||
void ModuleWidget::randomize() { | |||||
if (module) { | |||||
app()->engine->randomizeModule(module); | |||||
} | |||||
// history::ModuleChange | |||||
history::ModuleChange *h = new history::ModuleChange; | |||||
h->moduleId = module->id; | |||||
h->oldModuleJ = toJson(); | |||||
app()->engine->resetModule(module); | |||||
h->newModuleJ = toJson(); | |||||
app()->history->push(h); | |||||
} | } | ||||
void ModuleWidget::removeAction() { | |||||
history::ComplexAction *complexAction = new history::ComplexAction; | |||||
void ModuleWidget::randomizeAction() { | |||||
assert(module); | |||||
// Push ModuleRemove history action | |||||
history::ModuleRemove *moduleRemove = new history::ModuleRemove; | |||||
moduleRemove->setModule(this); | |||||
complexAction->push(moduleRemove); | |||||
// history::ModuleChange | |||||
history::ModuleChange *h = new history::ModuleChange; | |||||
h->moduleId = module->id; | |||||
h->oldModuleJ = toJson(); | |||||
app()->history->push(complexAction); | |||||
app()->engine->randomizeModule(module); | |||||
app()->scene->rackWidget->removeModule(this); | |||||
delete this; | |||||
h->newModuleJ = toJson(); | |||||
app()->history->push(h); | |||||
} | } | ||||
void ModuleWidget::bypassAction() { | |||||
// Push ModuleBypass history action | |||||
history::ModuleBypass *h = new history::ModuleBypass; | |||||
h->moduleId = module->id; | |||||
h->bypass = !module->bypass; | |||||
app()->history->push(h); | |||||
h->redo(); | |||||
static void disconnectActions(ModuleWidget *mw, history::ComplexAction *complexAction) { | |||||
// Add CableRemove action for all cables attached to outputs | |||||
for (PortWidget* output : mw->outputs) { | |||||
for (CableWidget *cw : app()->scene->rackWidget->getCablesOnPort(output)) { | |||||
if (!cw->isComplete()) | |||||
continue; | |||||
// history::CableRemove | |||||
history::CableRemove *h = new history::CableRemove; | |||||
h->setCable(cw); | |||||
complexAction->push(h); | |||||
} | |||||
} | |||||
// Add CableRemove action for all cables attached to inputs | |||||
for (PortWidget* input : mw->inputs) { | |||||
for (CableWidget *cw : app()->scene->rackWidget->getCablesOnPort(input)) { | |||||
if (!cw->isComplete()) | |||||
continue; | |||||
// Avoid creating duplicate actions for self-patched cables | |||||
if (cw->outputPort->module == mw->module) | |||||
continue; | |||||
// history::CableRemove | |||||
history::CableRemove *h = new history::CableRemove; | |||||
h->setCable(cw); | |||||
complexAction->push(h); | |||||
} | |||||
} | |||||
} | |||||
void ModuleWidget::disconnectAction() { | |||||
history::ComplexAction *complexAction = new history::ComplexAction; | |||||
disconnectActions(this, complexAction); | |||||
app()->history->push(complexAction); | |||||
disconnect(); | |||||
} | } | ||||
void ModuleWidget::cloneAction() { | void ModuleWidget::cloneAction() { | ||||
@@ -580,12 +626,38 @@ void ModuleWidget::cloneAction() { | |||||
app()->scene->rackWidget->addModuleAtMouse(clonedModuleWidget); | app()->scene->rackWidget->addModuleAtMouse(clonedModuleWidget); | ||||
// Push ModuleAdd history action | |||||
// history::ModuleAdd | |||||
history::ModuleAdd *h = new history::ModuleAdd; | history::ModuleAdd *h = new history::ModuleAdd; | ||||
h->setModule(clonedModuleWidget); | h->setModule(clonedModuleWidget); | ||||
app()->history->push(h); | app()->history->push(h); | ||||
} | } | ||||
void ModuleWidget::bypassAction() { | |||||
assert(module); | |||||
// history::ModuleBypass | |||||
history::ModuleBypass *h = new history::ModuleBypass; | |||||
h->moduleId = module->id; | |||||
h->bypass = !module->bypass; | |||||
app()->history->push(h); | |||||
h->redo(); | |||||
} | |||||
void ModuleWidget::removeAction() { | |||||
history::ComplexAction *complexAction = new history::ComplexAction; | |||||
disconnectActions(this, complexAction); | |||||
// history::ModuleRemove | |||||
history::ModuleRemove *moduleRemove = new history::ModuleRemove; | |||||
moduleRemove->setModule(this); | |||||
complexAction->push(moduleRemove); | |||||
app()->history->push(complexAction); | |||||
// This disconnects cables, removes the module, and transfers ownership to caller | |||||
app()->scene->rackWidget->removeModule(this); | |||||
delete this; | |||||
} | |||||
void ModuleWidget::createContextMenu() { | void ModuleWidget::createContextMenu() { | ||||
Menu *menu = createMenu(); | Menu *menu = createMenu(); | ||||
assert(model); | assert(model); | ||||
@@ -108,8 +108,6 @@ void PortWidget::onDragStart(const event::DragStart &e) { | |||||
} | } | ||||
void PortWidget::onDragEnd(const event::DragEnd &e) { | void PortWidget::onDragEnd(const event::DragEnd &e) { | ||||
// FIXME | |||||
// If the source PortWidget is deleted, this will be called, removing the cable | |||||
CableWidget *cw = app()->scene->rackWidget->releaseIncompleteCable(); | CableWidget *cw = app()->scene->rackWidget->releaseIncompleteCable(); | ||||
if (cw->isComplete()) { | if (cw->isComplete()) { | ||||
app()->scene->rackWidget->addCable(cw); | app()->scene->rackWidget->addCable(cw); | ||||
@@ -148,6 +148,22 @@ void RackWidget::onHover(const event::Hover &e) { | |||||
mousePos = e.pos; | mousePos = e.pos; | ||||
} | } | ||||
void RackWidget::onHoverKey(const event::HoverKey &e) { | |||||
OpaqueWidget::onHoverKey(e); | |||||
if (e.getConsumed() != this) | |||||
return; | |||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | |||||
switch (e.key) { | |||||
case GLFW_KEY_V: { | |||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
pastePresetClipboardAction(); | |||||
} | |||||
} break; | |||||
} | |||||
} | |||||
} | |||||
void RackWidget::onDragHover(const event::DragHover &e) { | void RackWidget::onDragHover(const event::DragHover &e) { | ||||
OpaqueWidget::onDragHover(e); | OpaqueWidget::onDragHover(e); | ||||
mousePos = e.pos; | mousePos = e.pos; | ||||
@@ -287,7 +303,7 @@ void RackWidget::fromJson(json_t *rootJ) { | |||||
} | } | ||||
} | } | ||||
void RackWidget::pastePresetClipboard() { | |||||
void RackWidget::pastePresetClipboardAction() { | |||||
const char *moduleJson = glfwGetClipboardString(app()->window->win); | const char *moduleJson = glfwGetClipboardString(app()->window->win); | ||||
if (!moduleJson) { | if (!moduleJson) { | ||||
WARN("Could not get text from clipboard."); | WARN("Could not get text from clipboard."); | ||||
@@ -297,13 +313,14 @@ void RackWidget::pastePresetClipboard() { | |||||
json_error_t error; | json_error_t error; | ||||
json_t *moduleJ = json_loads(moduleJson, 0, &error); | json_t *moduleJ = json_loads(moduleJson, 0, &error); | ||||
if (moduleJ) { | if (moduleJ) { | ||||
ModuleWidget *moduleWidget = moduleFromJson(moduleJ); | |||||
ModuleWidget *mw = moduleFromJson(moduleJ); | |||||
json_decref(moduleJ); | json_decref(moduleJ); | ||||
addModule(moduleWidget); | |||||
// Set moduleWidget position | |||||
math::Rect newBox = moduleWidget->box; | |||||
newBox.pos = mousePos.minus(newBox.size.div(2)); | |||||
requestModuleBoxNearest(moduleWidget, newBox); | |||||
addModuleAtMouse(mw); | |||||
// history::ModuleAdd | |||||
history::ModuleAdd *h = new history::ModuleAdd; | |||||
h->setModule(mw); | |||||
app()->history->push(h); | |||||
} | } | ||||
else { | else { | ||||
WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | ||||
@@ -349,7 +366,9 @@ bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect requestedBox) { | |||||
// Check intersection with other modules | // Check intersection with other modules | ||||
for (Widget *m2 : moduleContainer->children) { | for (Widget *m2 : moduleContainer->children) { | ||||
if (m == m2) continue; | |||||
// Don't intersect with self | |||||
if (m == m2) | |||||
continue; | |||||
if (requestedBox.intersects(m2->box)) { | if (requestedBox.intersects(m2->box)) { | ||||
return false; | return false; | ||||
} | } | ||||
@@ -401,8 +420,10 @@ void RackWidget::clearCables() { | |||||
for (Widget *w : cableContainer->children) { | for (Widget *w : cableContainer->children) { | ||||
CableWidget *cw = dynamic_cast<CableWidget*>(w); | CableWidget *cw = dynamic_cast<CableWidget*>(w); | ||||
assert(cw); | assert(cw); | ||||
if (cw != incompleteCable) | |||||
app()->engine->removeCable(cw->cable); | |||||
if (!cw->isComplete()) | |||||
continue; | |||||
app()->engine->removeCable(cw->cable); | |||||
} | } | ||||
incompleteCable = NULL; | incompleteCable = NULL; | ||||
cableContainer->clearChildren(); | cableContainer->clearChildren(); | ||||
@@ -415,7 +436,7 @@ void RackWidget::clearCablesAction() { | |||||
for (Widget *w : cableContainer->children) { | for (Widget *w : cableContainer->children) { | ||||
CableWidget *cw = dynamic_cast<CableWidget*>(w); | CableWidget *cw = dynamic_cast<CableWidget*>(w); | ||||
assert(cw); | assert(cw); | ||||
if (cw == incompleteCable) | |||||
if (!cw->isComplete()) | |||||
continue; | continue; | ||||
// history::CableRemove | // history::CableRemove | ||||
@@ -429,23 +450,16 @@ void RackWidget::clearCablesAction() { | |||||
} | } | ||||
void RackWidget::clearCablesOnPort(PortWidget *port) { | void RackWidget::clearCablesOnPort(PortWidget *port) { | ||||
assert(port); | |||||
std::list<Widget*> childrenCopy = cableContainer->children; | |||||
for (Widget *w : childrenCopy) { | |||||
CableWidget *cw = dynamic_cast<CableWidget*>(w); | |||||
assert(cw); | |||||
for (CableWidget *cw : getCablesOnPort(port)) { | |||||
// Check if cable is connected to port | // Check if cable is connected to port | ||||
if (cw->inputPort == port || cw->outputPort == port) { | |||||
if (cw == incompleteCable) { | |||||
incompleteCable = NULL; | |||||
cableContainer->removeChild(cw); | |||||
} | |||||
else { | |||||
removeCable(cw); | |||||
} | |||||
delete cw; | |||||
if (cw == incompleteCable) { | |||||
incompleteCable = NULL; | |||||
cableContainer->removeChild(cw); | |||||
} | |||||
else { | |||||
removeCable(cw); | |||||
} | } | ||||
delete cw; | |||||
} | } | ||||
} | } | ||||
@@ -503,5 +517,18 @@ CableWidget *RackWidget::getCable(int cableId) { | |||||
return NULL; | return NULL; | ||||
} | } | ||||
std::list<CableWidget*> RackWidget::getCablesOnPort(PortWidget *port) { | |||||
assert(port); | |||||
std::list<CableWidget*> cables; | |||||
for (Widget *w : cableContainer->children) { | |||||
CableWidget *cw = dynamic_cast<CableWidget*>(w); | |||||
assert(cw); | |||||
if (cw->inputPort == port || cw->outputPort == port) { | |||||
cables.push_back(cw); | |||||
} | |||||
} | |||||
return cables; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -124,12 +124,6 @@ void Scene::onHoverKey(const event::HoverKey &e) { | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
} break; | } break; | ||||
case GLFW_KEY_V: { | |||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||||
rackWidget->pastePresetClipboard(); | |||||
e.consume(this); | |||||
} | |||||
} break; | |||||
case GLFW_KEY_Z: { | case GLFW_KEY_Z: { | ||||
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
app()->history->undo(); | app()->history->undo(); | ||||
@@ -50,8 +50,6 @@ struct Engine::Internal { | |||||
float sampleTime; | float sampleTime; | ||||
float sampleRateRequested; | float sampleRateRequested; | ||||
Module *resetModule = NULL; | |||||
Module *randomizeModule = NULL; | |||||
int nextModuleId = 1; | int nextModuleId = 1; | ||||
int nextCableId = 1; | int nextCableId = 1; | ||||
@@ -93,16 +91,6 @@ static void Engine_step(Engine *engine) { | |||||
} | } | ||||
} | } | ||||
// Events | |||||
if (engine->internal->resetModule) { | |||||
engine->internal->resetModule->reset(); | |||||
engine->internal->resetModule = NULL; | |||||
} | |||||
if (engine->internal->randomizeModule) { | |||||
engine->internal->randomizeModule->randomize(); | |||||
engine->internal->randomizeModule = NULL; | |||||
} | |||||
// Param smoothing | // Param smoothing | ||||
{ | { | ||||
Module *smoothModule = engine->internal->smoothModule; | Module *smoothModule = engine->internal->smoothModule; | ||||
@@ -273,11 +261,17 @@ void Engine::removeModule(Module *module) { | |||||
} | } | ||||
void Engine::resetModule(Module *module) { | void Engine::resetModule(Module *module) { | ||||
internal->resetModule = module; | |||||
assert(module); | |||||
VIPLock vipLock(internal->vipMutex); | |||||
std::lock_guard<std::mutex> lock(internal->mutex); | |||||
module->reset(); | |||||
} | } | ||||
void Engine::randomizeModule(Module *module) { | void Engine::randomizeModule(Module *module) { | ||||
internal->randomizeModule = module; | |||||
assert(module); | |||||
VIPLock vipLock(internal->vipMutex); | |||||
std::lock_guard<std::mutex> lock(internal->mutex); | |||||
module->randomize(); | |||||
} | } | ||||
static void Engine_updateActive(Engine *engine) { | static void Engine_updateActive(Engine *engine) { | ||||
@@ -344,7 +338,7 @@ void Engine::removeCable(Cable *cable) { | |||||
} | } | ||||
void Engine::setParam(Module *module, int paramId, float value) { | void Engine::setParam(Module *module, int paramId, float value) { | ||||
// TODO Make thread safe | |||||
// TODO Does this need to be thread-safe? | |||||
module->params[paramId].value = value; | module->params[paramId].value = value; | ||||
} | } | ||||
@@ -90,6 +90,24 @@ void ModuleBypass::redo() { | |||||
} | } | ||||
ModuleChange::~ModuleChange() { | |||||
json_decref(oldModuleJ); | |||||
json_decref(newModuleJ); | |||||
} | |||||
void ModuleChange::undo() { | |||||
ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | |||||
assert(mw); | |||||
mw->fromJson(oldModuleJ); | |||||
} | |||||
void ModuleChange::redo() { | |||||
ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | |||||
assert(mw); | |||||
mw->fromJson(newModuleJ); | |||||
} | |||||
void ParamChange::undo() { | void ParamChange::undo() { | ||||
ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | ||||
assert(mw); | assert(mw); | ||||