189 lines
5.6 KiB
C++
189 lines
5.6 KiB
C++
#include "InspectWindow.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QCloseEvent>
|
|
#include <QHBoxLayout>
|
|
#include <QKeyEvent>
|
|
#include <QSignalMapper>
|
|
#include <QVBoxLayout>
|
|
|
|
#include "ArenaView.h"
|
|
|
|
const double InspectWindow::kSpeeds[] = { 0.0, 0.5, 1.0, 2.0, 4.0 };
|
|
const int InspectWindow::kSpeedCount = 5;
|
|
|
|
InspectWindow::InspectWindow(ArenaSimulation* sim, const VisualsConfig* visuals,
|
|
const std::string& arenaName, QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_sim(sim)
|
|
{
|
|
setWindowTitle(QString("Inspect \u2014 %1").arg(QString::fromStdString(arenaName)));
|
|
resize(900, 700);
|
|
setAttribute(Qt::WA_DeleteOnClose, false);
|
|
|
|
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
mainLayout->setSpacing(0);
|
|
|
|
// Header: arena name + speed buttons
|
|
{
|
|
QWidget* header = new QWidget(this);
|
|
QHBoxLayout* headerLayout = new QHBoxLayout(header);
|
|
headerLayout->setContentsMargins(8, 4, 8, 4);
|
|
headerLayout->setSpacing(8);
|
|
|
|
QLabel* nameLabel = new QLabel(QString::fromStdString(arenaName), header);
|
|
QFont nameFont = nameLabel->font();
|
|
nameFont.setBold(true);
|
|
nameFont.setPointSize(nameFont.pointSize() + 2);
|
|
nameLabel->setFont(nameFont);
|
|
headerLayout->addWidget(nameLabel);
|
|
|
|
headerLayout->addStretch();
|
|
|
|
const char* labels[] = { "0x", "0.5x", "1x", "2x", "4x" };
|
|
QSignalMapper* mapper = new QSignalMapper(this);
|
|
for (int i = 0; i < kSpeedCount; ++i)
|
|
{
|
|
QPushButton* btn = new QPushButton(labels[i], header);
|
|
btn->setCheckable(true);
|
|
btn->setChecked(i == 2);
|
|
headerLayout->addWidget(btn);
|
|
m_speedButtons.push_back(btn);
|
|
mapper->setMapping(btn, i);
|
|
connect(btn, &QPushButton::clicked,
|
|
mapper, qOverload<>(&QSignalMapper::map));
|
|
}
|
|
connect(mapper, qOverload<int>(&QSignalMapper::mapped),
|
|
this, &InspectWindow::onSpeedButton);
|
|
|
|
header->setFixedHeight(header->sizeHint().height());
|
|
mainLayout->addWidget(header);
|
|
}
|
|
|
|
// Arena view (center, stretch)
|
|
m_arenaView = new ArenaView(sim, visuals, this);
|
|
mainLayout->addWidget(m_arenaView, 1);
|
|
|
|
connect(m_arenaView, &ArenaView::speedChanged,
|
|
this, &InspectWindow::onSpeedChanged);
|
|
|
|
// Info panel (bottom)
|
|
{
|
|
QWidget* infoPanel = new QWidget(this);
|
|
QHBoxLayout* infoLayout = new QHBoxLayout(infoPanel);
|
|
infoLayout->setContentsMargins(8, 4, 8, 4);
|
|
infoLayout->setSpacing(16);
|
|
|
|
QVBoxLayout* team1Layout = new QVBoxLayout();
|
|
m_team1Header = new QLabel(infoPanel);
|
|
QFont headerFont = m_team1Header->font();
|
|
headerFont.setBold(true);
|
|
m_team1Header->setFont(headerFont);
|
|
team1Layout->addWidget(m_team1Header);
|
|
m_team1Content = new QLabel(infoPanel);
|
|
team1Layout->addWidget(m_team1Content);
|
|
team1Layout->addStretch();
|
|
infoLayout->addLayout(team1Layout);
|
|
|
|
QVBoxLayout* team2Layout = new QVBoxLayout();
|
|
m_team2Header = new QLabel(infoPanel);
|
|
m_team2Header->setFont(headerFont);
|
|
team2Layout->addWidget(m_team2Header);
|
|
m_team2Content = new QLabel(infoPanel);
|
|
team2Layout->addWidget(m_team2Content);
|
|
team2Layout->addStretch();
|
|
infoLayout->addLayout(team2Layout);
|
|
|
|
mainLayout->addWidget(infoPanel);
|
|
}
|
|
|
|
// Poll timer for info panel updates
|
|
m_pollTimer = new QTimer(this);
|
|
connect(m_pollTimer, &QTimer::timeout, this, &InspectWindow::pollStatus);
|
|
m_pollTimer->start(100);
|
|
|
|
// Show initial status
|
|
pollStatus();
|
|
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
}
|
|
|
|
void InspectWindow::closeEvent(QCloseEvent* event)
|
|
{
|
|
m_arenaView->stopRendering();
|
|
m_pollTimer->stop();
|
|
emit closed();
|
|
event->accept();
|
|
}
|
|
|
|
void InspectWindow::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
if (event->key() == Qt::Key_Space)
|
|
{
|
|
m_arenaView->togglePause();
|
|
}
|
|
else
|
|
{
|
|
QWidget::keyPressEvent(event);
|
|
}
|
|
}
|
|
|
|
void InspectWindow::onSpeedButton(int index)
|
|
{
|
|
if (index >= 0 && index < kSpeedCount)
|
|
{
|
|
m_arenaView->setGameSpeed(kSpeeds[index]);
|
|
}
|
|
}
|
|
|
|
void InspectWindow::onSpeedChanged(double multiplier)
|
|
{
|
|
for (int i = 0; i < kSpeedCount; ++i)
|
|
{
|
|
const bool active = (std::abs(kSpeeds[i] - multiplier) < 0.001);
|
|
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(active);
|
|
}
|
|
}
|
|
|
|
void InspectWindow::pollStatus()
|
|
{
|
|
const ArenaStatus status = m_sim->status();
|
|
updateInfoPanel(status);
|
|
}
|
|
|
|
void InspectWindow::updateInfoPanel(const ArenaStatus& status)
|
|
{
|
|
for (int ti = 0; ti < 2; ++ti)
|
|
{
|
|
const ArenaStatus::TeamStatus& team = status.teams[ti];
|
|
QLabel* header = (ti == 0) ? m_team1Header : m_team2Header;
|
|
QLabel* content = (ti == 0) ? m_team1Content : m_team2Content;
|
|
|
|
if (status.finished && status.winnerTeam == ti)
|
|
{
|
|
header->setText("[WON] " + QString::fromStdString(team.name));
|
|
}
|
|
else
|
|
{
|
|
header->setText(QString::fromStdString(team.name));
|
|
}
|
|
|
|
QString lines;
|
|
for (const ArenaStatus::Entry& entry : team.entries)
|
|
{
|
|
if (!lines.isEmpty())
|
|
{
|
|
lines += "\n";
|
|
}
|
|
lines += QString("%1/%2 %3 L%4")
|
|
.arg(entry.surviving)
|
|
.arg(entry.total)
|
|
.arg(QString::fromStdString(entry.displayName))
|
|
.arg(entry.level);
|
|
}
|
|
content->setText(lines);
|
|
}
|
|
}
|