make empty layout cells pulse while module is selected

This commit is contained in:
2026-07-20 22:12:56 +02:00
parent be475e2836
commit c7ecce6ac4
2 changed files with 45 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
#include "ShipLayoutDialog.h"
#include "ShipStatsPanel.h"
#include <cmath>
#include <functional>
#include "DisplayName.h"
@@ -12,8 +13,10 @@
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QElapsedTimer>
#include <QScrollArea>
#include <QSignalMapper>
#include <QTimer>
#include <QVBoxLayout>
namespace
@@ -21,6 +24,13 @@ namespace
const int kCellSize = 32;
// Empty ship tiles pulse between this grey and white at 1 Hz while a module is
// selected, to draw the player's attention to where modules can be placed.
const double kTwoPi = 6.283185307179586;
const int kPulseIntervalMs = 33;
const int kEmptyCellGrey = 240;
const int kPulseAmplitude = 15;
std::vector<std::string> rotateMaskCW(const std::vector<std::string>& grid)
{
if (grid.empty())
@@ -68,6 +78,10 @@ public:
, m_dialog(dialog)
{
setMouseTracking(true);
m_pulseClock.start();
m_pulseTimer = new QTimer(this);
m_pulseTimer->setInterval(kPulseIntervalMs);
connect(m_pulseTimer, &QTimer::timeout, this, [this]() { update(); });
}
void setGridData(const std::vector<std::vector<ShipLayoutDialog::CellInfo>>* grid,
@@ -87,6 +101,19 @@ public:
{
m_ghostModuleIdx = moduleIndex;
m_ghostRotation = rotation;
// Only animate the empty-tile pulse while a module is selected.
if (moduleIndex.has_value())
{
if (!m_pulseTimer->isActive())
{
m_pulseClock.restart();
m_pulseTimer->start();
}
}
else
{
m_pulseTimer->stop();
}
}
protected:
@@ -100,6 +127,19 @@ protected:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, false);
// While a module is selected, pulse empty tiles at 1 Hz around the base
// grey (kEmptyCellGrey +/- kPulseAmplitude). All empty tiles share the
// same phase, so compute it once.
QColor emptyCellColor(kEmptyCellGrey, kEmptyCellGrey, kEmptyCellGrey);
if (m_ghostModuleIdx.has_value())
{
const double seconds = m_pulseClock.elapsed() / 1000.0;
const double oscillation = std::sin(seconds * kTwoPi);
const int channel = kEmptyCellGrey
+ static_cast<int>(std::lround(oscillation * kPulseAmplitude));
emptyCellColor = QColor(channel, channel, channel);
}
for (int r = 0; r < m_rows; ++r)
{
for (int c = 0; c < m_cols; ++c)
@@ -131,7 +171,7 @@ protected:
}
else
{
painter.fillRect(cellRect, QColor(240, 240, 240));
painter.fillRect(cellRect, emptyCellColor);
}
painter.setPen(QColor(100, 100, 100));
@@ -241,6 +281,8 @@ private:
std::optional<int> m_ghostModuleIdx;
Rotation m_ghostRotation = Rotation::East;
QPoint m_hoverCell = QPoint(-1, -1);
QTimer* m_pulseTimer = nullptr;
QElapsedTimer m_pulseClock;
};