From 157dd07637180f333c8ab7bc12b61bdd11172c21 Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Tue, 24 Dec 2024 19:39:06 +0100 Subject: [PATCH] RMG: improve UI behavior of NetplaySessionBrowserDialog --- Source/RMG/CMakeLists.txt | 4 + .../Netplay/NetplaySessionBrowserDialog.cpp | 147 ++++++-------- .../Netplay/NetplaySessionBrowserDialog.hpp | 7 +- .../Netplay/NetplaySessionBrowserDialog.ui | 44 ++--- .../NetplaySessionBrowserEmptyWidget.cpp | 27 +++ .../NetplaySessionBrowserEmptyWidget.hpp | 31 +++ .../NetplaySessionBrowserEmptyWidget.ui | 63 ++++++ .../NetplaySessionBrowserLoadingWidget.cpp | 96 ++++++++++ .../NetplaySessionBrowserLoadingWidget.hpp | 49 +++++ .../Netplay/NetplaySessionBrowserWidget.cpp | 180 ++++++++++++++++++ .../Netplay/NetplaySessionBrowserWidget.hpp | 79 ++++++++ 11 files changed, 602 insertions(+), 125 deletions(-) create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.cpp create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.hpp create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.ui create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.cpp create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.hpp create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.cpp create mode 100644 Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.hpp diff --git a/Source/RMG/CMakeLists.txt b/Source/RMG/CMakeLists.txt index a11b64ac..bdd87470 100644 --- a/Source/RMG/CMakeLists.txt +++ b/Source/RMG/CMakeLists.txt @@ -99,6 +99,10 @@ if (NETPLAY) UserInterface/Dialog/Netplay/NetplaySessionDialog.ui UserInterface/Dialog/Netplay/NetplaySessionPasswordDialog.cpp UserInterface/Dialog/Netplay/NetplaySessionPasswordDialog.ui + UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.cpp + UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.cpp + UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.cpp + UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.ui ) endif(NETPLAY) diff --git a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.cpp b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.cpp index a7860b91..a76fd0e8 100644 --- a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.cpp +++ b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.cpp @@ -8,7 +8,6 @@ * along with this program. If not, see . */ #include "NetplaySessionBrowserDialog.hpp" -#include "UserInterface/NoFocusDelegate.hpp" #include "NetplaySessionPasswordDialog.hpp" #include "NetplayCommon.hpp" #include "Utilities/QtMessageBox.hpp" @@ -27,37 +26,18 @@ using namespace UserInterface::Dialog; using namespace Utilities; -// -// Local Structs -// - -struct NetplaySessionData_t -{ - QString SessionName; - QString GameName; - QString MD5; - bool PasswordProtected = false; - int Port = 0; - QString CpuEmulator; - QString RspPlugin; - QString GfxPlugin; -}; - -Q_DECLARE_METATYPE(NetplaySessionData_t); - // // Exported Functions // NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSocket* webSocket, QMap modelData) : QDialog(parent) { - qRegisterMetaType(); - this->setupUi(this); // prepare web socket this->webSocket = webSocket; connect(this->webSocket, &QWebSocket::connected, this, &NetplaySessionBrowserDialog::on_webSocket_connected); + connect(this->webSocket, &QWebSocket::disconnected, this, &NetplaySessionBrowserDialog::on_webSocket_disconnected); connect(this->webSocket, &QWebSocket::textMessageReceived, this, &NetplaySessionBrowserDialog::on_webSocket_textMessageReceived); // copy rom data for later @@ -86,25 +66,6 @@ NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSo this->nickNameLineEdit->setValidator(new QRegularExpressionValidator(re, this)); this->nickNameLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_Nickname))); - // prepare session browser - this->tableWidget->setFrameStyle(QFrame::NoFrame); - this->tableWidget->setItemDelegate(new NoFocusDelegate(this)); - this->tableWidget->setWordWrap(false); - this->tableWidget->setShowGrid(false); - this->tableWidget->setSortingEnabled(true); - this->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); - this->tableWidget->setSelectionBehavior(QTableView::SelectRows); - this->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); - this->tableWidget->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); - this->tableWidget->verticalHeader()->hide(); - this->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - this->tableWidget->horizontalHeader()->setSectionsMovable(true); - this->tableWidget->horizontalHeader()->setFirstSectionMovable(true); - this->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - this->tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); - this->tableWidget->horizontalHeader()->setSortIndicatorShown(false); - this->tableWidget->horizontalHeader()->setHighlightSections(false); - // request server list QString serverUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl)); if (!serverUrl.isEmpty() && QUrl(serverUrl).isValid()) @@ -174,7 +135,7 @@ bool NetplaySessionBrowserDialog::validate(void) return false; } - if (this->tableWidget->currentItem() == nullptr || + if (!this->sessionBrowserWidget->IsCurrentSessionValid() || this->serverComboBox->count() == 0) { return false; @@ -189,51 +150,24 @@ void NetplaySessionBrowserDialog::validateJoinButton(void) joinButton->setEnabled(this->validate()); } -void NetplaySessionBrowserDialog::addSessionData(QString name, QString game, QString md5, bool password, int port, - QString cpuEmulator, QString rspPlugin, QString gfxPlugin) -{ - const NetplaySessionData_t sessionData = - { - name, - game, - md5, - password, - port, - cpuEmulator, - rspPlugin, - gfxPlugin - }; - - int row = this->tableWidget->rowCount(); - this->tableWidget->insertRow(row); - - // Session name - QTableWidgetItem* tableWidgetItem1 = new QTableWidgetItem(name); - tableWidgetItem1->setData(Qt::UserRole, QVariant::fromValue(sessionData)); - this->tableWidget->setItem(row, 0, tableWidgetItem1); - - // Game - QTableWidgetItem* tableWidgetItem2 = new QTableWidgetItem(game); - this->tableWidget->setItem(row, 1, tableWidgetItem2); - - // MD5 - QTableWidgetItem* tableWidgetItem3 = new QTableWidgetItem(md5); - this->tableWidget->setItem(row, 2, tableWidgetItem3); - - // Password - QTableWidgetItem* tableWidgetItem4 = new QTableWidgetItem(password ? "Yes" : "No"); - this->tableWidget->setItem(row, 3, tableWidgetItem4); -} - void NetplaySessionBrowserDialog::on_webSocket_connected(void) { if (!this->webSocket->isValid()) { + QtMessageBox::Error(this, "Server Error", "Connection Failed"); return; } - // clear sessions from the table - this->tableWidget->model()->removeRows(0, this->tableWidget->rowCount()); + // disable refresh button while refreshing + QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults); + refreshButton->setEnabled(false); + + // disable join button while refreshing + QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok); + joinButton->setEnabled(false); + + // clear sessions + this->sessionBrowserWidget->StartRefresh(); // request session list from server QJsonObject json; @@ -254,14 +188,30 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa { if (json.value("accept").toInt() == 0) { - this->addSessionData(json.value("room_name").toString(), - json.value("game_name").toString(), - json.value("MD5").toString(), - json.value("protected").toBool(), - json.value("port").toInt(), - json.value("features").toObject().value("cpu_emulator").toString(), - json.value("features").toObject().value("rsp_plugin").toString(), - json.value("features").toObject().value("gfx_plugin").toString()); + this->sessionBrowserWidget->AddSessionData(json.value("room_name").toString(), + json.value("game_name").toString(), + json.value("MD5").toString(), + json.value("protected").toBool(), + json.value("port").toInt(), + json.value("features").toObject().value("cpu_emulator").toString(), + json.value("features").toObject().value("rsp_plugin").toString(), + json.value("features").toObject().value("gfx_plugin").toString()); + } + else + { + QtMessageBox::Error(this, "Server Error", json.value("message").toString()); + } + } + else if (type == "reply_get_rooms_done") + { + if (json.value("accept").toInt() == 0) + { + this->sessionBrowserWidget->RefreshDone(); + // enable refresh button when refreshing is done + QPushButton* refreshButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults); + refreshButton->setEnabled(true); + // re-validate join button after refresh + this->validateJoinButton(); } else { @@ -283,6 +233,11 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa } } +void NetplaySessionBrowserDialog::on_webSocket_disconnected() +{ + this->sessionBrowserWidget->Reset(); +} + void NetplaySessionBrowserDialog::on_broadcastSocket_readyRead(void) { while (this->broadcastSocket.hasPendingDatagrams()) @@ -304,6 +259,8 @@ void NetplaySessionBrowserDialog::on_networkAccessManager_Finished(QNetworkReply { if (reply->error()) { + this->sessionBrowserWidget->Reset(); + QtMessageBox::Error(this, "Server Error", "Failed to retrieve json server list: " + reply->errorString()); reply->deleteLater(); return; } @@ -330,14 +287,13 @@ void NetplaySessionBrowserDialog::on_serverComboBox_currentIndexChanged(int inde return; } - // clear sessions from the table - this->tableWidget->model()->removeRows(0, this->tableWidget->rowCount()); + this->sessionBrowserWidget->StartRefresh(); QString address = this->serverComboBox->itemData(index).toString(); this->webSocket->open(QUrl(address)); } -void NetplaySessionBrowserDialog::on_tableWidget_currentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) +void NetplaySessionBrowserDialog::on_sessionBrowserWidget_OnSessionChanged(bool valid) { this->validateJoinButton(); } @@ -364,14 +320,17 @@ void NetplaySessionBrowserDialog::accept() return; } + // retrieve session data + NetplaySessionData sessionData; + if (!this->sessionBrowserWidget->GetCurrentSession(sessionData)) + { + return; + } + // disable join button while we're processing the request QPushButton* joinButton = this->buttonBox->button(QDialogButtonBox::Ok); joinButton->setEnabled(false); - // retrieve information from row - QTableWidgetItem* item = this->tableWidget->item(this->tableWidget->currentRow(), 0); - NetplaySessionData_t sessionData = item->data(Qt::UserRole).value(); - // request password when needed QString password; if (sessionData.PasswordProtected) diff --git a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.hpp b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.hpp index 7723e6cc..45130e2f 100644 --- a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.hpp +++ b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.hpp @@ -49,17 +49,16 @@ class NetplaySessionBrowserDialog : public QDialog, private Ui::NetplaySessionBr bool validate(void); void validateJoinButton(void); - void addSessionData(QString name, QString game, QString md5, bool password, int port, - QString cpuEmulator, QString rspPlugin, QString gfxPlugin); - private slots: void on_webSocket_connected(void); void on_webSocket_textMessageReceived(QString message); + void on_webSocket_disconnected(void); + void on_broadcastSocket_readyRead(void); void on_networkAccessManager_Finished(QNetworkReply* reply); void on_serverComboBox_currentIndexChanged(int index); - void on_tableWidget_currentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous); + void on_sessionBrowserWidget_OnSessionChanged(bool valid); void on_nickNameLineEdit_textChanged(void); diff --git a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.ui b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.ui index 5919bf65..7a62c402 100644 --- a/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.ui +++ b/Source/RMG/UserInterface/Dialog/Netplay/NetplaySessionBrowserDialog.ui @@ -50,33 +50,15 @@ - - - true - - - false - - - - Name - - - - - Game - - - - - Game MD5 - - - - - Password? - - + + + + 0 + 0 + + + + @@ -91,6 +73,14 @@ + + + UserInterface::Widget::NetplaySessionBrowserWidget + QStackedWidget +
UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.hpp
+ 1 +
+
diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.cpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.cpp new file mode 100644 index 00000000..ab116c38 --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.cpp @@ -0,0 +1,27 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "NetplaySessionBrowserEmptyWidget.hpp" + +#include +#include +#include +#include +#include + +using namespace UserInterface::Widget; + +NetplaySessionBrowserEmptyWidget::NetplaySessionBrowserEmptyWidget(QWidget* parent) : QWidget(parent) +{ + this->setupUi(this); +} + +NetplaySessionBrowserEmptyWidget::~NetplaySessionBrowserEmptyWidget() +{ +} diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.hpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.hpp new file mode 100644 index 00000000..89ab5b5f --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.hpp @@ -0,0 +1,31 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef NETPLAYSESSIONBROWSEREMPTYWIDGET_HPP +#define NETPLAYSESSIONBROWSEREMPTYWIDGET_HPP + +#include + +#include "ui_NetplaySessionBrowserEmptyWidget.h" + +namespace UserInterface +{ +namespace Widget +{ +class NetplaySessionBrowserEmptyWidget : public QWidget, private Ui::NetplaySessionBrowserEmptyWidget +{ + Q_OBJECT +public: + NetplaySessionBrowserEmptyWidget(QWidget* parent); + ~NetplaySessionBrowserEmptyWidget(); +}; +} // namespace Widget +} // namespace UserInterface + +#endif // NETPLAYSESSIONBROWSEREMPTYWIDGET_HPP diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.ui b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.ui new file mode 100644 index 00000000..143d0dda --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserEmptyWidget.ui @@ -0,0 +1,63 @@ + + + NetplaySessionBrowserEmptyWidget + + + + 0 + 0 + 743 + 562 + + + + Form + + + + + + Qt::Orientation::Vertical + + + + 20 + 169 + + + + + + + + <html><head/><body><p><span style=" font-weight:700;">No sessions were found.</span></p><p>You can create your own session or refresh the session list.</p></body></html> + + + Qt::TextFormat::RichText + + + Qt::AlignmentFlag::AlignCenter + + + true + + + + + + + Qt::Orientation::Vertical + + + + 20 + 170 + + + + + + + + + diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.cpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.cpp new file mode 100644 index 00000000..ff2b64d5 --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.cpp @@ -0,0 +1,96 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "NetplaySessionBrowserLoadingWidget.hpp" + +#include +#include +#include + +using namespace UserInterface::Widget; + +NetplaySessionBrowserLoadingWidget::NetplaySessionBrowserLoadingWidget(QWidget* parent) : QWidget(parent) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + + this->loadingLabel = new QLabel(this); + this->loadingLabel->setText("Loading"); + this->loadingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + + layout->addWidget(loadingLabel); + + this->setLayout(layout); +} + +NetplaySessionBrowserLoadingWidget::~NetplaySessionBrowserLoadingWidget() +{ +} + +void NetplaySessionBrowserLoadingWidget::SetWidgetIndex(int index) +{ + this->widgetIndex = index; +} + +void NetplaySessionBrowserLoadingWidget::on_NetplaySessionBrowserWidget_currentChanged(int index) +{ + // start timer when it isnt running + // and when we've switched to our widget, + // else kill the timer + if (this->widgetIndex == index) + { + if (this->loadingLabelTimerId == -1) + { + this->dotCount = 0; + this->elapsedTimeSinceLoading.start(); + // reset loading text + this->updateLoadingText(); + this->loadingLabelTimerId = this->startTimer(1000); + } + } + else + { + if (this->loadingLabelTimerId != -1) + { + this->elapsedTimeSinceLoading.invalidate(); + this->killTimer(this->loadingLabelTimerId); + this->loadingLabelTimerId = -1; + } + } +} + +void NetplaySessionBrowserLoadingWidget::updateLoadingText() +{ + QString loadingText = "Loading"; + + if (dotCount <= 3) + { + for (int i = 0; i < dotCount; i++) + { + loadingText += "."; + } + + dotCount++; + } + else + { + dotCount = 1; + } + + this->loadingLabel->setText(loadingText); +} + +void NetplaySessionBrowserLoadingWidget::timerEvent(QTimerEvent *event) +{ + if (event->timerId() != this->loadingLabelTimerId) + { + return; + } + + this->updateLoadingText(); +} diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.hpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.hpp new file mode 100644 index 00000000..cd92ba96 --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserLoadingWidget.hpp @@ -0,0 +1,49 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef NETPLAYSESSIONLOADINGWIDGET_HPP +#define NETPLAYSESSIONLOADINGWIDGET_HPP + +#include +#include +#include + +namespace UserInterface +{ +namespace Widget +{ +class NetplaySessionBrowserLoadingWidget : public QWidget +{ + Q_OBJECT +public: + NetplaySessionBrowserLoadingWidget(QWidget* parent); + ~NetplaySessionBrowserLoadingWidget(); + + void SetWidgetIndex(int index); + +public slots: + void on_NetplaySessionBrowserWidget_currentChanged(int index); + +private: + QLabel* loadingLabel; + int loadingLabelTimerId = -1; + int widgetIndex = -1; + int dotCount = 0; + + QElapsedTimer elapsedTimeSinceLoading; + + void updateLoadingText(); + +protected: + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; +}; +} // namespace Widget +} // namespace UserInterface + +#endif // NETPLAYSESSIONLOADINGWIDGET_HPP diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.cpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.cpp new file mode 100644 index 00000000..1ebb606e --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.cpp @@ -0,0 +1,180 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "NetplaySessionBrowserWidget.hpp" +#include "UserInterface/NoFocusDelegate.hpp" + +#include + +Q_DECLARE_METATYPE(NetplaySessionData); + +using namespace UserInterface::Widget; + +// +// Exported Functions +// + +NetplaySessionBrowserWidget::NetplaySessionBrowserWidget(QWidget* parent) : QStackedWidget(parent) +{ + // configure signal types + qRegisterMetaType("NetplaySessionData"); + + // configure empty widget + this->emptyWidget = new Widget::NetplaySessionBrowserEmptyWidget(this); + this->addWidget(this->emptyWidget); + + // configure loading widget + this->loadingWidget = new Widget::NetplaySessionBrowserLoadingWidget(this); + connect(this, &QStackedWidget::currentChanged, this->loadingWidget, &NetplaySessionBrowserLoadingWidget::on_NetplaySessionBrowserWidget_currentChanged); + this->loadingWidget->SetWidgetIndex(this->addWidget(this->loadingWidget)); + + // configure table widget + this->tableWidget = new QTableWidget(this); + this->tableWidget->setFrameStyle(QFrame::NoFrame); + this->tableWidget->setItemDelegate(new NoFocusDelegate(this)); + this->tableWidget->setWordWrap(false); + this->tableWidget->setShowGrid(false); + this->tableWidget->setSortingEnabled(true); + this->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + this->tableWidget->setSelectionBehavior(QTableView::SelectRows); + this->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); + this->tableWidget->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + this->tableWidget->verticalHeader()->hide(); + this->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + this->tableWidget->horizontalHeader()->setSectionsMovable(true); + this->tableWidget->horizontalHeader()->setFirstSectionMovable(true); + this->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + this->tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); + this->tableWidget->horizontalHeader()->setSortIndicatorShown(false); + this->tableWidget->horizontalHeader()->setHighlightSections(false); + this->tableWidget->horizontalHeader()->setStretchLastSection(true); + this->addWidget(this->tableWidget); + connect(this->tableWidget, &QTableWidget::currentItemChanged, this, &NetplaySessionBrowserWidget::on_tableWidget_currentItemChanged); + + // set up table widget's columns + QStringList labels; + labels << "Name"; + labels << "Game"; + labels << "Game MD5"; + labels << "Password?"; + this->tableWidget->setColumnCount(labels.size()); + this->tableWidget->setHorizontalHeaderLabels(labels); + + this->setCurrentWidget(this->loadingWidget); +} + +NetplaySessionBrowserWidget::~NetplaySessionBrowserWidget() +{ +} + +void NetplaySessionBrowserWidget::Reset(void) +{ + this->setCurrentWidget(this->emptyWidget); + this->tableWidget->model()->removeRows(0, this->tableWidget->rowCount()); +} + +void NetplaySessionBrowserWidget::StartRefresh(void) +{ + this->refreshTimer.start(); + this->setCurrentWidget(this->loadingWidget); + this->tableWidget->model()->removeRows(0, this->tableWidget->rowCount()); +} + +void NetplaySessionBrowserWidget::AddSessionData(QString name, QString game, QString md5, bool password, int port, + QString cpuEmulator, QString rspPlugin, QString gfxPlugin) +{ + const NetplaySessionData sessionData = + { + name, + game, + md5, + password, + port, + cpuEmulator, + rspPlugin, + gfxPlugin + }; + + int row = this->tableWidget->rowCount(); + this->tableWidget->insertRow(row); + + // Session name + QTableWidgetItem* tableWidgetItem1 = new QTableWidgetItem(name); + tableWidgetItem1->setData(Qt::UserRole, QVariant::fromValue(sessionData)); + this->tableWidget->setItem(row, 0, tableWidgetItem1); + + // Game + QTableWidgetItem* tableWidgetItem2 = new QTableWidgetItem(game); + this->tableWidget->setItem(row, 1, tableWidgetItem2); + + // MD5 + QTableWidgetItem* tableWidgetItem3 = new QTableWidgetItem(md5); + this->tableWidget->setItem(row, 2, tableWidgetItem3); + + // Password + QTableWidgetItem* tableWidgetItem4 = new QTableWidgetItem(password ? "Yes" : "No"); + this->tableWidget->setItem(row, 3, tableWidgetItem4); +} + +void NetplaySessionBrowserWidget::RefreshDone(void) +{ + if (this->tableWidget->rowCount() == 0) + { + this->setCurrentWidget(this->emptyWidget); + return; + } + + // prevent flicker by forcing the loading screen + // to be shown at least 300ms + qint64 elapsedTime = this->refreshTimer.elapsed(); + if (elapsedTime < 300) + { + this->startTimer(300 - elapsedTime); + return; + } + + this->setCurrentWidget(this->tableWidget); +} + +bool NetplaySessionBrowserWidget::IsCurrentSessionValid() +{ + return this->currentWidget() == this->tableWidget && + this->tableWidget->currentItem() != nullptr; +} + +bool NetplaySessionBrowserWidget::GetCurrentSession(NetplaySessionData& data) +{ + if (!this->IsCurrentSessionValid()) + { + return false; + } + + QTableWidgetItem* item = this->tableWidget->item(this->tableWidget->currentRow(), 0); + if (item == nullptr) + { + return false; + } + + data = item->data(Qt::UserRole).value(); + return true; +} + +void NetplaySessionBrowserWidget::timerEvent(QTimerEvent *event) +{ + this->killTimer(event->timerId()); + this->setCurrentWidget(this->tableWidget); +} + +void NetplaySessionBrowserWidget::on_tableWidget_currentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) +{ + if (this->currentWidget() == this->tableWidget) + { + emit this->OnSessionChanged(current != nullptr); + } +} diff --git a/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.hpp b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.hpp new file mode 100644 index 00000000..50af4370 --- /dev/null +++ b/Source/RMG/UserInterface/Widget/Netplay/NetplaySessionBrowserWidget.hpp @@ -0,0 +1,79 @@ +/* + * Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG + * Copyright (C) 2020 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef NETPLAYSESSIONBROWSERWIDGET_HPP +#define NETPLAYSESSIONBROWSERWIDGET_HPP + +#include "NetplaySessionBrowserEmptyWidget.hpp" +#include "NetplaySessionBrowserLoadingWidget.hpp" + +#include +#include +#include + +// session data +struct NetplaySessionData +{ + QString SessionName; + QString GameName; + QString MD5; + bool PasswordProtected = false; + int Port = 0; + QString CpuEmulator; + QString RspPlugin; + QString GfxPlugin; +}; + +namespace UserInterface +{ +namespace Widget +{ +class NetplaySessionBrowserWidget : public QStackedWidget +{ + Q_OBJECT + + public: + NetplaySessionBrowserWidget(QWidget *); + ~NetplaySessionBrowserWidget(void); + + void Reset(void); + + void StartRefresh(void); + + void AddSessionData(QString name, QString game, QString md5, bool password, int port, + QString cpuEmulator, QString rspPlugin, QString gfxPlugin); + + void RefreshDone(void); + + bool IsCurrentSessionValid(void); + bool GetCurrentSession(NetplaySessionData& data); + + private: + Widget::NetplaySessionBrowserEmptyWidget* emptyWidget = nullptr; + Widget::NetplaySessionBrowserLoadingWidget* loadingWidget = nullptr; + + QTableWidget* tableWidget = nullptr; + QWidget* currentViewWidget = nullptr; + + QElapsedTimer refreshTimer; + + protected: + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; + + private slots: + void on_tableWidget_currentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous); + + signals: + void OnSessionChanged(bool valid); + +}; +} // namespace Widget +} // namespace UserInterface + +#endif // NETPLAYSESSIONBROWSERWIDGET_HPP