Hyprscrolling: focus left/right moves to the best vertical neighbour (#482)

* Hyprscrolling: feat: focus left/right moves to the best vertical neighbour (closes #473)

When moving focus horizontally between columns we now pick the window
whose vertical span overlaps the current window the most.
If no overlap exists we fall back to the top-most window of the target
column.
This makes `layoutmsg focus l/r` behave intuitively in multi-column
setups: from the bottom-left terminal you land on the bottom-left
terminal of the neighbouring column instead of always jumping to the
top.

* Hyprscrolling: fix: remove `{}` from short ifs in `findBestNeighbor()`

* Hyprscrolling: fix: Simplify nested ifs
This commit is contained in:
Ralph Zhou 2025-09-19 06:04:18 +08:00 committed by GitHub
parent 5ff379f4e5
commit ebb4040cac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 2 deletions

View File

@ -773,6 +773,30 @@ void CScrollingLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFull
g_pCompositor->changeWindowZOrder(pWindow, true);
}
SP<SScrollingWindowData> CScrollingLayout::findBestNeighbor(SP<SScrollingWindowData> pCurrent, SP<SColumnData> pTargetCol) {
if (!pCurrent || !pTargetCol || pTargetCol->windowDatas.empty())
return nullptr;
const double currentTop = pCurrent->layoutBox.y;
const double currentBottom = pCurrent->layoutBox.y + pCurrent->layoutBox.h;
SP<SScrollingWindowData> bestMatch = nullptr;
for (const auto& candidate : pTargetCol->windowDatas) {
const double candidateTop = candidate->layoutBox.y;
const double candidateBottom = candidate->layoutBox.y + candidate->layoutBox.h;
const bool overlaps = (candidateTop < currentBottom) && (candidateBottom > currentTop);
if (overlaps && (!bestMatch || candidateTop < bestMatch->layoutBox.y))
bestMatch = candidate;
}
if (!bestMatch && !pTargetCol->windowDatas.empty())
return pTargetCol->windowDatas.front();
return bestMatch;
}
std::any CScrollingLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
static auto centerOrFit = [](const SP<SWorkspaceData> WS, const SP<SColumnData> COL) -> void {
static const auto PFITMETHOD = CConfigValue<Hyprlang::INT>("plugin:hyprscrolling:focus_fit_method");
@ -1108,7 +1132,8 @@ std::any CScrollingLayout::layoutMessage(SLayoutMessageHeader header, std::strin
PREV = WDATA->column->workspace->columns.back();
}
g_pCompositor->focusWindow(PREV->windowDatas.front()->window.lock());
auto pTargetWindowData = findBestNeighbor(WDATA, PREV);
g_pCompositor->focusWindow(pTargetWindowData->window.lock());
centerOrFit(WDATA->column->workspace.lock(), PREV);
WDATA->column->workspace->recalculate();
g_pCompositor->warpCursorTo(PREV->windowDatas.front()->window.lock()->middle());
@ -1127,7 +1152,8 @@ std::any CScrollingLayout::layoutMessage(SLayoutMessageHeader header, std::strin
NEXT = WDATA->column->workspace->columns.front();
}
g_pCompositor->focusWindow(NEXT->windowDatas.front()->window.lock());
auto pTargetWindowData = findBestNeighbor(WDATA, NEXT);
g_pCompositor->focusWindow(pTargetWindowData->window.lock());
centerOrFit(WDATA->column->workspace.lock(), NEXT);
WDATA->column->workspace->recalculate();
g_pCompositor->warpCursorTo(NEXT->windowDatas.front()->window.lock()->middle());

View File

@ -114,6 +114,7 @@ class CScrollingLayout : public IHyprLayout {
std::vector<float> configuredWidths;
} m_config;
SP<SScrollingWindowData> findBestNeighbor(SP<SScrollingWindowData> pCurrent, SP<SColumnData> pTargetCol);
SP<SWorkspaceData> dataFor(PHLWORKSPACE ws);
SP<SScrollingWindowData> dataFor(PHLWINDOW w);
SP<SWorkspaceData> currentWorkspaceData();