mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Move DolphinQt2 to DolphinQt
This commit is contained in:
73
Source/Core/DolphinQt/NetPlay/GameListDialog.cpp
Normal file
73
Source/Core/DolphinQt/NetPlay/GameListDialog.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/NetPlay/GameListDialog.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QListWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "DolphinQt/GameList/GameListModel.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
GameListDialog::GameListDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle(tr("Select a game"));
|
||||
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
}
|
||||
|
||||
void GameListDialog::CreateWidgets()
|
||||
{
|
||||
m_main_layout = new QVBoxLayout;
|
||||
m_game_list = new QListWidget;
|
||||
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||
m_button_box->setEnabled(false);
|
||||
|
||||
m_main_layout->addWidget(m_game_list);
|
||||
m_main_layout->addWidget(m_button_box);
|
||||
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
||||
void GameListDialog::ConnectWidgets()
|
||||
{
|
||||
connect(m_game_list, &QListWidget::itemSelectionChanged, [this] {
|
||||
int row = m_game_list->currentRow();
|
||||
|
||||
m_button_box->setEnabled(row != -1);
|
||||
m_game_id = m_game_list->currentItem()->text();
|
||||
});
|
||||
|
||||
connect(m_game_list, &QListWidget::itemDoubleClicked, this, &GameListDialog::accept);
|
||||
connect(m_button_box, &QDialogButtonBox::accepted, this, &GameListDialog::accept);
|
||||
}
|
||||
|
||||
void GameListDialog::PopulateGameList()
|
||||
{
|
||||
auto* game_list_model = Settings::Instance().GetGameListModel();
|
||||
|
||||
m_game_list->clear();
|
||||
|
||||
for (int i = 0; i < game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
auto* item = new QListWidgetItem(game_list_model->GetUniqueIdentifier(i));
|
||||
m_game_list->addItem(item);
|
||||
}
|
||||
|
||||
m_game_list->sortItems();
|
||||
}
|
||||
|
||||
const QString& GameListDialog::GetSelectedUniqueID() const
|
||||
{
|
||||
return m_game_id;
|
||||
}
|
||||
|
||||
int GameListDialog::exec()
|
||||
{
|
||||
PopulateGameList();
|
||||
return QDialog::exec();
|
||||
}
|
32
Source/Core/DolphinQt/NetPlay/GameListDialog.h
Normal file
32
Source/Core/DolphinQt/NetPlay/GameListDialog.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class GameListModel;
|
||||
class QVBoxLayout;
|
||||
class QListWidget;
|
||||
class QDialogButtonBox;
|
||||
|
||||
class GameListDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GameListDialog(QWidget* parent);
|
||||
|
||||
int exec() override;
|
||||
const QString& GetSelectedUniqueID() const;
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
void PopulateGameList();
|
||||
|
||||
QVBoxLayout* m_main_layout;
|
||||
QListWidget* m_game_list;
|
||||
QDialogButtonBox* m_button_box;
|
||||
QString m_game_id;
|
||||
};
|
140
Source/Core/DolphinQt/NetPlay/MD5Dialog.cpp
Normal file
140
Source/Core/DolphinQt/NetPlay/MD5Dialog.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/NetPlay/MD5Dialog.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
static QString GetPlayerNameFromPID(int pid)
|
||||
{
|
||||
QString player_name = QObject::tr("Invalid Player ID");
|
||||
for (const auto* player : Settings::Instance().GetNetPlayClient()->GetPlayers())
|
||||
{
|
||||
if (player->pid == pid)
|
||||
{
|
||||
player_name = QString::fromStdString(player->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return player_name;
|
||||
}
|
||||
|
||||
MD5Dialog::MD5Dialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
setWindowTitle(tr("MD5 Checksum"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
}
|
||||
|
||||
void MD5Dialog::CreateWidgets()
|
||||
{
|
||||
m_main_layout = new QVBoxLayout;
|
||||
m_progress_box = new QGroupBox;
|
||||
m_progress_layout = new QVBoxLayout;
|
||||
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||
m_check_label = new QLabel;
|
||||
|
||||
m_progress_box->setLayout(m_progress_layout);
|
||||
|
||||
m_main_layout->addWidget(m_progress_box);
|
||||
m_main_layout->addWidget(m_check_label);
|
||||
m_main_layout->addWidget(m_button_box);
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
||||
void MD5Dialog::ConnectWidgets()
|
||||
{
|
||||
connect(m_button_box, &QDialogButtonBox::rejected, this, &MD5Dialog::reject);
|
||||
}
|
||||
|
||||
void MD5Dialog::show(const QString& title)
|
||||
{
|
||||
m_progress_box->setTitle(title);
|
||||
|
||||
for (auto& pair : m_progress_bars)
|
||||
{
|
||||
m_progress_layout->removeWidget(pair.second);
|
||||
pair.second->deleteLater();
|
||||
}
|
||||
|
||||
for (auto& pair : m_status_labels)
|
||||
{
|
||||
m_progress_layout->removeWidget(pair.second);
|
||||
pair.second->deleteLater();
|
||||
}
|
||||
|
||||
m_progress_bars.clear();
|
||||
m_status_labels.clear();
|
||||
m_results.clear();
|
||||
m_check_label->setText(QString::fromStdString(""));
|
||||
|
||||
for (const auto* player : Settings::Instance().GetNetPlayClient()->GetPlayers())
|
||||
{
|
||||
m_progress_bars[player->pid] = new QProgressBar;
|
||||
m_status_labels[player->pid] = new QLabel;
|
||||
|
||||
m_progress_layout->addWidget(m_progress_bars[player->pid]);
|
||||
m_progress_layout->addWidget(m_status_labels[player->pid]);
|
||||
}
|
||||
|
||||
QDialog::show();
|
||||
}
|
||||
|
||||
void MD5Dialog::SetProgress(int pid, int progress)
|
||||
{
|
||||
QString player_name = GetPlayerNameFromPID(pid);
|
||||
|
||||
if (!m_status_labels.count(pid))
|
||||
return;
|
||||
|
||||
m_status_labels[pid]->setText(
|
||||
tr("%1[%2]: %3 %").arg(player_name, QString::number(pid), QString::number(progress)));
|
||||
m_progress_bars[pid]->setValue(progress);
|
||||
}
|
||||
|
||||
void MD5Dialog::SetResult(int pid, const std::string& result)
|
||||
{
|
||||
QString player_name = GetPlayerNameFromPID(pid);
|
||||
|
||||
if (!m_status_labels.count(pid))
|
||||
return;
|
||||
|
||||
m_status_labels[pid]->setText(
|
||||
tr("%1[%2]: %3").arg(player_name, QString::number(pid), QString::fromStdString(result)));
|
||||
|
||||
m_results.push_back(result);
|
||||
|
||||
if (m_results.size() >= Settings::Instance().GetNetPlayClient()->GetPlayers().size())
|
||||
{
|
||||
if (std::adjacent_find(m_results.begin(), m_results.end(), std::not_equal_to<>()) ==
|
||||
m_results.end())
|
||||
{
|
||||
m_check_label->setText(tr("The hashes match!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_check_label->setText(tr("The hashes do not match!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MD5Dialog::reject()
|
||||
{
|
||||
auto* server = Settings::Instance().GetNetPlayServer();
|
||||
|
||||
if (server)
|
||||
server->AbortMD5();
|
||||
|
||||
QDialog::reject();
|
||||
}
|
46
Source/Core/DolphinQt/NetPlay/MD5Dialog.h
Normal file
46
Source/Core/DolphinQt/NetPlay/MD5Dialog.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QDialogButtonBox;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QProgressBar;
|
||||
class QVBoxLayout;
|
||||
class QWidget;
|
||||
|
||||
class MD5Dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MD5Dialog(QWidget* parent);
|
||||
|
||||
void show(const QString& title);
|
||||
void SetProgress(int pid, int progress);
|
||||
void SetResult(int pid, const std::string& md5);
|
||||
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
std::map<int, QProgressBar*> m_progress_bars;
|
||||
std::map<int, QLabel*> m_status_labels;
|
||||
|
||||
std::vector<std::string> m_results;
|
||||
|
||||
QGroupBox* m_progress_box;
|
||||
QVBoxLayout* m_progress_layout;
|
||||
QVBoxLayout* m_main_layout;
|
||||
QLabel* m_check_label;
|
||||
QDialogButtonBox* m_button_box;
|
||||
};
|
669
Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp
Normal file
669
Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp
Normal file
@ -0,0 +1,669 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/NetPlay/NetPlayDialog.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QClipboard>
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QSplitter>
|
||||
#include <QTableWidget>
|
||||
#include <QTextBrowser>
|
||||
#include <QToolButton>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Common/TraversalClient.h"
|
||||
|
||||
#include "Core/Config/SYSCONFSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/NetPlayServer.h"
|
||||
|
||||
#include "DolphinQt/GameList/GameList.h"
|
||||
#include "DolphinQt/NetPlay/GameListDialog.h"
|
||||
#include "DolphinQt/NetPlay/MD5Dialog.h"
|
||||
#include "DolphinQt/NetPlay/PadMappingDialog.h"
|
||||
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
||||
#include "DolphinQt/QtUtils/RunOnObject.h"
|
||||
#include "DolphinQt/Resources.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
NetPlayDialog::NetPlayDialog(QWidget* parent)
|
||||
: QDialog(parent), m_game_list_model(Settings::Instance().GetGameListModel())
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
setWindowTitle(tr("NetPlay"));
|
||||
setWindowIcon(Resources::GetAppIcon());
|
||||
|
||||
m_pad_mapping = new PadMappingDialog(this);
|
||||
m_md5_dialog = new MD5Dialog(this);
|
||||
|
||||
CreateChatLayout();
|
||||
CreatePlayersLayout();
|
||||
CreateMainLayout();
|
||||
ConnectWidgets();
|
||||
|
||||
auto& settings = Settings::Instance().GetQSettings();
|
||||
|
||||
restoreGeometry(settings.value(QStringLiteral("netplaydialog/geometry")).toByteArray());
|
||||
m_splitter->restoreState(settings.value(QStringLiteral("netplaydialog/splitter")).toByteArray());
|
||||
}
|
||||
|
||||
NetPlayDialog::~NetPlayDialog()
|
||||
{
|
||||
auto& settings = Settings::Instance().GetQSettings();
|
||||
|
||||
settings.setValue(QStringLiteral("netplaydialog/geometry"), saveGeometry());
|
||||
settings.setValue(QStringLiteral("netplaydialog/splitter"), m_splitter->saveState());
|
||||
}
|
||||
|
||||
void NetPlayDialog::CreateMainLayout()
|
||||
{
|
||||
m_main_layout = new QGridLayout;
|
||||
m_game_button = new QPushButton;
|
||||
m_md5_button = new QToolButton;
|
||||
m_start_button = new QPushButton(tr("Start"));
|
||||
m_buffer_size_box = new QSpinBox;
|
||||
m_save_sd_box = new QCheckBox(tr("Write save/SD data"));
|
||||
m_load_wii_box = new QCheckBox(tr("Load Wii Save"));
|
||||
m_record_input_box = new QCheckBox(tr("Record inputs"));
|
||||
m_reduce_polling_rate_box = new QCheckBox(tr("Reduce Polling Rate"));
|
||||
m_buffer_label = new QLabel(tr("Buffer:"));
|
||||
m_quit_button = new QPushButton(tr("Quit"));
|
||||
m_splitter = new QSplitter(Qt::Horizontal);
|
||||
|
||||
m_game_button->setDefault(false);
|
||||
m_game_button->setAutoDefault(false);
|
||||
|
||||
auto* default_button = new QAction(tr("Calculate MD5 hash"), m_md5_button);
|
||||
|
||||
auto* menu = new QMenu(this);
|
||||
|
||||
auto* other_game_button = new QAction(tr("Other game"), this);
|
||||
auto* sdcard_button = new QAction(tr("SD Card"), this);
|
||||
|
||||
menu->addAction(other_game_button);
|
||||
menu->addAction(sdcard_button);
|
||||
|
||||
connect(default_button, &QAction::triggered,
|
||||
[this] { Settings::Instance().GetNetPlayServer()->ComputeMD5(m_current_game); });
|
||||
connect(other_game_button, &QAction::triggered, [this] {
|
||||
GameListDialog gld(this);
|
||||
|
||||
if (gld.exec() == QDialog::Accepted)
|
||||
{
|
||||
Settings::Instance().GetNetPlayServer()->ComputeMD5(gld.GetSelectedUniqueID().toStdString());
|
||||
}
|
||||
});
|
||||
connect(sdcard_button, &QAction::triggered,
|
||||
[] { Settings::Instance().GetNetPlayServer()->ComputeMD5(WII_SDCARD); });
|
||||
|
||||
m_md5_button->setDefaultAction(default_button);
|
||||
m_md5_button->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
m_md5_button->setMenu(menu);
|
||||
|
||||
m_reduce_polling_rate_box->setToolTip(
|
||||
tr("This will reduce bandwidth usage, but may add up to one frame of additional latency, as "
|
||||
"controllers will be polled only once per frame."));
|
||||
|
||||
m_main_layout->addWidget(m_game_button, 0, 0);
|
||||
m_main_layout->addWidget(m_md5_button, 0, 1);
|
||||
m_main_layout->addWidget(m_splitter, 1, 0, 1, -1);
|
||||
|
||||
m_splitter->addWidget(m_chat_box);
|
||||
m_splitter->addWidget(m_players_box);
|
||||
|
||||
auto* options_widget = new QHBoxLayout;
|
||||
|
||||
options_widget->addWidget(m_start_button);
|
||||
options_widget->addWidget(m_buffer_label);
|
||||
options_widget->addWidget(m_buffer_size_box);
|
||||
options_widget->addWidget(m_save_sd_box);
|
||||
options_widget->addWidget(m_load_wii_box);
|
||||
options_widget->addWidget(m_record_input_box);
|
||||
options_widget->addWidget(m_reduce_polling_rate_box);
|
||||
options_widget->addWidget(m_quit_button);
|
||||
m_main_layout->addLayout(options_widget, 2, 0, 1, -1, Qt::AlignRight);
|
||||
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
||||
void NetPlayDialog::CreateChatLayout()
|
||||
{
|
||||
m_chat_box = new QGroupBox(tr("Chat"));
|
||||
m_chat_edit = new QTextBrowser;
|
||||
m_chat_type_edit = new QLineEdit;
|
||||
m_chat_send_button = new QPushButton(tr("Send"));
|
||||
|
||||
m_chat_send_button->setDefault(false);
|
||||
m_chat_send_button->setAutoDefault(false);
|
||||
|
||||
m_chat_edit->setReadOnly(true);
|
||||
|
||||
auto* layout = new QGridLayout;
|
||||
|
||||
layout->addWidget(m_chat_edit, 0, 0, 1, -1);
|
||||
layout->addWidget(m_chat_type_edit, 1, 0);
|
||||
layout->addWidget(m_chat_send_button, 1, 1);
|
||||
|
||||
m_chat_box->setLayout(layout);
|
||||
}
|
||||
|
||||
void NetPlayDialog::CreatePlayersLayout()
|
||||
{
|
||||
m_players_box = new QGroupBox(tr("Players"));
|
||||
m_room_box = new QComboBox;
|
||||
m_hostcode_label = new QLabel;
|
||||
m_hostcode_action_button = new QPushButton(tr("Copy"));
|
||||
m_players_list = new QTableWidget;
|
||||
m_kick_button = new QPushButton(tr("Kick Player"));
|
||||
m_assign_ports_button = new QPushButton(tr("Assign Controller Ports"));
|
||||
|
||||
m_players_list->setColumnCount(5);
|
||||
m_players_list->verticalHeader()->hide();
|
||||
m_players_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_players_list->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_players_list->horizontalHeader()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
|
||||
|
||||
auto* layout = new QGridLayout;
|
||||
|
||||
layout->addWidget(m_room_box, 0, 0);
|
||||
layout->addWidget(m_hostcode_label, 0, 1);
|
||||
layout->addWidget(m_hostcode_action_button, 0, 2);
|
||||
layout->addWidget(m_players_list, 1, 0, 1, -1);
|
||||
layout->addWidget(m_kick_button, 2, 0, 1, -1);
|
||||
layout->addWidget(m_assign_ports_button, 3, 0, 1, -1);
|
||||
|
||||
m_players_box->setLayout(layout);
|
||||
}
|
||||
|
||||
void NetPlayDialog::ConnectWidgets()
|
||||
{
|
||||
// Players
|
||||
connect(m_room_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
&NetPlayDialog::UpdateGUI);
|
||||
connect(m_hostcode_action_button, &QPushButton::clicked, [this] {
|
||||
if (m_is_copy_button_retry && m_room_box->currentIndex() == 0)
|
||||
g_TraversalClient->ReconnectToServer();
|
||||
else
|
||||
QApplication::clipboard()->setText(m_hostcode_label->text());
|
||||
});
|
||||
connect(m_players_list, &QTableWidget::itemSelectionChanged, [this] {
|
||||
int row = m_players_list->currentRow();
|
||||
m_kick_button->setEnabled(row > 0 &&
|
||||
!m_players_list->currentItem()->data(Qt::UserRole).isNull());
|
||||
});
|
||||
connect(m_kick_button, &QPushButton::clicked, [this] {
|
||||
auto id = m_players_list->currentItem()->data(Qt::UserRole).toInt();
|
||||
Settings::Instance().GetNetPlayServer()->KickPlayer(id);
|
||||
});
|
||||
connect(m_assign_ports_button, &QPushButton::clicked, [this] {
|
||||
m_pad_mapping->exec();
|
||||
|
||||
Settings::Instance().GetNetPlayServer()->SetPadMapping(m_pad_mapping->GetGCPadArray());
|
||||
Settings::Instance().GetNetPlayServer()->SetWiimoteMapping(m_pad_mapping->GetWiimoteArray());
|
||||
});
|
||||
|
||||
// Chat
|
||||
connect(m_chat_send_button, &QPushButton::clicked, this, &NetPlayDialog::OnChat);
|
||||
connect(m_chat_type_edit, &QLineEdit::returnPressed, this, &NetPlayDialog::OnChat);
|
||||
|
||||
// Other
|
||||
connect(m_buffer_size_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||
[this](int value) {
|
||||
if (value == m_buffer_size)
|
||||
return;
|
||||
|
||||
if (Settings::Instance().GetNetPlayServer() != nullptr)
|
||||
Settings::Instance().GetNetPlayServer()->AdjustPadBufferSize(value);
|
||||
});
|
||||
|
||||
connect(m_start_button, &QPushButton::clicked, this, &NetPlayDialog::OnStart);
|
||||
connect(m_quit_button, &QPushButton::clicked, this, &NetPlayDialog::reject);
|
||||
|
||||
connect(m_game_button, &QPushButton::clicked, [this] {
|
||||
GameListDialog gld(this);
|
||||
if (gld.exec() == QDialog::Accepted)
|
||||
{
|
||||
auto unique_id = gld.GetSelectedUniqueID();
|
||||
Settings::Instance().GetNetPlayServer()->ChangeGame(unique_id.toStdString());
|
||||
}
|
||||
});
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [=](Core::State state) {
|
||||
if (isVisible())
|
||||
{
|
||||
GameStatusChanged(state != Core::State::Uninitialized);
|
||||
if (state == Core::State::Uninitialized)
|
||||
DisplayMessage(tr("Stopped game"), "red");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnChat()
|
||||
{
|
||||
QueueOnObject(this, [this] {
|
||||
auto msg = m_chat_type_edit->text().toStdString();
|
||||
Settings::Instance().GetNetPlayClient()->SendChatMessage(msg);
|
||||
m_chat_type_edit->clear();
|
||||
|
||||
DisplayMessage(QStringLiteral("%1: %2").arg(QString::fromStdString(m_nickname).toHtmlEscaped(),
|
||||
QString::fromStdString(msg).toHtmlEscaped()),
|
||||
"blue");
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnStart()
|
||||
{
|
||||
if (!Settings::Instance().GetNetPlayClient()->DoAllPlayersHaveGame())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Warning"),
|
||||
tr("Not all players have the game. Do you really want to start?")) ==
|
||||
QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
|
||||
NetSettings settings;
|
||||
|
||||
// Copy all relevant settings
|
||||
SConfig& instance = SConfig::GetInstance();
|
||||
settings.m_CPUthread = instance.bCPUThread;
|
||||
settings.m_CPUcore = instance.cpu_core;
|
||||
settings.m_EnableCheats = instance.bEnableCheats;
|
||||
settings.m_SelectedLanguage = instance.SelectedLanguage;
|
||||
settings.m_OverrideGCLanguage = instance.bOverrideGCLanguage;
|
||||
settings.m_ProgressiveScan = Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN);
|
||||
settings.m_PAL60 = Config::Get(Config::SYSCONF_PAL60);
|
||||
settings.m_DSPHLE = instance.bDSPHLE;
|
||||
settings.m_DSPEnableJIT = instance.m_DSPEnableJIT;
|
||||
settings.m_WriteToMemcard = m_save_sd_box->isChecked();
|
||||
settings.m_CopyWiiSave = m_load_wii_box->isChecked();
|
||||
settings.m_OCEnable = instance.m_OCEnable;
|
||||
settings.m_OCFactor = instance.m_OCFactor;
|
||||
settings.m_ReducePollingRate = m_reduce_polling_rate_box->isChecked();
|
||||
settings.m_EXIDevice[0] = instance.m_EXIDevice[0];
|
||||
settings.m_EXIDevice[1] = instance.m_EXIDevice[1];
|
||||
|
||||
Settings::Instance().GetNetPlayServer()->SetNetSettings(settings);
|
||||
Settings::Instance().GetNetPlayServer()->StartGame();
|
||||
}
|
||||
|
||||
void NetPlayDialog::reject()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Confirmation"),
|
||||
tr("Are you sure you want to quit NetPlay?")) == QMessageBox::Yes)
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlayDialog::show(std::string nickname, bool use_traversal)
|
||||
{
|
||||
m_nickname = nickname;
|
||||
m_use_traversal = use_traversal;
|
||||
m_buffer_size = 0;
|
||||
|
||||
m_room_box->clear();
|
||||
m_chat_edit->clear();
|
||||
m_chat_type_edit->clear();
|
||||
|
||||
bool is_hosting = Settings::Instance().GetNetPlayServer() != nullptr;
|
||||
|
||||
if (is_hosting)
|
||||
{
|
||||
if (use_traversal)
|
||||
m_room_box->addItem(tr("Room ID"));
|
||||
|
||||
for (const auto& iface : Settings::Instance().GetNetPlayServer()->GetInterfaceSet())
|
||||
{
|
||||
const auto interface = QString::fromStdString(iface);
|
||||
m_room_box->addItem(iface == "!local!" ? tr("Local") : interface, interface);
|
||||
}
|
||||
}
|
||||
|
||||
m_start_button->setHidden(!is_hosting);
|
||||
m_save_sd_box->setHidden(!is_hosting);
|
||||
m_load_wii_box->setHidden(!is_hosting);
|
||||
m_reduce_polling_rate_box->setHidden(!is_hosting);
|
||||
m_buffer_size_box->setHidden(!is_hosting);
|
||||
m_buffer_label->setHidden(!is_hosting);
|
||||
m_kick_button->setHidden(!is_hosting);
|
||||
m_assign_ports_button->setHidden(!is_hosting);
|
||||
m_md5_button->setHidden(!is_hosting);
|
||||
m_room_box->setHidden(!is_hosting);
|
||||
m_hostcode_label->setHidden(!is_hosting);
|
||||
m_hostcode_action_button->setHidden(!is_hosting);
|
||||
m_game_button->setEnabled(is_hosting);
|
||||
m_kick_button->setEnabled(false);
|
||||
|
||||
QDialog::show();
|
||||
UpdateGUI();
|
||||
}
|
||||
|
||||
void NetPlayDialog::UpdateGUI()
|
||||
{
|
||||
auto* client = Settings::Instance().GetNetPlayClient();
|
||||
|
||||
// Update Player List
|
||||
const auto players = client->GetPlayers();
|
||||
const auto player_count = static_cast<int>(players.size());
|
||||
|
||||
int selection_pid = m_players_list->currentItem() ?
|
||||
m_players_list->currentItem()->data(Qt::UserRole).toInt() :
|
||||
-1;
|
||||
|
||||
m_players_list->clear();
|
||||
m_players_list->setHorizontalHeaderLabels(
|
||||
{tr("Player"), tr("Game Status"), tr("Ping"), tr("Mapping"), tr("Revision")});
|
||||
m_players_list->setRowCount(player_count);
|
||||
|
||||
const auto get_mapping_string = [](const Player* player, const PadMappingArray& array) {
|
||||
std::string str;
|
||||
for (size_t i = 0; i < array.size(); i++)
|
||||
{
|
||||
if (player->pid == array[i])
|
||||
str += std::to_string(i + 1);
|
||||
else
|
||||
str += '-';
|
||||
}
|
||||
|
||||
return '|' + str + '|';
|
||||
};
|
||||
|
||||
static const std::map<PlayerGameStatus, QString> player_status{
|
||||
{PlayerGameStatus::Ok, tr("OK")}, {PlayerGameStatus::NotFound, tr("Not Found")}};
|
||||
|
||||
for (int i = 0; i < player_count; i++)
|
||||
{
|
||||
const auto* p = players[i];
|
||||
|
||||
auto* name_item = new QTableWidgetItem(QString::fromStdString(p->name));
|
||||
auto* status_item = new QTableWidgetItem(player_status.count(p->game_status) ?
|
||||
player_status.at(p->game_status) :
|
||||
QStringLiteral("?"));
|
||||
auto* ping_item = new QTableWidgetItem(QStringLiteral("%1 ms").arg(p->ping));
|
||||
auto* mapping_item = new QTableWidgetItem(
|
||||
QString::fromStdString(get_mapping_string(p, client->GetPadMapping()) +
|
||||
get_mapping_string(p, client->GetWiimoteMapping())));
|
||||
auto* revision_item = new QTableWidgetItem(QString::fromStdString(p->revision));
|
||||
|
||||
for (auto* item : {name_item, status_item, ping_item, mapping_item, revision_item})
|
||||
{
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
item->setData(Qt::UserRole, static_cast<int>(p->pid));
|
||||
}
|
||||
|
||||
m_players_list->setItem(i, 0, name_item);
|
||||
m_players_list->setItem(i, 1, status_item);
|
||||
m_players_list->setItem(i, 2, ping_item);
|
||||
m_players_list->setItem(i, 3, mapping_item);
|
||||
m_players_list->setItem(i, 4, revision_item);
|
||||
|
||||
if (p->pid == selection_pid)
|
||||
m_players_list->selectRow(i);
|
||||
}
|
||||
|
||||
// Update Room ID / IP label
|
||||
if (m_use_traversal && m_room_box->currentIndex() == 0)
|
||||
{
|
||||
switch (g_TraversalClient->GetState())
|
||||
{
|
||||
case TraversalClient::Connecting:
|
||||
m_hostcode_label->setText(tr("..."));
|
||||
m_hostcode_action_button->setEnabled(false);
|
||||
break;
|
||||
case TraversalClient::Connected:
|
||||
{
|
||||
const auto host_id = g_TraversalClient->GetHostID();
|
||||
m_hostcode_label->setText(
|
||||
QString::fromStdString(std::string(host_id.begin(), host_id.end())));
|
||||
m_hostcode_action_button->setEnabled(true);
|
||||
m_hostcode_action_button->setText(tr("Copy"));
|
||||
m_is_copy_button_retry = false;
|
||||
break;
|
||||
}
|
||||
case TraversalClient::Failure:
|
||||
m_hostcode_label->setText(tr("Error"));
|
||||
m_hostcode_action_button->setText(tr("Retry"));
|
||||
m_hostcode_action_button->setEnabled(true);
|
||||
m_is_copy_button_retry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Settings::Instance().GetNetPlayServer())
|
||||
{
|
||||
m_hostcode_label->setText(
|
||||
QString::fromStdString(Settings::Instance().GetNetPlayServer()->GetInterfaceHost(
|
||||
m_room_box->currentData().toString().toStdString())));
|
||||
m_hostcode_action_button->setText(tr("Copy"));
|
||||
m_hostcode_action_button->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// NetPlayUI methods
|
||||
|
||||
void NetPlayDialog::BootGame(const std::string& filename)
|
||||
{
|
||||
m_got_stop_request = false;
|
||||
emit Boot(QString::fromStdString(filename));
|
||||
}
|
||||
|
||||
void NetPlayDialog::StopGame()
|
||||
{
|
||||
if (m_got_stop_request)
|
||||
return;
|
||||
|
||||
m_got_stop_request = true;
|
||||
emit Stop();
|
||||
}
|
||||
|
||||
void NetPlayDialog::Update()
|
||||
{
|
||||
QueueOnObject(this, &NetPlayDialog::UpdateGUI);
|
||||
}
|
||||
|
||||
void NetPlayDialog::DisplayMessage(const QString& msg, const std::string& color, int duration)
|
||||
{
|
||||
QueueOnObject(m_chat_edit, [this, color, msg] {
|
||||
m_chat_edit->append(
|
||||
QStringLiteral("<font color='%1'>%2</font>").arg(QString::fromStdString(color), msg));
|
||||
});
|
||||
|
||||
if (g_ActiveConfig.bShowNetPlayMessages && Core::IsRunning())
|
||||
{
|
||||
u32 osd_color;
|
||||
|
||||
// Convert the color string to a OSD color
|
||||
if (color == "red")
|
||||
osd_color = OSD::Color::RED;
|
||||
else if (color == "cyan")
|
||||
osd_color = OSD::Color::CYAN;
|
||||
else if (color == "green")
|
||||
osd_color = OSD::Color::GREEN;
|
||||
else
|
||||
osd_color = OSD::Color::YELLOW;
|
||||
|
||||
OSD::AddTypedMessage(OSD::MessageType::NetPlayBuffer, msg.toStdString(), OSD::Duration::NORMAL,
|
||||
osd_color);
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlayDialog::AppendChat(const std::string& msg)
|
||||
{
|
||||
DisplayMessage(QString::fromStdString(msg).toHtmlEscaped(), "");
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnMsgChangeGame(const std::string& title)
|
||||
{
|
||||
QString qtitle = QString::fromStdString(title);
|
||||
QueueOnObject(this, [this, qtitle, title] {
|
||||
m_game_button->setText(qtitle);
|
||||
m_current_game = title;
|
||||
});
|
||||
DisplayMessage(tr("Game changed to \"%1\"").arg(qtitle), "magenta");
|
||||
}
|
||||
|
||||
void NetPlayDialog::GameStatusChanged(bool running)
|
||||
{
|
||||
if (!running && !m_got_stop_request)
|
||||
Settings::Instance().GetNetPlayClient()->RequestStopGame();
|
||||
|
||||
QueueOnObject(this, [this, running] {
|
||||
if (Settings::Instance().GetNetPlayServer() != nullptr)
|
||||
{
|
||||
m_start_button->setEnabled(!running);
|
||||
m_game_button->setEnabled(!running);
|
||||
m_load_wii_box->setEnabled(!running);
|
||||
m_save_sd_box->setEnabled(!running);
|
||||
m_assign_ports_button->setEnabled(!running);
|
||||
m_reduce_polling_rate_box->setEnabled(!running);
|
||||
}
|
||||
|
||||
m_record_input_box->setEnabled(!running);
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnMsgStartGame()
|
||||
{
|
||||
DisplayMessage(tr("Started game"), "green");
|
||||
|
||||
QueueOnObject(this, [this] {
|
||||
Settings::Instance().GetNetPlayClient()->StartGame(FindGame(m_current_game));
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnMsgStopGame()
|
||||
{
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnPadBufferChanged(u32 buffer)
|
||||
{
|
||||
QueueOnObject(this, [this, buffer] { m_buffer_size_box->setValue(buffer); });
|
||||
DisplayMessage(tr("Buffer size changed to %1").arg(buffer), "");
|
||||
|
||||
m_buffer_size = static_cast<int>(buffer);
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnDesync(u32 frame, const std::string& player)
|
||||
{
|
||||
DisplayMessage(tr("Possible desync detected: %1 might have desynced at frame %2")
|
||||
.arg(QString::fromStdString(player), QString::number(frame)),
|
||||
"red", OSD::Duration::VERY_LONG);
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnConnectionLost()
|
||||
{
|
||||
DisplayMessage(tr("Lost connection to NetPlay server..."), "red");
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnConnectionError(const std::string& message)
|
||||
{
|
||||
QueueOnObject(this, [this, message] {
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to connect to server: %1").arg(tr(message.c_str())));
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnTraversalError(TraversalClient::FailureReason error)
|
||||
{
|
||||
QueueOnObject(this, [this, error] {
|
||||
switch (error)
|
||||
{
|
||||
case TraversalClient::FailureReason::BadHost:
|
||||
QMessageBox::critical(this, tr("Traversal Error"), tr("Couldn't look up central server"));
|
||||
QDialog::reject();
|
||||
break;
|
||||
case TraversalClient::FailureReason::VersionTooOld:
|
||||
QMessageBox::critical(this, tr("Traversal Error"),
|
||||
tr("Dolphin is too old for traversal server"));
|
||||
QDialog::reject();
|
||||
break;
|
||||
case TraversalClient::FailureReason::ServerForgotAboutUs:
|
||||
case TraversalClient::FailureReason::SocketSendError:
|
||||
case TraversalClient::FailureReason::ResendTimeout:
|
||||
UpdateGUI();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool NetPlayDialog::IsRecording()
|
||||
{
|
||||
std::optional<bool> is_recording = RunOnObject(m_record_input_box, &QCheckBox::isChecked);
|
||||
if (is_recording)
|
||||
return *is_recording;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string NetPlayDialog::FindGame(const std::string& game)
|
||||
{
|
||||
std::optional<std::string> path = RunOnObject(this, [this, game] {
|
||||
for (int i = 0; i < m_game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
if (m_game_list_model->GetUniqueIdentifier(i).toStdString() == game)
|
||||
return m_game_list_model->GetPath(i).toStdString();
|
||||
}
|
||||
return std::string("");
|
||||
});
|
||||
if (path)
|
||||
return *path;
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
void NetPlayDialog::ShowMD5Dialog(const std::string& file_identifier)
|
||||
{
|
||||
QueueOnObject(this, [this, file_identifier] {
|
||||
m_md5_button->setEnabled(false);
|
||||
|
||||
if (m_md5_dialog->isVisible())
|
||||
m_md5_dialog->close();
|
||||
|
||||
m_md5_dialog->show(QString::fromStdString(file_identifier));
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::SetMD5Progress(int pid, int progress)
|
||||
{
|
||||
QueueOnObject(this, [this, pid, progress] {
|
||||
if (m_md5_dialog->isVisible())
|
||||
m_md5_dialog->SetProgress(pid, progress);
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::SetMD5Result(int pid, const std::string& result)
|
||||
{
|
||||
QueueOnObject(this, [this, pid, result] {
|
||||
m_md5_dialog->SetResult(pid, result);
|
||||
m_md5_button->setEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::AbortMD5()
|
||||
{
|
||||
QueueOnObject(this, [this] {
|
||||
m_md5_dialog->close();
|
||||
m_md5_button->setEnabled(true);
|
||||
});
|
||||
}
|
116
Source/Core/DolphinQt/NetPlay/NetPlayDialog.h
Normal file
116
Source/Core/DolphinQt/NetPlay/NetPlayDialog.h
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "Core/NetPlayClient.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
|
||||
class MD5Dialog;
|
||||
class GameListModel;
|
||||
class NetPlayServer;
|
||||
class PadMappingDialog;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QGridLayout;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QSpinBox;
|
||||
class QSplitter;
|
||||
class QTableWidget;
|
||||
class QTextEdit;
|
||||
class QToolButton;
|
||||
|
||||
class NetPlayDialog : public QDialog, public NetPlayUI
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NetPlayDialog(QWidget* parent = nullptr);
|
||||
~NetPlayDialog();
|
||||
|
||||
void show(std::string nickname, bool use_traversal);
|
||||
void reject() override;
|
||||
|
||||
// NetPlayUI methods
|
||||
void BootGame(const std::string& filename) override;
|
||||
void StopGame() override;
|
||||
|
||||
void Update() override;
|
||||
void AppendChat(const std::string& msg) override;
|
||||
|
||||
void OnMsgChangeGame(const std::string& filename) override;
|
||||
void OnMsgStartGame() override;
|
||||
void OnMsgStopGame() override;
|
||||
void OnPadBufferChanged(u32 buffer) override;
|
||||
void OnDesync(u32 frame, const std::string& player) override;
|
||||
void OnConnectionLost() override;
|
||||
void OnConnectionError(const std::string& message) override;
|
||||
void OnTraversalError(TraversalClient::FailureReason error) override;
|
||||
bool IsRecording() override;
|
||||
std::string FindGame(const std::string& game) override;
|
||||
void ShowMD5Dialog(const std::string& file_identifier) override;
|
||||
void SetMD5Progress(int pid, int progress) override;
|
||||
void SetMD5Result(int pid, const std::string& result) override;
|
||||
void AbortMD5() override;
|
||||
signals:
|
||||
void Boot(const QString& filename);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void CreateChatLayout();
|
||||
void CreatePlayersLayout();
|
||||
void CreateMainLayout();
|
||||
void ConnectWidgets();
|
||||
void OnChat();
|
||||
void OnStart();
|
||||
void DisplayMessage(const QString& msg, const std::string& color,
|
||||
int duration = OSD::Duration::NORMAL);
|
||||
void UpdateGUI();
|
||||
void GameStatusChanged(bool running);
|
||||
|
||||
void SetGame(const QString& game_path);
|
||||
|
||||
// Chat
|
||||
QGroupBox* m_chat_box;
|
||||
QTextEdit* m_chat_edit;
|
||||
QLineEdit* m_chat_type_edit;
|
||||
QPushButton* m_chat_send_button;
|
||||
|
||||
// Players
|
||||
QGroupBox* m_players_box;
|
||||
QComboBox* m_room_box;
|
||||
QLabel* m_hostcode_label;
|
||||
QPushButton* m_hostcode_action_button;
|
||||
QTableWidget* m_players_list;
|
||||
QPushButton* m_kick_button;
|
||||
QPushButton* m_assign_ports_button;
|
||||
|
||||
// Other
|
||||
QPushButton* m_game_button;
|
||||
QToolButton* m_md5_button;
|
||||
QPushButton* m_start_button;
|
||||
QLabel* m_buffer_label;
|
||||
QSpinBox* m_buffer_size_box;
|
||||
QCheckBox* m_save_sd_box;
|
||||
QCheckBox* m_load_wii_box;
|
||||
QCheckBox* m_record_input_box;
|
||||
QCheckBox* m_reduce_polling_rate_box;
|
||||
QPushButton* m_quit_button;
|
||||
QSplitter* m_splitter;
|
||||
|
||||
QGridLayout* m_main_layout;
|
||||
MD5Dialog* m_md5_dialog;
|
||||
PadMappingDialog* m_pad_mapping;
|
||||
std::string m_current_game;
|
||||
std::string m_nickname;
|
||||
GameListModel* m_game_list_model = nullptr;
|
||||
bool m_use_traversal = false;
|
||||
bool m_is_copy_button_retry = false;
|
||||
bool m_got_stop_request = true;
|
||||
int m_buffer_size = 0;
|
||||
};
|
280
Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp
Normal file
280
Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/NetPlay/NetPlaySetupDialog.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QTabWidget>
|
||||
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
|
||||
#include "DolphinQt/GameList/GameListModel.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
NetPlaySetupDialog::NetPlaySetupDialog(QWidget* parent)
|
||||
: QDialog(parent), m_game_list_model(Settings::Instance().GetGameListModel())
|
||||
{
|
||||
setWindowTitle(tr("NetPlay Setup"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
CreateMainLayout();
|
||||
|
||||
std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
||||
std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||
int connect_port = Config::Get(Config::NETPLAY_CONNECT_PORT);
|
||||
int host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
||||
int host_listen_port = Config::Get(Config::NETPLAY_LISTEN_PORT);
|
||||
#ifdef USE_UPNP
|
||||
bool use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
|
||||
|
||||
m_host_upnp->setChecked(use_upnp);
|
||||
#endif
|
||||
|
||||
m_nickname_edit->setText(QString::fromStdString(nickname));
|
||||
m_connection_type->setCurrentIndex(traversal_choice == "direct" ? 0 : 1);
|
||||
m_connect_port_box->setValue(connect_port);
|
||||
m_host_port_box->setValue(host_port);
|
||||
|
||||
m_host_force_port_check->setChecked(false);
|
||||
m_host_force_port_box->setValue(host_listen_port);
|
||||
m_host_force_port_box->setEnabled(false);
|
||||
|
||||
OnConnectionTypeChanged(m_connection_type->currentIndex());
|
||||
|
||||
int selected_game = Settings::GetQSettings().value(QStringLiteral("netplay/hostgame"), 0).toInt();
|
||||
|
||||
if (selected_game >= m_host_games->count())
|
||||
selected_game = 0;
|
||||
|
||||
m_host_games->setCurrentItem(m_host_games->item(selected_game));
|
||||
|
||||
ConnectWidgets();
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::CreateMainLayout()
|
||||
{
|
||||
m_main_layout = new QGridLayout;
|
||||
m_button_box = new QDialogButtonBox(QDialogButtonBox::Cancel);
|
||||
m_nickname_edit = new QLineEdit;
|
||||
m_connection_type = new QComboBox;
|
||||
m_reset_traversal_button = new QPushButton(tr("Reset Traversal Settings"));
|
||||
m_tab_widget = new QTabWidget;
|
||||
|
||||
// Connection widget
|
||||
auto* connection_widget = new QWidget;
|
||||
auto* connection_layout = new QGridLayout;
|
||||
|
||||
m_ip_label = new QLabel;
|
||||
m_ip_edit = new QLineEdit;
|
||||
m_connect_port_label = new QLabel(tr("Port:"));
|
||||
m_connect_port_box = new QSpinBox;
|
||||
m_connect_button = new QPushButton(tr("Connect"));
|
||||
|
||||
m_connect_port_box->setMaximum(65535);
|
||||
|
||||
connection_layout->addWidget(m_ip_label, 0, 0);
|
||||
connection_layout->addWidget(m_ip_edit, 0, 1);
|
||||
connection_layout->addWidget(m_connect_port_label, 0, 2);
|
||||
connection_layout->addWidget(m_connect_port_box, 0, 3);
|
||||
connection_layout->addWidget(
|
||||
new QLabel(tr(
|
||||
"ALERT:\n\n"
|
||||
"All players must use the same Dolphin version.\n"
|
||||
"All memory cards, SD cards and cheats must be identical between players or disabled.\n"
|
||||
"If DSP LLE is used, DSP ROMs must be identical between players.\n"
|
||||
"If connecting directly, the host must have the chosen UDP port open/forwarded!\n"
|
||||
"\n"
|
||||
"Wii Remote support in netplay is experimental and should not be expected to work.\n")),
|
||||
1, 0, -1, -1);
|
||||
connection_layout->addWidget(m_connect_button, 3, 3, Qt::AlignRight);
|
||||
|
||||
connection_widget->setLayout(connection_layout);
|
||||
|
||||
// Host widget
|
||||
auto* host_widget = new QWidget;
|
||||
auto* host_layout = new QGridLayout;
|
||||
m_host_port_label = new QLabel(tr("Port:"));
|
||||
m_host_port_box = new QSpinBox;
|
||||
m_host_force_port_check = new QCheckBox(tr("Force Listen Port:"));
|
||||
m_host_force_port_box = new QSpinBox;
|
||||
|
||||
#ifdef USE_UPNP
|
||||
m_host_upnp = new QCheckBox(tr("Forward port (UPnP)"));
|
||||
#endif
|
||||
m_host_games = new QListWidget;
|
||||
m_host_button = new QPushButton(tr("Host"));
|
||||
|
||||
m_host_port_box->setMaximum(65535);
|
||||
m_host_force_port_box->setMaximum(65535);
|
||||
|
||||
host_layout->addWidget(m_host_port_label, 0, 0);
|
||||
host_layout->addWidget(m_host_port_box, 0, 1);
|
||||
#ifdef USE_UPNP
|
||||
host_layout->addWidget(m_host_upnp, 0, 2);
|
||||
#endif
|
||||
host_layout->addWidget(m_host_games, 1, 0, 1, -1);
|
||||
host_layout->addWidget(m_host_force_port_check, 2, 0);
|
||||
host_layout->addWidget(m_host_force_port_box, 2, 1, Qt::AlignLeft);
|
||||
host_layout->addWidget(m_host_button, 2, 2, Qt::AlignRight);
|
||||
|
||||
host_widget->setLayout(host_layout);
|
||||
|
||||
m_connection_type->addItem(tr("Direct Connection"));
|
||||
m_connection_type->addItem(tr("Traversal Server"));
|
||||
|
||||
m_main_layout->addWidget(new QLabel(tr("Connection Type:")), 0, 0);
|
||||
m_main_layout->addWidget(m_connection_type, 0, 1);
|
||||
m_main_layout->addWidget(m_reset_traversal_button, 0, 2);
|
||||
m_main_layout->addWidget(new QLabel(tr("Nickname:")), 1, 0);
|
||||
m_main_layout->addWidget(m_nickname_edit, 1, 1);
|
||||
m_main_layout->addWidget(m_tab_widget, 2, 0, 1, -1);
|
||||
m_main_layout->addWidget(m_button_box, 3, 0, 1, -1);
|
||||
|
||||
// Tabs
|
||||
m_tab_widget->addTab(connection_widget, tr("Connect"));
|
||||
m_tab_widget->addTab(host_widget, tr("Host"));
|
||||
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::ConnectWidgets()
|
||||
{
|
||||
connect(m_connection_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||
this, &NetPlaySetupDialog::OnConnectionTypeChanged);
|
||||
connect(m_nickname_edit, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
|
||||
|
||||
// Connect widget
|
||||
connect(m_ip_edit, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
|
||||
connect(m_connect_port_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&NetPlaySetupDialog::SaveSettings);
|
||||
// Host widget
|
||||
connect(m_host_port_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&NetPlaySetupDialog::SaveSettings);
|
||||
connect(m_host_games, static_cast<void (QListWidget::*)(int)>(&QListWidget::currentRowChanged),
|
||||
[](int index) {
|
||||
Settings::GetQSettings().setValue(QStringLiteral("netplay/hostgame"), index);
|
||||
});
|
||||
|
||||
connect(m_host_games, &QListWidget::itemDoubleClicked, this, &NetPlaySetupDialog::accept);
|
||||
|
||||
connect(m_host_force_port_check, &QCheckBox::toggled,
|
||||
[this](int value) { m_host_force_port_box->setEnabled(value); });
|
||||
#ifdef USE_UPNP
|
||||
connect(m_host_upnp, &QCheckBox::stateChanged, this, &NetPlaySetupDialog::SaveSettings);
|
||||
#endif
|
||||
|
||||
connect(m_connect_button, &QPushButton::clicked, this, &QDialog::accept);
|
||||
connect(m_host_button, &QPushButton::clicked, this, &QDialog::accept);
|
||||
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(m_reset_traversal_button, &QPushButton::clicked, this,
|
||||
&NetPlaySetupDialog::ResetTraversalHost);
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::SaveSettings()
|
||||
{
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_NICKNAME, m_nickname_edit->text().toStdString());
|
||||
Config::SetBaseOrCurrent(m_connection_type->currentIndex() == 0 ? Config::NETPLAY_ADDRESS :
|
||||
Config::NETPLAY_HOST_CODE,
|
||||
m_ip_edit->text().toStdString());
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_CONNECT_PORT,
|
||||
static_cast<u16>(m_connect_port_box->value()));
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_HOST_PORT, static_cast<u16>(m_host_port_box->value()));
|
||||
#ifdef USE_UPNP
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_USE_UPNP, m_host_upnp->isChecked());
|
||||
#endif
|
||||
|
||||
if (m_host_force_port_check->isChecked())
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_LISTEN_PORT,
|
||||
static_cast<u16>(m_host_force_port_box->value()));
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::OnConnectionTypeChanged(int index)
|
||||
{
|
||||
m_connect_port_box->setHidden(index != 0);
|
||||
m_connect_port_label->setHidden(index != 0);
|
||||
|
||||
m_host_port_label->setHidden(index != 0);
|
||||
m_host_port_box->setHidden(index != 0);
|
||||
#ifdef USE_UPNP
|
||||
m_host_upnp->setHidden(index != 0);
|
||||
#endif
|
||||
m_host_force_port_check->setHidden(index == 0);
|
||||
m_host_force_port_box->setHidden(index == 0);
|
||||
|
||||
m_reset_traversal_button->setHidden(index == 0);
|
||||
|
||||
std::string address =
|
||||
index == 0 ? Config::Get(Config::NETPLAY_ADDRESS) : Config::Get(Config::NETPLAY_HOST_CODE);
|
||||
|
||||
m_ip_label->setText(index == 0 ? tr("IP Address:") : tr("Host Code:"));
|
||||
m_ip_edit->setText(QString::fromStdString(address));
|
||||
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_CHOICE,
|
||||
std::string(index == 0 ? "direct" : "traversal"));
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::show()
|
||||
{
|
||||
PopulateGameList();
|
||||
QDialog::show();
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::accept()
|
||||
{
|
||||
SaveSettings();
|
||||
if (m_tab_widget->currentIndex() == 0)
|
||||
{
|
||||
emit Join();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto items = m_host_games->selectedItems();
|
||||
if (items.size() == 0)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("You must select a game to host!"));
|
||||
return;
|
||||
}
|
||||
|
||||
emit Host(items[0]->text());
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::PopulateGameList()
|
||||
{
|
||||
m_host_games->clear();
|
||||
for (int i = 0; i < m_game_list_model->rowCount(QModelIndex()); i++)
|
||||
{
|
||||
auto title = m_game_list_model->GetUniqueIdentifier(i);
|
||||
auto path = m_game_list_model->GetPath(i);
|
||||
|
||||
auto* item = new QListWidgetItem(title);
|
||||
item->setData(Qt::UserRole, path);
|
||||
m_host_games->addItem(item);
|
||||
}
|
||||
|
||||
m_host_games->sortItems();
|
||||
}
|
||||
|
||||
void NetPlaySetupDialog::ResetTraversalHost()
|
||||
{
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_SERVER,
|
||||
Config::NETPLAY_TRAVERSAL_SERVER.default_value);
|
||||
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_PORT,
|
||||
Config::NETPLAY_TRAVERSAL_PORT.default_value);
|
||||
|
||||
QMessageBox::information(
|
||||
this, tr("Reset Traversal Server"),
|
||||
tr("Reset Traversal Server to %1:%2")
|
||||
.arg(QString::fromStdString(Config::NETPLAY_TRAVERSAL_SERVER.default_value),
|
||||
QString::number(Config::NETPLAY_TRAVERSAL_PORT.default_value)));
|
||||
}
|
72
Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.h
Normal file
72
Source/Core/DolphinQt/NetPlay/NetPlaySetupDialog.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class GameListModel;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QGridLayout;
|
||||
class QPushButton;
|
||||
class QSpinBox;
|
||||
class QTabWidget;
|
||||
|
||||
class NetPlaySetupDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NetPlaySetupDialog(QWidget* parent);
|
||||
|
||||
void accept() override;
|
||||
void show();
|
||||
|
||||
signals:
|
||||
bool Join();
|
||||
bool Host(const QString& game_identifier);
|
||||
|
||||
private:
|
||||
void CreateMainLayout();
|
||||
void ConnectWidgets();
|
||||
void PopulateGameList();
|
||||
void ResetTraversalHost();
|
||||
|
||||
void SaveSettings();
|
||||
|
||||
void OnConnectionTypeChanged(int index);
|
||||
|
||||
// Main Widget
|
||||
QDialogButtonBox* m_button_box;
|
||||
QComboBox* m_connection_type;
|
||||
QLineEdit* m_nickname_edit;
|
||||
QGridLayout* m_main_layout;
|
||||
QTabWidget* m_tab_widget;
|
||||
QPushButton* m_reset_traversal_button;
|
||||
|
||||
// Connection Widget
|
||||
QLabel* m_ip_label;
|
||||
QLineEdit* m_ip_edit;
|
||||
QLabel* m_connect_port_label;
|
||||
QSpinBox* m_connect_port_box;
|
||||
QPushButton* m_connect_button;
|
||||
|
||||
// Host Widget
|
||||
QLabel* m_host_port_label;
|
||||
QSpinBox* m_host_port_box;
|
||||
QListWidget* m_host_games;
|
||||
QPushButton* m_host_button;
|
||||
QCheckBox* m_host_force_port_check;
|
||||
QSpinBox* m_host_force_port_box;
|
||||
|
||||
#ifdef USE_UPNP
|
||||
QCheckBox* m_host_upnp;
|
||||
#endif
|
||||
|
||||
GameListModel* m_game_list_model;
|
||||
};
|
117
Source/Core/DolphinQt/NetPlay/PadMappingDialog.cpp
Normal file
117
Source/Core/DolphinQt/NetPlay/PadMappingDialog.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/NetPlay/PadMappingDialog.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
#include "Core/NetPlayClient.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
|
||||
PadMappingDialog::PadMappingDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle(tr("Assign Controllers"));
|
||||
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
}
|
||||
|
||||
void PadMappingDialog::CreateWidgets()
|
||||
{
|
||||
m_main_layout = new QGridLayout;
|
||||
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||
|
||||
for (unsigned int i = 0; i < m_wii_boxes.size(); i++)
|
||||
{
|
||||
m_gc_boxes[i] = new QComboBox;
|
||||
m_wii_boxes[i] = new QComboBox;
|
||||
|
||||
m_main_layout->addWidget(new QLabel(tr("GC Port %1").arg(i + 1)), 0, i);
|
||||
m_main_layout->addWidget(new QLabel(tr("Wii Remote %1").arg(i + 1)), 0, 4 + i);
|
||||
m_main_layout->addWidget(m_gc_boxes[i], 1, i);
|
||||
m_main_layout->addWidget(m_wii_boxes[i], 1, 4 + i);
|
||||
}
|
||||
|
||||
m_main_layout->addWidget(m_button_box, 2, 0, 1, -1);
|
||||
|
||||
setLayout(m_main_layout);
|
||||
}
|
||||
|
||||
void PadMappingDialog::ConnectWidgets()
|
||||
{
|
||||
connect(m_button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
for (auto& combo_group : {m_gc_boxes, m_wii_boxes})
|
||||
{
|
||||
for (auto& combo : combo_group)
|
||||
{
|
||||
connect(combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
&PadMappingDialog::OnMappingChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PadMappingDialog::exec()
|
||||
{
|
||||
auto* client = Settings::Instance().GetNetPlayClient();
|
||||
auto* server = Settings::Instance().GetNetPlayServer();
|
||||
// Load Settings
|
||||
m_players = client->GetPlayers();
|
||||
m_pad_mapping = server->GetPadMapping();
|
||||
m_wii_mapping = server->GetWiimoteMapping();
|
||||
|
||||
QStringList players;
|
||||
|
||||
players.append(tr("None"));
|
||||
|
||||
for (const auto& player : m_players)
|
||||
{
|
||||
players.append(
|
||||
QStringLiteral("%1 (%2)").arg(QString::fromStdString(player->name)).arg(player->pid));
|
||||
}
|
||||
|
||||
for (auto& combo_group : {m_gc_boxes, m_wii_boxes})
|
||||
{
|
||||
bool gc = combo_group == m_gc_boxes;
|
||||
for (size_t i = 0; i < combo_group.size(); i++)
|
||||
{
|
||||
auto& combo = combo_group[i];
|
||||
const bool old = combo->blockSignals(true);
|
||||
|
||||
combo->clear();
|
||||
combo->addItems(players);
|
||||
|
||||
const auto index = gc ? m_pad_mapping[i] : m_wii_mapping[i];
|
||||
|
||||
combo->setCurrentIndex(index == -1 ? 0 : index);
|
||||
combo->blockSignals(old);
|
||||
}
|
||||
}
|
||||
|
||||
return QDialog::exec();
|
||||
}
|
||||
PadMappingArray PadMappingDialog::GetGCPadArray()
|
||||
{
|
||||
return m_pad_mapping;
|
||||
}
|
||||
|
||||
PadMappingArray PadMappingDialog::GetWiimoteArray()
|
||||
{
|
||||
return m_wii_mapping;
|
||||
}
|
||||
|
||||
void PadMappingDialog::OnMappingChanged()
|
||||
{
|
||||
for (unsigned int i = 0; i < m_wii_boxes.size(); i++)
|
||||
{
|
||||
int gc_id = m_gc_boxes[i]->currentIndex();
|
||||
int wii_id = m_wii_boxes[i]->currentIndex();
|
||||
|
||||
m_pad_mapping[i] = gc_id > 0 ? m_players[gc_id - 1]->pid : -1;
|
||||
m_wii_mapping[i] = wii_id > 0 ? m_players[wii_id - 1]->pid : -1;
|
||||
}
|
||||
}
|
42
Source/Core/DolphinQt/NetPlay/PadMappingDialog.h
Normal file
42
Source/Core/DolphinQt/NetPlay/PadMappingDialog.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "Core/NetPlayProto.h"
|
||||
|
||||
class NetPlayClient;
|
||||
class Player;
|
||||
class QGridLayout;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
|
||||
class PadMappingDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PadMappingDialog(QWidget* widget);
|
||||
|
||||
int exec() override;
|
||||
|
||||
PadMappingArray GetGCPadArray();
|
||||
PadMappingArray GetWiimoteArray();
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
void OnMappingChanged();
|
||||
|
||||
PadMappingArray m_pad_mapping;
|
||||
PadMappingArray m_wii_mapping;
|
||||
|
||||
QGridLayout* m_main_layout;
|
||||
std::array<QComboBox*, 4> m_gc_boxes;
|
||||
std::array<QComboBox*, 4> m_wii_boxes;
|
||||
std::vector<const Player*> m_players;
|
||||
QDialogButtonBox* m_button_box;
|
||||
};
|
Reference in New Issue
Block a user