Fixed games tab - went rogue but its looks better

This commit is contained in:
Jon ESA
2026-04-01 19:43:28 +01:00
parent 9f0f870e6d
commit 0146bcb6f2

344
main.cpp
View File

@@ -1,9 +1,15 @@
#include <QApplication>
#include <QButtonGroup>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QHash>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QRegularExpression>
#include <QSlider>
#include <QSpinBox>
#include <QTabWidget>
#include <QTextEdit>
#include <QTreeWidgetItem>
@@ -36,11 +42,198 @@ static QWidget *makeSettingsTab(WebSocketController *ctrl, QWidget *parent)
auto *page = new QWidget(parent);
auto *layout = new QVBoxLayout(page);
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(4);
// --- Sliders row: brightness and volume side by side (top) ---
auto *slidersRow = new QHBoxLayout();
auto *brightnessLabel = new QLabel("Brightness:", page);
auto *brightnessSlider = new QSlider(Qt::Horizontal, page);
brightnessSlider->setMinimum(1);
brightnessSlider->setMaximum(12);
brightnessSlider->setValue(1);
brightnessSlider->setEnabled(false);
auto *brightnessVal = new QLabel("", page);
brightnessVal->setFixedWidth(28);
auto *volumeLabel = new QLabel("Volume:", page);
auto *volumeSlider = new QSlider(Qt::Horizontal, page);
volumeSlider->setMinimum(1);
volumeSlider->setMaximum(6);
volumeSlider->setValue(1);
volumeSlider->setEnabled(false);
auto *volumeVal = new QLabel("", page);
volumeVal->setFixedWidth(28);
slidersRow->addWidget(brightnessLabel);
slidersRow->addWidget(brightnessSlider, 1);
slidersRow->addWidget(brightnessVal);
slidersRow->addSpacing(16);
slidersRow->addWidget(volumeLabel);
slidersRow->addWidget(volumeSlider, 1);
slidersRow->addWidget(volumeVal);
layout->addLayout(slidersRow);
// --- Tree (takes all spare vertical space) ---
auto *tree = new SettingsTree(page);
auto *ph = new QTreeWidgetItem(tree);
ph->setText(0, "Connect to load settings...");
layout->addWidget(tree, 1);
ctrl->setSettingsTree(tree);
// --- Single compact toolbar row: name input + 3 GBL buttons + checkbox (below tree) ---
auto *toolbar = new QHBoxLayout();
auto *nameEdit = new QLineEdit(page);
nameEdit->setPlaceholderText("Config name...");
nameEdit->setMaximumWidth(160);
auto *saveBtn = new QPushButton("Save", page);
auto *loadBtn = new QPushButton("Restore From File", page);
auto *resetBtn = new QPushButton("Restore Defaults", page);
resetBtn->setStyleSheet(
"QPushButton { color: white; background-color: #c62828; border-radius: 4px; padding: 3px 8px; }"
"QPushButton:hover { background-color: #b71c1c; }"
"QPushButton:disabled { background-color: #888888; color: #cccccc; }");
auto *autoPowerOff = new QCheckBox("Auto Power Off", page);
toolbar->addWidget(nameEdit);
toolbar->addWidget(saveBtn);
toolbar->addWidget(loadBtn);
toolbar->addWidget(resetBtn);
toolbar->addStretch(1);
toolbar->addWidget(autoPowerOff);
layout->addLayout(toolbar);
// --- Reset to defaults (inline confirm row — no QMessageBox::exec on WASM) ---
auto *confirmRow = new QHBoxLayout();
auto *confirmLabel = new QLabel(page);
confirmLabel->setText("Click again to confirm reset:");
confirmLabel->setStyleSheet("color: #c62828;");
confirmLabel->setVisible(false);
auto *confirmYesBtn = new QPushButton("Yes, Reset", page);
confirmYesBtn->setStyleSheet(
"QPushButton { color: white; background-color: #c62828; border-radius: 4px; padding: 2px 8px; }");
confirmYesBtn->setVisible(false);
auto *confirmNoBtn = new QPushButton("Cancel", page);
confirmNoBtn->setVisible(false);
confirmRow->addWidget(confirmLabel);
confirmRow->addWidget(confirmYesBtn);
confirmRow->addWidget(confirmNoBtn);
confirmRow->addStretch(1);
layout->addLayout(confirmRow);
// ----------------------------------------------------------------
// Connections
// ----------------------------------------------------------------
// Save config
auto doSave = [ctrl, nameEdit]() {
QString name = nameEdit->text().trimmed();
name.remove(QRegularExpression("[^A-Za-z0-9]"));
if (name.isEmpty()) return;
ctrl->sendCommand(QString("GBL SaveToFile %1").arg(name));
nameEdit->clear();
};
QObject::connect(saveBtn, &QPushButton::clicked, page, doSave);
QObject::connect(nameEdit, &QLineEdit::returnPressed, page, doSave);
// Restore from file
QObject::connect(loadBtn, &QPushButton::clicked, page, [ctrl, nameEdit]() {
QString name = nameEdit->text().trimmed();
name.remove(QRegularExpression("[^A-Za-z0-9]"));
if (name.isEmpty()) return;
ctrl->sendCommand(QString("GBL LoadFromFile %1").arg(name));
nameEdit->clear();
});
// Reset confirm
QObject::connect(resetBtn, &QPushButton::clicked, page,
[confirmLabel, confirmYesBtn, confirmNoBtn]() {
confirmLabel->setVisible(true);
confirmYesBtn->setVisible(true);
confirmNoBtn->setVisible(true);
});
QObject::connect(confirmYesBtn, &QPushButton::clicked, page,
[ctrl, confirmLabel, confirmYesBtn, confirmNoBtn]() {
ctrl->sendCommand(QStringLiteral("GBL ResetAllToDefaults"));
confirmLabel->setVisible(false);
confirmYesBtn->setVisible(false);
confirmNoBtn->setVisible(false);
});
QObject::connect(confirmNoBtn, &QPushButton::clicked, page,
[confirmLabel, confirmYesBtn, confirmNoBtn]() {
confirmLabel->setVisible(false);
confirmYesBtn->setVisible(false);
confirmNoBtn->setVisible(false);
});
// Auto power off
QObject::connect(autoPowerOff, &QCheckBox::toggled, page, [ctrl](bool checked) {
ctrl->sendCommand(checked ? QStringLiteral("POW EnableAutoOff")
: QStringLiteral("POW KeepOn"));
});
// Query brightness/volume ranges+values on connect; disable on disconnect
QObject::connect(ctrl->socket(), &QWebSocket::connected, page, [ctrl]() {
ctrl->sendCommand(QStringLiteral("GBL brightnessMin"));
ctrl->sendCommand(QStringLiteral("GBL brightnessMax"));
ctrl->sendCommand(QStringLiteral("GBL brightness"));
ctrl->sendCommand(QStringLiteral("GBL sound/volumeMin"));
ctrl->sendCommand(QStringLiteral("GBL sound/volumeMax"));
ctrl->sendCommand(QStringLiteral("GBL sound/volume"));
});
QObject::connect(ctrl->socket(), &QWebSocket::disconnected, page,
[brightnessSlider, brightnessVal, volumeSlider, volumeVal]() {
brightnessSlider->setEnabled(false);
brightnessVal->setText(QStringLiteral(""));
volumeSlider->setEnabled(false);
volumeVal->setText(QStringLiteral(""));
});
// Parse incoming GBL brightness / sound/volume responses
QObject::connect(ctrl->socket(), &QWebSocket::textMessageReceived, page,
[brightnessSlider, brightnessVal, volumeSlider, volumeVal](const QString &msg) {
// helper: parse "GBL <key>=<int>" and return {ok, value}
auto parseGbl = [&](const QString &key) -> std::pair<bool,int> {
const QString prefix = QString("GBL %1=").arg(key);
if (!msg.startsWith(prefix)) return {false, 0};
bool ok = false;
int v = msg.mid(prefix.length()).toInt(&ok);
return {ok, v};
};
if (auto [ok, v] = parseGbl("brightness"); ok) {
brightnessSlider->setValue(v);
brightnessVal->setText(QString::number(v));
brightnessSlider->setEnabled(true);
} else if (auto [ok, v] = parseGbl("brightnessMin"); ok) {
brightnessSlider->setMinimum(v);
} else if (auto [ok, v] = parseGbl("brightnessMax"); ok) {
brightnessSlider->setMaximum(v);
} else if (auto [ok, v] = parseGbl("sound/volume"); ok) {
volumeSlider->setValue(v);
volumeVal->setText(QString::number(v));
volumeSlider->setEnabled(true);
} else if (auto [ok, v] = parseGbl("sound/volumeMin"); ok) {
volumeSlider->setMinimum(v);
} else if (auto [ok, v] = parseGbl("sound/volumeMax"); ok) {
volumeSlider->setMaximum(v);
}
});
// Live label update while dragging; send command only on release
QObject::connect(brightnessSlider, &QSlider::valueChanged, page,
[brightnessVal](int v) { brightnessVal->setText(QString::number(v)); });
QObject::connect(brightnessSlider, &QSlider::sliderReleased, page,
[ctrl, brightnessSlider]() {
ctrl->sendCommand(QString("GBL brightness=%1").arg(brightnessSlider->value()));
});
QObject::connect(volumeSlider, &QSlider::valueChanged, page,
[volumeVal](int v) { volumeVal->setText(QString::number(v)); });
QObject::connect(volumeSlider, &QSlider::sliderReleased, page,
[ctrl, volumeSlider]() {
ctrl->sendCommand(QString("GBL sound/volume=%1").arg(volumeSlider->value()));
});
return page;
}
@@ -109,11 +302,65 @@ int main(int argc, char *argv[])
mainLayout->setContentsMargins(6, 6, 6, 6);
mainLayout->setSpacing(4);
// --- Header bar ---
auto *headerRow = new QHBoxLayout();
// --- ICON → IP helper (formula + hardcoded overrides) ---
// Returns the IP string for a given ICON number.
static const auto iconToIp = [](int icon) -> QString {
static const QHash<int,QString> overrides = {
{280, QStringLiteral("10.10.1.30")},
};
if (overrides.contains(icon))
return overrides[icon];
const int subnet = (icon - 1) / 254;
const int host = ((icon - 1) % 254) + 1;
return QString("10.10.%1.%2").arg(subnet).arg(host);
};
// --- Hidden urlEdit still used by WebSocketController::startConnection() ---
auto *urlEdit = new QLineEdit(&window);
urlEdit->setPlaceholderText("ws://127.0.0.1:3491/");
urlEdit->setText("ws://127.0.0.1:3491/");
urlEdit->setVisible(false);
auto *statusLabel = new QLabel("Disconnected", &window);
// --- Network connection row ---
auto *headerRow = new QHBoxLayout();
headerRow->addWidget(new QLabel("Network connection:", &window));
// Option 1 fixed IP
auto *radioFixed = new QRadioButton("10.110.110.10", &window);
// Option 2 ICON number → derived IP
auto *radioIcon = new QRadioButton(&window);
auto *iconSpin = new QSpinBox(&window);
iconSpin->setRange(1, 9999);
iconSpin->setValue(280);
iconSpin->setFixedWidth(68);
iconSpin->setAlignment(Qt::AlignRight);
auto *iconIpLabel = new QLabel(iconToIp(280), &window);
iconIpLabel->setStyleSheet("color: #555; font-style: italic;");
// Option 3 free text (hostname or raw IP)
auto *radioOther = new QRadioButton("other:", &window);
auto *otherEdit = new QLineEdit(&window);
otherEdit->setText("ftsDevkit4.local");
otherEdit->setFixedWidth(160);
otherEdit->setEnabled(false); // only active when radioOther selected
auto *btnGroup = new QButtonGroup(&window);
btnGroup->addButton(radioFixed, 0);
btnGroup->addButton(radioIcon, 1);
btnGroup->addButton(radioOther, 2);
radioIcon->setChecked(true); // default selection
headerRow->addWidget(radioFixed);
headerRow->addWidget(radioIcon);
headerRow->addWidget(iconSpin);
headerRow->addWidget(iconIpLabel);
headerRow->addSpacing(8);
headerRow->addWidget(radioOther);
headerRow->addWidget(otherEdit);
headerRow->addStretch(1);
// Buttons
auto *connectBtn = new QPushButton("Connect", &window);
auto *disconnectBtn = new QPushButton("Disconnect", &window);
auto *shutdownBtn = new QPushButton("Shutdown", &window);
@@ -124,41 +371,86 @@ int main(int argc, char *argv[])
" border-radius: 4px; padding: 3px 10px; }"
"QPushButton:hover { background-color: #b71c1c; }"
"QPushButton:disabled { background-color: #888888; color: #cccccc; }");
auto *statusLabel = new QLabel("Disconnected", &window);
headerRow->addWidget(new QLabel("WebSocket URL:", &window));
headerRow->addWidget(urlEdit, 1);
headerRow->addWidget(connectBtn);
headerRow->addWidget(disconnectBtn);
headerRow->addWidget(shutdownBtn);
headerRow->addWidget(statusLabel);
mainLayout->addLayout(headerRow);
// --- Build URL from current selection into the hidden urlEdit ---
auto updateUrl = [=]() {
const int port = 5424;
QString host;
if (radioFixed->isChecked()) {
host = QStringLiteral("10.110.110.10");
} else if (radioIcon->isChecked()) {
host = iconToIp(iconSpin->value());
} else {
host = otherEdit->text().trimmed();
if (host.isEmpty()) host = QStringLiteral("127.0.0.1");
}
urlEdit->setText(QString("ws://%1:%2/").arg(host).arg(port));
};
updateUrl(); // set initial value
// Keep iconIpLabel in sync and rebuild URL whenever ICON changes
QObject::connect(iconSpin, QOverload<int>::of(&QSpinBox::valueChanged), &window,
[=](int v) { iconIpLabel->setText(iconToIp(v)); updateUrl(); });
QObject::connect(btnGroup, QOverload<int>::of(&QButtonGroup::idClicked), &window,
[=](int) {
otherEdit->setEnabled(radioOther->isChecked());
updateUrl();
});
QObject::connect(otherEdit, &QLineEdit::textChanged, &window, [=]() {
if (radioOther->isChecked()) updateUrl();
});
// --- Controller ---
auto *ctrl = new WebSocketController(urlEdit, statusLabel, &window);
// --- Tabs ---
auto *tabs = new QTabWidget(&window);
tabs->addTab(makeGamesTab (ctrl, &window), "games");
tabs->addTab(makeVersionsTab(ctrl, &window), "versions");
tabs->addTab(makeManualTab (ctrl, &window), "manual");
tabs->addTab(makeSettingsTab(ctrl, &window), "settings");
tabs->addTab(makePowerTab (ctrl, &window), "power");
tabs->addTab(makeLogsTab (ctrl, &window), "logs");
tabs->addTab(makePanelsTab (ctrl, &window), "panels");
tabs->addTab(makeGamesTab (ctrl, &window), "Games");
tabs->addTab(makeVersionsTab(ctrl, &window), "Versions");
tabs->addTab(makeManualTab (ctrl, &window), "Manual");
tabs->addTab(makeSettingsTab(ctrl, &window), "Settings");
tabs->addTab(makePowerTab (ctrl, &window), "Power");
tabs->addTab(makeLogsTab (ctrl, &window), "Logs");
tabs->addTab(makePanelsTab (ctrl, &window), "Panels");
mainLayout->addWidget(tabs, 1);
// --- Shutdown: confirm then send ---
QObject::connect(shutdownBtn, &QPushButton::clicked, &window, [ctrl, &window]() {
QMessageBox msgBox(&window);
msgBox.setWindowTitle("Confirm Shutdown");
msgBox.setText("Are you sure you want to shut down the machine?");
msgBox.setInformativeText("This will send the POW ShutDown command immediately.");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
if (msgBox.exec() == QMessageBox::Yes)
// --- Shutdown: inline confirm (no QMessageBox::exec on WASM) ---
auto *shutdownConfirmLabel = new QLabel("Confirm shutdown:", &window);
auto *shutdownConfirmYes = new QPushButton("Yes, Shutdown", &window);
auto *shutdownConfirmNo = new QPushButton("Cancel", &window);
shutdownConfirmLabel->setStyleSheet("color: #c62828; font-weight: bold;");
shutdownConfirmYes->setStyleSheet(
"QPushButton { color: white; background-color: #c62828; border-radius: 4px; padding: 2px 8px; }");
shutdownConfirmLabel->setVisible(false);
shutdownConfirmYes->setVisible(false);
shutdownConfirmNo->setVisible(false);
headerRow->addWidget(shutdownConfirmLabel);
headerRow->addWidget(shutdownConfirmYes);
headerRow->addWidget(shutdownConfirmNo);
QObject::connect(shutdownBtn, &QPushButton::clicked, &window,
[shutdownConfirmLabel, shutdownConfirmYes, shutdownConfirmNo]() {
shutdownConfirmLabel->setVisible(true);
shutdownConfirmYes->setVisible(true);
shutdownConfirmNo->setVisible(true);
});
QObject::connect(shutdownConfirmYes, &QPushButton::clicked, &window,
[ctrl, shutdownConfirmLabel, shutdownConfirmYes, shutdownConfirmNo]() {
ctrl->sendCommand(QStringLiteral("POW ShutDown"));
shutdownConfirmLabel->setVisible(false);
shutdownConfirmYes->setVisible(false);
shutdownConfirmNo->setVisible(false);
});
QObject::connect(shutdownConfirmNo, &QPushButton::clicked, &window,
[shutdownConfirmLabel, shutdownConfirmYes, shutdownConfirmNo]() {
shutdownConfirmLabel->setVisible(false);
shutdownConfirmYes->setVisible(false);
shutdownConfirmNo->setVisible(false);
});
// --- Wire up buttons ---