diff options
Diffstat (limited to 'src/yuzu')
36 files changed, 622 insertions, 297 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index dfc675cc8..06d982d9b 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -353,7 +353,7 @@ if (USE_DISCORD_PRESENCE) discord_impl.cpp discord_impl.h ) - target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc) + target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib) target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) endif() diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 0db62baa3..35fef506a 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -70,28 +70,28 @@ const std::array<int, 2> Config::default_ringcon_analogs{{ // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, }}; // clang-format on @@ -440,6 +440,7 @@ void Config::ReadControlValues() { ReadBasicSetting(Settings::values.emulate_analog_keyboard); Settings::values.mouse_panning = false; ReadBasicSetting(Settings::values.mouse_panning_sensitivity); + ReadBasicSetting(Settings::values.enable_joycon_driver); ReadBasicSetting(Settings::values.tas_enable); ReadBasicSetting(Settings::values.tas_loop); @@ -747,7 +748,7 @@ void Config::ReadShortcutValues() { for (const auto& [name, group, shortcut] : default_hotkeys) { qt_config->beginGroup(group); qt_config->beginGroup(name); - // No longer using ReadSetting for shortcut.second as it innacurately returns a value of 1 + // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open // a file dialog in windowed mode UISettings::values.shortcuts.push_back( @@ -756,7 +757,7 @@ void Config::ReadShortcutValues() { {ReadSetting(QStringLiteral("KeySeq"), shortcut.keyseq).toString(), ReadSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq) .toString(), - shortcut.context}}); + shortcut.context, ReadSetting(QStringLiteral("Repeat"), shortcut.repeat).toBool()}}); qt_config->endGroup(); qt_config->endGroup(); } @@ -1139,6 +1140,7 @@ void Config::SaveControlValues() { WriteGlobalSetting(Settings::values.enable_accurate_vibrations); WriteGlobalSetting(Settings::values.motion_enabled); WriteBasicSetting(Settings::values.enable_raw_input); + WriteBasicSetting(Settings::values.enable_joycon_driver); WriteBasicSetting(Settings::values.keyboard_enabled); WriteBasicSetting(Settings::values.emulate_analog_keyboard); WriteBasicSetting(Settings::values.mouse_panning_sensitivity); @@ -1393,6 +1395,7 @@ void Config::SaveShortcutValues() { WriteSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq, default_hotkey.controller_keyseq); WriteSetting(QStringLiteral("Context"), shortcut.context, default_hotkey.context); + WriteSetting(QStringLiteral("Repeat"), shortcut.repeat, default_hotkey.repeat); qt_config->endGroup(); qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 97fb664bf..ac42cc7fc 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -92,3 +92,13 @@ void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text); combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX); } + +int ConfigurationShared::GetComboboxIndex(int global_setting_index, const QComboBox* combobox) { + if (Settings::IsConfiguringGlobal()) { + return combobox->currentIndex(); + } + if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { + return global_setting_index; + } + return combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET; +} diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index e597dcdb5..04c88758c 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -69,4 +69,7 @@ void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global); // Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox void InsertGlobalItem(QComboBox* combobox, int global_index); +// Returns the correct index of a QComboBox taking into account global configuration +int GetComboboxIndex(int global_setting_index, const QComboBox* combobox); + } // namespace ConfigurationShared diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4301313cf..2aaefcc05 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -66,7 +66,6 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, web_tab->SetWebServiceConfigEnabled(enable_web_config); hotkeys_tab->Populate(registry); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); input_tab->Initialize(input_subsystem); diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index bb9910a53..a45ec69ec 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -460,7 +460,7 @@ </item> <item> <property name="text"> - <string>AMD FidelityFX™️ Super Resolution (Vulkan Only)</string> + <string>AMD FidelityFX™️ Super Resolution</string> </property> </item> </widget> diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 235b813d9..77b976e74 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -138,6 +138,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.controller_navigation = ui->controller_navigation->isChecked(); Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); + Settings::values.enable_joycon_driver = ui->enable_joycon_driver->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -172,6 +173,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); + ui->enable_joycon_driver->setChecked(Settings::values.enable_joycon_driver.GetValue()); UpdateUIEnabled(); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index fac8cf827..75d96d3ab 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2696,6 +2696,22 @@ </widget> </item> <item row="5" column="0"> + <widget class="QCheckBox" name="enable_joycon_driver"> + <property name="toolTip"> + <string>Requires restarting yuzu</string> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>23</height> + </size> + </property> + <property name="text"> + <string>Enable direct JoyCon driver</string> + </property> + </widget> + </item> + <item row="6" column="0"> <widget class="QCheckBox" name="mouse_panning"> <property name="minimumSize"> <size> @@ -2708,7 +2724,7 @@ </property> </widget> </item> - <item row="5" column="2"> + <item row="6" column="2"> <widget class="QSpinBox" name="mouse_panning_sensitivity"> <property name="toolTip"> <string>Mouse sensitivity</string> @@ -2730,14 +2746,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="motion_touch"> <property name="text"> <string>Motion / Touch</string> </property> </widget> </item> - <item row="6" column="2"> + <item row="7" column="2"> <widget class="QPushButton" name="buttonMotionTouch"> <property name="text"> <string>Configure</string> diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index c40d980c9..723690e71 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -66,6 +66,18 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { return QObject::tr("R"); case Common::Input::ButtonNames::TriggerL: return QObject::tr("L"); + case Common::Input::ButtonNames::TriggerZR: + return QObject::tr("ZR"); + case Common::Input::ButtonNames::TriggerZL: + return QObject::tr("ZL"); + case Common::Input::ButtonNames::TriggerSR: + return QObject::tr("SR"); + case Common::Input::ButtonNames::TriggerSL: + return QObject::tr("SL"); + case Common::Input::ButtonNames::ButtonStickL: + return QObject::tr("Stick L"); + case Common::Input::ButtonNames::ButtonStickR: + return QObject::tr("Stick R"); case Common::Input::ButtonNames::ButtonA: return QObject::tr("A"); case Common::Input::ButtonNames::ButtonB: @@ -76,6 +88,14 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { return QObject::tr("Y"); case Common::Input::ButtonNames::ButtonStart: return QObject::tr("Start"); + case Common::Input::ButtonNames::ButtonPlus: + return QObject::tr("Plus"); + case Common::Input::ButtonNames::ButtonMinus: + return QObject::tr("Minus"); + case Common::Input::ButtonNames::ButtonHome: + return QObject::tr("Home"); + case Common::Input::ButtonNames::ButtonCapture: + return QObject::tr("Capture"); case Common::Input::ButtonNames::L1: return QObject::tr("L1"); case Common::Input::ButtonNames::L2: @@ -162,12 +182,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : ""); const QString invert = QString::fromStdString(param.Get("invert", "+") == "-" ? "-" : ""); + const QString turbo = QString::fromStdString(param.Get("turbo", false) ? "$" : ""); const auto common_button_name = input_subsystem->GetButtonName(param); // Retrieve the names from Qt if (param.Get("engine", "") == "keyboard") { const QString button_str = GetKeyName(param.Get("code", 0)); - return QObject::tr("%1%2%3").arg(toggle, inverted, button_str); + return QObject::tr("%1%2%3%4").arg(turbo, toggle, inverted, button_str); } if (common_button_name == Common::Input::ButtonNames::Invalid) { @@ -181,7 +202,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { if (common_button_name == Common::Input::ButtonNames::Value) { if (param.Has("hat")) { const QString hat = GetDirectionName(param.Get("direction", "")); - return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); + return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, hat); } if (param.Has("axis")) { const QString axis = QString::fromStdString(param.Get("axis", "")); @@ -199,13 +220,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { } if (param.Has("button")) { const QString button = QString::fromStdString(param.Get("button", "")); - return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); + return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button); } } QString button_name = GetButtonName(common_button_name); if (param.Has("hat")) { - return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); + return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name); } if (param.Has("axis")) { return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); @@ -214,7 +235,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); } if (param.Has("button")) { - return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); + return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button_name); } return QObject::tr("[unknown]"); @@ -375,6 +396,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i button_map[button_id]->setText(ButtonToText(param)); emulated_controller->SetButtonParam(button_id, param); }); + context_menu.addAction(tr("Turbo button"), [&] { + const bool turbo_value = !param.Get("turbo", false); + param.Set("turbo", turbo_value); + button_map[button_id]->setText(ButtonToText(param)); + emulated_controller->SetButtonParam(button_id, param); + }); } if (param.Has("axis")) { context_menu.addAction(tr("Invert axis"), [&] { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 11390fec0..c287220fc 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -81,7 +81,6 @@ void PlayerControlPreview::UpdateColors() { colors.outline = QColor(0, 0, 0); colors.primary = QColor(225, 225, 225); colors.button = QColor(109, 111, 114); - colors.button2 = QColor(109, 111, 114); colors.button2 = QColor(77, 80, 84); colors.slider_arrow = QColor(65, 68, 73); colors.font2 = QColor(0, 0, 0); @@ -100,12 +99,17 @@ void PlayerControlPreview::UpdateColors() { colors.led_off = QColor(170, 238, 255); colors.indicator2 = QColor(59, 165, 93); colors.charging = QColor(250, 168, 26); + colors.button_turbo = QColor(217, 158, 4); colors.left = colors.primary; colors.right = colors.primary; - // Possible alternative to set colors from settings - // colors.left = QColor(controller->GetColors().left.body); - // colors.right = QColor(controller->GetColors().right.body); + + const auto color_left = controller->GetColorsValues()[0].body; + const auto color_right = controller->GetColorsValues()[1].body; + if (color_left != 0 && color_right != 0) { + colors.left = QColor(color_left); + colors.right = QColor(color_right); + } } void PlayerControlPreview::ResetInputs() { @@ -2465,7 +2469,6 @@ void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, float width, float height, Direction direction, float radius) { - p.setBrush(button_color); if (pressed.value) { switch (direction) { case Direction::Left: @@ -2483,16 +2486,16 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, case Direction::None: break; } - p.setBrush(colors.highlight); } QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f}; + p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo)); p.drawRoundedRect(rect, radius, radius); } void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, const Common::Input::ButtonStatus& pressed, int button_size) { p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawRectangle(p, center, button_size, button_size / 3.0f); } void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, @@ -2500,7 +2503,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, int button_size) { // Draw outer line p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawRectangle(p, center, button_size, button_size / 3.0f); DrawRectangle(p, center, button_size / 3.0f, button_size); @@ -2522,7 +2525,7 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawPolygon(p, button_x); } @@ -2535,7 +2538,7 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawPolygon(p, button_x); } @@ -2549,17 +2552,15 @@ void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button2); + p.setBrush(GetButtonColor(colors.button2, pressed.value, pressed.turbo)); DrawPolygon(p, button_x); } void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, const Common::Input::ButtonStatus& pressed, float button_size) { - p.setBrush(button_color); - if (pressed.value) { - p.setBrush(colors.highlight); - } + + p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo)); p.drawEllipse(center, button_size, button_size); } @@ -2616,7 +2617,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, // Draw arrow button p.setPen(pressed.value ? colors.highlight : colors.button); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawPolygon(p, arrow_button); switch (direction) { @@ -2668,10 +2669,20 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, // Draw arrow button p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo)); DrawPolygon(p, qtrigger_button); } +QColor PlayerControlPreview::GetButtonColor(QColor default_color, bool is_pressed, bool turbo) { + if (is_pressed && turbo) { + return colors.button_turbo; + } + if (is_pressed) { + return colors.highlight; + } + return default_color; +} + void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery) { if (battery == Common::Input::BatteryLevel::None) { diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index b258c6d77..0e9e95e85 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -81,6 +81,7 @@ private: QColor right{}; QColor button{}; QColor button2{}; + QColor button_turbo{}; QColor font{}; QColor font2{}; QColor highlight{}; @@ -183,6 +184,7 @@ private: const Common::Input::ButtonStatus& pressed, float size = 1.0f); void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, const Common::Input::ButtonStatus& pressed); + QColor GetButtonColor(QColor default_color, bool is_pressed, bool turbo); // Draw battery functions void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery); diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index d1b870c72..fb1292f07 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -89,7 +89,6 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, "using-a-controller-or-android-phone-for-motion-or-touch-input'><span " "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); SetConfiguration(); UpdateUiDisplay(); ConnectEvents(); diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 93db47cfd..7e757eafd 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -66,8 +66,6 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); - // remove Help question mark button from the title bar - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); addons_tab->SetTitleId(title_id); diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 688c2dd38..1275f10c8 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -4,9 +4,11 @@ #include <memory> #include <QKeyEvent> #include <QMenu> +#include <QMessageBox> #include <QTimer> +#include <fmt/format.h> -#include "core/hid/emulated_devices.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" @@ -126,9 +128,16 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, ui->buttonRingAnalogPush, }; - emulated_device = hid_core_.GetEmulatedDevices(); - emulated_device->SaveCurrentConfig(); - emulated_device->EnableConfiguration(); + emulated_controller = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1); + emulated_controller->SaveCurrentConfig(); + emulated_controller->EnableConfiguration(); + + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, + .is_npad_service = false, + }; + callback_key = emulated_controller->SetCallback(engine_callback); + is_controller_set = true; LoadConfiguration(); @@ -143,9 +152,9 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, HandleClick( analog_map_buttons[sub_button_id], [=, this](const Common::ParamPackage& params) { - Common::ParamPackage param = emulated_device->GetRingParam(); + Common::ParamPackage param = emulated_controller->GetRingParam(); SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]); - emulated_device->SetRingParam(param); + emulated_controller->SetRingParam(param); }, InputCommon::Polling::InputType::Stick); }); @@ -155,16 +164,16 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, connect(analog_button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; - Common::ParamPackage param = emulated_device->GetRingParam(); + Common::ParamPackage param = emulated_controller->GetRingParam(); context_menu.addAction(tr("Clear"), [&] { - emulated_device->SetRingParam({}); + emulated_controller->SetRingParam(param); analog_map_buttons[sub_button_id]->setText(tr("[not set]")); }); context_menu.addAction(tr("Invert axis"), [&] { const bool invert_value = param.Get("invert_x", "+") == "-"; const std::string invert_str = invert_value ? "+" : "-"; param.Set("invert_x", invert_str); - emulated_device->SetRingParam(param); + emulated_controller->SetRingParam(param); for (int sub_button_id2 = 0; sub_button_id2 < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id2) { analog_map_buttons[sub_button_id2]->setText( @@ -177,16 +186,19 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, } connect(ui->sliderRingAnalogDeadzone, &QSlider::valueChanged, [=, this] { - Common::ParamPackage param = emulated_device->GetRingParam(); + Common::ParamPackage param = emulated_controller->GetRingParam(); const auto slider_value = ui->sliderRingAnalogDeadzone->value(); ui->labelRingAnalogDeadzone->setText(tr("Deadzone: %1%").arg(slider_value)); param.Set("deadzone", slider_value / 100.0f); - emulated_device->SetRingParam(param); + emulated_controller->SetRingParam(param); }); connect(ui->restore_defaults_button, &QPushButton::clicked, this, &ConfigureRingController::RestoreDefaults); + connect(ui->enable_ring_controller_button, &QPushButton::clicked, this, + &ConfigureRingController::EnableRingController); + timeout_timer->setSingleShot(true); connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); @@ -202,7 +214,14 @@ ConfigureRingController::ConfigureRingController(QWidget* parent, } ConfigureRingController::~ConfigureRingController() { - emulated_device->DisableConfiguration(); + emulated_controller->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); + emulated_controller->DisableConfiguration(); + + if (is_controller_set) { + emulated_controller->DeleteCallback(callback_key); + is_controller_set = false; + } }; void ConfigureRingController::changeEvent(QEvent* event) { @@ -219,7 +238,7 @@ void ConfigureRingController::RetranslateUI() { void ConfigureRingController::UpdateUI() { RetranslateUI(); - const Common::ParamPackage param = emulated_device->GetRingParam(); + const Common::ParamPackage param = emulated_controller->GetRingParam(); for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { auto* const analog_button = analog_map_buttons[sub_button_id]; @@ -240,9 +259,9 @@ void ConfigureRingController::UpdateUI() { } void ConfigureRingController::ApplyConfiguration() { - emulated_device->DisableConfiguration(); - emulated_device->SaveCurrentConfig(); - emulated_device->EnableConfiguration(); + emulated_controller->DisableConfiguration(); + emulated_controller->SaveCurrentConfig(); + emulated_controller->EnableConfiguration(); } void ConfigureRingController::LoadConfiguration() { @@ -252,10 +271,62 @@ void ConfigureRingController::LoadConfiguration() { void ConfigureRingController::RestoreDefaults() { const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); - emulated_device->SetRingParam(Common::ParamPackage(default_ring_string)); + emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); UpdateUI(); } +void ConfigureRingController::EnableRingController() { + const auto dialog_title = tr("Error enabling ring input"); + + is_ring_enabled = false; + ui->ring_controller_sensor_value->setText(tr("Not connected")); + + if (!Settings::values.enable_joycon_driver) { + QMessageBox::warning(this, dialog_title, tr("Direct Joycon driver is not enabled")); + return; + } + + ui->enable_ring_controller_button->setEnabled(false); + ui->enable_ring_controller_button->setText(tr("Configuring")); + // SetPollingMode is blocking. Allow to update the button status before calling the command + repaint(); + + const auto result = emulated_controller->SetPollingMode( + Core::HID::EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Ring); + switch (result) { + case Common::Input::DriverResult::Success: + is_ring_enabled = true; + break; + case Common::Input::DriverResult::NotSupported: + QMessageBox::warning(this, dialog_title, + tr("The current mapped device doesn't support the ring controller")); + break; + case Common::Input::DriverResult::NoDeviceDetected: + QMessageBox::warning(this, dialog_title, + tr("The current mapped device doesn't have a ring attached")); + break; + default: + QMessageBox::warning(this, dialog_title, + tr("Unexpected driver result %1").arg(static_cast<int>(result))); + break; + } + ui->enable_ring_controller_button->setEnabled(true); + ui->enable_ring_controller_button->setText(tr("Enable")); +} + +void ConfigureRingController::ControllerUpdate(Core::HID::ControllerTriggerType type) { + if (!is_ring_enabled) { + return; + } + if (type != Core::HID::ControllerTriggerType::RingController) { + return; + } + + const auto value = emulated_controller->GetRingSensorValues(); + const auto tex_value = QString::fromStdString(fmt::format("{:.3f}", value.raw_value)); + ui->ring_controller_sensor_value->setText(tex_value); +} + void ConfigureRingController::HandleClick( QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, InputCommon::Polling::InputType type) { diff --git a/src/yuzu/configuration/configure_ringcon.h b/src/yuzu/configuration/configure_ringcon.h index 38a9cb716..b23c27906 100644 --- a/src/yuzu/configuration/configure_ringcon.h +++ b/src/yuzu/configuration/configure_ringcon.h @@ -13,7 +13,7 @@ class InputSubsystem; namespace Core::HID { class HIDCore; -class EmulatedDevices; +class EmulatedController; } // namespace Core::HID namespace Ui { @@ -42,6 +42,12 @@ private: /// Restore all buttons to their default values. void RestoreDefaults(); + /// Sets current polling mode to ring input + void EnableRingController(); + + // Handles emulated controller events + void ControllerUpdate(Core::HID::ControllerTriggerType type); + /// Called when the button was pressed. void HandleClick(QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, @@ -78,7 +84,11 @@ private: std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; InputCommon::InputSubsystem* input_subsystem; - Core::HID::EmulatedDevices* emulated_device; + Core::HID::EmulatedController* emulated_controller; + + bool is_ring_enabled{}; + bool is_controller_set{}; + int callback_key; std::unique_ptr<Ui::ConfigureRingController> ui; }; diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui index 9ec634dd4..514dff372 100644 --- a/src/yuzu/configuration/configure_ringcon.ui +++ b/src/yuzu/configuration/configure_ringcon.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>298</width> - <height>339</height> + <width>315</width> + <height>400</height> </rect> </property> <property name="windowTitle"> @@ -46,187 +46,283 @@ </property> </spacer> </item> - <item> - <widget class="QGroupBox" name="RingAnalog"> - <property name="title"> - <string>Ring Sensor Parameters</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="spacing"> - <number>0</number> - </property> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="buttonRingAnalogPullHorizontaLayout"> + <item> + <widget class="QGroupBox" name="RingAnalog"> + <property name="title"> + <string>Virtual Ring Sensor Parameters</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <layout class="QVBoxLayout" name="verticalLayout_1"> <property name="spacing"> - <number>3</number> + <number>0</number> </property> - <item alignment="Qt::AlignHCenter"> - <widget class="QGroupBox" name="buttonRingAnalogPullGroup"> - <property name="title"> - <string>Pull</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="buttonRingAnalogPullHorizontaLayout"> + <property name="spacing"> + <number>3</number> </property> - <layout class="QVBoxLayout" name="buttonRingAnalogPullVerticalLayout"> - <property name="spacing"> - <number>3</number> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonRingAnalogPullGroup"> + <property name="title"> + <string>Pull</string> </property> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> - <property name="rightMargin"> - <number>3</number> + <layout class="QVBoxLayout" name="buttonRingAnalogPullVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonRingAnalogPull"> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>Pull</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonRingAnalogPushGroup"> + <property name="title"> + <string>Push</string> </property> - <property name="bottomMargin"> - <number>3</number> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> - <item> - <widget class="QPushButton" name="buttonRingAnalogPull"> - <property name="minimumSize"> - <size> - <width>68</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>68</width> - <height>16777215</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">min-width: 68px;</string> - </property> - <property name="text"> - <string>Pull</string> - </property> - </widget> - </item> - </layout> - </widget> + <layout class="QVBoxLayout" name="buttonRingAnalogPushVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonRingAnalogPush"> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>Push</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QGroupBox" name="buttonRingAnalogPushGroup"> - <property name="title"> - <string>Push</string> + <item> + <layout class="QVBoxLayout" name="sliderRingAnalogDeadzoneVerticalLayout"> + <property name="spacing"> + <number>3</number> </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> </property> - <layout class="QVBoxLayout" name="buttonRingAnalogPushVerticalLayout"> - <property name="spacing"> - <number>3</number> - </property> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>10</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <layout class="QHBoxLayout" name="sliderRingAnalogDeadzoneHorizontalLayout"> <item> - <widget class="QPushButton" name="buttonRingAnalogPush"> - <property name="minimumSize"> - <size> - <width>68</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>68</width> - <height>16777215</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">min-width: 68px;</string> - </property> + <widget class="QLabel" name="labelRingAnalogDeadzone"> <property name="text"> - <string>Push</string> + <string>Deadzone: 0%</string> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter</set> </property> - </widget> + </widget> </item> - </layout> - </widget> + </layout> + </item> + <item> + <widget class="QSlider" name="sliderRingAnalogDeadzone"> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> </item> - </layout> - </item> - <item> - <layout class="QVBoxLayout" name="sliderRingAnalogDeadzoneVerticalLayout"> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="RingDriver"> + <property name="title"> + <string>Direct Joycon Driver</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> <property name="spacing"> - <number>3</number> + <number>0</number> </property> <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> + <enum>QLayout::SetDefaultConstraint</enum> </property> <property name="leftMargin"> - <number>0</number> + <number>3</number> </property> <property name="topMargin"> - <number>10</number> + <number>6</number> </property> <property name="rightMargin"> - <number>0</number> + <number>3</number> </property> <property name="bottomMargin"> - <number>3</number> + <number>10</number> </property> <item> - <layout class="QHBoxLayout" name="sliderRingAnalogDeadzoneHorizontalLayout"> - <item> - <widget class="QLabel" name="labelRingAnalogDeadzone"> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>10</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>10</number> + </property> + <property name="bottomMargin"> + <number>10</number> + </property> + <property name="verticalSpacing"> + <number>10</number> + </property> + <item row="0" column="1"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>76</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="enable_ring_controller_label"> + <property name="text"> + <string>Enable Ring Input</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="enable_ring_controller_button"> <property name="text"> - <string>Deadzone: 0%</string> + <string>Enable</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="ring_controller_sensor_label"> + <property name="text"> + <string>Ring Sensor Value</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="ring_controller_sensor_value"> + <property name="text"> + <string>Not connected</string> </property> <property name="alignment"> - <set>Qt::AlignHCenter</set> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - </widget> + </widget> </item> - </layout> - </item> - <item> - <widget class="QSlider" name="sliderRingAnalogDeadzone"> - <property name="maximum"> - <number>100</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> + </layout> </item> - </layout> - </item> - </layout> - </widget> - </item> + </layout> + </widget> + </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> @@ -273,6 +369,6 @@ <signal>rejected()</signal> <receiver>ConfigureRingController</receiver> <slot>reject()</slot> - </connection> + </connection> </connections> </ui> diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 94049f2f4..9ea4c02da 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -31,6 +31,9 @@ constexpr std::array<u32, 7> LOCALE_BLOCKLIST{ }; static bool IsValidLocale(u32 region_index, u32 language_index) { + if (region_index >= LOCALE_BLOCKLIST.size()) { + return false; + } return ((LOCALE_BLOCKLIST.at(region_index) >> language_index) & 1) == 0; } @@ -55,8 +58,11 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent) }); const auto locale_check = [this](int index) { - const bool valid_locale = - IsValidLocale(ui->combo_region->currentIndex(), ui->combo_language->currentIndex()); + const auto region_index = ConfigurationShared::GetComboboxIndex( + Settings::values.region_index.GetValue(true), ui->combo_region); + const auto language_index = ConfigurationShared::GetComboboxIndex( + Settings::values.language_index.GetValue(true), ui->combo_language); + const bool valid_locale = IsValidLocale(region_index, language_index); ui->label_warn_invalid_locale->setVisible(!valid_locale); if (!valid_locale) { ui->label_warn_invalid_locale->setText( diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index 8f02880a7..a7f086258 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h @@ -42,13 +42,7 @@ private: std::unique_ptr<Ui::ConfigureSystem> ui; bool enabled = false; - int language_index = 0; - int region_index = 0; - int time_zone_index = 0; - int sound_index = 0; - ConfigurationShared::CheckState use_rng_seed; - ConfigurationShared::CheckState use_custom_rtc; Core::System& system; }; diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 1edc5f1f3..5a545aa70 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -17,7 +17,6 @@ ConfigureTasDialog::ConfigureTasDialog(QWidget* parent) setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("TAS Configuration")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); connect(ui->tas_path_button, &QToolButton::pressed, this, [this] { SetDirectory(DirectoryTarget::TAS, ui->tas_path_edit); }); diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 9bb69cab1..41ef4250a 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp @@ -58,13 +58,16 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() { std::vector<std::string> profile_names; profile_names.reserve(map_profiles.size()); - for (const auto& [profile_name, config] : map_profiles) { + auto it = map_profiles.cbegin(); + while (it != map_profiles.cend()) { + const auto& [profile_name, config] = *it; if (!ProfileExistsInFilesystem(profile_name)) { - DeleteProfile(profile_name); + it = map_profiles.erase(it); continue; } profile_names.push_back(profile_name); + ++it; } std::stable_sort(profile_names.begin(), profile_names.end()); diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 19f3775a3..e2f55ebae 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -20,9 +20,8 @@ ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_, setWindowTitle(tr("Controller P1")); resize(500, 350); setMinimumSize(500, 350); - // Remove the "?" button from the titlebar and enable the maximize button - setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | - Qt::WindowMaximizeButtonHint); + // Enable the maximize button + setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); refreshConfiguration(); diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index d3e2d3c12..493ee0b17 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -49,9 +49,8 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Di setObjectName(QStringLiteral("MicroProfile")); setWindowTitle(tr("&MicroProfile")); resize(1000, 600); - // Remove the "?" button from the titlebar and enable the maximize button - setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | - Qt::WindowMaximizeButtonHint); + // Enable the maximize button + setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint); #if MICROPROFILE_ENABLED diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp index c351e9b83..de0c307d4 100644 --- a/src/yuzu/discord_impl.cpp +++ b/src/yuzu/discord_impl.cpp @@ -4,7 +4,10 @@ #include <chrono> #include <string> #include <discord_rpc.h> +#include <fmt/format.h> +#include <httplib.h> #include "common/common_types.h" +#include "common/string_util.h" #include "core/core.h" #include "core/loader/loader.h" #include "yuzu/discord_impl.h" @@ -14,7 +17,6 @@ namespace DiscordRPC { DiscordImpl::DiscordImpl(Core::System& system_) : system{system_} { DiscordEventHandlers handlers{}; - // The number is the client ID for yuzu, it's used for images and the // application name Discord_Initialize("712465656758665259", &handlers, 1, nullptr); @@ -29,23 +31,74 @@ void DiscordImpl::Pause() { Discord_ClearPresence(); } +static std::string GetGameString(const std::string& title) { + // Convert to lowercase + std::string icon_name = Common::ToLower(title); + + // Replace spaces with dashes + std::replace(icon_name.begin(), icon_name.end(), ' ', '-'); + + // Remove non-alphanumeric characters but keep dashes + std::erase_if(icon_name, [](char c) { return !std::isalnum(c) && c != '-'; }); + + // Remove dashes from the start and end of the string + icon_name.erase(icon_name.begin(), std::find_if(icon_name.begin(), icon_name.end(), + [](int ch) { return ch != '-'; })); + icon_name.erase( + std::find_if(icon_name.rbegin(), icon_name.rend(), [](int ch) { return ch != '-'; }).base(), + icon_name.end()); + + // Remove double dashes + icon_name.erase(std::unique(icon_name.begin(), icon_name.end(), + [](char a, char b) { return a == '-' && b == '-'; }), + icon_name.end()); + + return icon_name; +} + void DiscordImpl::Update() { s64 start_time = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()) .count(); + const std::string default_text = "yuzu is an emulator for the Nintendo Switch"; + const std::string default_image = "yuzu_logo"; + std::string game_cover_url = "https://yuzu-emu.org"; std::string title; - if (system.IsPoweredOn()) { - system.GetAppLoader().ReadTitle(title); - } + DiscordRichPresence presence{}; - presence.largeImageKey = "yuzu_logo"; - presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; + if (system.IsPoweredOn()) { + system.GetAppLoader().ReadTitle(title); + + // Used to format Icon URL for yuzu website game compatibility page + std::string icon_name = GetGameString(title); + + // New Check for game cover + httplib::Client cli(game_cover_url); + + if (auto res = cli.Head(fmt::format("/images/game/boxart/{}.png", icon_name).c_str())) { + if (res->status == 200) { + game_cover_url += fmt::format("/images/game/boxart/{}.png", icon_name); + } else { + game_cover_url = "yuzu_logo"; + } + } else { + game_cover_url = "yuzu_logo"; + } + + presence.largeImageKey = game_cover_url.c_str(); + presence.largeImageText = title.c_str(); + + presence.smallImageKey = default_image.c_str(); + presence.smallImageText = default_text.c_str(); presence.state = title.c_str(); presence.details = "Currently in game"; } else { - presence.details = "Not in game"; + presence.largeImageKey = default_image.c_str(); + presence.largeImageText = default_text.c_str(); + presence.details = "Currently not in game"; } + presence.startTimestamp = start_time; Discord_UpdatePresence(&presence); } diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 13723f6e5..6530186c1 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -21,7 +21,7 @@ void HotkeyRegistry::SaveHotkeys() { {hotkey.first, group.first, UISettings::ContextualShortcut({hotkey.second.keyseq.toString(), hotkey.second.controller_keyseq, - hotkey.second.context})}); + hotkey.second.context, hotkey.second.repeat})}); } } } @@ -47,6 +47,7 @@ void HotkeyRegistry::LoadHotkeys() { hk.controller_shortcut->disconnect(); hk.controller_shortcut->SetKey(hk.controller_keyseq); } + hk.repeat = shortcut.shortcut.repeat; } } @@ -57,8 +58,7 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context); } - hk.shortcut->setAutoRepeat(false); - + hk.shortcut->setAutoRepeat(hk.repeat); return hk.shortcut; } diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index dc5b7f628..848239c35 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h @@ -115,6 +115,7 @@ private: QShortcut* shortcut = nullptr; ControllerShortcut* controller_shortcut = nullptr; Qt::ShortcutContext context = Qt::WindowShortcut; + bool repeat; }; using HotkeyMap = std::map<QString, Hotkey>; diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 84ec4fe13..673bbaa83 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -46,7 +46,6 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo vbox_layout->addLayout(hbox_layout); setLayout(vbox_layout); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowTitle(tr("Install Files to NAND")); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c278620ab..f5e6e0f58 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1015,11 +1015,6 @@ void GMainWindow::InitializeWidgets() { filter_status_button->setFocusPolicy(Qt::NoFocus); connect(filter_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleAdaptingFilter); - auto filter = Settings::values.scaling_filter.GetValue(); - if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && - filter == Settings::ScalingFilter::Fsr) { - Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); - } UpdateFilterText(); filter_status_button->setCheckable(true); filter_status_button->setChecked(true); @@ -2769,8 +2764,7 @@ void GMainWindow::OnMenuInstallToNAND() { ui->action_Install_File_NAND->setEnabled(false); install_progress = new QProgressDialog(QString{}, tr("Cancel"), 0, total_size, this); - install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & - ~Qt::WindowMaximizeButtonHint); + install_progress->setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint); install_progress->setAttribute(Qt::WA_DeleteOnClose, true); install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40); install_progress->show(); @@ -3513,10 +3507,6 @@ void GMainWindow::OnToggleAdaptingFilter() { } else { filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1); } - if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && - filter == Settings::ScalingFilter::Fsr) { - filter = Settings::ScalingFilter::NearestNeighbor; - } Settings::values.scaling_filter.SetValue(filter); filter_status_button->setChecked(true); UpdateFilterText(); @@ -4513,6 +4503,11 @@ int main(int argc, char* argv[]) { } #endif +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + // Disables the "?" button on all dialogs. Disabled by default on Qt6. + QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); +#endif + // Enables the core to make the qt created contexts current on std::threads QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); QApplication app(argc, argv); diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index cbd52da85..d71cc23a7 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -81,20 +81,13 @@ void DirectConnectWindow::Connect() { } } } - switch (static_cast<ConnectionType>(ui->connection_type->currentIndex())) { - case ConnectionType::TraversalServer: - break; - case ConnectionType::IP: - if (!ui->ip->hasAcceptableInput()) { - NetworkMessage::ErrorManager::ShowError( - NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID); - return; - } - if (!ui->port->hasAcceptableInput()) { - NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID); - return; - } - break; + if (!ui->ip->hasAcceptableInput()) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID); + return; + } + if (!ui->port->hasAcceptableInput()) { + NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID); + return; } // Store settings diff --git a/src/yuzu/multiplayer/direct_connect.ui b/src/yuzu/multiplayer/direct_connect.ui index 57d6ec25a..0dd4e6829 100644 --- a/src/yuzu/multiplayer/direct_connect.ui +++ b/src/yuzu/multiplayer/direct_connect.ui @@ -27,19 +27,10 @@ <number>0</number> </property> <item> - <widget class="QComboBox" name="connection_type"> - <item> - <property name="text"> - <string>IP Address</string> - </property> - </item> - </widget> - </item> - <item> <widget class="QWidget" name="ip_container" native="true"> <layout class="QHBoxLayout" name="ip_layout"> <property name="leftMargin"> - <number>5</number> + <number>0</number> </property> <property name="topMargin"> <number>0</number> @@ -53,17 +44,17 @@ <item> <widget class="QLabel" name="label_2"> <property name="text"> - <string>IP</string> + <string>Server Address</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="ip"> <property name="toolTip"> - <string><html><head/><body><p>IPv4 address of the host</p></body></html></string> + <string><html><head/><body><p>Server address of the host</p></body></html></string> </property> <property name="maxLength"> - <number>16</number> + <number>253</number> </property> </widget> </item> @@ -85,6 +76,12 @@ <property name="placeholderText"> <string notr="true" extracomment="placeholder string that tells user default port">24872</string> </property> + <property name="maximumSize"> + <size> + <width>65</width> + <height>50</height> + </size> + </property> </widget> </item> </layout> diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 08c275696..6c93e3511 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -77,6 +77,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, // UI Buttons connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby); 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); @@ -329,6 +330,16 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s return true; } + // filter by empty rooms + if (filter_empty) { + QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent); + int player_count = + sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size(); + if (player_count == 0) { + return false; + } + } + // filter by filled rooms if (filter_full) { QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent); @@ -399,6 +410,11 @@ void LobbyFilterProxyModel::SetFilterOwned(bool filter) { invalidate(); } +void LobbyFilterProxyModel::SetFilterEmpty(bool filter) { + filter_empty = filter; + invalidate(); +} + void LobbyFilterProxyModel::SetFilterFull(bool filter) { filter_full = filter; invalidate(); diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h index 300dad13e..2674ae7c3 100644 --- a/src/yuzu/multiplayer/lobby.h +++ b/src/yuzu/multiplayer/lobby.h @@ -130,12 +130,14 @@ public: public slots: void SetFilterOwned(bool); + void SetFilterEmpty(bool); void SetFilterFull(bool); void SetFilterSearch(const QString&); private: QStandardItemModel* game_list; bool filter_owned = false; + bool filter_empty = false; bool filter_full = false; QString filter_search; }; diff --git a/src/yuzu/multiplayer/lobby.ui b/src/yuzu/multiplayer/lobby.ui index 4c9901c9a..0ef0ef762 100644 --- a/src/yuzu/multiplayer/lobby.ui +++ b/src/yuzu/multiplayer/lobby.ui @@ -78,6 +78,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="hide_empty"> + <property name="text"> + <string>Hide Empty Rooms</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="hide_full"> <property name="text"> <string>Hide Full Rooms</string> diff --git a/src/yuzu/multiplayer/validation.h b/src/yuzu/multiplayer/validation.h index dd25af280..cbbe6757b 100644 --- a/src/yuzu/multiplayer/validation.h +++ b/src/yuzu/multiplayer/validation.h @@ -38,11 +38,28 @@ private: QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}")); QRegularExpressionValidator nickname; - /// ipv4 address only - // TODO remove this when we support hostnames in direct connect + /// ipv4 / ipv6 / hostnames QRegularExpression ip_regex = QRegularExpression(QStringLiteral( - "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|" - "2[0-4][0-9]|25[0-5])")); + // IPv4 regex + "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|" + // IPv6 regex + "^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|" + "(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-" + "5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|" + "(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)" + "(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|" + "(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]" + "\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[" + "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[" + "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[" + "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|" + "(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?" + "\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$|" + // Hostname regex + "^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}$")); QRegularExpressionValidator ip; /// port must be between 0 and 65535 diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 2006b883e..db43b7033 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -22,6 +22,7 @@ struct ContextualShortcut { QString keyseq; QString controller_keyseq; int context; + bool repeat; }; struct Shortcut { diff --git a/src/yuzu/util/limitable_input_dialog.cpp b/src/yuzu/util/limitable_input_dialog.cpp index bbb370595..5f6a9c193 100644 --- a/src/yuzu/util/limitable_input_dialog.cpp +++ b/src/yuzu/util/limitable_input_dialog.cpp @@ -16,8 +16,6 @@ LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} { LimitableInputDialog::~LimitableInputDialog() = default; void LimitableInputDialog::CreateUI() { - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - text_label = new QLabel(this); text_entry = new QLineEdit(this); text_label_invalid = new QLabel(this); diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp index 4b10fa517..1670aa596 100644 --- a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp +++ b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp @@ -8,7 +8,6 @@ SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Enter a hotkey")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); key_sequence = new QKeySequenceEdit; |