From 05dae996ebbed14c6476b83a7d014d00754febd2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 18 May 2025 19:03:07 +0200 Subject: [PATCH] hyprscroller: add mouse resize controls fixes #347 --- hyprscrolling/Scrolling.cpp | 166 +++++++++++++++++++++++++++++++++--- hyprscrolling/Scrolling.hpp | 12 ++- 2 files changed, 164 insertions(+), 14 deletions(-) diff --git a/hyprscrolling/Scrolling.cpp b/hyprscrolling/Scrolling.cpp index 7891578..a973382 100644 --- a/hyprscrolling/Scrolling.cpp +++ b/hyprscrolling/Scrolling.cpp @@ -5,17 +5,46 @@ #include #include +constexpr float MIN_COLUMN_WIDTH = 0.05F; +constexpr float MAX_COLUMN_WIDTH = 1.F; +constexpr float MIN_ROW_HEIGHT = 0.1F; +constexpr float MAX_ROW_HEIGHT = 1.F; + +// void SColumnData::add(PHLWINDOW w) { - windowDatas.emplace_back(makeShared(w, self.lock())); + for (auto& wd : windowDatas) { + wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); + } + + windowDatas.emplace_back(makeShared(w, self.lock(), 1.F / (float)(windowDatas.size() + 1))); } void SColumnData::add(SP w) { + for (auto& wd : windowDatas) { + wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); + } + windowDatas.emplace_back(w); - w->column = self; + w->column = self; + w->windowSize = 1.F / (float)(windowDatas.size() + 1); } void SColumnData::remove(PHLWINDOW w) { + const auto SIZE_BEFORE = windowDatas.size(); std::erase_if(windowDatas, [&w](const auto& e) { return e->window == w; }); + + if (SIZE_BEFORE == windowDatas.size() && SIZE_BEFORE > 0) + return; + + float newMaxSize = 0.F; + for (auto& wd : windowDatas) { + newMaxSize += wd->windowSize; + } + + for (auto& wd : windowDatas) { + wd->windowSize *= 1.F / newMaxSize; + } + if (windowDatas.empty() && workspace) workspace->remove(self.lock()); } @@ -38,6 +67,28 @@ void SColumnData::down(SP w) { } } +SP SColumnData::next(SP w) { + for (size_t i = 0; i < windowDatas.size() - 1; ++i) { + if (windowDatas[i] != w) + continue; + + return windowDatas[i + 1]; + } + + return nullptr; +} + +SP SColumnData::prev(SP w) { + for (size_t i = 1; i < windowDatas.size(); ++i) { + if (windowDatas[i] != w) + continue; + + return windowDatas[i - 1]; + } + + return nullptr; +} + SP SWorkspaceData::add() { static const auto PCOLWIDTH = CConfigValue("plugin:hyprscrolling:column_width"); auto col = columns.emplace_back(makeShared(self.lock())); @@ -131,19 +182,18 @@ void SWorkspaceData::recalculate() { PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - const CBox USABLE = CBox{PMONITOR->m_reservedTopLeft, PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight}; + const CBox USABLE = layout->usableAreaFor(PMONITOR); double currentLeft = MAX_WIDTH < USABLE.w ? std::round((USABLE.w - MAX_WIDTH) / 2.0) : leftOffset; // layout pixels for (const auto& COL : columns) { - double currentTop = 0.0; - const double ITEM_HEIGHT = USABLE.h / COL->windowDatas.size(); - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; + double currentTop = 0.0; + const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; for (const auto& WINDOW : COL->windowDatas) { - WINDOW->layoutBox = CBox{currentLeft, currentTop, ITEM_WIDTH, ITEM_HEIGHT}.translate(PMONITOR->m_position + PMONITOR->m_reservedTopLeft); + WINDOW->layoutBox = CBox{currentLeft, currentTop, ITEM_WIDTH, WINDOW->windowSize * USABLE.h}.translate(PMONITOR->m_position + PMONITOR->m_reservedTopLeft); - currentTop += ITEM_HEIGHT; + currentTop += WINDOW->windowSize * USABLE.h; layout->applyNodeDataToWindow(WINDOW, false); } @@ -376,8 +426,98 @@ void CScrollingLayout::onBeginDragWindow() { IHyprLayout::onBeginDragWindow(); } -void CScrollingLayout::resizeActiveWindow(const Vector2D&, eRectCorner corner, PHLWINDOW pWindow) { - ; +void CScrollingLayout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow) { + const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_lastWindow.lock(); + + if (!validMapped(PWINDOW)) + return; + + const auto DATA = dataFor(PWINDOW); + + if (!DATA) { + *PWINDOW->m_realSize = + (PWINDOW->m_realSize->goal() + delta) + .clamp(PWINDOW->m_windowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_windowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); + PWINDOW->updateWindowDecos(); + return; + } + + if (corner == CORNER_NONE) + return; + + if (!DATA->column || !DATA->column->workspace || !DATA->column->workspace->workspace || !DATA->column->workspace->workspace->m_monitor) + return; + + const auto USABLE = usableAreaFor(DATA->column->workspace->workspace->m_monitor.lock()); + const auto DELTA_AS_PERC = delta / USABLE.size(); + + const auto CURR_COLUMN = DATA->column.lock(); + const auto NEXT_COLUMN = DATA->column->workspace->next(CURR_COLUMN); + const auto PREV_COLUMN = DATA->column->workspace->prev(CURR_COLUMN); + + switch (corner) { + case CORNER_BOTTOMLEFT: + case CORNER_TOPLEFT: { + if (!PREV_COLUMN) + break; + + PREV_COLUMN->columnWidth = std::clamp(PREV_COLUMN->columnWidth + (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); + CURR_COLUMN->columnWidth = std::clamp(CURR_COLUMN->columnWidth - (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); + break; + } + case CORNER_BOTTOMRIGHT: + case CORNER_TOPRIGHT: { + if (!NEXT_COLUMN) + break; + + NEXT_COLUMN->columnWidth = std::clamp(NEXT_COLUMN->columnWidth - (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); + CURR_COLUMN->columnWidth = std::clamp(CURR_COLUMN->columnWidth + (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); + break; + } + + default: break; + } + + if (DATA->column->windowDatas.size() > 1) { + const auto CURR_WD = DATA; + const auto NEXT_WD = DATA->column->next(DATA); + const auto PREV_WD = DATA->column->prev(DATA); + + switch (corner) { + case CORNER_BOTTOMLEFT: + case CORNER_BOTTOMRIGHT: { + if (!NEXT_WD) + break; + + if (NEXT_WD->windowSize <= MIN_ROW_HEIGHT && delta.y >= 0) + break; + + float adjust = std::clamp((float)(delta.y / USABLE.h), (-CURR_WD->windowSize + MIN_ROW_HEIGHT), (NEXT_WD->windowSize - MIN_ROW_HEIGHT)); + + NEXT_WD->windowSize = std::clamp(NEXT_WD->windowSize - adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); + CURR_WD->windowSize = std::clamp(CURR_WD->windowSize + adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); + break; + } + case CORNER_TOPLEFT: + case CORNER_TOPRIGHT: { + if (!PREV_WD) + break; + + if (PREV_WD->windowSize <= MIN_ROW_HEIGHT && delta.y <= 0 || CURR_WD->windowSize <= MIN_ROW_HEIGHT && delta.y >= 0) + break; + + float adjust = std::clamp((float)(delta.y / USABLE.h), -(PREV_WD->windowSize - MIN_ROW_HEIGHT), (CURR_WD->windowSize - MIN_ROW_HEIGHT)); + + PREV_WD->windowSize = std::clamp(PREV_WD->windowSize + adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); + CURR_WD->windowSize = std::clamp(CURR_WD->windowSize - adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); + break; + } + + default: break; + } + } + + DATA->column->workspace->recalculate(); } void CScrollingLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { @@ -467,7 +607,7 @@ std::any CScrollingLayout::layoutMessage(SLayoutMessageHeader header, std::strin WDATA->column->columnWidth = abs; } - WDATA->column->columnWidth = std::clamp(WDATA->column->columnWidth, 0.05F, 1.F); + WDATA->column->columnWidth = std::clamp(WDATA->column->columnWidth, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); WDATA->column->workspace->recalculate(); } else if (ARGS[0] == "movewindowto") { @@ -576,3 +716,7 @@ SP CScrollingLayout::currentWorkspaceData() { return dataFor(g_pCompositor->m_lastMonitor->m_activeWorkspace); } + +CBox CScrollingLayout::usableAreaFor(PHLMONITOR m) { + return CBox{m->m_reservedTopLeft, m->m_size - m->m_reservedTopLeft - m->m_reservedBottomRight}; +} diff --git a/hyprscrolling/Scrolling.hpp b/hyprscrolling/Scrolling.hpp index 94ffda8..3e1ff68 100644 --- a/hyprscrolling/Scrolling.hpp +++ b/hyprscrolling/Scrolling.hpp @@ -9,12 +9,13 @@ struct SColumnData; struct SWorkspaceData; struct SScrollingWindowData { - SScrollingWindowData(PHLWINDOW w, SP col) : window(w), column(col) { + SScrollingWindowData(PHLWINDOW w, SP col, float ws = 1.F) : window(w), column(col), windowSize(ws) { ; } PHLWINDOWREF window; WP column; + float windowSize = 1.F; CBox layoutBox; }; @@ -28,8 +29,11 @@ struct SColumnData { void add(SP w); void remove(PHLWINDOW w); - void up(SP w); - void down(SP w); + void up(SP w); + void down(SP w); + + SP next(SP w); + SP prev(SP w); std::vector> windowDatas; float columnSize = 1.F; @@ -85,6 +89,8 @@ class CScrollingLayout : public IHyprLayout { virtual void onEnable(); virtual void onDisable(); + CBox usableAreaFor(PHLMONITOR m); + private: std::vector> m_workspaceDatas;