From 5995391ef9f7f3e2671df7d1666e6b70d2494353 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 4 Aug 2021 01:55:08 -0400 Subject: [PATCH] Add basic module selection dragging. --- include/app/RackWidget.hpp | 1 + src/app/ModuleWidget.cpp | 22 ++++++++++----- src/app/RackWidget.cpp | 58 +++++++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/include/app/RackWidget.hpp b/include/app/RackWidget.hpp index c2beee26..b866ff90 100644 --- a/include/app/RackWidget.hpp +++ b/include/app/RackWidget.hpp @@ -78,6 +78,7 @@ struct RackWidget : widget::OpaqueWidget { void disconnectSelectedModulesAction(); void bypassSelectedModulesAction(); void deleteSelectedModulesAction(); + bool requestSelectedModulePos(math::Vec delta); // Cable methods diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 39d8fc99..61b953b5 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -402,9 +402,10 @@ void ModuleWidget::onDragEnd(const DragEndEvent& e) { internal->dragEnabled = true; history::ComplexAction* h = APP->scene->rack->getModuleDragAction(); - if (!h) - return; - APP->history->push(h); + if (!h->isEmpty()) + APP->history->push(h); + else + delete h; } } @@ -429,10 +430,17 @@ void ModuleWidget::onDragMove(const DragMoveEvent& e) { math::Vec pos = mousePos; pos.x -= internal->dragOffset.x; pos.y -= RACK_GRID_HEIGHT / 2; - if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) - APP->scene->rack->setModulePosForce(this, pos); - else - APP->scene->rack->setModulePosNearest(this, pos); + if (internal->selected) { + pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; + math::Vec delta = pos.minus(box.pos); + APP->scene->rack->requestSelectedModulePos(delta); + } + else { + if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) + APP->scene->rack->setModulePosForce(this, pos); + else + APP->scene->rack->setModulePosNearest(this, pos); + } } } } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index b9fd9eef..a0f14c7b 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -206,12 +206,9 @@ void RackWidget::clear() { // This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case. clearCables(); // Remove ModuleWidgets - std::list widgets = internal->moduleContainer->children; - for (widget::Widget* w : widgets) { - ModuleWidget* moduleWidget = dynamic_cast(w); - assert(moduleWidget); - removeModule(moduleWidget); - delete moduleWidget; + for (ModuleWidget* mw : getModules()) { + removeModule(mw); + delete mw; } } @@ -486,9 +483,6 @@ bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) { // Don't intersect with self if (mw == w2) continue; - // Don't intersect with invisible modules - if (!w2->visible) - continue; // Check intersection math::Rect w2Box = w2->box; if (mwBox.intersects(w2Box)) @@ -628,9 +622,7 @@ bool RackWidget::hasModules() { void RackWidget::updateModuleOldPositions() { // Set all modules' oldPos field from their current position. - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); + for (ModuleWidget* mw : getModules()) { mw->oldPos() = mw->box.pos; } } @@ -638,9 +630,7 @@ void RackWidget::updateModuleOldPositions() { history::ComplexAction* RackWidget::getModuleDragAction() { history::ComplexAction* h = new history::ComplexAction; - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); + for (ModuleWidget* mw : getModules()) { // Create ModuleMove action if the module was moved. math::Vec oldPos = mw->oldPos(); if (!oldPos.equals(mw->box.pos)) { @@ -652,18 +642,12 @@ history::ComplexAction* RackWidget::getModuleDragAction() { } } - if (h->isEmpty()) { - delete h; - return NULL; - } return h; } void RackWidget::updateModuleSelections() { math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd); - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); + for (ModuleWidget* mw : getModules()) { bool selected = internal->selecting && selectionBox.intersects(mw->box); mw->selected() = selected; } @@ -770,6 +754,36 @@ void RackWidget::deleteSelectedModulesAction() { APP->history->push(complexAction); } +bool RackWidget::requestSelectedModulePos(math::Vec delta) { + // Check intersection with other modules + std::map mwBoxes; + for (ModuleWidget* mw : getSelectedModules()) { + math::Rect mwBox = mw->box; + mwBox.pos += delta; + mwBoxes[mw] = mwBox; + } + + for (widget::Widget* w2 : internal->moduleContainer->children) { + // Don't intersect with selected modules + auto it = mwBoxes.find(w2); + if (it != mwBoxes.end()) + continue; + math::Rect w2Box = w2->box; + // Check intersection with all selected modules + for (const auto& pair : mwBoxes) { + if (pair.second.intersects(w2Box)) + return false; + } + } + + // Accept requested position + for (const auto& pair : mwBoxes) { + pair.first->setPosition(pair.second.pos); + } + RackWidget_updateExpanders(this); + return true; +} + void RackWidget::clearCables() { incompleteCable = NULL; internal->cableContainer->clearChildren();