summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/yuzu/main.cpp397
-rw-r--r--src/yuzu/main.h6
-rw-r--r--src/yuzu/main.ui9
3 files changed, 175 insertions, 237 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5058c3e4e..88e84e8f7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -952,164 +952,80 @@ void GMainWindow::InitializeRecentFileMenuActions() {
952 UpdateRecentFiles(); 952 UpdateRecentFiles();
953} 953}
954 954
955void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) {
956 static const QString main_window = QStringLiteral("Main Window");
957 action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
958 action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
959
960 this->addAction(action);
961}
962
955void GMainWindow::InitializeHotkeys() { 963void GMainWindow::InitializeHotkeys() {
956 hotkey_registry.LoadHotkeys(); 964 hotkey_registry.LoadHotkeys();
957 965
958 const QString main_window = QStringLiteral("Main Window"); 966 LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File"));
959 const QString load_file = QStringLiteral("Load File"); 967 LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load Amiibo"));
960 const QString load_amiibo = QStringLiteral("Load Amiibo"); 968 LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu"));
961 const QString exit_yuzu = QStringLiteral("Exit yuzu"); 969 LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation"));
962 const QString restart_emulation = QStringLiteral("Restart Emulation"); 970 LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation"));
963 const QString stop_emulation = QStringLiteral("Stop Emulation"); 971 LinkActionShortcut(ui->action_Stop, QStringLiteral("Stop Emulation"));
964 const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); 972 LinkActionShortcut(ui->action_Show_Filter_Bar, QStringLiteral("Toggle Filter Bar"));
965 const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); 973 LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
966 const QString fullscreen = QStringLiteral("Fullscreen"); 974 LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
967 const QString capture_screenshot = QStringLiteral("Capture Screenshot"); 975 LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
968 const QString tas_start_stop = QStringLiteral("TAS Start/Stop"); 976 LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"));
969 const QString tas_record = QStringLiteral("TAS Record"); 977 LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"));
970 const QString tas_reset = QStringLiteral("TAS Reset"); 978 LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"));
971 979
972 ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); 980 static const QString main_window = QStringLiteral("Main Window");
973 ui->action_Load_File->setShortcutContext( 981 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
974 hotkey_registry.GetShortcutContext(main_window, load_file)); 982 const QShortcut* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this);
975 983 connect(hotkey, &QShortcut::activated, this, function);
976 ui->action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo)); 984 };
977 ui->action_Load_Amiibo->setShortcutContext( 985
978 hotkey_registry.GetShortcutContext(main_window, load_amiibo)); 986 connect_shortcut(QStringLiteral("Exit Fullscreen"), [&] {
979 987 if (emulation_running && ui->action_Fullscreen->isChecked()) {
980 ui->action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); 988 ui->action_Fullscreen->setChecked(false);
981 ui->action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); 989 ToggleFullscreen();
982 990 }
983 ui->action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation)); 991 });
984 ui->action_Restart->setShortcutContext( 992 connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] {
985 hotkey_registry.GetShortcutContext(main_window, restart_emulation)); 993 Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
986 994 UpdateStatusBar();
987 ui->action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); 995 });
988 ui->action_Stop->setShortcutContext(
989 hotkey_registry.GetShortcutContext(main_window, stop_emulation));
990
991 ui->action_Show_Filter_Bar->setShortcut(
992 hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
993 ui->action_Show_Filter_Bar->setShortcutContext(
994 hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar));
995
996 ui->action_Show_Status_Bar->setShortcut(
997 hotkey_registry.GetKeySequence(main_window, toggle_status_bar));
998 ui->action_Show_Status_Bar->setShortcutContext(
999 hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
1000
1001 ui->action_Capture_Screenshot->setShortcut(
1002 hotkey_registry.GetKeySequence(main_window, capture_screenshot));
1003 ui->action_Capture_Screenshot->setShortcutContext(
1004 hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
1005
1006 ui->action_Fullscreen->setShortcut(
1007 hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
1008 ui->action_Fullscreen->setShortcutContext(
1009 hotkey_registry.GetShortcutContext(main_window, fullscreen));
1010
1011 ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop));
1012 ui->action_TAS_Start->setShortcutContext(
1013 hotkey_registry.GetShortcutContext(main_window, tas_start_stop));
1014
1015 ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record));
1016 ui->action_TAS_Record->setShortcutContext(
1017 hotkey_registry.GetShortcutContext(main_window, tas_record));
1018
1019 ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset));
1020 ui->action_TAS_Reset->setShortcutContext(
1021 hotkey_registry.GetShortcutContext(main_window, tas_reset));
1022
1023 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
1024 &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
1025 connect(
1026 hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this),
1027 &QShortcut::activated, this, [&] {
1028 if (emulation_running) {
1029 if (emu_thread->IsRunning()) {
1030 OnPauseGame();
1031 } else {
1032 OnStartGame();
1033 }
1034 }
1035 });
1036 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this),
1037 &QShortcut::activated, this, [this] {
1038 if (!system->IsPoweredOn()) {
1039 return;
1040 }
1041 BootGame(game_path);
1042 });
1043 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
1044 &QShortcut::activated, ui->action_Fullscreen, &QAction::trigger);
1045 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
1046 &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
1047 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
1048 &QShortcut::activated, this, [&] {
1049 if (emulation_running && ui->action_Fullscreen->isChecked()) {
1050 ui->action_Fullscreen->setChecked(false);
1051 ToggleFullscreen();
1052 }
1053 });
1054 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
1055 &QShortcut::activated, this, [&] {
1056 Settings::values.use_speed_limit.SetValue(
1057 !Settings::values.use_speed_limit.GetValue());
1058 UpdateStatusBar();
1059 });
1060 constexpr u16 SPEED_LIMIT_STEP = 5; 996 constexpr u16 SPEED_LIMIT_STEP = 5;
1061 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), 997 connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] {
1062 &QShortcut::activated, this, [&] { 998 if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
1063 if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { 999 Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
1064 Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP + 1000 Settings::values.speed_limit.GetValue());
1065 Settings::values.speed_limit.GetValue()); 1001 UpdateStatusBar();
1066 UpdateStatusBar(); 1002 }
1067 } 1003 });
1068 }); 1004 connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] {
1069 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), 1005 if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
1070 &QShortcut::activated, this, [&] { 1006 Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
1071 if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) { 1007 SPEED_LIMIT_STEP);
1072 Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() - 1008 UpdateStatusBar();
1073 SPEED_LIMIT_STEP); 1009 }
1074 UpdateStatusBar(); 1010 });
1075 } 1011 connect_shortcut(QStringLiteral("Change Docked Mode"), [&] {
1076 }); 1012 Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue());
1077 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this), 1013 OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
1078 &QShortcut::activated, this, [&] { 1014 Settings::values.use_docked_mode.GetValue(), *system);
1079 if (ui->action_Load_Amiibo->isEnabled()) { 1015 dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
1080 OnLoadAmiibo(); 1016 });
1081 } 1017 connect_shortcut(QStringLiteral("Mute Audio"),
1082 }); 1018 [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
1083 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this), 1019 connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
1084 &QShortcut::activated, this, [&] { 1020 Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue());
1085 if (emu_thread != nullptr && emu_thread->IsRunning()) { 1021 });
1086 OnCaptureScreenshot(); 1022 connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] {
1087 } 1023 Settings::values.mouse_panning = !Settings::values.mouse_panning;
1088 }); 1024 if (Settings::values.mouse_panning) {
1089 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this), 1025 render_window->installEventFilter(render_window);
1090 &QShortcut::activated, this, [&] { 1026 render_window->setAttribute(Qt::WA_Hover, true);
1091 Settings::values.use_docked_mode.SetValue( 1027 }
1092 !Settings::values.use_docked_mode.GetValue()); 1028 });
1093 OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
1094 Settings::values.use_docked_mode.GetValue(), *system);
1095 dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
1096 });
1097 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
1098 &QShortcut::activated, this,
1099 [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
1100 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Framerate Limit"), this),
1101 &QShortcut::activated, this, [] {
1102 Settings::values.disable_fps_limit.SetValue(
1103 !Settings::values.disable_fps_limit.GetValue());
1104 });
1105 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
1106 &QShortcut::activated, this, [&] {
1107 Settings::values.mouse_panning = !Settings::values.mouse_panning;
1108 if (Settings::values.mouse_panning) {
1109 render_window->installEventFilter(render_window);
1110 render_window->setAttribute(Qt::WA_Hover, true);
1111 }
1112 });
1113} 1029}
1114 1030
1115void GMainWindow::SetDefaultUIGeometry() { 1031void GMainWindow::SetDefaultUIGeometry() {
@@ -1164,7 +1080,8 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1164 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { 1080 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
1165 auto_paused = true; 1081 auto_paused = true;
1166 OnPauseGame(); 1082 OnPauseGame();
1167 } else if (ui->action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) { 1083 } else if (emulation_running && !emu_thread->IsRunning() && auto_paused &&
1084 state == Qt::ApplicationActive) {
1168 auto_paused = false; 1085 auto_paused = false;
1169 OnStartGame(); 1086 OnStartGame();
1170 } 1087 }
@@ -1208,64 +1125,86 @@ void GMainWindow::ConnectWidgetEvents() {
1208} 1125}
1209 1126
1210void GMainWindow::ConnectMenuEvents() { 1127void GMainWindow::ConnectMenuEvents() {
1128 const auto connect_menu = [&]<typename Fn>(QAction* action, const Fn& event_fn) {
1129 connect(action, &QAction::triggered, this, event_fn);
1130 // Add actions to this window so that hiding menus in fullscreen won't disable them
1131 addAction(action);
1132 // Add actions to the render window so that they work outside of single window mode
1133 render_window->addAction(action);
1134 };
1135
1211 // File 1136 // File
1212 connect(ui->action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); 1137 connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile);
1213 connect(ui->action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); 1138 connect_menu(ui->action_Load_Folder, &GMainWindow::OnMenuLoadFolder);
1214 connect(ui->action_Install_File_NAND, &QAction::triggered, this, 1139 connect_menu(ui->action_Install_File_NAND, &GMainWindow::OnMenuInstallToNAND);
1215 &GMainWindow::OnMenuInstallToNAND); 1140 connect_menu(ui->action_Exit, &QMainWindow::close);
1216 connect(ui->action_Exit, &QAction::triggered, this, &QMainWindow::close); 1141 connect_menu(ui->action_Load_Amiibo, &GMainWindow::OnLoadAmiibo);
1217 connect(ui->action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
1218 1142
1219 // Emulation 1143 // Emulation
1220 connect(ui->action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); 1144 connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame);
1221 connect(ui->action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame); 1145 connect_menu(ui->action_Stop, &GMainWindow::OnStopGame);
1222 connect(ui->action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); 1146 connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility);
1223 connect(ui->action_Report_Compatibility, &QAction::triggered, this, 1147 connect_menu(ui->action_Open_Mods_Page, &GMainWindow::OnOpenModsPage);
1224 &GMainWindow::OnMenuReportCompatibility); 1148 connect_menu(ui->action_Open_Quickstart_Guide, &GMainWindow::OnOpenQuickstartGuide);
1225 connect(ui->action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); 1149 connect_menu(ui->action_Open_FAQ, &GMainWindow::OnOpenFAQ);
1226 connect(ui->action_Open_Quickstart_Guide, &QAction::triggered, this, 1150 connect_menu(ui->action_Restart, &GMainWindow::OnRestartGame);
1227 &GMainWindow::OnOpenQuickstartGuide); 1151 connect_menu(ui->action_Configure, &GMainWindow::OnConfigure);
1228 connect(ui->action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); 1152 connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame);
1229 connect(ui->action_Restart, &QAction::triggered, this,
1230 [this] { BootGame(QString(game_path)); });
1231 connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
1232 connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
1233 &GMainWindow::OnConfigurePerGame);
1234 1153
1235 // View 1154 // View
1236 connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); 1155 connect_menu(ui->action_Fullscreen, &GMainWindow::ToggleFullscreen);
1237 connect(ui->action_Single_Window_Mode, &QAction::triggered, this, 1156 connect_menu(ui->action_Single_Window_Mode, &GMainWindow::ToggleWindowMode);
1238 &GMainWindow::ToggleWindowMode); 1157 connect_menu(ui->action_Display_Dock_Widget_Headers, &GMainWindow::OnDisplayTitleBars);
1239 connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this, 1158 connect_menu(ui->action_Show_Filter_Bar, &GMainWindow::OnToggleFilterBar);
1240 &GMainWindow::OnDisplayTitleBars); 1159
1241 connect(ui->action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
1242 connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); 1160 connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
1243 1161
1244 connect(ui->action_Reset_Window_Size_720, &QAction::triggered, this, 1162 connect_menu(ui->action_Reset_Window_Size_720, &GMainWindow::ResetWindowSize720);
1245 &GMainWindow::ResetWindowSize720); 1163 connect_menu(ui->action_Reset_Window_Size_900, &GMainWindow::ResetWindowSize900);
1246 connect(ui->action_Reset_Window_Size_900, &QAction::triggered, this, 1164 connect_menu(ui->action_Reset_Window_Size_1080, &GMainWindow::ResetWindowSize1080);
1247 &GMainWindow::ResetWindowSize900); 1165 ui->menu_Reset_Window_Size->addActions({ui->action_Reset_Window_Size_720,
1248 connect(ui->action_Reset_Window_Size_1080, &QAction::triggered, this, 1166 ui->action_Reset_Window_Size_900,
1249 &GMainWindow::ResetWindowSize1080); 1167 ui->action_Reset_Window_Size_1080});
1250 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_720);
1251 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
1252 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
1253 1168
1254 // Tools 1169 // Tools
1255 connect(ui->action_Rederive, &QAction::triggered, this, 1170 connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
1256 std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); 1171 ReinitializeKeyBehavior::Warning));
1257 connect(ui->action_Capture_Screenshot, &QAction::triggered, this, 1172 connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot);
1258 &GMainWindow::OnCaptureScreenshot);
1259 1173
1260 // TAS 1174 // TAS
1261 connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop); 1175 connect_menu(ui->action_TAS_Start, &GMainWindow::OnTasStartStop);
1262 connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord); 1176 connect_menu(ui->action_TAS_Record, &GMainWindow::OnTasRecord);
1263 connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset); 1177 connect_menu(ui->action_TAS_Reset, &GMainWindow::OnTasReset);
1264 connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); 1178 connect_menu(ui->action_Configure_Tas, &GMainWindow::OnConfigureTas);
1265 1179
1266 // Help 1180 // Help
1267 connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); 1181 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
1268 connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout); 1182 connect_menu(ui->action_About, &GMainWindow::OnAbout);
1183}
1184
1185void GMainWindow::UpdateMenuState() {
1186 const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning();
1187
1188 const std::array running_actions{
1189 ui->action_Stop,
1190 ui->action_Restart,
1191 ui->action_Configure_Current_Game,
1192 ui->action_Report_Compatibility,
1193 ui->action_Load_Amiibo,
1194 ui->action_Pause,
1195 };
1196
1197 for (QAction* action : running_actions) {
1198 action->setEnabled(emulation_running);
1199 }
1200
1201 ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
1202
1203 if (emulation_running && is_paused) {
1204 ui->action_Pause->setText(tr("&Continue"));
1205 } else {
1206 ui->action_Pause->setText(tr("&Pause"));
1207 }
1269} 1208}
1270 1209
1271void GMainWindow::OnDisplayTitleBars(bool show) { 1210void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -1558,15 +1497,8 @@ void GMainWindow::ShutdownGame() {
1558 disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); 1497 disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
1559 1498
1560 // Update the GUI 1499 // Update the GUI
1561 ui->action_Start->setEnabled(false); 1500 UpdateMenuState();
1562 ui->action_Start->setText(tr("Start")); 1501
1563 ui->action_Pause->setEnabled(false);
1564 ui->action_Stop->setEnabled(false);
1565 ui->action_Restart->setEnabled(false);
1566 ui->action_Configure_Current_Game->setEnabled(false);
1567 ui->action_Report_Compatibility->setEnabled(false);
1568 ui->action_Load_Amiibo->setEnabled(false);
1569 ui->action_Capture_Screenshot->setEnabled(false);
1570 render_window->hide(); 1502 render_window->hide();
1571 loading_screen->hide(); 1503 loading_screen->hide();
1572 loading_screen->Clear(); 1504 loading_screen->Clear();
@@ -2498,32 +2430,36 @@ void GMainWindow::OnStartGame() {
2498 2430
2499 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); 2431 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
2500 2432
2501 ui->action_Start->setEnabled(false); 2433 UpdateMenuState();
2502 ui->action_Start->setText(tr("&Continue"));
2503
2504 ui->action_Pause->setEnabled(true);
2505 ui->action_Stop->setEnabled(true);
2506 ui->action_Restart->setEnabled(true);
2507 ui->action_Configure_Current_Game->setEnabled(true);
2508 ui->action_Report_Compatibility->setEnabled(true);
2509 OnTasStateChanged(); 2434 OnTasStateChanged();
2510 2435
2511 discord_rpc->Update(); 2436 discord_rpc->Update();
2512 ui->action_Load_Amiibo->setEnabled(true); 2437}
2513 ui->action_Capture_Screenshot->setEnabled(true); 2438
2439void GMainWindow::OnRestartGame() {
2440 if (!system->IsPoweredOn()) {
2441 return;
2442 }
2443 // Make a copy since BootGame edits game_path
2444 BootGame(QString(game_path));
2514} 2445}
2515 2446
2516void GMainWindow::OnPauseGame() { 2447void GMainWindow::OnPauseGame() {
2517 emu_thread->SetRunning(false); 2448 emu_thread->SetRunning(false);
2518 2449 UpdateMenuState();
2519 ui->action_Start->setEnabled(true);
2520 ui->action_Pause->setEnabled(false);
2521 ui->action_Stop->setEnabled(true);
2522 ui->action_Capture_Screenshot->setEnabled(false);
2523
2524 AllowOSSleep(); 2450 AllowOSSleep();
2525} 2451}
2526 2452
2453void GMainWindow::OnPauseContinueGame() {
2454 if (emulation_running) {
2455 if (emu_thread->IsRunning()) {
2456 OnPauseGame();
2457 } else {
2458 OnStartGame();
2459 }
2460 }
2461}
2462
2527void GMainWindow::OnStopGame() { 2463void GMainWindow::OnStopGame() {
2528 if (system->GetExitLock() && !ConfirmForceLockedExit()) { 2464 if (system->GetExitLock() && !ConfirmForceLockedExit()) {
2529 return; 2465 return;
@@ -2882,6 +2818,10 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
2882} 2818}
2883 2819
2884void GMainWindow::OnLoadAmiibo() { 2820void GMainWindow::OnLoadAmiibo() {
2821 if (emu_thread == nullptr || !emu_thread->IsRunning()) {
2822 return;
2823 }
2824
2885 const QString extensions{QStringLiteral("*.bin")}; 2825 const QString extensions{QStringLiteral("*.bin")};
2886 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); 2826 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
2887 const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter); 2827 const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter);
@@ -2945,6 +2885,10 @@ void GMainWindow::OnToggleFilterBar() {
2945} 2885}
2946 2886
2947void GMainWindow::OnCaptureScreenshot() { 2887void GMainWindow::OnCaptureScreenshot() {
2888 if (emu_thread == nullptr || !emu_thread->IsRunning()) {
2889 return;
2890 }
2891
2948 const u64 title_id = system->GetCurrentProcessProgramID(); 2892 const u64 title_id = system->GetCurrentProcessProgramID();
2949 const auto screenshot_path = 2893 const auto screenshot_path =
2950 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)); 2894 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir));
@@ -3593,9 +3537,6 @@ void GMainWindow::OnLanguageChanged(const QString& locale) {
3593 LoadTranslation(); 3537 LoadTranslation();
3594 ui->retranslateUi(this); 3538 ui->retranslateUi(this);
3595 UpdateWindowTitle(); 3539 UpdateWindowTitle();
3596
3597 if (emulation_running)
3598 ui->action_Start->setText(tr("&Continue"));
3599} 3540}
3600 3541
3601void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { 3542void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 556cbbaf7..0fd41ed4f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -191,6 +191,7 @@ private:
191 191
192 void ConnectWidgetEvents(); 192 void ConnectWidgetEvents();
193 void ConnectMenuEvents(); 193 void ConnectMenuEvents();
194 void UpdateMenuState();
194 195
195 void PreventOSSleep(); 196 void PreventOSSleep();
196 void AllowOSSleep(); 197 void AllowOSSleep();
@@ -240,7 +241,9 @@ private:
240 241
241private slots: 242private slots:
242 void OnStartGame(); 243 void OnStartGame();
244 void OnRestartGame();
243 void OnPauseGame(); 245 void OnPauseGame();
246 void OnPauseContinueGame();
244 void OnStopGame(); 247 void OnStopGame();
245 void OnMenuReportCompatibility(); 248 void OnMenuReportCompatibility();
246 void OnOpenModsPage(); 249 void OnOpenModsPage();
@@ -294,6 +297,9 @@ private slots:
294 void OnMouseActivity(); 297 void OnMouseActivity();
295 298
296private: 299private:
300 /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry.
301 void LinkActionShortcut(QAction* action, const QString& action_name);
302
297 void RemoveBaseContent(u64 program_id, const QString& entry_type); 303 void RemoveBaseContent(u64 program_id, const QString& entry_type);
298 void RemoveUpdateContent(u64 program_id, const QString& entry_type); 304 void RemoveUpdateContent(u64 program_id, const QString& entry_type);
299 void RemoveAddOnContent(u64 program_id, const QString& entry_type); 305 void RemoveAddOnContent(u64 program_id, const QString& entry_type);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index c58aa2866..5719b2ee4 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -66,7 +66,6 @@
66 <property name="title"> 66 <property name="title">
67 <string>&amp;Emulation</string> 67 <string>&amp;Emulation</string>
68 </property> 68 </property>
69 <addaction name="action_Start"/>
70 <addaction name="action_Pause"/> 69 <addaction name="action_Pause"/>
71 <addaction name="action_Stop"/> 70 <addaction name="action_Stop"/>
72 <addaction name="action_Restart"/> 71 <addaction name="action_Restart"/>
@@ -180,14 +179,6 @@
180 <string>E&amp;xit</string> 179 <string>E&amp;xit</string>
181 </property> 180 </property>
182 </action> 181 </action>
183 <action name="action_Start">
184 <property name="enabled">
185 <bool>false</bool>
186 </property>
187 <property name="text">
188 <string>&amp;Start</string>
189 </property>
190 </action>
191 <action name="action_Pause"> 182 <action name="action_Pause">
192 <property name="enabled"> 183 <property name="enabled">
193 <bool>false</bool> 184 <bool>false</bool>