From 3b7401b065d78582fe67591f37d36021e94d2f0a Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:31:33 +0000 Subject: [PATCH] algo/scroll: improve directional moves (#13423) --- .../tiled/scrolling/ScrollTapeController.cpp | 6 +- .../tiled/scrolling/ScrollTapeController.hpp | 2 +- .../tiled/scrolling/ScrollingAlgorithm.cpp | 159 ++++++++++++------ .../tiled/scrolling/ScrollingAlgorithm.hpp | 4 +- 4 files changed, 117 insertions(+), 54 deletions(-) diff --git a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp index c6cda4b5..77ab74b1 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp @@ -55,12 +55,14 @@ size_t CScrollTapeController::addStrip(float size) { return m_strips.size() - 1; } -void CScrollTapeController::insertStrip(size_t afterIndex, float size) { - if (afterIndex >= m_strips.size()) { +void CScrollTapeController::insertStrip(ssize_t afterIndex, float size) { + if (afterIndex >= sc(m_strips.size())) { addStrip(size); return; } + afterIndex = std::clamp(afterIndex, -1L, sc(INT32_MAX)); + SStripData newStrip; newStrip.size = size; m_strips.insert(m_strips.begin() + afterIndex + 1, newStrip); diff --git a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp index 4e0fef7f..da2efbba 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp @@ -40,7 +40,7 @@ namespace Layout::Tiled { bool isReversed() const; size_t addStrip(float size = 1.0F); - void insertStrip(size_t afterIndex, float size = 1.0F); + void insertStrip(ssize_t afterIndex, float size = 1.0F); void removeStrip(size_t index); size_t stripCount() const; SStripData& getStrip(size_t index); diff --git a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp index 2862ef4a..35234f1f 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp @@ -247,24 +247,28 @@ void SColumnData::remove(SP t) { scrollingData->remove(self.lock()); } -void SColumnData::up(SP w) { +bool SColumnData::up(SP w) { for (size_t i = 1; i < targetDatas.size(); ++i) { if (targetDatas[i] != w) continue; std::swap(targetDatas[i], targetDatas[i - 1]); - break; + return true; } + + return false; } -void SColumnData::down(SP w) { +bool SColumnData::down(SP w) { for (size_t i = 0; i < targetDatas.size() - 1; ++i) { if (targetDatas[i] != w) continue; std::swap(targetDatas[i], targetDatas[i + 1]); - break; + return true; } + + return false; } SP SColumnData::next(SP w) { @@ -845,61 +849,118 @@ void CScrollingAlgorithm::moveTargetTo(SP t, Math::eDirection dir, bool if (!DATA) return; - const auto TAPE_DIR = getDynamicDirection(); const auto CURRENT_COL = DATA->column.lock(); const auto current_idx = m_scrollingData->idx(CURRENT_COL); - if (dir == Math::DIRECTION_LEFT) { - const auto COL = m_scrollingData->prev(DATA->column.lock()); + auto rotateDir = [this](Math::eDirection dir) -> Math::eDirection { + switch (m_scrollingData->controller->getDirection()) { + case SCROLL_DIR_RIGHT: return dir; + case SCROLL_DIR_LEFT: { + if (dir == Math::DIRECTION_LEFT) + return Math::DIRECTION_RIGHT; + if (dir == Math::DIRECTION_RIGHT) + return Math::DIRECTION_LEFT; + return dir; + } + case SCROLL_DIR_UP: { + switch (dir) { + case Math::DIRECTION_UP: return Math::DIRECTION_RIGHT; + case Math::DIRECTION_DOWN: return Math::DIRECTION_LEFT; + case Math::DIRECTION_LEFT: return Math::DIRECTION_DOWN; + case Math::DIRECTION_RIGHT: return Math::DIRECTION_UP; + default: break; + } - // ignore moves to the "origin" when on first column and moving opposite to tape direction - if (!COL && current_idx == 0 && (TAPE_DIR == SCROLL_DIR_RIGHT || TAPE_DIR == SCROLL_DIR_DOWN)) - return; + return dir; + } + case SCROLL_DIR_DOWN: { + switch (dir) { + case Math::DIRECTION_UP: return Math::DIRECTION_LEFT; + case Math::DIRECTION_DOWN: return Math::DIRECTION_RIGHT; + case Math::DIRECTION_LEFT: return Math::DIRECTION_DOWN; + case Math::DIRECTION_RIGHT: return Math::DIRECTION_UP; + default: break; + } - DATA->column->remove(t); - - if (!COL) { - const auto NEWCOL = m_scrollingData->add(-1); - NEWCOL->add(DATA); - m_scrollingData->centerOrFitCol(NEWCOL); - } else { - if (COL->targetDatas.size() > 0) - COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); - else - COL->add(DATA); - m_scrollingData->centerOrFitCol(COL); - } - } else if (dir == Math::DIRECTION_RIGHT) { - const auto COL = m_scrollingData->next(DATA->column.lock()); - - // ignore moves to the "origin" when on last column and moving opposite to tape direction - if (!COL && current_idx == (int64_t)m_scrollingData->columns.size() - 1 && (TAPE_DIR == SCROLL_DIR_LEFT || TAPE_DIR == SCROLL_DIR_UP)) - return; - - DATA->column->remove(t); - - if (!COL) { - // make a new one - const auto NEWCOL = m_scrollingData->add(); - NEWCOL->add(DATA); - m_scrollingData->centerOrFitCol(NEWCOL); - } else { - if (COL->targetDatas.size() > 0) - COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); - else - COL->add(DATA); - m_scrollingData->centerOrFitCol(COL); + return dir; + } + default: break; } - } else if (dir == Math::DIRECTION_UP) - DATA->column->up(DATA); - else if (dir == Math::DIRECTION_DOWN) - DATA->column->down(DATA); + return dir; + }; + + const auto ROTATED_DIR = rotateDir(dir); + + auto commenceDir = [&]() -> bool { + if (ROTATED_DIR == Math::DIRECTION_LEFT) { + const auto COL = m_scrollingData->prev(DATA->column.lock()); + + // ignore moves to the origin if we are alone + if (!COL && current_idx == 0 && DATA->column->targetDatas.size() == 1) + return false; + + DATA->column->remove(t); + + if (!COL) { + const auto NEWCOL = m_scrollingData->add(-1); + NEWCOL->add(DATA); + m_scrollingData->centerOrFitCol(NEWCOL); + } else { + if (COL->targetDatas.size() > 0) + COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); + else + COL->add(DATA); + m_scrollingData->centerOrFitCol(COL); + } + + return true; + } else if (ROTATED_DIR == Math::DIRECTION_RIGHT) { + const auto COL = m_scrollingData->next(DATA->column.lock()); + + // ignore move to the right when there is no next column and we're alone + if (!COL && current_idx == (int64_t)m_scrollingData->columns.size() - 1 && DATA->column->targetDatas.size() == 1) + return false; + + DATA->column->remove(t); + + if (!COL) { + // make a new one + const auto NEWCOL = m_scrollingData->add(); + NEWCOL->add(DATA); + m_scrollingData->centerOrFitCol(NEWCOL); + } else { + if (COL->targetDatas.size() > 0) + COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); + else + COL->add(DATA); + m_scrollingData->centerOrFitCol(COL); + } + + return true; + } else if (ROTATED_DIR == Math::DIRECTION_UP) + return DATA->column->up(DATA); + else if (ROTATED_DIR == Math::DIRECTION_DOWN) + return DATA->column->down(DATA); + + return false; + }; + + if (!commenceDir()) { + // dir wasn't commenced, move to a workspace if possible + // with the original dir + const auto MONINDIR = g_pCompositor->getMonitorInDirection(m_parent->space()->workspace()->m_monitor.lock(), dir); + if (MONINDIR && MONINDIR != m_parent->space()->workspace()->m_monitor && MONINDIR->m_activeWorkspace) { + t->assignToSpace(MONINDIR->m_activeWorkspace->m_space); + + m_scrollingData->recalculate(); + + return; + } + } m_scrollingData->recalculate(); focusTargetUpdate(t); - if (t->window()) - g_pCompositor->warpCursorTo(t->window()->middle()); } std::expected CScrollingAlgorithm::layoutMsg(const std::string_view& sv) { diff --git a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp index a414a22f..d95b3197 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp @@ -40,8 +40,8 @@ namespace Layout::Tiled { // index of lowest target that is above y. size_t idxForHeight(float y); - void up(SP w); - void down(SP w); + bool up(SP w); + bool down(SP w); SP next(SP w); SP prev(SP w);