diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index 2289fa94..d46113e2 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -119,7 +119,6 @@ struct ModuleWidget : widget::OpaqueWidget { INTERNAL bool& dragEnabled(); INTERNAL math::Vec& oldPos(); INTERNAL engine::Module* releaseModule(); - INTERNAL bool& selected(); }; diff --git a/include/app/RackWidget.hpp b/include/app/RackWidget.hpp index fbe391c1..c397008d 100644 --- a/include/app/RackWidget.hpp +++ b/include/app/RackWidget.hpp @@ -10,6 +10,8 @@ #include #include +#include + namespace rack { namespace app { @@ -75,10 +77,11 @@ struct RackWidget : widget::OpaqueWidget { void updateSelectionFromRect(); void selectAll(); - void deselect(); + void deselectAll(); + void select(ModuleWidget* mw, bool selected = true); bool hasSelection(); - int getNumSelected(); - std::vector getSelectedModules(); + const std::set& getSelected(); + bool isSelected(ModuleWidget* mw); json_t* selectionToJson(); void loadSelection(std::string path); void loadSelectionDialog(); diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 76e3f571..edfbddc8 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -42,8 +42,6 @@ struct ModuleWidget::Internal { math::Vec oldPos; widget::Widget* panel = NULL; - - bool selected = false; }; @@ -286,7 +284,7 @@ void ModuleWidget::draw(const DrawArgs& args) { // } // Selection - if (internal->selected) { + if (APP->scene->rack->isSelected(this)) { nvgBeginPath(args.vg); nvgRect(args.vg, 0.0, 0.0, VEC_ARGS(box.size)); nvgFillColor(args.vg, nvgRGBAf(1, 0, 0, 0.25)); @@ -313,7 +311,7 @@ void ModuleWidget::drawShadow(const DrawArgs& args) { } void ModuleWidget::onHover(const HoverEvent& e) { - if (internal->selected) { + if (APP->scene->rack->isSelected(this)) { e.consume(this); } @@ -368,7 +366,9 @@ void ModuleWidget::onHoverKey(const HoverKeyEvent& e) { } void ModuleWidget::onButton(const ButtonEvent& e) { - if (internal->selected) { + bool selected = APP->scene->rack->isSelected(this); + + if (selected) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { ui::Menu* menu = createMenu(); APP->scene->rack->appendSelectionContextMenu(menu); @@ -386,11 +386,11 @@ void ModuleWidget::onButton(const ButtonEvent& e) { } // Toggle selection on Shift-click if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - internal->selected ^= true; + APP->scene->rack->select(this, !selected); } } - if (!e.isConsumed() && !internal->selected) { + if (!e.isConsumed() && !selected) { // Open context menu on right-click if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { createContextMenu(); @@ -448,7 +448,7 @@ void ModuleWidget::onDragMove(const DragMoveEvent& e) { math::Vec pos = mousePos; pos.x -= internal->dragOffset.x; pos.y -= RACK_GRID_HEIGHT / 2; - if (internal->selected) { + if (APP->scene->rack->isSelected(this)) { pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; math::Vec delta = pos.minus(box.pos); APP->scene->rack->setSelectionPosNearest(delta); @@ -465,7 +465,7 @@ void ModuleWidget::onDragMove(const DragMoveEvent& e) { } void ModuleWidget::onDragHover(const DragHoverEvent& e) { - if (internal->selected) { + if (APP->scene->rack->isSelected(this)) { e.consume(this); } @@ -1035,11 +1035,6 @@ engine::Module* ModuleWidget::releaseModule() { return module; } -bool& ModuleWidget::selected() { - return internal->selected; -} - - } // namespace app } // namespace rack \ No newline at end of file diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 9d04aef9..87c24df9 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -84,6 +84,7 @@ struct RackWidget::Internal { bool selecting = false; math::Vec selectionStart; math::Vec selectionEnd; + std::set selectedModules; }; @@ -397,7 +398,7 @@ struct PasteJsonReturn { std::map newModuleIds; }; static PasteJsonReturn RackWidget_pasteJson(RackWidget* that, json_t* rootJ, history::ComplexAction* complexAction) { - that->deselect(); + that->deselectAll(); std::map newModuleIds; @@ -438,7 +439,7 @@ static PasteJsonReturn RackWidget_pasteJson(RackWidget* that, json_t* rootJ, his mw->box.pos = pos.plus(RACK_OFFSET); that->internal->moduleContainer->addChild(mw); - mw->selected() = true; + that->select(mw); newModuleIds[id] = mw->module->id; } @@ -447,7 +448,7 @@ static PasteJsonReturn RackWidget_pasteJson(RackWidget* that, json_t* rootJ, his that->setSelectionPosNearest(math::Vec(0, 0)); // Add positioned selected modules to history - for (ModuleWidget* mw : that->getSelectedModules()) { + for (ModuleWidget* mw : that->getSelected()) { // history::ModuleAdd history::ModuleAdd* h = new history::ModuleAdd; h->setModule(mw); @@ -790,56 +791,49 @@ history::ComplexAction* RackWidget::getModuleDragAction() { void RackWidget::updateSelectionFromRect() { math::Rect selectionBox = math::Rect::fromCorners(internal->selectionStart, internal->selectionEnd); + deselectAll(); for (ModuleWidget* mw : getModules()) { bool selected = internal->selecting && selectionBox.intersects(mw->box); - mw->selected() = selected; + if (selected) + select(mw); } } void RackWidget::selectAll() { - for (ModuleWidget* mw : getModules()) { - mw->selected() = true; + internal->selectedModules.clear(); + for (widget::Widget* w : internal->moduleContainer->children) { + ModuleWidget* mw = dynamic_cast(w); + assert(mw); + internal->selectedModules.insert(mw); } } -void RackWidget::deselect() { - for (ModuleWidget* mw : getModules()) { - mw->selected() = false; +void RackWidget::deselectAll() { + internal->selectedModules.clear(); +} + +void RackWidget::select(ModuleWidget* mw, bool selected) { + if (selected) { + internal->selectedModules.insert(mw); + } + else { + auto it = internal->selectedModules.find(mw); + if (it != internal->selectedModules.end()) + internal->selectedModules.erase(it); } } bool RackWidget::hasSelection() { - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); - if (mw->selected()) - return true; - } - return false; + return !internal->selectedModules.empty(); } -int RackWidget::getNumSelected() { - int count = 0; - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); - if (mw->selected()) - count++; - } - return count; +const std::set& RackWidget::getSelected() { + return internal->selectedModules; } -std::vector RackWidget::getSelectedModules() { - std::vector mws; - mws.reserve(internal->moduleContainer->children.size()); - for (widget::Widget* w : internal->moduleContainer->children) { - ModuleWidget* mw = dynamic_cast(w); - assert(mw); - if (mw->selected()) - mws.push_back(mw); - } - mws.shrink_to_fit(); - return mws; +bool RackWidget::isSelected(ModuleWidget* mw) { + auto it = internal->selectedModules.find(mw); + return (it != internal->selectedModules.end()); } json_t* RackWidget::selectionToJson() { @@ -849,7 +843,7 @@ json_t* RackWidget::selectionToJson() { // modules json_t* modulesJ = json_array(); - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { json_t* moduleJ = mw->toJson(); // pos @@ -982,7 +976,7 @@ void RackWidget::resetSelectionAction() { history::ComplexAction* complexAction = new history::ComplexAction; complexAction->name = "reset modules"; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { assert(mw->module); // history::ModuleChange @@ -1003,7 +997,7 @@ void RackWidget::randomizeSelectionAction() { history::ComplexAction* complexAction = new history::ComplexAction; complexAction->name = "randomize modules"; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { assert(mw->module); // history::ModuleChange @@ -1024,7 +1018,7 @@ void RackWidget::disconnectSelectionAction() { history::ComplexAction* complexAction = new history::ComplexAction; complexAction->name = "disconnect cables"; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { mw->appendDisconnectActions(complexAction); } @@ -1086,7 +1080,7 @@ void RackWidget::bypassSelectionAction(bool bypassed) { history::ComplexAction* complexAction = new history::ComplexAction; complexAction->name = bypassed ? "bypass modules" : "un-bypass modules"; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { assert(mw->module); if (mw->module->isBypassed() == bypassed) continue; @@ -1107,7 +1101,7 @@ void RackWidget::bypassSelectionAction(bool bypassed) { } bool RackWidget::isSelectionBypassed() { - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { if (!mw->getModule()->isBypassed()) return false; } @@ -1118,7 +1112,7 @@ void RackWidget::deleteSelectionAction() { history::ComplexAction* complexAction = new history::ComplexAction; complexAction->name = "remove modules"; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { mw->appendDisconnectActions(complexAction); // history::ModuleRemove @@ -1136,7 +1130,7 @@ void RackWidget::deleteSelectionAction() { bool RackWidget::requestSelectionPos(math::Vec delta) { // Calculate new positions std::map mwBoxes; - for (ModuleWidget* mw : getSelectedModules()) { + for (ModuleWidget* mw : getSelected()) { math::Rect mwBox = mw->box; mwBox.pos += delta; mwBoxes[mw] = mwBox; @@ -1171,7 +1165,7 @@ void RackWidget::setSelectionPosNearest(math::Vec delta) { } void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { - int n = getNumSelected(); + int n = getSelected().size(); menu->addChild(createMenuLabel(string::f("%d selected %s", n, n == 1 ? "module" : "modules"))); // Enable alwaysConsume of menu items if the number of selected modules changes @@ -1183,7 +1177,7 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { // Deselect menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() { - deselect(); + deselectAll(); }, n == 0, true)); // Copy diff --git a/src/app/Scene.cpp b/src/app/Scene.cpp index 3e9e72be..024f91da 100644 --- a/src/app/Scene.cpp +++ b/src/app/Scene.cpp @@ -214,7 +214,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { e.consume(this); } if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) { - rack->deselect(); + rack->deselectAll(); e.consume(this); } if (e.keyName == "c" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {