From 91995c57ee8454886dcd670370e1382deaf7450d Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Sun, 19 Jul 2026 21:21:26 +0200 Subject: [PATCH] Add paused-state vignette border to game world view Draw a black gradient border (50% alpha at the viewport edges fading to transparent toward the center) while the game is paused (speed 0x), making the paused state hard to miss. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc --- src/ui/GameWorldView.cpp | 41 ++++++++++++++++++++++++++++++++++++++++ src/ui/GameWorldView.h | 4 ++++ 2 files changed, 45 insertions(+) diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 0005915..a552723 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -431,6 +431,7 @@ void GameWorldView::paintGL() drawBeams(painter); drawOverlays(painter); drawScreenSpace(painter); + drawPauseBorder(painter); drawReplayOverlay(painter); } @@ -1695,6 +1696,46 @@ void GameWorldView::drawScreenSpace(QPainter& /*painter*/) { } +void GameWorldView::drawPauseBorder(QPainter& painter) +{ + if (m_gameSpeedMultiplier > 0.0) { return; } + + // Border thickness in pixels, capped so it never exceeds half the viewport on + // very small windows (which would leave no un-darkened center). + const qreal borderPx = std::min( + 100.0, std::min(width(), height()) / 2.0); + if (borderPx <= 0.0) { return; } + + const QColor edge(0, 0, 0, 128); // 50% black at the viewport edge + const QColor inner(0, 0, 0, 0); // fully transparent toward the center + + painter.save(); + + // Each side is a linear gradient fading from `edge` at the viewport border to + // `inner` toward the center. Corners overlap and read as a natural vignette. + QLinearGradient left(0, 0, borderPx, 0); + left.setColorAt(0.0, edge); + left.setColorAt(1.0, inner); + painter.fillRect(QRectF(0, 0, borderPx, height()), left); + + QLinearGradient right(width(), 0, width() - borderPx, 0); + right.setColorAt(0.0, edge); + right.setColorAt(1.0, inner); + painter.fillRect(QRectF(width() - borderPx, 0, borderPx, height()), right); + + QLinearGradient top(0, 0, 0, borderPx); + top.setColorAt(0.0, edge); + top.setColorAt(1.0, inner); + painter.fillRect(QRectF(0, 0, width(), borderPx), top); + + QLinearGradient bottom(0, height(), 0, height() - borderPx); + bottom.setColorAt(0.0, edge); + bottom.setColorAt(1.0, inner); + painter.fillRect(QRectF(0, height() - borderPx, width(), borderPx), bottom); + + painter.restore(); +} + void GameWorldView::drawReplayOverlay(QPainter& painter) { if (!m_replayPlayer) { return; } diff --git a/src/ui/GameWorldView.h b/src/ui/GameWorldView.h index d65a7ef..d0ef2c0 100644 --- a/src/ui/GameWorldView.h +++ b/src/ui/GameWorldView.h @@ -131,6 +131,10 @@ private: void drawBeams(QPainter& painter); void drawOverlays(QPainter& painter); void drawScreenSpace(QPainter& painter); + // Vignette-style border shown while the game is paused (speed 0x) to make the + // paused state hard to miss: a black frame whose alpha fades from 50% at the + // viewport edges to 0% toward the center. + void drawPauseBorder(QPainter& painter); void drawReplayOverlay(QPainter& painter); float getTilePx() const;