Move DolphinQt2 to DolphinQt

This commit is contained in:
spycrab
2018-07-07 00:40:15 +02:00
parent 059880bb16
commit 13ba24c5a6
233 changed files with 392 additions and 392 deletions

View 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();
}

View 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;
};

View 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();
}

View 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;
};

View 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);
});
}

View 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;
};

View 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)));
}

View 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;
};

View 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;
}
}

View 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;
};