diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2026-05-07 15:21:06 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-07 15:21:06 +0100 |
| commit | 58833eb1d79d7f03402cee0730c309b79f2e4501 (patch) | |
| tree | 180cadc5d2e6fcb9e2f090eeccc6fb4ccace9b51 /src/layout/algorithm/tiled | |
| parent | 6b8b20100253c083227e611be20360f4d8e7794e (diff) | |
layout/scrolling: handle fullscreen manually (#14190)
Makes scroll handle fullscreen by itself, allowing for fs scrolls.
Diffstat (limited to 'src/layout/algorithm/tiled')
4 files changed, 448 insertions, 48 deletions
diff --git a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp index 657b6542..722b9bd8 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.cpp @@ -147,14 +147,10 @@ double CScrollTapeController::calculateStripSize(size_t stripIndex, const CBox& return usablePrimary * m_strips[stripIndex].size; } -CBox CScrollTapeController::calculateTargetBox(size_t stripIndex, size_t targetIndex, const CBox& usableArea, const Vector2D& workspaceOffset, bool fullscreenOnOne) { +CBox CScrollTapeController::calculateStripBox(size_t stripIndex, const CBox& usableArea, const Vector2D& workspaceOffset, bool fullscreenOnOne) { if (stripIndex >= m_strips.size()) return {}; - const auto& strip = m_strips[stripIndex]; - if (targetIndex >= strip.targetSizes.size()) - return {}; - const double usableSecondary = getSecondary(usableArea.size()); const double usablePrimary = getPrimary(usableArea.size()); const double cameraOffset = calculateCameraOffset(usableArea, fullscreenOnOne); @@ -163,13 +159,6 @@ CBox CScrollTapeController::calculateTargetBox(size_t stripIndex, size_t targetI double primaryPos = calculateStripStart(stripIndex, usableArea, fullscreenOnOne); double primarySize = calculateStripSize(stripIndex, usableArea, fullscreenOnOne); - // calculate position along secondary axis (within strip) - double secondaryPos = 0.0; - for (size_t i = 0; i < targetIndex; ++i) { - secondaryPos += strip.targetSizes[i] * usableSecondary; - } - double secondarySize = strip.targetSizes[targetIndex] * usableSecondary; - // apply camera offset based on direction // for RIGHT/DOWN: scroll offset moves content left/up (subtract) // for LEFT/UP: scroll offset moves content right/down (different coordinate system) @@ -185,8 +174,8 @@ CBox CScrollTapeController::calculateTargetBox(size_t stripIndex, size_t targetI } // create the box in primary/secondary coordinates - Vector2D pos = makeVector(primaryPos, secondaryPos); - Vector2D size = makeVector(primarySize, secondarySize); + Vector2D pos = makeVector(primaryPos, 0.0); + Vector2D size = makeVector(primarySize, usableSecondary); // translate to workspace position pos = pos + workspaceOffset; @@ -194,6 +183,35 @@ CBox CScrollTapeController::calculateTargetBox(size_t stripIndex, size_t targetI return CBox{pos, size}; } +CBox CScrollTapeController::calculateTargetBox(size_t stripIndex, size_t targetIndex, const CBox& usableArea, const Vector2D& workspaceOffset, bool fullscreenOnOne) { + if (stripIndex >= m_strips.size()) + return {}; + + const auto& strip = m_strips[stripIndex]; + if (targetIndex >= strip.targetSizes.size()) + return {}; + + CBox stripBox = calculateStripBox(stripIndex, usableArea, workspaceOffset, fullscreenOnOne); + const double usableSecondary = getSecondary(usableArea.size()); + + double secondaryPos = 0.0; + for (size_t i = 0; i < targetIndex; ++i) { + secondaryPos += strip.targetSizes[i] * usableSecondary; + } + + const double secondarySize = strip.targetSizes[targetIndex] * usableSecondary; + + if (isPrimaryHorizontal()) { + stripBox.y = workspaceOffset.y + secondaryPos; + stripBox.h = secondarySize; + } else { + stripBox.x = workspaceOffset.x + secondaryPos; + stripBox.w = secondarySize; + } + + return stripBox; +} + double CScrollTapeController::calculateCameraOffset(const CBox& usableArea, bool fullscreenOnOne) { const double maxExtent = calculateMaxExtent(usableArea, fullscreenOnOne); const double usablePrimary = getPrimary(usableArea.size()); @@ -275,13 +293,14 @@ size_t CScrollTapeController::getStripAtCenter(const CBox& usableArea, bool full return 0; const double usablePrimary = getPrimary(usableArea.size()); - double currentPos = m_offset; + const double viewCenter = m_offset + usablePrimary / 2.0; + double currentEnd = 0.0; for (size_t i = 0; i < m_strips.size(); ++i) { const double stripSize = calculateStripSize(i, usableArea, fullscreenOnOne); - currentPos += stripSize; + currentEnd += stripSize; - if (currentPos >= usablePrimary / 2.0 - 2.0) + if (currentEnd >= viewCenter - 2.0) return i; } diff --git a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp index da2efbba..8006c4a5 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollTapeController.hpp @@ -55,6 +55,7 @@ namespace Layout::Tiled { double calculateStripStart(size_t stripIndex, const CBox& usableArea, bool fullscreenOnOne = false) const; double calculateStripSize(size_t stripIndex, const CBox& usableArea, bool fullscreenOnOne = false) const; + CBox calculateStripBox(size_t stripIndex, const CBox& usableArea, const Vector2D& workspaceOffset, bool fullscreenOnOne = false); CBox calculateTargetBox(size_t stripIndex, size_t targetIndex, const CBox& usableArea, const Vector2D& workspaceOffset, bool fullscreenOnOne = false); double calculateCameraOffset(const CBox& usableArea, bool fullscreenOnOne = false); diff --git a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp index 28941109..2914ae8b 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.cpp @@ -11,6 +11,7 @@ #include "../../../../config/shared/workspace/WorkspaceRuleManager.hpp" #include "../../../../render/Renderer.hpp" #include "../../../../managers/input/InputManager.hpp" +#include "../../../../managers/animation/DesktopAnimationManager.hpp" #include "../../../../event/EventBus.hpp" #include <hyprutils/string/VarList2.hpp> @@ -427,23 +428,83 @@ void SScrollingData::recalculate(bool forceInstant) { algorithm->m_parent->space()->workspace()->m_hasFullscreenWindow) return; + algorithm->syncFullscreenTargets(); + static const auto PFSONONE = CConfigValue<Config::INTEGER>("scrolling:fullscreen_on_one_column"); const CBox USABLE = algorithm->usableArea(); const auto WORKAREA = algorithm->m_parent->space()->workArea(); + const CBox MONBOX = algorithm->m_parent->space()->workspace()->m_monitor->logicalBox(); + + const auto WORKSPACERULE = Config::workspaceRuleMgr()->getWorkspaceRuleFor(algorithm->m_parent->space()->workspace()); + static auto PGAPSINDATA = CConfigValue<Config::IComplexConfigValue>("general:gaps_in"); + auto* const PGAPSIN = sc<Config::CCssGapData*>((PGAPSINDATA.ptr())); + const auto GAPSIN = (WORKSPACERULE && WORKSPACERULE->m_gapsIn.has_value()) ? WORKSPACERULE->m_gapsIn.value() : *PGAPSIN; + + bool anyFullscreenCovers = false; + for (const auto& COL : columns) { + if (algorithm->fullscreenTargetDataForColumn(COL) && algorithm->fullscreenColumnCoversMonitor(COL)) { + anyFullscreenCovers = true; + break; + } + } controller->setDirection(algorithm->getDynamicDirection()); + algorithm->updateFullscreenFade(anyFullscreenCovers); + + const auto targetBoxWithGaps = [&](const CBox& logical, size_t colIdx, size_t targetIdx, bool fullscreenOrHidden) -> STargetBox { + if (fullscreenOrHidden) + return {.logicalBox = logical, .visualBox = logical}; + + CBox visual = logical; + const bool PRIMARY_HORIZ = controller->isPrimaryHorizontal(); + + const bool GAP_LEFT = PRIMARY_HORIZ ? colIdx > 0 : targetIdx > 0; + const bool GAP_RIGHT = PRIMARY_HORIZ ? colIdx + 1 < columns.size() : targetIdx + 1 < columns[colIdx]->targetDatas.size(); + const bool GAP_TOP = PRIMARY_HORIZ ? targetIdx > 0 : colIdx > 0; + const bool GAP_BOTTOM = PRIMARY_HORIZ ? targetIdx + 1 < columns[colIdx]->targetDatas.size() : colIdx + 1 < columns.size(); + + const auto GAPOFFSETTOPLEFT = Vector2D(sc<double>(GAP_LEFT ? GAPSIN.m_left : 0), sc<double>(GAP_TOP ? GAPSIN.m_top : 0)); + const auto GAPOFFSETBOTTOMRIGHT = Vector2D(sc<double>(GAP_RIGHT ? GAPSIN.m_right : 0), sc<double>(GAP_BOTTOM ? GAPSIN.m_bottom : 0)); + + visual.x += GAPOFFSETTOPLEFT.x; + visual.y += GAPOFFSETTOPLEFT.y; + visual.w = std::max(1.0, visual.w - GAPOFFSETTOPLEFT.x - GAPOFFSETBOTTOMRIGHT.x); + visual.h = std::max(1.0, visual.h - GAPOFFSETTOPLEFT.y - GAPOFFSETBOTTOMRIGHT.y); + + return {.logicalBox = logical, .visualBox = visual}; + }; for (size_t i = 0; i < columns.size(); ++i) { const auto& COL = columns[i]; + const auto FS = algorithm->fullscreenTargetDataForColumn(COL); for (size_t j = 0; j < COL->targetDatas.size(); ++j) { const auto& TARGET = COL->targetDatas[j]; - TARGET->layoutBox = controller->calculateTargetBox(i, j, USABLE, WORKAREA.pos(), *PFSONONE); + if (FS) { + if (TARGET == FS) { + if (algorithm->fullscreenColumnCoversMonitor(COL)) + TARGET->layoutBox = MONBOX; + else { + TARGET->layoutBox = controller->calculateStripBox(i, USABLE, WORKAREA.pos(), *PFSONONE); + + if (controller->isPrimaryHorizontal()) { + TARGET->layoutBox.y = MONBOX.y; + TARGET->layoutBox.h = MONBOX.h; + } else { + TARGET->layoutBox.x = MONBOX.x; + TARGET->layoutBox.w = MONBOX.w; + } + } + } else + TARGET->layoutBox = CBox{WORKAREA.pos() - Vector2D{100000.0, 100000.0}, Vector2D{1.0, 1.0}}; + } else + TARGET->layoutBox = controller->calculateTargetBox(i, j, USABLE, WORKAREA.pos(), *PFSONONE); if (TARGET->target) - TARGET->target->setPositionGlobal(TARGET->layoutBox); + TARGET->target->setPositionGlobal(targetBoxWithGaps(TARGET->layoutBox, i, j, FS)); + if (forceInstant && TARGET->target) TARGET->target->warpPositionSize(); } @@ -544,6 +605,9 @@ CScrollingAlgorithm::CScrollingAlgorithm() { } CScrollingAlgorithm::~CScrollingAlgorithm() { + clearFullscreenTarget(); + updateFullscreenFade(false); + m_configCallback.reset(); m_focusCallback.reset(); } @@ -631,6 +695,8 @@ void CScrollingAlgorithm::removeTarget(SP<ITarget> target) { if (!DATA) return; + clearFullscreenTarget(target); + if (!m_scrollingData->next(DATA->column.lock()) && DATA->column->targetDatas.size() <= 1) { // move the view if this is the last column const auto USABLE = usableArea(); @@ -814,6 +880,303 @@ void CScrollingAlgorithm::recalculate() { m_scrollingData->recalculate(); } +void CScrollingAlgorithm::syncFullscreenTargets() { + for (auto it = m_fullscreenTargets.begin(); it != m_fullscreenTargets.end();) { + const auto TARGET = it->target.lock(); + + if (!TARGET || !TARGET->layoutManagedFullscreen() || TARGET->fullscreenMode() != FSMODE_FULLSCREEN || TARGET->space() != m_parent->space()) { + it = m_fullscreenTargets.erase(it); + continue; + } + + const auto TDATA = dataFor(TARGET); + if (!TDATA) { + ++it; + continue; + } + + if (const auto COL = TDATA->column.lock()) + COL->setColumnWidth(fullscreenColumnWidth()); + + ++it; + } + + for (const auto& COL : m_scrollingData->columns) { + for (const auto& TDATA : COL->targetDatas) { + const auto TARGET = TDATA->target.lock(); + if (!TARGET || !TARGET->layoutManagedFullscreen() || TARGET->fullscreenMode() != FSMODE_FULLSCREEN || TARGET->space() != m_parent->space()) + continue; + + if (!fullscreenStateForTarget(TARGET)) + m_fullscreenTargets.emplace_back(SFullscreenScrollState{.target = TARGET, .restoreColumnWidth = COL ? std::optional<float>{COL->getColumnWidth()} : std::nullopt}); + + COL->setColumnWidth(fullscreenColumnWidth()); + } + } +} + +CScrollingAlgorithm::SFullscreenScrollState* CScrollingAlgorithm::fullscreenStateForTarget(SP<ITarget> target) { + if (!target) + return nullptr; + + for (auto& state : m_fullscreenTargets) { + if (state.target.lock() == target) + return &state; + } + + return nullptr; +} + +CScrollingAlgorithm::SFullscreenScrollState* CScrollingAlgorithm::fullscreenStateForData(SP<SScrollingTargetData> target) { + if (!target) + return nullptr; + + return fullscreenStateForTarget(target->target.lock()); +} + +void CScrollingAlgorithm::expelTarget(SP<SScrollingTargetData> tdata, SP<SColumnData> srcCol, std::optional<int64_t> insertIdx) { + auto col = !insertIdx ? m_scrollingData->add() : m_scrollingData->add(*insertIdx); + srcCol->remove(tdata->target.lock()); + col->add(tdata); + m_scrollingData->centerOrFitCol(col); +} + +eFullscreenRequestResult CScrollingAlgorithm::requestFullscreen(const SFullscreenRequest& request) { + if (!request.target || !m_parent || request.target->space() != m_parent->space()) + return FULLSCREEN_REQUEST_DEFAULT; + + const auto TDATA = dataFor(request.target); + if (!TDATA) + return FULLSCREEN_REQUEST_DEFAULT; + + if (request.effectiveMode == FSMODE_FULLSCREEN) { + if (!fullscreenStateForTarget(request.target)) { + const auto COL = TDATA->column.lock(); + m_fullscreenTargets.emplace_back( + SFullscreenScrollState{.target = request.target, .restoreColumnWidth = COL ? std::optional<float>{COL->getColumnWidth()} : std::nullopt}); + } + + if (const auto COL = TDATA->column.lock()) { + COL->setColumnWidth(fullscreenColumnWidth()); + m_scrollingData->centerOrFitCol(COL); + } + + request.target->setFullscreenMode(FSMODE_FULLSCREEN); + + return FULLSCREEN_REQUEST_HANDLED_BY_LAYOUT; + } else if (request.effectiveMode == FSMODE_MAXIMIZED) { + // expel, then max width + const auto CURRENT_COL = TDATA->column.lock(); + + if (CURRENT_COL->targetDatas.size() > 1) { + const auto lastTarget = CURRENT_COL->targetDatas.back(); + const auto currentIdx = m_scrollingData->idx(CURRENT_COL); + const auto NEXT_COL = m_scrollingData->next(CURRENT_COL); + const auto insertIdx = !NEXT_COL ? std::nullopt : std::optional<int64_t>{currentIdx}; + + expelTarget(lastTarget, CURRENT_COL, insertIdx); + + TDATA->column->setColumnWidth(1.F); + } else + CURRENT_COL->setColumnWidth(1.F); + + request.target->setFullscreenMode(FSMODE_NONE); + + return FULLSCREEN_REQUEST_HANDLED_BY_LAYOUT; + } + + if (isFullscreenTarget(TDATA) || request.target->layoutManagedFullscreen()) { + clearFullscreenTarget(request.target); + request.target->setFullscreenMode(FSMODE_NONE); + return request.effectiveMode == FSMODE_NONE ? FULLSCREEN_REQUEST_HANDLED_BY_LAYOUT : FULLSCREEN_REQUEST_DEFAULT; + } + + return FULLSCREEN_REQUEST_DEFAULT; +} + +SP<ITarget> CScrollingAlgorithm::layoutFullscreenTarget() const { + SP<SScrollingTargetData> fallback; + + for (const auto& COL : m_scrollingData->columns) { + for (const auto& TDATA : COL->targetDatas) { + if (!isFullscreenTarget(TDATA)) + continue; + + if (!fallback) + fallback = TDATA; + + if (fullscreenColumnCoversMonitor(TDATA->column.lock())) + return TDATA->target.lock(); + } + } + + return fallback ? fallback->target.lock() : nullptr; +} + +bool CScrollingAlgorithm::layoutFullscreenCoversMonitor() const { + for (const auto& COL : m_scrollingData->columns) { + for (const auto& TDATA : COL->targetDatas) { + if (!isFullscreenTarget(TDATA)) + continue; + + if (fullscreenColumnCoversMonitor(TDATA->column.lock())) + return true; + } + } + + return false; +} + +SP<SScrollingTargetData> CScrollingAlgorithm::fullscreenTargetDataForColumn(SP<SColumnData> col) const { + if (!col) + return nullptr; + + for (const auto& TDATA : col->targetDatas) { + if (!isFullscreenTarget(TDATA)) + continue; + + return TDATA; + } + + return nullptr; +} + +bool CScrollingAlgorithm::isFullscreenTarget(SP<SScrollingTargetData> target) const { + if (!target) + return false; + + const auto TARGET = target->target.lock(); + if (!TARGET || !TARGET->layoutManagedFullscreen() || TARGET->fullscreenMode() == FSMODE_NONE) + return false; + + return dataFor(TARGET) == target; +} + +float CScrollingAlgorithm::fullscreenColumnWidth() const { + if (!m_parent || !m_parent->space() || !m_parent->space()->workspace() || !m_parent->space()->workspace()->m_monitor || !m_scrollingData || !m_scrollingData->controller) + return 1.F; + + const auto USABLE = usableArea(); + const auto MONBOX = m_parent->space()->workspace()->m_monitor->logicalBox(); + const bool PRIMARY_HORIZ = m_scrollingData->controller->isPrimaryHorizontal(); + const double usablePrimary = PRIMARY_HORIZ ? USABLE.w : USABLE.h; + const double monitorPrimary = PRIMARY_HORIZ ? MONBOX.w : MONBOX.h; + + if (usablePrimary <= 0.0) + return 1.F; + + return std::max(1.F, sc<float>(monitorPrimary / usablePrimary)); +} + +bool CScrollingAlgorithm::fullscreenColumnCoversMonitor(SP<SColumnData> col) const { + if (!col || !m_scrollingData || !m_scrollingData->controller || !m_parent || !m_parent->space() || !m_parent->space()->workspace() || + !m_parent->space()->workspace()->m_monitor) + return false; + + if (!fullscreenTargetDataForColumn(col)) + return false; + + const int64_t COL_IDX = m_scrollingData->idx(col); + if (COL_IDX < 0) + return false; + + static const auto PFSONONE = CConfigValue<Config::INTEGER>("scrolling:fullscreen_on_one_column"); + + const auto USABLE = usableArea(); + const bool PRIMARY_HORIZ = m_scrollingData->controller->isPrimaryHorizontal(); + const double VIEW_SIZE = PRIMARY_HORIZ ? USABLE.w : USABLE.h; + const double VIEW_START = m_scrollingData->controller->getOffset(); + const double VIEW_END = VIEW_START + VIEW_SIZE; + const double COL_START = m_scrollingData->controller->calculateStripStart(COL_IDX, USABLE, *PFSONONE); + const double COL_END = COL_START + m_scrollingData->controller->calculateStripSize(COL_IDX, USABLE, *PFSONONE); + + return COL_START <= VIEW_START + 1.0 && COL_END >= VIEW_END - 1.0; +} + +void CScrollingAlgorithm::updateFullscreenFade(bool coversMonitor) { + if (m_lastFullscreenCover == coversMonitor) + return; + + m_lastFullscreenCover = coversMonitor; + + if (!coversMonitor) { + // prevent stuck focus + g_pInputManager->unconstrainMouse(); + for (const auto& fs : m_fullscreenTargets) { + if (!fs.target || !fs.target->window()) + continue; + + auto w = fs.target->window(); + + w->m_layoutFlags.cantLockCursor = true; + } + } else { + for (const auto& fs : m_fullscreenTargets) { + if (!fs.target || !fs.target->window()) + continue; + + auto w = fs.target->window(); + + w->m_layoutFlags.cantLockCursor = false; + } + } + + if (!m_parent || !m_parent->space() || !m_parent->space()->workspace()) + return; + + // properly update things on top / bottom + m_parent->space()->workspace()->setNoMembersAboveFullscreen(); + + g_pDesktopAnimationManager->setFullscreenFadeAnimation(m_parent->space()->workspace(), + coversMonitor ? CDesktopAnimationManager::ANIMATION_TYPE_IN : CDesktopAnimationManager::ANIMATION_TYPE_OUT); +} + +void CScrollingAlgorithm::clearFullscreenTarget(SP<ITarget> target) { + bool cleared = false; + + auto clear = [&](SP<ITarget> t) { + t->setLayoutManagedFullscreen(false); + if (t->window()) + t->window()->m_layoutFlags.cantLockCursor = false; + cleared = true; + }; + + for (auto it = m_fullscreenTargets.begin(); it != m_fullscreenTargets.end();) { + const auto TARGET = it->target.lock(); + + if (!TARGET || (target && TARGET != target)) { + if (!TARGET) + it = m_fullscreenTargets.erase(it); + else + ++it; + continue; + } + + const auto TDATA = dataFor(TARGET); + + clear(TARGET); + + if (const auto COL = TDATA ? TDATA->column.lock() : nullptr; COL && it->restoreColumnWidth) + COL->setColumnWidth(*it->restoreColumnWidth); + + it = m_fullscreenTargets.erase(it); + } + + if (target && target->layoutManagedFullscreen()) + clear(target); + else if (!target) { + for (const auto& COL : m_scrollingData->columns) { + for (const auto& TDATA : COL->targetDatas) { + const auto TARGET = TDATA->target.lock(); + if (!TARGET || !TARGET->layoutManagedFullscreen()) + continue; + + clear(TARGET); + } + } + } +} + SP<SScrollingTargetData> CScrollingAlgorithm::closestNode(const Vector2D& posGlobglobgabgalab) { SP<SScrollingTargetData> res = nullptr; double distClosest = -1; @@ -1372,14 +1735,6 @@ Config::ErrorResult CScrollingAlgorithm::layoutMsg(const std::string_view& sv) { if (!CURRENT_COL) return stateErr("no current col"); - // expel a target from srcCol into its own new column at insertIdx - auto expelTarget = [&](SP<SScrollingTargetData> tdata, SP<SColumnData> srcCol, std::optional<int64_t> insertIdx) { - auto col = !insertIdx ? m_scrollingData->add() : m_scrollingData->add(*insertIdx); - srcCol->remove(tdata->target.lock()); - col->add(tdata); - m_scrollingData->centerOrFitCol(col); - }; - // consume the first target from adjCol into dstCol auto consumeTarget = [&](SP<SColumnData> dstCol, SP<SColumnData> adjCol) { const auto target = adjCol->targetDatas.front(); @@ -1546,7 +1901,7 @@ SP<SScrollingTargetData> CScrollingAlgorithm::findBestNeighbor(SP<SScrollingTarg return nullptr; } -SP<SScrollingTargetData> CScrollingAlgorithm::dataFor(SP<ITarget> t) { +SP<SScrollingTargetData> CScrollingAlgorithm::dataFor(SP<ITarget> t) const { if (!t) return nullptr; @@ -1584,7 +1939,7 @@ eScrollDirection CScrollingAlgorithm::getDynamicDirection() { return SCROLL_DIR_RIGHT; // default } -CBox CScrollingAlgorithm::usableArea() { +CBox CScrollingAlgorithm::usableArea() const { if (!m_parent || !m_parent->space()) return {}; diff --git a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp index 288d15a6..19eb9ba6 100644 --- a/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp +++ b/src/layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp @@ -5,6 +5,7 @@ #include "ScrollTapeController.hpp" #include "../../../../helpers/signal/Signal.hpp" +#include <optional> #include <vector> namespace Layout::Tiled { @@ -94,23 +95,27 @@ namespace Layout::Tiled { CScrollingAlgorithm(); virtual ~CScrollingAlgorithm(); - virtual void newTarget(SP<ITarget> target); - virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt); - virtual void removeTarget(SP<ITarget> target); + virtual void newTarget(SP<ITarget> target); + virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt); + virtual void removeTarget(SP<ITarget> target); - virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE); - virtual void recalculate(); + virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE); + virtual void recalculate(); - virtual SP<ITarget> getNextCandidate(SP<ITarget> old); + virtual SP<ITarget> getNextCandidate(SP<ITarget> old); - virtual Config::ErrorResult layoutMsg(const std::string_view& sv); - virtual std::optional<Vector2D> predictSizeForNewTarget(); + virtual Config::ErrorResult layoutMsg(const std::string_view& sv); + virtual std::optional<Vector2D> predictSizeForNewTarget(); - virtual void swapTargets(SP<ITarget> a, SP<ITarget> b); - virtual void moveTargetInDirection(SP<ITarget> t, Math::eDirection dir, bool silent); + virtual void swapTargets(SP<ITarget> a, SP<ITarget> b); + virtual void moveTargetInDirection(SP<ITarget> t, Math::eDirection dir, bool silent); - CBox usableArea(); - SP<SScrollingTargetData> dataFor(SP<ITarget> t); + virtual eFullscreenRequestResult requestFullscreen(const SFullscreenRequest& request); + virtual SP<ITarget> layoutFullscreenTarget() const; + virtual bool layoutFullscreenCoversMonitor() const; + + CBox usableArea() const; + SP<SScrollingTargetData> dataFor(SP<ITarget> t) const; enum eInputMode : uint8_t { INPUT_MODE_SOFT = 0, @@ -129,16 +134,36 @@ namespace Layout::Tiled { std::vector<float> configuredWidths; } m_config; - eScrollDirection getDynamicDirection(); + eScrollDirection getDynamicDirection(); + + struct SFullscreenScrollState { + WP<ITarget> target; + std::optional<float> restoreColumnWidth; + }; + + void syncFullscreenTargets(); + SFullscreenScrollState* fullscreenStateForTarget(SP<ITarget> target); + SFullscreenScrollState* fullscreenStateForData(SP<SScrollingTargetData> target); + SP<SScrollingTargetData> fullscreenTargetDataForColumn(SP<SColumnData> col) const; + bool isFullscreenTarget(SP<SScrollingTargetData> target) const; + float fullscreenColumnWidth() const; + bool fullscreenColumnCoversMonitor(SP<SColumnData> col) const; + void updateFullscreenFade(bool coversMonitor); + void clearFullscreenTarget(SP<ITarget> target = nullptr); + + SP<SScrollingTargetData> findBestNeighbor(SP<SScrollingTargetData> pCurrent, SP<SColumnData> pTargetCol); + SP<SScrollingTargetData> closestNode(const Vector2D& posGlobglobgabgalab); + + void focusTargetUpdate(SP<ITarget> target); + void moveTargetTo(SP<ITarget> t, Math::eDirection dir, bool silent); + void focusOnInput(SP<ITarget> target, eInputMode input); - SP<SScrollingTargetData> findBestNeighbor(SP<SScrollingTargetData> pCurrent, SP<SColumnData> pTargetCol); - SP<SScrollingTargetData> closestNode(const Vector2D& posGlobglobgabgalab); + void expelTarget(SP<SScrollingTargetData> tdata, SP<SColumnData> srcCol, std::optional<int64_t> insertIdx); - void focusTargetUpdate(SP<ITarget> target); - void moveTargetTo(SP<ITarget> t, Math::eDirection dir, bool silent); - void focusOnInput(SP<ITarget> target, eInputMode input); + float defaultColumnWidth(); - float defaultColumnWidth(); + std::vector<SFullscreenScrollState> m_fullscreenTargets; + bool m_lastFullscreenCover = false; friend struct SScrollingData; }; |
