| @@ -696,30 +696,31 @@ void RackWidget::setModulePosNearest(ModuleWidget* mw, math::Vec pos) { | |||
| } | |||
| void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) { | |||
| mw->setPosition(pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE)); | |||
| math::Rect newBox = mw->box; | |||
| newBox.pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; | |||
| // Comparison of X coordinates | |||
| auto cmp = [&](const widget::Widget* a, const widget::Widget* b) { | |||
| return a->box.pos.x < b->box.pos.x; | |||
| }; | |||
| // Collect modules to the left and right of `mw` | |||
| // Collect modules to the left and right of pos | |||
| std::set<widget::Widget*, decltype(cmp)> leftModules(cmp); | |||
| std::set<widget::Widget*, decltype(cmp)> rightModules(cmp); | |||
| for (widget::Widget* w2 : internal->moduleContainer->children) { | |||
| // Skip this module | |||
| if (w2 == mw) | |||
| continue; | |||
| // Reset position to old position | |||
| // Reset position to old position, including this module | |||
| auto it = internal->moduleOldPositions.find(w2); | |||
| if (it != internal->moduleOldPositions.end()) { | |||
| w2->box.pos = it->second; | |||
| } | |||
| // Modules must be on the same row as `mw` | |||
| if (w2->box.getTop() != mw->box.getTop()) | |||
| // Skip this module | |||
| if (w2 == mw) | |||
| continue; | |||
| // Modules must be on the same row as pos | |||
| if (w2->box.getTop() != newBox.getTop()) | |||
| continue; | |||
| // Insert into leftModules or rightModules | |||
| if (w2->box.getCenter().x < mw->box.getCenter().x) | |||
| if (w2->box.getCenter().x < newBox.getCenter().x) | |||
| leftModules.insert(w2); | |||
| else | |||
| rightModules.insert(w2); | |||
| @@ -729,35 +730,52 @@ void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) { | |||
| widget::Widget* rightModule = rightModules.empty() ? NULL : *rightModules.begin(); | |||
| if (leftModule) { | |||
| if (leftModule->box.getRight() > mw->box.getLeft()) { | |||
| mw->box.pos.x = leftModule->box.getRight(); | |||
| // Place right of leftModule | |||
| if (leftModule->box.getRight() > newBox.getLeft()) { | |||
| newBox.pos.x = leftModule->box.getRight(); | |||
| } | |||
| } | |||
| if (rightModule) { | |||
| if (mw->box.getRight() > rightModule->box.getLeft()) { | |||
| mw->box.pos.x = rightModule->box.getLeft() - mw->box.size.x; | |||
| // Place left of rightModule | |||
| if (newBox.getRight() > rightModule->box.getLeft()) { | |||
| newBox.pos.x = rightModule->box.getLeft() - newBox.size.x; | |||
| } | |||
| } | |||
| if (leftModule && rightModule) { | |||
| // If there isn't enough space between the last leftModule and first rightModule, place module to the right of the leftModule. | |||
| if (leftModule->box.getRight() + mw->box.getWidth() > rightModule->box.getLeft()) { | |||
| mw->box.pos.x = leftModule->box.getRight(); | |||
| // Shove right modules | |||
| float xLimit = mw->box.getRight(); | |||
| for (auto it = rightModules.begin(); it != rightModules.end(); it++) { | |||
| widget::Widget* w2 = *it; | |||
| math::Vec newPos = w2->box.pos; | |||
| newPos.x = xLimit; | |||
| newPos.x = std::round(newPos.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH; | |||
| if (w2->box.pos.x > newPos.x) | |||
| break; | |||
| w2->box.pos = newPos; | |||
| xLimit = w2->box.getRight(); | |||
| if (leftModule->box.getRight() + newBox.getWidth() > rightModule->box.getLeft()) { | |||
| // If module old position is to the left of the new position, shove other modules to the left instead of the right. | |||
| if (mw->box.getTop() == newBox.getTop() && mw->box.getLeft() < newBox.getLeft()) { | |||
| newBox.pos.x = rightModule->box.getLeft() - newBox.size.x; | |||
| // Shove left modules | |||
| float xLeft = newBox.getLeft(); | |||
| for (auto it = leftModules.rbegin(); it != leftModules.rend(); it++) { | |||
| widget::Widget* w2 = *it; | |||
| if (w2->box.getRight() <= xLeft) | |||
| break; | |||
| w2->box.pos.x = std::round((xLeft - w2->box.size.x) / RACK_GRID_WIDTH) * RACK_GRID_WIDTH; | |||
| xLeft = w2->box.getLeft(); | |||
| } | |||
| } | |||
| else { | |||
| newBox.pos.x = leftModule->box.getRight(); | |||
| // Shove right modules | |||
| float xRight = newBox.getRight(); | |||
| for (auto it = rightModules.begin(); it != rightModules.end(); it++) { | |||
| widget::Widget* w2 = *it; | |||
| if (w2->box.getLeft() >= xRight) | |||
| break; | |||
| w2->box.pos.x = std::round(xRight / RACK_GRID_WIDTH) * RACK_GRID_WIDTH; | |||
| xRight = w2->box.getRight(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| mw->box.pos = (newBox.pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; | |||
| updateExpanders(); | |||
| } | |||