Files
esa-remote-lite/GamesPanel.cpp
2026-04-01 19:44:03 +01:00

141 lines
5.4 KiB
C++

#include "GamesPanel.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QListWidget>
#include <QPushButton>
#include <QSet>
#include <QSplitter>
#include <QVBoxLayout>
// ---------------------------------------------------------------------------
// Helper: parse "GAM <cmd> CODE1Name1 CODE2Name2 ..." → name->code map
// ---------------------------------------------------------------------------
static QMap<QString,QString> parseGamResponse(const QString &response,
const QString &subCmd)
{
QMap<QString,QString> result;
const QStringList tokens = response.split(' ', Qt::SkipEmptyParts);
if (tokens.size() < 3 || tokens[0] != "GAM" || tokens[1] != subCmd)
return result;
for (const QString &entry : tokens.mid(2)) {
if (entry.isEmpty()) continue;
// First up-to-4 uppercase chars = code, remainder = name
int splitPos = 0;
while (splitPos < entry.size() && entry[splitPos].isUpper())
++splitPos;
const QString code = entry.left(qMin(splitPos, 4));
QString name = entry.mid(code.size());
name.replace("_S", " ");
if (code.isEmpty() || name.isEmpty()) continue;
result[name] = code;
}
return result;
}
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
GamesPanel::GamesPanel(QWidget *parent) : QWidget(parent)
{
auto *layout = new QHBoxLayout(this);
layout->setContentsMargins(2, 2, 2, 2);
auto *splitter = new QSplitter(Qt::Horizontal, this);
// ---- Left pane: Available (not installed) games ----
auto *leftWidget = new QWidget(splitter);
auto *leftLayout = new QVBoxLayout(leftWidget);
leftLayout->setContentsMargins(4, 4, 4, 4);
leftLayout->setSpacing(4);
auto *availLabel = new QLabel("<b>Available Games</b>", leftWidget);
availLabel->setStyleSheet("color: #555;");
m_availableList = new QListWidget(leftWidget);
m_availableList->addItem("Connect to load available games...");
m_addBtn = new QPushButton("Add to Installed →", leftWidget);
m_addBtn->setEnabled(false);
leftLayout->addWidget(availLabel);
leftLayout->addWidget(m_availableList, 1);
leftLayout->addWidget(m_addBtn);
// ---- Right pane: Installed games ----
auto *rightWidget = new QWidget(splitter);
auto *rightLayout = new QVBoxLayout(rightWidget);
rightLayout->setContentsMargins(4, 4, 4, 4);
rightLayout->setSpacing(4);
auto *instLabel = new QLabel("<b>Installed Games</b>", rightWidget);
instLabel->setStyleSheet("color: #555;");
m_installedList = new QListWidget(rightWidget);
m_installedList->addItem("Connect to load installed games...");
rightLayout->addWidget(instLabel);
rightLayout->addWidget(m_installedList, 1);
splitter->addWidget(leftWidget);
splitter->addWidget(rightWidget);
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);
splitter->setSizes({420, 420});
layout->addWidget(splitter);
// Enable Add button only when something is selected in available list
connect(m_availableList, &QListWidget::currentRowChanged, this,
[this](int row) { m_addBtn->setEnabled(row >= 0); });
connect(m_addBtn, &QPushButton::clicked, this, &GamesPanel::onAddClicked);
}
// ---------------------------------------------------------------------------
// Load installed games (GAM list response)
// ---------------------------------------------------------------------------
void GamesPanel::loadFromResponse(const QString &response)
{
m_installedGames = parseGamResponse(response, "list");
m_installedList->clear();
for (const QString &name : m_installedGames.keys())
m_installedList->addItem(name);
rebuildAvailable();
}
// ---------------------------------------------------------------------------
// Load all available games (GAM listall response)
// ---------------------------------------------------------------------------
void GamesPanel::loadAllFromResponse(const QString &response)
{
m_allGames = parseGamResponse(response, "listall");
rebuildAvailable();
}
// ---------------------------------------------------------------------------
// Rebuild available list = allGames minus installedGames (by code)
// ---------------------------------------------------------------------------
void GamesPanel::rebuildAvailable()
{
const QSet<QString> installedCodes(m_installedGames.values().begin(),
m_installedGames.values().end());
m_availableList->clear();
for (auto it = m_allGames.constBegin(); it != m_allGames.constEnd(); ++it) {
if (!installedCodes.contains(it.value()))
m_availableList->addItem(it.key());
}
if (m_availableList->count() == 0 && !m_allGames.isEmpty())
m_availableList->addItem("(all available games are installed)");
m_addBtn->setEnabled(false);
}
// ---------------------------------------------------------------------------
// Add button clicked → emit GAM add <code>
// ---------------------------------------------------------------------------
void GamesPanel::onAddClicked()
{
auto *item = m_availableList->currentItem();
if (!item) return;
const QString name = item->text();
if (!m_allGames.contains(name)) return;
emit commandRequested(QString("GAM add %1").arg(m_allGames[name]));
}