aboutsummaryrefslogtreecommitdiff
path: root/src/yuzu/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r--src/yuzu/main.cpp531
1 files changed, 261 insertions, 270 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c4c76b094f..9bd0db10ac 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -26,6 +26,8 @@
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/software_keyboard.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@@ -106,8 +108,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "core/telemetry_session.h"
+#include "input_common/drivers/tas_input.h"
#include "input_common/main.h"
-#include "input_common/tas/tas_input.h"
#include "ui_main.h"
#include "util/overlay_dialog.h"
#include "video_core/gpu.h"
@@ -227,6 +229,9 @@ GMainWindow::GMainWindow()
ConnectMenuEvents();
ConnectWidgetEvents();
+ system->HIDCore().ReloadInputDevices();
+ controller_dialog->refreshConfiguration();
+
const auto branch_name = std::string(Common::g_scm_branch);
const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id);
@@ -829,15 +834,16 @@ void GMainWindow::InitializeWidgets() {
dock_status_button->setFocusPolicy(Qt::NoFocus);
connect(dock_status_button, &QPushButton::clicked, [&] {
const bool is_docked = Settings::values.use_docked_mode.GetValue();
- auto& controller_type = Settings::values.players.GetValue()[0].controller_type;
+ auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
+ auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
- if (!is_docked && controller_type == Settings::ControllerType::Handheld) {
+ if (!is_docked && handheld->IsConnected()) {
QMessageBox::warning(this, tr("Invalid config detected"),
tr("Handheld controller can't be used on docked mode. Pro "
"controller will be selected."));
- controller_type = Settings::ControllerType::ProController;
- ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system);
- configure_dialog.ApplyConfiguration();
+ handheld->Disconnect();
+ player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
+ player_1->Connect();
controller_dialog->refreshConfiguration();
}
@@ -922,7 +928,7 @@ void GMainWindow::InitializeDebugWidgets() {
waitTreeWidget->hide();
debug_menu->addAction(waitTreeWidget->toggleViewAction());
- controller_dialog = new ControllerDialog(this, input_subsystem.get());
+ controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this);
controller_dialog->hide();
debug_menu->addAction(controller_dialog->toggleViewAction());
@@ -952,171 +958,80 @@ void GMainWindow::InitializeRecentFileMenuActions() {
UpdateRecentFiles();
}
+void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) {
+ static const QString main_window = QStringLiteral("Main Window");
+ action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
+ action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
+
+ this->addAction(action);
+}
+
void GMainWindow::InitializeHotkeys() {
hotkey_registry.LoadHotkeys();
- const QString main_window = QStringLiteral("Main Window");
- const QString load_file = QStringLiteral("Load File");
- const QString load_amiibo = QStringLiteral("Load Amiibo");
- const QString exit_yuzu = QStringLiteral("Exit yuzu");
- const QString restart_emulation = QStringLiteral("Restart Emulation");
- const QString stop_emulation = QStringLiteral("Stop Emulation");
- const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar");
- const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
- const QString fullscreen = QStringLiteral("Fullscreen");
- const QString capture_screenshot = QStringLiteral("Capture Screenshot");
-
- ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
- ui->action_Load_File->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, load_file));
-
- ui->action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo));
- ui->action_Load_Amiibo->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, load_amiibo));
-
- ui->action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu));
- ui->action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu));
-
- ui->action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation));
- ui->action_Restart->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, restart_emulation));
-
- ui->action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation));
- ui->action_Stop->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, stop_emulation));
-
- ui->action_Show_Filter_Bar->setShortcut(
- hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
- ui->action_Show_Filter_Bar->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar));
-
- ui->action_Show_Status_Bar->setShortcut(
- hotkey_registry.GetKeySequence(main_window, toggle_status_bar));
- ui->action_Show_Status_Bar->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
-
- ui->action_Capture_Screenshot->setShortcut(
- hotkey_registry.GetKeySequence(main_window, capture_screenshot));
- ui->action_Capture_Screenshot->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
-
- ui->action_Fullscreen->setShortcut(
- hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
- ui->action_Fullscreen->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, fullscreen));
-
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
- &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
- connect(
- hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this),
- &QShortcut::activated, this, [&] {
- if (emulation_running) {
- if (emu_thread->IsRunning()) {
- OnPauseGame();
- } else {
- OnStartGame();
- }
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this),
- &QShortcut::activated, this, [this] {
- if (!system->IsPoweredOn()) {
- return;
- }
- BootGame(game_path);
- });
- connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
- &QShortcut::activated, ui->action_Fullscreen, &QAction::trigger);
- connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
- &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
- &QShortcut::activated, this, [&] {
- if (emulation_running && ui->action_Fullscreen->isChecked()) {
- ui->action_Fullscreen->setChecked(false);
- ToggleFullscreen();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.use_speed_limit.SetValue(
- !Settings::values.use_speed_limit.GetValue());
- UpdateStatusBar();
- });
+ LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File"));
+ LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load Amiibo"));
+ LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu"));
+ LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation"));
+ LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation"));
+ LinkActionShortcut(ui->action_Stop, QStringLiteral("Stop Emulation"));
+ LinkActionShortcut(ui->action_Show_Filter_Bar, QStringLiteral("Toggle Filter Bar"));
+ LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
+ LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
+ LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
+ LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"));
+ LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"));
+ LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"));
+
+ static const QString main_window = QStringLiteral("Main Window");
+ const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
+ const QShortcut* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this);
+ connect(hotkey, &QShortcut::activated, this, function);
+ };
+
+ connect_shortcut(QStringLiteral("Exit Fullscreen"), [&] {
+ if (emulation_running && ui->action_Fullscreen->isChecked()) {
+ ui->action_Fullscreen->setChecked(false);
+ ToggleFullscreen();
+ }
+ });
+ connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] {
+ Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
+ UpdateStatusBar();
+ });
constexpr u16 SPEED_LIMIT_STEP = 5;
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
- Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
- Settings::values.speed_limit.GetValue());
- UpdateStatusBar();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
- Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
- SPEED_LIMIT_STEP);
- UpdateStatusBar();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this),
- &QShortcut::activated, this, [&] {
- if (ui->action_Load_Amiibo->isEnabled()) {
- OnLoadAmiibo();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this),
- &QShortcut::activated, this, [&] {
- if (emu_thread != nullptr && emu_thread->IsRunning()) {
- OnCaptureScreenshot();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.use_docked_mode.SetValue(
- !Settings::values.use_docked_mode.GetValue());
- OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
- Settings::values.use_docked_mode.GetValue(), *system);
- dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
- &QShortcut::activated, this,
- [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Framerate Limit"), this),
- &QShortcut::activated, this, [] {
- Settings::values.disable_fps_limit.SetValue(
- !Settings::values.disable_fps_limit.GetValue());
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.mouse_panning = !Settings::values.mouse_panning;
- if (Settings::values.mouse_panning) {
- render_window->installEventFilter(render_window);
- render_window->setAttribute(Qt::WA_Hover, true);
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- input_subsystem->GetTas()->StartStop();
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this),
- &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- bool is_recording = input_subsystem->GetTas()->Record();
- if (!is_recording) {
- const auto res = QMessageBox::question(this, tr("TAS Recording"),
- tr("Overwrite file of player 1?"),
- QMessageBox::Yes | QMessageBox::No);
- input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
- }
- });
+ connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] {
+ if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
+ Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
+ Settings::values.speed_limit.GetValue());
+ UpdateStatusBar();
+ }
+ });
+ connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] {
+ if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
+ Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
+ SPEED_LIMIT_STEP);
+ UpdateStatusBar();
+ }
+ });
+ connect_shortcut(QStringLiteral("Change Docked Mode"), [&] {
+ Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue());
+ OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
+ Settings::values.use_docked_mode.GetValue(), *system);
+ dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
+ });
+ connect_shortcut(QStringLiteral("Mute Audio"),
+ [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
+ connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
+ Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue());
+ });
+ connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] {
+ Settings::values.mouse_panning = !Settings::values.mouse_panning;
+ if (Settings::values.mouse_panning) {
+ render_window->installEventFilter(render_window);
+ render_window->setAttribute(Qt::WA_Hover, true);
+ }
+ });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -1171,7 +1086,8 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
auto_paused = true;
OnPauseGame();
- } else if (ui->action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) {
+ } else if (emulation_running && !emu_thread->IsRunning() && auto_paused &&
+ state == Qt::ApplicationActive) {
auto_paused = false;
OnStartGame();
}
@@ -1215,61 +1131,86 @@ void GMainWindow::ConnectWidgetEvents() {
}
void GMainWindow::ConnectMenuEvents() {
+ const auto connect_menu = [&]<typename Fn>(QAction* action, const Fn& event_fn) {
+ connect(action, &QAction::triggered, this, event_fn);
+ // Add actions to this window so that hiding menus in fullscreen won't disable them
+ addAction(action);
+ // Add actions to the render window so that they work outside of single window mode
+ render_window->addAction(action);
+ };
+
// File
- connect(ui->action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
- connect(ui->action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
- connect(ui->action_Install_File_NAND, &QAction::triggered, this,
- &GMainWindow::OnMenuInstallToNAND);
- connect(ui->action_Exit, &QAction::triggered, this, &QMainWindow::close);
- connect(ui->action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
+ connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile);
+ connect_menu(ui->action_Load_Folder, &GMainWindow::OnMenuLoadFolder);
+ connect_menu(ui->action_Install_File_NAND, &GMainWindow::OnMenuInstallToNAND);
+ connect_menu(ui->action_Exit, &QMainWindow::close);
+ connect_menu(ui->action_Load_Amiibo, &GMainWindow::OnLoadAmiibo);
// Emulation
- connect(ui->action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
- connect(ui->action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame);
- connect(ui->action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame);
- connect(ui->action_Report_Compatibility, &QAction::triggered, this,
- &GMainWindow::OnMenuReportCompatibility);
- connect(ui->action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage);
- connect(ui->action_Open_Quickstart_Guide, &QAction::triggered, this,
- &GMainWindow::OnOpenQuickstartGuide);
- connect(ui->action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
- connect(ui->action_Restart, &QAction::triggered, this,
- [this] { BootGame(QString(game_path)); });
- connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
- connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
- connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
- &GMainWindow::OnConfigurePerGame);
+ connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame);
+ connect_menu(ui->action_Stop, &GMainWindow::OnStopGame);
+ connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility);
+ connect_menu(ui->action_Open_Mods_Page, &GMainWindow::OnOpenModsPage);
+ connect_menu(ui->action_Open_Quickstart_Guide, &GMainWindow::OnOpenQuickstartGuide);
+ connect_menu(ui->action_Open_FAQ, &GMainWindow::OnOpenFAQ);
+ connect_menu(ui->action_Restart, &GMainWindow::OnRestartGame);
+ connect_menu(ui->action_Configure, &GMainWindow::OnConfigure);
+ connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame);
// View
- connect(ui->action_Single_Window_Mode, &QAction::triggered, this,
- &GMainWindow::ToggleWindowMode);
- connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this,
- &GMainWindow::OnDisplayTitleBars);
- connect(ui->action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
+ connect_menu(ui->action_Fullscreen, &GMainWindow::ToggleFullscreen);
+ connect_menu(ui->action_Single_Window_Mode, &GMainWindow::ToggleWindowMode);
+ connect_menu(ui->action_Display_Dock_Widget_Headers, &GMainWindow::OnDisplayTitleBars);
+ connect_menu(ui->action_Show_Filter_Bar, &GMainWindow::OnToggleFilterBar);
+
connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
- connect(ui->action_Reset_Window_Size_720, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize720);
- connect(ui->action_Reset_Window_Size_900, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize900);
- connect(ui->action_Reset_Window_Size_1080, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize1080);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_720);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
+ connect_menu(ui->action_Reset_Window_Size_720, &GMainWindow::ResetWindowSize720);
+ connect_menu(ui->action_Reset_Window_Size_900, &GMainWindow::ResetWindowSize900);
+ connect_menu(ui->action_Reset_Window_Size_1080, &GMainWindow::ResetWindowSize1080);
+ ui->menu_Reset_Window_Size->addActions({ui->action_Reset_Window_Size_720,
+ ui->action_Reset_Window_Size_900,
+ ui->action_Reset_Window_Size_1080});
- // Fullscreen
- connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
+ // Tools
+ connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
+ ReinitializeKeyBehavior::Warning));
+ connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot);
- // Movie
- connect(ui->action_Capture_Screenshot, &QAction::triggered, this,
- &GMainWindow::OnCaptureScreenshot);
+ // TAS
+ connect_menu(ui->action_TAS_Start, &GMainWindow::OnTasStartStop);
+ connect_menu(ui->action_TAS_Record, &GMainWindow::OnTasRecord);
+ connect_menu(ui->action_TAS_Reset, &GMainWindow::OnTasReset);
+ connect_menu(ui->action_Configure_Tas, &GMainWindow::OnConfigureTas);
// Help
- connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
- connect(ui->action_Rederive, &QAction::triggered, this,
- std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
- connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
+ connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
+ connect_menu(ui->action_About, &GMainWindow::OnAbout);
+}
+
+void GMainWindow::UpdateMenuState() {
+ const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning();
+
+ const std::array running_actions{
+ ui->action_Stop,
+ ui->action_Restart,
+ ui->action_Configure_Current_Game,
+ ui->action_Report_Compatibility,
+ ui->action_Load_Amiibo,
+ ui->action_Pause,
+ };
+
+ for (QAction* action : running_actions) {
+ action->setEnabled(emulation_running);
+ }
+
+ ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
+
+ if (emulation_running && is_paused) {
+ ui->action_Pause->setText(tr("&Continue"));
+ } else {
+ ui->action_Pause->setText(tr("&Pause"));
+ }
}
void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -1439,8 +1380,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig);
}
- ConfigureVibration::SetAllVibrationDevices();
-
// Disable fps limit toggle when booting a new title
Settings::values.disable_fps_limit.SetValue(false);
@@ -1562,15 +1501,8 @@ void GMainWindow::ShutdownGame() {
disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
// Update the GUI
- ui->action_Start->setEnabled(false);
- ui->action_Start->setText(tr("Start"));
- ui->action_Pause->setEnabled(false);
- ui->action_Stop->setEnabled(false);
- ui->action_Restart->setEnabled(false);
- ui->action_Configure_Current_Game->setEnabled(false);
- ui->action_Report_Compatibility->setEnabled(false);
- ui->action_Load_Amiibo->setEnabled(false);
- ui->action_Capture_Screenshot->setEnabled(false);
+ UpdateMenuState();
+
render_window->hide();
loading_screen->hide();
loading_screen->Clear();
@@ -1582,6 +1514,7 @@ void GMainWindow::ShutdownGame() {
game_list->SetFilterFocus();
tas_label->clear();
input_subsystem->GetTas()->Stop();
+ OnTasStateChanged();
render_window->removeEventFilter(render_window);
render_window->setAttribute(Qt::WA_Hover, false);
@@ -2501,31 +2434,36 @@ void GMainWindow::OnStartGame() {
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
- ui->action_Start->setEnabled(false);
- ui->action_Start->setText(tr("&Continue"));
-
- ui->action_Pause->setEnabled(true);
- ui->action_Stop->setEnabled(true);
- ui->action_Restart->setEnabled(true);
- ui->action_Configure_Current_Game->setEnabled(true);
- ui->action_Report_Compatibility->setEnabled(true);
+ UpdateMenuState();
+ OnTasStateChanged();
discord_rpc->Update();
- ui->action_Load_Amiibo->setEnabled(true);
- ui->action_Capture_Screenshot->setEnabled(true);
+}
+
+void GMainWindow::OnRestartGame() {
+ if (!system->IsPoweredOn()) {
+ return;
+ }
+ // Make a copy since BootGame edits game_path
+ BootGame(QString(game_path));
}
void GMainWindow::OnPauseGame() {
emu_thread->SetRunning(false);
-
- ui->action_Start->setEnabled(true);
- ui->action_Pause->setEnabled(false);
- ui->action_Stop->setEnabled(true);
- ui->action_Capture_Screenshot->setEnabled(false);
-
+ UpdateMenuState();
AllowOSSleep();
}
+void GMainWindow::OnPauseContinueGame() {
+ if (emulation_running) {
+ if (emu_thread->IsRunning()) {
+ OnPauseGame();
+ } else {
+ OnStartGame();
+ }
+ }
+}
+
void GMainWindow::OnStopGame() {
if (system->GetExitLock() && !ConfirmForceLockedExit()) {
return;
@@ -2774,7 +2712,6 @@ void GMainWindow::OnConfigure() {
ShowTelemetryCallout();
}
- controller_dialog->refreshConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme) {
@@ -2807,6 +2744,7 @@ void GMainWindow::OnConfigure() {
}
UpdateStatusButtons();
+ controller_dialog->refreshConfiguration();
}
void GMainWindow::OnConfigureTas() {
@@ -2821,6 +2759,32 @@ void GMainWindow::OnConfigureTas() {
}
}
+void GMainWindow::OnTasStartStop() {
+ if (!emulation_running) {
+ return;
+ }
+ input_subsystem->GetTas()->StartStop();
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasRecord() {
+ if (!emulation_running) {
+ return;
+ }
+ const bool is_recording = input_subsystem->GetTas()->Record();
+ if (!is_recording) {
+ const auto res =
+ QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
+ QMessageBox::Yes | QMessageBox::No);
+ input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
+ }
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasReset() {
+ input_subsystem->GetTas()->Reset();
+}
+
void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, game_path.toStdString());
@@ -2858,6 +2822,10 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
}
void GMainWindow::OnLoadAmiibo() {
+ if (emu_thread == nullptr || !emu_thread->IsRunning()) {
+ return;
+ }
+
const QString extensions{QStringLiteral("*.bin")};
const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter);
@@ -2921,6 +2889,10 @@ void GMainWindow::OnToggleFilterBar() {
}
void GMainWindow::OnCaptureScreenshot() {
+ if (emu_thread == nullptr || !emu_thread->IsRunning()) {
+ return;
+ }
+
const u64 title_id = system->GetCurrentProcessProgramID();
const auto screenshot_path =
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir));
@@ -3003,17 +2975,35 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
QString GMainWindow::GetTasStateDescription() const {
auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus();
switch (tas_status) {
- case TasInput::TasState::Running:
+ case InputCommon::TasInput::TasState::Running:
return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames);
- case TasInput::TasState::Recording:
+ case InputCommon::TasInput::TasState::Recording:
return tr("TAS state: Recording %1").arg(total_tas_frames);
- case TasInput::TasState::Stopped:
+ case InputCommon::TasInput::TasState::Stopped:
return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames);
default:
return tr("TAS State: Invalid");
}
}
+void GMainWindow::OnTasStateChanged() {
+ bool is_running = false;
+ bool is_recording = false;
+ if (emulation_running) {
+ const InputCommon::TasInput::TasState tas_status =
+ std::get<0>(input_subsystem->GetTas()->GetStatus());
+ is_running = tas_status == InputCommon::TasInput::TasState::Running;
+ is_recording = tas_status == InputCommon::TasInput::TasState::Recording;
+ }
+
+ ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start"));
+ ui->action_TAS_Record->setText(is_recording ? tr("Stop R&ecording") : tr("R&ecord"));
+
+ ui->action_TAS_Start->setEnabled(emulation_running);
+ ui->action_TAS_Record->setEnabled(emulation_running);
+ ui->action_TAS_Reset->setEnabled(emulation_running);
+}
+
void GMainWindow::UpdateStatusBar() {
if (emu_thread == nullptr) {
status_bar_update_timer.stop();
@@ -3386,6 +3376,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UpdateUISettings();
game_list->SaveInterfaceLayout();
hotkey_registry.SaveHotkeys();
+ controller_dialog->UnloadController();
+ system->HIDCore().UnloadInputDevices();
// Shutdown session if the emu thread is active...
if (emu_thread != nullptr) {
@@ -3487,36 +3479,38 @@ void GMainWindow::filterBarSetChecked(bool state) {
}
void GMainWindow::UpdateUITheme() {
- const QString default_icons = QStringLiteral("default");
- const QString& current_theme = UISettings::values.theme;
- const bool is_default_theme = current_theme == QString::fromUtf8(UISettings::themes[0].second);
+ const QString default_theme = QStringLiteral("default");
+ QString current_theme = UISettings::values.theme;
QStringList theme_paths(default_theme_paths);
- if (is_default_theme || current_theme.isEmpty()) {
- const QString theme_uri(QStringLiteral(":default/style.qss"));
+ if (current_theme.isEmpty()) {
+ current_theme = default_theme;
+ }
+
+ if (current_theme != default_theme) {
+ QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)};
QFile f(theme_uri);
- if (f.open(QFile::ReadOnly | QFile::Text)) {
- QTextStream ts(&f);
- qApp->setStyleSheet(ts.readAll());
- setStyleSheet(ts.readAll());
- } else {
- qApp->setStyleSheet({});
- setStyleSheet({});
+ if (!f.open(QFile::ReadOnly | QFile::Text)) {
+ LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme",
+ UISettings::values.theme.toStdString());
+ current_theme = default_theme;
}
- QIcon::setThemeName(default_icons);
+ }
+
+ QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)};
+ QFile f(theme_uri);
+ if (f.open(QFile::ReadOnly | QFile::Text)) {
+ QTextStream ts(&f);
+ qApp->setStyleSheet(ts.readAll());
+ setStyleSheet(ts.readAll());
} else {
- const QString theme_uri(QLatin1Char{':'} + current_theme + QStringLiteral("/style.qss"));
- QFile f(theme_uri);
- if (f.open(QFile::ReadOnly | QFile::Text)) {
- QTextStream ts(&f);
- qApp->setStyleSheet(ts.readAll());
- setStyleSheet(ts.readAll());
- } else {
- LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
- }
- QIcon::setThemeName(current_theme);
+ LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found",
+ UISettings::values.theme.toStdString());
+ qApp->setStyleSheet({});
+ setStyleSheet({});
}
+ QIcon::setThemeName(current_theme);
QIcon::setThemeSearchPaths(theme_paths);
}
@@ -3552,9 +3546,6 @@ void GMainWindow::OnLanguageChanged(const QString& locale) {
LoadTranslation();
ui->retranslateUi(this);
UpdateWindowTitle();
-
- if (emulation_running)
- ui->action_Start->setText(tr("&Continue"));
}
void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {