Port several small multiplayer PRs from yuzu (#7419)
* yuzu: Use displayed port on direct connect * Color player counts in the multiplayer public lobby list - Full lobbies have their player count displayed in red. - Lobbies with one slot left have their player count displayed in orange. - Empty lobbies have their player count grayed out. * Add hotkeys for multiplayer actions Default shortcuts were chosen as to be intuitive (use the first letter of the action, or the second word's first letter) and work on all types of keyboards. The hotkeys can be used while playing a game too, as they are application-wide. * Persist filters in multiplayer public lobby list After connecting to a room, the chosen filter text, "Games I Own", "Hide Empty Rooms" and "Hide Full Rooms" values are persisted to configuration so they are preserved across restarts. This makes it easier to rejoin a room if you regularly play the same game, or after a crash. * citra_qt/lobby: Fix multiplayer player count color in dark theme Co-Authored-By: Kevnkkm <56404895+kevnkkm@users.noreply.github.com> * Address review comments --------- Co-authored-by: Narr the Reg <juangerman-13@hotmail.com> Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro> Co-authored-by: Kevnkkm <56404895+kevnkkm@users.noreply.github.com>
This commit is contained in:
parent
aa6809e2a8
commit
7638f87f74
|
@ -54,7 +54,7 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
|
|||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<UISettings::Shortcut, 30> Config::default_hotkeys {{
|
||||
const std::array<UISettings::Shortcut, 35> Config::default_hotkeys {{
|
||||
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
|
||||
|
@ -71,6 +71,11 @@ const std::array<UISettings::Shortcut, 30> Config::default_hotkeys {{
|
|||
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WidgetWithChildrenShortcut}},
|
||||
{QStringLiteral("Load from Newest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Multiplayer Browse Public Game Lobby"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+B"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Multiplayer Create Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+N"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Multiplayer Direct Connect to Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Shift"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Multiplayer Leave Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+L"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Multiplayer Show Current Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+R"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
|
||||
|
@ -557,6 +562,15 @@ void Config::ReadMultiplayerValues() {
|
|||
UISettings::values.game_id = ReadSetting(QStringLiteral("game_id"), 0).toULongLong();
|
||||
UISettings::values.room_description =
|
||||
ReadSetting(QStringLiteral("room_description"), QString{}).toString();
|
||||
UISettings::values.multiplayer_filter_text =
|
||||
ReadSetting(QStringLiteral("multiplayer_filter_text"), QString{}).toString();
|
||||
UISettings::values.multiplayer_filter_games_owned =
|
||||
ReadSetting(QStringLiteral("multiplayer_filter_games_owned"), false).toBool();
|
||||
UISettings::values.multiplayer_filter_hide_empty =
|
||||
ReadSetting(QStringLiteral("multiplayer_filter_hide_empty"), false).toBool();
|
||||
UISettings::values.multiplayer_filter_hide_full =
|
||||
ReadSetting(QStringLiteral("multiplayer_filter_hide_full"), false).toBool();
|
||||
|
||||
// Read ban list back
|
||||
int size = qt_config->beginReadArray(QStringLiteral("username_ban_list"));
|
||||
UISettings::values.ban_list.first.resize(size);
|
||||
|
@ -1074,6 +1088,15 @@ void Config::SaveMultiplayerValues() {
|
|||
WriteSetting(QStringLiteral("game_id"), UISettings::values.game_id, 0);
|
||||
WriteSetting(QStringLiteral("room_description"), UISettings::values.room_description,
|
||||
QString{});
|
||||
WriteSetting(QStringLiteral("multiplayer_filter_text"),
|
||||
UISettings::values.multiplayer_filter_text, QString{});
|
||||
WriteSetting(QStringLiteral("multiplayer_filter_games_owned"),
|
||||
UISettings::values.multiplayer_filter_games_owned, false);
|
||||
WriteSetting(QStringLiteral("multiplayer_filter_hide_empty"),
|
||||
UISettings::values.multiplayer_filter_hide_empty, false);
|
||||
WriteSetting(QStringLiteral("multiplayer_filter_hide_full"),
|
||||
UISettings::values.multiplayer_filter_hide_full, false);
|
||||
|
||||
// Write ban list
|
||||
qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
|
||||
for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) {
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||
static const std::array<UISettings::Shortcut, 30> default_hotkeys;
|
||||
static const std::array<UISettings::Shortcut, 35> default_hotkeys;
|
||||
|
||||
private:
|
||||
void Initialize(const std::string& config_name);
|
||||
|
|
|
@ -647,6 +647,13 @@ void GMainWindow::InitializeHotkeys() {
|
|||
link_action_shortcut(ui->action_Advance_Frame, QStringLiteral("Advance Frame"));
|
||||
link_action_shortcut(ui->action_Load_from_Newest_Slot, QStringLiteral("Load from Newest Slot"));
|
||||
link_action_shortcut(ui->action_Save_to_Oldest_Slot, QStringLiteral("Save to Oldest Slot"));
|
||||
link_action_shortcut(ui->action_View_Lobby,
|
||||
QStringLiteral("Multiplayer Browse Public Game Lobby"));
|
||||
link_action_shortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
|
||||
link_action_shortcut(ui->action_Connect_To_Room,
|
||||
QStringLiteral("Multiplayer Direct Connect to Room"));
|
||||
link_action_shortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room"));
|
||||
link_action_shortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room"));
|
||||
|
||||
const auto add_secondary_window_hotkey = [this](QKeySequence hotkey, const char* slot) {
|
||||
// This action will fire specifically when secondary_window is in focus
|
||||
|
|
|
@ -80,9 +80,8 @@ void DirectConnectWindow::Connect() {
|
|||
// Store settings
|
||||
UISettings::values.nickname = ui->nickname->text();
|
||||
UISettings::values.ip = ui->ip->text();
|
||||
UISettings::values.port = (ui->port->isModified() && !ui->port->text().isEmpty())
|
||||
? ui->port->text()
|
||||
: UISettings::values.port;
|
||||
UISettings::values.port =
|
||||
!ui->port->text().isEmpty() ? ui->port->text() : UISettings::values.port;
|
||||
|
||||
// attempt to connect in a different thread
|
||||
QFuture<void> f = QtConcurrent::run([&] {
|
||||
|
|
|
@ -63,10 +63,10 @@ Lobby::Lobby(Core::System& system_, QWidget* parent, QStandardItemModel* list,
|
|||
|
||||
// UI Buttons
|
||||
connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);
|
||||
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
|
||||
connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned);
|
||||
connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);
|
||||
connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);
|
||||
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
|
||||
connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom);
|
||||
connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom);
|
||||
|
||||
|
@ -74,6 +74,12 @@ Lobby::Lobby(Core::System& system_, QWidget* parent, QStandardItemModel* list,
|
|||
connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
|
||||
&Lobby::OnRefreshLobby);
|
||||
|
||||
// Load persistent filters after events are connected to make sure they apply
|
||||
ui->search->setText(UISettings::values.multiplayer_filter_text);
|
||||
ui->games_owned->setChecked(UISettings::values.multiplayer_filter_games_owned);
|
||||
ui->hide_empty->setChecked(UISettings::values.multiplayer_filter_hide_empty);
|
||||
ui->hide_full->setChecked(UISettings::values.multiplayer_filter_hide_full);
|
||||
|
||||
// manually start a refresh when the window is opening
|
||||
// TODO(jroweboy): if this refresh is slow for people with bad internet, then don't do it as
|
||||
// part of the constructor, but offload the refresh until after the window shown. perhaps emit a
|
||||
|
@ -180,6 +186,10 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
|||
UISettings::values.nickname = ui->nickname->text();
|
||||
UISettings::values.ip = proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
|
||||
UISettings::values.port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toString();
|
||||
UISettings::values.multiplayer_filter_text = ui->search->text();
|
||||
UISettings::values.multiplayer_filter_games_owned = ui->games_owned->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_empty = ui->hide_empty->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_full = ui->hide_full->isChecked();
|
||||
}
|
||||
|
||||
void Lobby::ResetModel() {
|
||||
|
|
|
@ -188,13 +188,38 @@ public:
|
|||
}
|
||||
|
||||
QVariant data(int role) const override {
|
||||
if (role != Qt::DisplayRole) {
|
||||
return LobbyItem::data(role);
|
||||
}
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
auto members = data(MemberListRole).toList();
|
||||
return QStringLiteral("%1 / %2").arg(QString::number(members.size()),
|
||||
data(MaxPlayerRole).toString());
|
||||
}
|
||||
case Qt::ForegroundRole: {
|
||||
auto members = data(MemberListRole).toList();
|
||||
auto max_players = data(MaxPlayerRole).toInt();
|
||||
const QColor room_full_color(255, 48, 32);
|
||||
const QColor room_almost_full_color(255, 140, 32);
|
||||
const QColor room_has_players_color(32, 160, 32);
|
||||
const QColor room_empty_color(128, 128, 128);
|
||||
|
||||
if (members.size() >= max_players) {
|
||||
return QBrush(room_full_color);
|
||||
} else if (members.size() == (max_players - 1)) {
|
||||
return QBrush(room_almost_full_color);
|
||||
} else if (members.size() == 0) {
|
||||
return QBrush(room_empty_color);
|
||||
} else if (members.size() > 0 && members.size() < (max_players - 1)) {
|
||||
return QBrush(room_has_players_color);
|
||||
}
|
||||
|
||||
// FIXME: How to return a value that tells Qt not to modify the
|
||||
// text color from the default (as if Qt::ForegroundRole wasn't overridden)?
|
||||
return QBrush(nullptr);
|
||||
}
|
||||
default:
|
||||
return LobbyItem::data(role);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator<(const QStandardItem& other) const override {
|
||||
// sort by rooms that have the most players
|
||||
|
|
|
@ -138,6 +138,11 @@ struct Values {
|
|||
QString room_description;
|
||||
std::pair<std::vector<std::string>, std::vector<std::string>> ban_list;
|
||||
|
||||
QString multiplayer_filter_text;
|
||||
bool multiplayer_filter_games_owned;
|
||||
bool multiplayer_filter_hide_empty;
|
||||
bool multiplayer_filter_hide_full;
|
||||
|
||||
// logging
|
||||
Settings::Setting<bool> show_console{false, "showConsole"};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue