diff options
| -rw-r--r-- | src/common/settings.cpp | 5 | ||||
| -rw-r--r-- | src/common/settings.h | 5 | ||||
| -rw-r--r-- | src/common/settings_enums.h | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/shared_translation.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 115 | ||||
| -rw-r--r-- | src/yuzu/main.h | 18 | ||||
| -rw-r--r-- | src/yuzu/uisettings.h | 11 | 
8 files changed, 125 insertions, 43 deletions
| diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 3fde3cae6..98b43e49c 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -45,6 +45,7 @@ SWITCHABLE(CpuAccuracy, true);  SWITCHABLE(FullscreenMode, true);  SWITCHABLE(GpuAccuracy, true);  SWITCHABLE(Language, true); +SWITCHABLE(MemoryLayout, true);  SWITCHABLE(NvdecEmulation, false);  SWITCHABLE(Region, true);  SWITCHABLE(RendererBackend, true); @@ -61,6 +62,10 @@ SWITCHABLE(u32, false);  SWITCHABLE(u8, false);  SWITCHABLE(u8, true); +// Used in UISettings +// TODO see if we can move this to uisettings.cpp +SWITCHABLE(ConfirmStop, true); +  #undef SETTING  #undef SWITCHABLE  #endif diff --git a/src/common/settings.h b/src/common/settings.h index 98ab0ec2e..236e33bee 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -67,6 +67,7 @@ SWITCHABLE(CpuAccuracy, true);  SWITCHABLE(FullscreenMode, true);  SWITCHABLE(GpuAccuracy, true);  SWITCHABLE(Language, true); +SWITCHABLE(MemoryLayout, true);  SWITCHABLE(NvdecEmulation, false);  SWITCHABLE(Region, true);  SWITCHABLE(RendererBackend, true); @@ -83,6 +84,10 @@ SWITCHABLE(u32, false);  SWITCHABLE(u8, false);  SWITCHABLE(u8, true); +// Used in UISettings +// TODO see if we can move this to uisettings.h +SWITCHABLE(ConfirmStop, true); +  #undef SETTING  #undef SWITCHABLE  #endif diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 815cafe15..11429d7a8 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -133,6 +133,8 @@ ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);  ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb); +ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never); +  ENUM(FullscreenMode, Borderless, Exclusive);  ENUM(NvdecEmulation, Off, Cpu, Gpu); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 1de093447..d5157c502 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -128,8 +128,8 @@ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{      {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", "Restart Emulation")),        QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"),      QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}}, +    {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")),           QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"),      QStringLiteral("L+Plus+Minus"), 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}}, diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index a4e8af1b4..3fe448f27 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -157,6 +157,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {      INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");      INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");      INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); +    INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");      INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");      INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); @@ -383,6 +384,13 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {      translations->insert(          {Settings::EnumMetadata<Settings::ConsoleMode>::Index(),           {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); +    translations->insert( +        {Settings::EnumMetadata<Settings::ConfirmStop>::Index(), +         { +             PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"), +             PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"), +             PAIR(ConfirmStop, Ask_Never, "Never ask"), +         }});  #undef PAIR  #undef CTX_PAIR diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 1a6b63856..1431cf2fe 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -211,7 +211,7 @@ void GMainWindow::ShowTelemetryCallout() {          tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "             "data is collected</a> to help improve yuzu. "             "<br/><br/>Would you like to share your usage data with us?"); -    if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { +    if (!question(this, tr("Telemetry"), telemetry_message)) {          Settings::values.enable_telemetry = false;          system->ApplySettings();      } @@ -2420,9 +2420,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT          }      }(); -    if (QMessageBox::question(this, tr("Remove Entry"), entry_question, -                              QMessageBox::Yes | QMessageBox::No, -                              QMessageBox::No) != QMessageBox::Yes) { +    if (!question(this, tr("Remove Entry"), entry_question, QMessageBox::Yes | QMessageBox::No, +                  QMessageBox::No)) {          return;      } @@ -2521,8 +2520,8 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ          }      }(); -    if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No, -                              QMessageBox::No) != QMessageBox::Yes) { +    if (!GMainWindow::question(this, tr("Remove File"), question, +                               QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {          return;      } @@ -3409,10 +3408,13 @@ void GMainWindow::OnRestartGame() {      if (!system->IsPoweredOn()) {          return;      } -    // Make a copy since ShutdownGame edits game_path -    const auto current_game = QString(current_game_path); -    ShutdownGame(); -    BootGame(current_game); + +    if (ConfirmShutdownGame()) { +        // Make a copy since ShutdownGame edits game_path +        const auto current_game = QString(current_game_path); +        ShutdownGame(); +        BootGame(current_game); +    }  }  void GMainWindow::OnPauseGame() { @@ -3434,18 +3436,39 @@ void GMainWindow::OnPauseContinueGame() {  }  void GMainWindow::OnStopGame() { -    if (system->GetExitLocked() && !ConfirmForceLockedExit()) { -        return; +    if (ConfirmShutdownGame()) { +        play_time_manager->Stop(); +        // Update game list to show new play time +        game_list->PopulateAsync(UISettings::values.game_dirs); +        if (OnShutdownBegin()) { +            OnShutdownBeginDialog(); +        } else { +            OnEmulationStopped(); +        }      } +} -    play_time_manager->Stop(); -    // Update game list to show new play time -    game_list->PopulateAsync(UISettings::values.game_dirs); -    if (OnShutdownBegin()) { -        OnShutdownBeginDialog(); +bool GMainWindow::ConfirmShutdownGame() { +    if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) { +        if (system->GetExitLocked()) { +            if (!ConfirmForceLockedExit()) { +                return false; +            } +        } else { +            if (!ConfirmChangeGame()) { +                return false; +            } +        }      } else { -        OnEmulationStopped(); +        if (UISettings::values.confirm_before_stopping.GetValue() == +                ConfirmStop::Ask_Based_On_Game && +            system->GetExitLocked()) { +            if (!ConfirmForceLockedExit()) { +                return false; +            } +        }      } +    return true;  }  void GMainWindow::OnLoadComplete() { @@ -3825,22 +3848,11 @@ void GMainWindow::OnTasRecord() {      const bool is_recording = input_subsystem->GetTas()->Record();      if (!is_recording) {          is_tas_recording_dialog_active = true; -        ControllerNavigation* controller_navigation = -            new ControllerNavigation(system->HIDCore(), this); -        // Use QMessageBox instead of question so we can link controller navigation -        QMessageBox* box_dialog = new QMessageBox(); -        box_dialog->setWindowTitle(tr("TAS Recording")); -        box_dialog->setText(tr("Overwrite file of player 1?")); -        box_dialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); -        box_dialog->setDefaultButton(QMessageBox::Yes); -        connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, -                [box_dialog](Qt::Key key) { -                    QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); -                    QCoreApplication::postEvent(box_dialog, event); -                }); -        int res = box_dialog->exec(); -        controller_navigation->UnloadController(); -        input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); + +        bool answer = question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"), +                               QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + +        input_subsystem->GetTas()->SaveRecording(answer);          is_tas_recording_dialog_active = false;      }      OnTasStateChanged(); @@ -4081,6 +4093,29 @@ void GMainWindow::OnLoadAmiibo() {      LoadAmiibo(filename);  } +bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, +                           QMessageBox::StandardButtons buttons, +                           QMessageBox::StandardButton defaultButton) { + +    QMessageBox* box_dialog = new QMessageBox(parent); +    box_dialog->setWindowTitle(title); +    box_dialog->setText(text); +    box_dialog->setStandardButtons(buttons); +    box_dialog->setDefaultButton(defaultButton); + +    ControllerNavigation* controller_navigation = +        new ControllerNavigation(system->HIDCore(), box_dialog); +    connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, +            [box_dialog](Qt::Key key) { +                QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); +                QCoreApplication::postEvent(box_dialog, event); +            }); +    int res = box_dialog->exec(); + +    controller_navigation->UnloadController(); +    return res == QMessageBox::Yes; +} +  void GMainWindow::LoadAmiibo(const QString& filename) {      auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo();      const QString title = tr("Error loading Amiibo data"); @@ -4814,8 +4849,7 @@ bool GMainWindow::ConfirmClose() {          return true;      }      const auto text = tr("Are you sure you want to close yuzu?"); -    const auto answer = QMessageBox::question(this, tr("yuzu"), text); -    return answer != QMessageBox::No; +    return question(this, tr("yuzu"), text);  }  void GMainWindow::closeEvent(QCloseEvent* event) { @@ -4908,11 +4942,11 @@ bool GMainWindow::ConfirmChangeGame() {      if (emu_thread == nullptr)          return true; -    const auto answer = QMessageBox::question( +    // Use custom question to link controller navigation +    return question(          this, tr("yuzu"),          tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."), -        QMessageBox::Yes | QMessageBox::No, QMessageBox::No); -    return answer != QMessageBox::No; +        QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);  }  bool GMainWindow::ConfirmForceLockedExit() { @@ -4922,8 +4956,7 @@ bool GMainWindow::ConfirmForceLockedExit() {      const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"                           "Would you like to bypass this and exit anyway?"); -    const auto answer = QMessageBox::question(this, tr("yuzu"), text); -    return answer != QMessageBox::No; +    return question(this, tr("yuzu"), text);  }  void GMainWindow::RequestGameExit() { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 2346eb3bd..270a40c5f 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -7,6 +7,7 @@  #include <optional>  #include <QMainWindow> +#include <QMessageBox>  #include <QTimer>  #include <QTranslator> @@ -15,6 +16,7 @@  #include "input_common/drivers/tas_input.h"  #include "yuzu/compatibility_list.h"  #include "yuzu/hotkeys.h" +#include "yuzu/util/controller_navigation.h"  #ifdef __unix__  #include <QVariant> @@ -424,6 +426,11 @@ private:      bool CheckSystemArchiveDecryption();      bool CheckFirmwarePresence();      void ConfigureFilesystemProvider(const std::string& filepath); +    /** +     * Open (or not) the right confirm dialog based on current setting and game exit lock +     * @returns true if the player confirmed or the settings do no require it +     */ +    bool ConfirmShutdownGame();      QString GetTasStateDescription() const;      bool CreateShortcut(const std::string& shortcut_path, const std::string& title, @@ -431,6 +438,17 @@ private:                          const std::string& command, const std::string& arguments,                          const std::string& categories, const std::string& keywords); +    /** +     * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog +     * The only difference is that it returns a boolean. +     * +     * @returns true if buttons contains QMessageBox::Yes and the user clicks on the "Yes" button. +     */ +    bool question(QWidget* parent, const QString& title, const QString& text, +                  QMessageBox::StandardButtons buttons = +                      QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), +                  QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); +      std::unique_ptr<Ui::MainWindow> ui;      std::unique_ptr<Core::System> system; diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 975008159..b62ff620c 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -16,7 +16,9 @@  #include "common/settings_enums.h"  using Settings::Category; +using Settings::ConfirmStop;  using Settings::Setting; +using Settings::SwitchableSetting;  #ifndef CANNOT_EXPLICITLY_INSTANTIATE  namespace Settings { @@ -94,6 +96,15 @@ struct Values {      Setting<bool> confirm_before_closing{          linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,          true,    true}; + +    SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, +                                                           ConfirmStop::Ask_Always, +                                                           "confirmStop", +                                                           Category::UiGeneral, +                                                           Settings::Specialization::Default, +                                                           true, +                                                           true}; +      Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};      Setting<bool> pause_when_in_background{linkage,                                             false, | 
