diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index a676a5ff..be8185ce 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -80,6 +80,7 @@ struct ModuleWidget : OpaqueWidget { void removeAction(); void bypassAction(); + void cloneAction(); void createContextMenu(); /** Override to add context menu entries to your subclass. It is recommended to add a blank MenuEntry first for spacing. diff --git a/include/app/RackWidget.hpp b/include/app/RackWidget.hpp index 70e33762..75b64010 100644 --- a/include/app/RackWidget.hpp +++ b/include/app/RackWidget.hpp @@ -45,7 +45,6 @@ struct RackWidget : OpaqueWidget { void addModuleAtMouse(ModuleWidget *m); /** Removes the module and transfers ownership to the caller */ 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 */ diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index a822eda6..64089859 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -97,7 +97,7 @@ struct ModuleCloneItem : MenuItem { rightText = WINDOW_MOD_CTRL_NAME "+D"; } void onAction(const event::Action &e) override { - app()->scene->rackWidget->cloneModule(moduleWidget); + moduleWidget->cloneAction(); } }; @@ -229,8 +229,7 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { } break; case GLFW_KEY_D: { if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { - app()->scene->rackWidget->cloneModule(this); - e.consume(this); + cloneAction(); } } break; case GLFW_KEY_U: { @@ -548,6 +547,24 @@ void ModuleWidget::bypassAction() { h->redo(); } +void ModuleWidget::cloneAction() { + ModuleWidget *clonedModuleWidget = model->createModuleWidget(); + assert(clonedModuleWidget); + // JSON serialization is the obvious way to do this + json_t *moduleJ = toJson(); + clonedModuleWidget->fromJson(moduleJ); + json_decref(moduleJ); + + app()->scene->rackWidget->addModuleAtMouse(clonedModuleWidget); + + // Push ModuleAdd history action + history::ModuleAdd *h = new history::ModuleAdd; + h->model = clonedModuleWidget->model; + h->moduleId = clonedModuleWidget->module->id; + h->pos = clonedModuleWidget->box.pos; + app()->history->push(h); +} + void ModuleWidget::createContextMenu() { Menu *menu = createMenu(); assert(model); diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 92d415ec..6215a328 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -495,17 +495,6 @@ void RackWidget::removeModule(ModuleWidget *m) { moduleContainer->removeChild(m); } -void RackWidget::cloneModule(ModuleWidget *m) { - // JSON serialization is the obvious way to do this - json_t *moduleJ = m->toJson(); - ModuleWidget *clonedModuleWidget = moduleFromJson(moduleJ); - json_decref(moduleJ); - addModule(clonedModuleWidget); - math::Rect clonedBox = clonedModuleWidget->box; - clonedBox.pos = m->box.pos; - requestModuleBoxNearest(clonedModuleWidget, clonedBox); -} - bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect box) { if (box.pos.x < 0 || box.pos.y < 0) return false;