--- a/src/layout/algorithm/tiled/dwindle/DwindleAlgorithm.cpp +++ b/src/layout/algorithm/tiled/dwindle/DwindleAlgorithm.cpp @@ -297,6 +297,56 @@ recalculate(); } +// Moving a split only changes that node's ratio, so every split nested on +// either side of it gets rescaled and edges that weren't dragged slide along. +// Record the size of each region that doesn't touch the moved edge, so it can +// be pinned afterwards and only the windows along the edge absorb the resize. +struct SFarSide { + SP node; + bool farIsSecond = false; + float size = 0; +}; +using FarSides = std::vector; + +static void collectFarSides(const SP& node, bool vertical, bool edgeAtStart, FarSides& out) { + if (!node || !node->children[0] || !node->children[1]) + return; + + const auto C0 = node->children[0].lock(); + const auto C1 = node->children[1].lock(); + + if (node->splitTop == vertical) { + // split along the resize axis: pin the far child, follow the near one + const auto FARCHILD = edgeAtStart ? C1 : C0; + out.push_back({node, edgeAtStart, (float)(vertical ? FARCHILD->box.h : FARCHILD->box.w)}); + collectFarSides(edgeAtStart ? C0 : C1, vertical, edgeAtStart, out); + } else { + // perpendicular split: both children touch the edge + collectFarSides(C0, vertical, edgeAtStart, out); + collectFarSides(C1, vertical, edgeAtStart, out); + } +} + +static FarSides collectFarSides(const SP& split, bool vertical) { + FarSides out; + collectFarSides(split->children[0].lock(), vertical, false, out); + collectFarSides(split->children[1].lock(), vertical, true, out); + return out; +} + +// parents come before their children in `far`, so each node's box is already +// final by the time its own ratio is recomputed +static void restoreFarSides(const FarSides& far, bool vertical, bool force) { + for (const auto& [node, farIsSecond, size] : far) { + const float TOTAL = vertical ? node->box.h : node->box.w; + if (TOTAL <= 0) + continue; + + node->splitRatio = std::clamp(farIsSecond ? 2.f - size / TOTAL * 2.f : size / TOTAL * 2.f, 0.1F, 1.9F); + node->recalcSizePosRecursive(force); + } +} + void CDwindleAlgorithm::resizeTarget(const Vector2D& Δ, SP target, eRectCorner corner) { if (!validMapped(target->window())) return; @@ -356,6 +406,8 @@ } if (PHOUTER) { + const auto HFAR = collectFarSides(PHOUTER->pParent.lock(), false); + PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->box.w, 0.1, 1.9); if (PHINNER) { @@ -368,9 +420,13 @@ PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0); } else PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); + + restoreFarSides(HFAR, false, *PANIMATE == 0); } if (PVOUTER) { + const auto VFAR = collectFarSides(PVOUTER->pParent.lock(), true); + PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->box.h, 0.1, 1.9); if (PVINNER) { @@ -383,6 +439,8 @@ PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0); } else PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); + + restoreFarSides(VFAR, true, *PANIMATE == 0); } } else { // get the correct containers to apply splitratio to