Browse Source

Improve RackWidget::setModulePosForce() with a few intuitive special cases.

tags/v2.1.0
Andrew Belt 2 years ago
parent
commit
88db0b74e9
1 changed files with 57 additions and 47 deletions
  1. +57
    -47
      src/app/RackWidget.cpp

+ 57
- 47
src/app/RackWidget.cpp View File

@@ -699,20 +699,52 @@ void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) {
math::Rect newBox = mw->box; math::Rect newBox = mw->box;
newBox.pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; newBox.pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE;


// Comparison of X coordinates
// Reset modules to their old positions, including this module
for (auto& pair : internal->moduleOldPositions) {
widget::Widget* w2 = pair.first;
w2->box.pos = pair.second;
}

// Comparator of X coordinates
auto cmp = [&](const widget::Widget* a, const widget::Widget* b) { auto cmp = [&](const widget::Widget* a, const widget::Widget* b) {
return a->box.pos.x < b->box.pos.x;
return a->box.getLeft() < b->box.getLeft();
}; };


// Collect modules to the right of old pos
std::set<widget::Widget*, decltype(cmp)> rightOldModules(cmp);
for (widget::Widget* w2 : internal->moduleContainer->children) {
// Skip this module
if (w2 == mw)
continue;
// Modules must be on the same row as old pos
if (w2->box.getTop() != mw->box.getTop())
continue;
// Insert into rightOldModules
if (w2->box.getCenter().x >= mw->box.getCenter().x)
rightOldModules.insert(w2);
}

// Shove old right modules to the left
float xDelta = newBox.pos.x - mw->box.pos.x;
if (newBox.pos.y != mw->box.pos.y || xDelta > 0 || xDelta < -mw->box.size.x) {
xDelta = -mw->box.size.x;
}

float xRight = mw->box.getRight();
for (auto it = rightOldModules.begin(); it != rightOldModules.end(); it++) {
widget::Widget* w2 = *it;
// Break when module is no longer touching
if (xRight < w2->box.getLeft())
break;
xRight = w2->box.getRight();
// Move module to the left by the width of mw, so it replaces its position
w2->box.pos.x += xDelta;
}

// Collect modules to the left and right of pos // Collect modules to the left and right of pos
std::set<widget::Widget*, decltype(cmp)> leftModules(cmp); std::set<widget::Widget*, decltype(cmp)> leftModules(cmp);
std::set<widget::Widget*, decltype(cmp)> rightModules(cmp); std::set<widget::Widget*, decltype(cmp)> rightModules(cmp);
for (widget::Widget* w2 : internal->moduleContainer->children) { for (widget::Widget* w2 : internal->moduleContainer->children) {
// Reset position to old position, including this module
auto it = internal->moduleOldPositions.find(w2);
if (it != internal->moduleOldPositions.end()) {
w2->box.pos = it->second;
}
// Skip this module // Skip this module
if (w2 == mw) if (w2 == mw)
continue; continue;
@@ -729,49 +761,27 @@ void RackWidget::setModulePosForce(ModuleWidget* mw, math::Vec pos) {
widget::Widget* leftModule = leftModules.empty() ? NULL : *leftModules.rbegin(); widget::Widget* leftModule = leftModules.empty() ? NULL : *leftModules.rbegin();
widget::Widget* rightModule = rightModules.empty() ? NULL : *rightModules.begin(); widget::Widget* rightModule = rightModules.empty() ? NULL : *rightModules.begin();


if (leftModule) {
// Place right of leftModule
if (leftModule->box.getRight() > newBox.getLeft()) {
newBox.pos.x = leftModule->box.getRight();
// If there isn't enough space between the last leftModule and first rightModule, place module to the right of the leftModule and shove right modules.
if (leftModule && rightModule && leftModule->box.getRight() + newBox.getWidth() > rightModule->box.getLeft()) {
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();
} }
} }
if (rightModule) {
// Place left of rightModule
if (newBox.getRight() > rightModule->box.getLeft()) {
newBox.pos.x = rightModule->box.getLeft() - newBox.size.x;
}
// Place right of leftModule
else if (leftModule && leftModule->box.getRight() > newBox.getLeft()) {
newBox.pos.x = leftModule->box.getRight();
} }
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() + 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();
}
}
}
// Place left of rightModule
else if (rightModule && newBox.getRight() > rightModule->box.getLeft()) {
newBox.pos.x = rightModule->box.getLeft() - newBox.size.x;
} }


mw->box.pos = (newBox.pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; mw->box.pos = (newBox.pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE;


Loading…
Cancel
Save