diff options
Diffstat (limited to 'src/citra_qt/main.cpp')
| -rw-r--r-- | src/citra_qt/main.cpp | 242 |
1 files changed, 171 insertions, 71 deletions
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index f765c0147..fd51659b9 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -54,28 +54,30 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); | |||
| 54 | 54 | ||
| 55 | GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | 55 | GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { |
| 56 | Pica::g_debug_context = Pica::DebugContext::Construct(); | 56 | Pica::g_debug_context = Pica::DebugContext::Construct(); |
| 57 | 57 | setAcceptDrops(true); | |
| 58 | ui.setupUi(this); | 58 | ui.setupUi(this); |
| 59 | statusBar()->hide(); | 59 | statusBar()->hide(); |
| 60 | 60 | ||
| 61 | InitializeWidgets(); | 61 | InitializeWidgets(); |
| 62 | InitializeDebugMenuActions(); | 62 | InitializeDebugWidgets(); |
| 63 | InitializeRecentFileMenuActions(); | 63 | InitializeRecentFileMenuActions(); |
| 64 | InitializeHotkeys(); | 64 | InitializeHotkeys(); |
| 65 | 65 | ||
| 66 | SetDefaultUIGeometry(); | 66 | SetDefaultUIGeometry(); |
| 67 | RestoreUIState(); | 67 | RestoreUIState(); |
| 68 | 68 | ||
| 69 | ConnectMenuEvents(); | ||
| 69 | ConnectWidgetEvents(); | 70 | ConnectWidgetEvents(); |
| 70 | 71 | ||
| 71 | setWindowTitle(QString("Citra | %1-%2").arg(Common::g_scm_branch, Common::g_scm_desc)); | 72 | setWindowTitle(QString("Citra %1| %2-%3") |
| 73 | .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); | ||
| 72 | show(); | 74 | show(); |
| 73 | 75 | ||
| 74 | game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | 76 | game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); |
| 75 | 77 | ||
| 76 | QStringList args = QApplication::arguments(); | 78 | QStringList args = QApplication::arguments(); |
| 77 | if (args.length() >= 2) { | 79 | if (args.length() >= 2) { |
| 78 | BootGame(args[1].toStdString()); | 80 | BootGame(args[1]); |
| 79 | } | 81 | } |
| 80 | } | 82 | } |
| 81 | 83 | ||
| @@ -94,73 +96,99 @@ void GMainWindow::InitializeWidgets() { | |||
| 94 | game_list = new GameList(); | 96 | game_list = new GameList(); |
| 95 | ui.horizontalLayout->addWidget(game_list); | 97 | ui.horizontalLayout->addWidget(game_list); |
| 96 | 98 | ||
| 97 | profilerWidget = new ProfilerWidget(this); | 99 | // Create status bar |
| 98 | addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); | 100 | emu_speed_label = new QLabel(); |
| 99 | profilerWidget->hide(); | 101 | emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% " |
| 102 | "indicate emulation is running faster or slower than a 3DS.")); | ||
| 103 | game_fps_label = new QLabel(); | ||
| 104 | game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. " | ||
| 105 | "This will vary from game to game and scene to scene.")); | ||
| 106 | emu_frametime_label = new QLabel(); | ||
| 107 | emu_frametime_label->setToolTip( | ||
| 108 | tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For " | ||
| 109 | "full-speed emulation this should be at most 16.67 ms.")); | ||
| 110 | |||
| 111 | for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) { | ||
| 112 | label->setVisible(false); | ||
| 113 | label->setFrameStyle(QFrame::NoFrame); | ||
| 114 | label->setContentsMargins(4, 0, 4, 0); | ||
| 115 | statusBar()->addPermanentWidget(label); | ||
| 116 | } | ||
| 117 | statusBar()->setVisible(true); | ||
| 118 | } | ||
| 119 | |||
| 120 | void GMainWindow::InitializeDebugWidgets() { | ||
| 121 | connect(ui.action_Create_Pica_Surface_Viewer, &QAction::triggered, this, | ||
| 122 | &GMainWindow::OnCreateGraphicsSurfaceViewer); | ||
| 123 | |||
| 124 | QMenu* debug_menu = ui.menu_View_Debugging; | ||
| 100 | 125 | ||
| 101 | #if MICROPROFILE_ENABLED | 126 | #if MICROPROFILE_ENABLED |
| 102 | microProfileDialog = new MicroProfileDialog(this); | 127 | microProfileDialog = new MicroProfileDialog(this); |
| 103 | microProfileDialog->hide(); | 128 | microProfileDialog->hide(); |
| 129 | debug_menu->addAction(microProfileDialog->toggleViewAction()); | ||
| 104 | #endif | 130 | #endif |
| 105 | 131 | ||
| 106 | disasmWidget = new DisassemblerWidget(this, emu_thread.get()); | 132 | disasmWidget = new DisassemblerWidget(this, emu_thread.get()); |
| 107 | addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); | 133 | addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); |
| 108 | disasmWidget->hide(); | 134 | disasmWidget->hide(); |
| 135 | debug_menu->addAction(disasmWidget->toggleViewAction()); | ||
| 136 | connect(this, &GMainWindow::EmulationStarting, disasmWidget, | ||
| 137 | &DisassemblerWidget::OnEmulationStarting); | ||
| 138 | connect(this, &GMainWindow::EmulationStopping, disasmWidget, | ||
| 139 | &DisassemblerWidget::OnEmulationStopping); | ||
| 109 | 140 | ||
| 110 | registersWidget = new RegistersWidget(this); | 141 | registersWidget = new RegistersWidget(this); |
| 111 | addDockWidget(Qt::RightDockWidgetArea, registersWidget); | 142 | addDockWidget(Qt::RightDockWidgetArea, registersWidget); |
| 112 | registersWidget->hide(); | 143 | registersWidget->hide(); |
| 144 | debug_menu->addAction(registersWidget->toggleViewAction()); | ||
| 145 | connect(this, &GMainWindow::EmulationStarting, registersWidget, | ||
| 146 | &RegistersWidget::OnEmulationStarting); | ||
| 147 | connect(this, &GMainWindow::EmulationStopping, registersWidget, | ||
| 148 | &RegistersWidget::OnEmulationStopping); | ||
| 113 | 149 | ||
| 114 | callstackWidget = new CallstackWidget(this); | 150 | callstackWidget = new CallstackWidget(this); |
| 115 | addDockWidget(Qt::RightDockWidgetArea, callstackWidget); | 151 | addDockWidget(Qt::RightDockWidgetArea, callstackWidget); |
| 116 | callstackWidget->hide(); | 152 | callstackWidget->hide(); |
| 153 | debug_menu->addAction(callstackWidget->toggleViewAction()); | ||
| 117 | 154 | ||
| 118 | graphicsWidget = new GPUCommandStreamWidget(this); | 155 | graphicsWidget = new GPUCommandStreamWidget(this); |
| 119 | addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); | 156 | addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); |
| 120 | graphicsWidget->hide(); | 157 | graphicsWidget->hide(); |
| 158 | debug_menu->addAction(graphicsWidget->toggleViewAction()); | ||
| 121 | 159 | ||
| 122 | graphicsCommandsWidget = new GPUCommandListWidget(this); | 160 | graphicsCommandsWidget = new GPUCommandListWidget(this); |
| 123 | addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); | 161 | addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); |
| 124 | graphicsCommandsWidget->hide(); | 162 | graphicsCommandsWidget->hide(); |
| 163 | debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); | ||
| 125 | 164 | ||
| 126 | graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this); | 165 | graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this); |
| 127 | addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); | 166 | addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); |
| 128 | graphicsBreakpointsWidget->hide(); | 167 | graphicsBreakpointsWidget->hide(); |
| 168 | debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); | ||
| 129 | 169 | ||
| 130 | graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this); | 170 | graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this); |
| 131 | addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); | 171 | addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); |
| 132 | graphicsVertexShaderWidget->hide(); | 172 | graphicsVertexShaderWidget->hide(); |
| 173 | debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); | ||
| 133 | 174 | ||
| 134 | graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this); | 175 | graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this); |
| 135 | addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget); | 176 | addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget); |
| 136 | graphicsTracingWidget->hide(); | 177 | graphicsTracingWidget->hide(); |
| 178 | debug_menu->addAction(graphicsTracingWidget->toggleViewAction()); | ||
| 179 | connect(this, &GMainWindow::EmulationStarting, graphicsTracingWidget, | ||
| 180 | &GraphicsTracingWidget::OnEmulationStarting); | ||
| 181 | connect(this, &GMainWindow::EmulationStopping, graphicsTracingWidget, | ||
| 182 | &GraphicsTracingWidget::OnEmulationStopping); | ||
| 137 | 183 | ||
| 138 | waitTreeWidget = new WaitTreeWidget(this); | 184 | waitTreeWidget = new WaitTreeWidget(this); |
| 139 | addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); | 185 | addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); |
| 140 | waitTreeWidget->hide(); | 186 | waitTreeWidget->hide(); |
| 141 | } | ||
| 142 | |||
| 143 | void GMainWindow::InitializeDebugMenuActions() { | ||
| 144 | auto graphicsSurfaceViewerAction = new QAction(tr("Create Pica Surface Viewer"), this); | ||
| 145 | connect(graphicsSurfaceViewerAction, SIGNAL(triggered()), this, | ||
| 146 | SLOT(OnCreateGraphicsSurfaceViewer())); | ||
| 147 | |||
| 148 | QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); | ||
| 149 | debug_menu->addAction(graphicsSurfaceViewerAction); | ||
| 150 | debug_menu->addSeparator(); | ||
| 151 | debug_menu->addAction(profilerWidget->toggleViewAction()); | ||
| 152 | #if MICROPROFILE_ENABLED | ||
| 153 | debug_menu->addAction(microProfileDialog->toggleViewAction()); | ||
| 154 | #endif | ||
| 155 | debug_menu->addAction(disasmWidget->toggleViewAction()); | ||
| 156 | debug_menu->addAction(registersWidget->toggleViewAction()); | ||
| 157 | debug_menu->addAction(callstackWidget->toggleViewAction()); | ||
| 158 | debug_menu->addAction(graphicsWidget->toggleViewAction()); | ||
| 159 | debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); | ||
| 160 | debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); | ||
| 161 | debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); | ||
| 162 | debug_menu->addAction(graphicsTracingWidget->toggleViewAction()); | ||
| 163 | debug_menu->addAction(waitTreeWidget->toggleViewAction()); | 187 | debug_menu->addAction(waitTreeWidget->toggleViewAction()); |
| 188 | connect(this, &GMainWindow::EmulationStarting, waitTreeWidget, | ||
| 189 | &WaitTreeWidget::OnEmulationStarting); | ||
| 190 | connect(this, &GMainWindow::EmulationStopping, waitTreeWidget, | ||
| 191 | &WaitTreeWidget::OnEmulationStopping); | ||
| 164 | } | 192 | } |
| 165 | 193 | ||
| 166 | void GMainWindow::InitializeRecentFileMenuActions() { | 194 | void GMainWindow::InitializeRecentFileMenuActions() { |
| @@ -215,41 +243,46 @@ void GMainWindow::RestoreUIState() { | |||
| 215 | ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode); | 243 | ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode); |
| 216 | ToggleWindowMode(); | 244 | ToggleWindowMode(); |
| 217 | 245 | ||
| 218 | ui.actionDisplay_widget_title_bars->setChecked(UISettings::values.display_titlebar); | 246 | ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar); |
| 219 | OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked()); | 247 | OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); |
| 248 | |||
| 249 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); | ||
| 250 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); | ||
| 220 | } | 251 | } |
| 221 | 252 | ||
| 222 | void GMainWindow::ConnectWidgetEvents() { | 253 | void GMainWindow::ConnectWidgetEvents() { |
| 223 | connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)), | 254 | connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString))); |
| 224 | Qt::DirectConnection); | ||
| 225 | connect(game_list, SIGNAL(OpenSaveFolderRequested(u64)), this, | 255 | connect(game_list, SIGNAL(OpenSaveFolderRequested(u64)), this, |
| 226 | SLOT(OnGameListOpenSaveFolder(u64)), Qt::DirectConnection); | 256 | SLOT(OnGameListOpenSaveFolder(u64))); |
| 227 | connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(OnConfigure())); | 257 | |
| 228 | connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()), | ||
| 229 | Qt::DirectConnection); | ||
| 230 | connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); | ||
| 231 | connect(ui.action_Select_Game_List_Root, SIGNAL(triggered()), this, | ||
| 232 | SLOT(OnMenuSelectGameListRoot())); | ||
| 233 | connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); | ||
| 234 | connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); | ||
| 235 | connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); | ||
| 236 | connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); | ||
| 237 | |||
| 238 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, | ||
| 239 | SLOT(OnEmulationStarting(EmuThread*))); | ||
| 240 | connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping())); | ||
| 241 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), registersWidget, | ||
| 242 | SLOT(OnEmulationStarting(EmuThread*))); | ||
| 243 | connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); | ||
| 244 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, | 258 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, |
| 245 | SLOT(OnEmulationStarting(EmuThread*))); | 259 | SLOT(OnEmulationStarting(EmuThread*))); |
| 246 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); | 260 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); |
| 247 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), graphicsTracingWidget, | 261 | |
| 248 | SLOT(OnEmulationStarting(EmuThread*))); | 262 | connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); |
| 249 | connect(this, SIGNAL(EmulationStopping()), graphicsTracingWidget, SLOT(OnEmulationStopping())); | 263 | } |
| 250 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), waitTreeWidget, | 264 | |
| 251 | SLOT(OnEmulationStarting(EmuThread*))); | 265 | void GMainWindow::ConnectMenuEvents() { |
| 252 | connect(this, SIGNAL(EmulationStopping()), waitTreeWidget, SLOT(OnEmulationStopping())); | 266 | // File |
| 267 | connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); | ||
| 268 | connect(ui.action_Load_Symbol_Map, &QAction::triggered, this, | ||
| 269 | &GMainWindow::OnMenuLoadSymbolMap); | ||
| 270 | connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, | ||
| 271 | &GMainWindow::OnMenuSelectGameListRoot); | ||
| 272 | connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); | ||
| 273 | |||
| 274 | // Emulation | ||
| 275 | connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); | ||
| 276 | connect(ui.action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame); | ||
| 277 | connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); | ||
| 278 | connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); | ||
| 279 | |||
| 280 | // View | ||
| 281 | connect(ui.action_Single_Window_Mode, &QAction::triggered, this, | ||
| 282 | &GMainWindow::ToggleWindowMode); | ||
| 283 | connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, | ||
| 284 | &GMainWindow::OnDisplayTitleBars); | ||
| 285 | connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); | ||
| 253 | } | 286 | } |
| 254 | 287 | ||
| 255 | void GMainWindow::OnDisplayTitleBars(bool show) { | 288 | void GMainWindow::OnDisplayTitleBars(bool show) { |
| @@ -272,7 +305,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
| 272 | } | 305 | } |
| 273 | } | 306 | } |
| 274 | 307 | ||
| 275 | bool GMainWindow::LoadROM(const std::string& filename) { | 308 | bool GMainWindow::LoadROM(const QString& filename) { |
| 276 | // Shutdown previous session if the emu thread is still active... | 309 | // Shutdown previous session if the emu thread is still active... |
| 277 | if (emu_thread != nullptr) | 310 | if (emu_thread != nullptr) |
| 278 | ShutdownGame(); | 311 | ShutdownGame(); |
| @@ -290,12 +323,13 @@ bool GMainWindow::LoadROM(const std::string& filename) { | |||
| 290 | 323 | ||
| 291 | Core::System& system{Core::System::GetInstance()}; | 324 | Core::System& system{Core::System::GetInstance()}; |
| 292 | 325 | ||
| 293 | const Core::System::ResultStatus result{system.Load(render_window, filename)}; | 326 | const Core::System::ResultStatus result{system.Load(render_window, filename.toStdString())}; |
| 294 | 327 | ||
| 295 | if (result != Core::System::ResultStatus::Success) { | 328 | if (result != Core::System::ResultStatus::Success) { |
| 296 | switch (result) { | 329 | switch (result) { |
| 297 | case Core::System::ResultStatus::ErrorGetLoader: | 330 | case Core::System::ResultStatus::ErrorGetLoader: |
| 298 | LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filename.c_str()); | 331 | LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", |
| 332 | filename.toStdString().c_str()); | ||
| 299 | QMessageBox::critical(this, tr("Error while loading ROM!"), | 333 | QMessageBox::critical(this, tr("Error while loading ROM!"), |
| 300 | tr("The ROM format is not supported.")); | 334 | tr("The ROM format is not supported.")); |
| 301 | break; | 335 | break; |
| @@ -335,7 +369,7 @@ bool GMainWindow::LoadROM(const std::string& filename) { | |||
| 335 | return true; | 369 | return true; |
| 336 | } | 370 | } |
| 337 | 371 | ||
| 338 | void GMainWindow::BootGame(const std::string& filename) { | 372 | void GMainWindow::BootGame(const QString& filename) { |
| 339 | LOG_INFO(Frontend, "Citra starting..."); | 373 | LOG_INFO(Frontend, "Citra starting..."); |
| 340 | StoreRecentFile(filename); // Put the filename on top of the list | 374 | StoreRecentFile(filename); // Put the filename on top of the list |
| 341 | 375 | ||
| @@ -374,6 +408,8 @@ void GMainWindow::BootGame(const std::string& filename) { | |||
| 374 | if (ui.action_Single_Window_Mode->isChecked()) { | 408 | if (ui.action_Single_Window_Mode->isChecked()) { |
| 375 | game_list->hide(); | 409 | game_list->hide(); |
| 376 | } | 410 | } |
| 411 | status_bar_update_timer.start(2000); | ||
| 412 | |||
| 377 | render_window->show(); | 413 | render_window->show(); |
| 378 | render_window->setFocus(); | 414 | render_window->setFocus(); |
| 379 | 415 | ||
| @@ -408,11 +444,17 @@ void GMainWindow::ShutdownGame() { | |||
| 408 | render_window->hide(); | 444 | render_window->hide(); |
| 409 | game_list->show(); | 445 | game_list->show(); |
| 410 | 446 | ||
| 447 | // Disable status bar updates | ||
| 448 | status_bar_update_timer.stop(); | ||
| 449 | emu_speed_label->setVisible(false); | ||
| 450 | game_fps_label->setVisible(false); | ||
| 451 | emu_frametime_label->setVisible(false); | ||
| 452 | |||
| 411 | emulation_running = false; | 453 | emulation_running = false; |
| 412 | } | 454 | } |
| 413 | 455 | ||
| 414 | void GMainWindow::StoreRecentFile(const std::string& filename) { | 456 | void GMainWindow::StoreRecentFile(const QString& filename) { |
| 415 | UISettings::values.recent_files.prepend(QString::fromStdString(filename)); | 457 | UISettings::values.recent_files.prepend(filename); |
| 416 | UISettings::values.recent_files.removeDuplicates(); | 458 | UISettings::values.recent_files.removeDuplicates(); |
| 417 | while (UISettings::values.recent_files.size() > max_recent_files_item) { | 459 | while (UISettings::values.recent_files.size() > max_recent_files_item) { |
| 418 | UISettings::values.recent_files.removeLast(); | 460 | UISettings::values.recent_files.removeLast(); |
| @@ -447,7 +489,7 @@ void GMainWindow::UpdateRecentFiles() { | |||
| 447 | } | 489 | } |
| 448 | 490 | ||
| 449 | void GMainWindow::OnGameListLoadFile(QString game_path) { | 491 | void GMainWindow::OnGameListLoadFile(QString game_path) { |
| 450 | BootGame(game_path.toStdString()); | 492 | BootGame(game_path); |
| 451 | } | 493 | } |
| 452 | 494 | ||
| 453 | void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) { | 495 | void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) { |
| @@ -466,19 +508,25 @@ void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) { | |||
| 466 | } | 508 | } |
| 467 | 509 | ||
| 468 | void GMainWindow::OnMenuLoadFile() { | 510 | void GMainWindow::OnMenuLoadFile() { |
| 469 | QString filename = | 511 | QString extensions; |
| 470 | QFileDialog::getOpenFileName(this, tr("Load File"), UISettings::values.roms_path, | 512 | for (const auto& piece : game_list->supported_file_extensions) |
| 471 | tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)")); | 513 | extensions += "*." + piece + " "; |
| 514 | |||
| 515 | QString file_filter = tr("3DS Executable") + " (" + extensions + ")"; | ||
| 516 | file_filter += ";;" + tr("All Files (*.*)"); | ||
| 517 | |||
| 518 | QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), | ||
| 519 | UISettings::values.roms_path, file_filter); | ||
| 472 | if (!filename.isEmpty()) { | 520 | if (!filename.isEmpty()) { |
| 473 | UISettings::values.roms_path = QFileInfo(filename).path(); | 521 | UISettings::values.roms_path = QFileInfo(filename).path(); |
| 474 | 522 | ||
| 475 | BootGame(filename.toStdString()); | 523 | BootGame(filename); |
| 476 | } | 524 | } |
| 477 | } | 525 | } |
| 478 | 526 | ||
| 479 | void GMainWindow::OnMenuLoadSymbolMap() { | 527 | void GMainWindow::OnMenuLoadSymbolMap() { |
| 480 | QString filename = QFileDialog::getOpenFileName( | 528 | QString filename = QFileDialog::getOpenFileName( |
| 481 | this, tr("Load Symbol Map"), UISettings::values.symbols_path, tr("Symbol map (*)")); | 529 | this, tr("Load Symbol Map"), UISettings::values.symbols_path, tr("Symbol Map (*.*)")); |
| 482 | if (!filename.isEmpty()) { | 530 | if (!filename.isEmpty()) { |
| 483 | UISettings::values.symbols_path = QFileInfo(filename).path(); | 531 | UISettings::values.symbols_path = QFileInfo(filename).path(); |
| 484 | 532 | ||
| @@ -501,7 +549,7 @@ void GMainWindow::OnMenuRecentFile() { | |||
| 501 | QString filename = action->data().toString(); | 549 | QString filename = action->data().toString(); |
| 502 | QFileInfo file_info(filename); | 550 | QFileInfo file_info(filename); |
| 503 | if (file_info.exists()) { | 551 | if (file_info.exists()) { |
| 504 | BootGame(filename.toStdString()); | 552 | BootGame(filename); |
| 505 | } else { | 553 | } else { |
| 506 | // Display an error message and remove the file from the list. | 554 | // Display an error message and remove the file from the list. |
| 507 | QMessageBox::information(this, tr("File not found"), | 555 | QMessageBox::information(this, tr("File not found"), |
| @@ -581,6 +629,23 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() { | |||
| 581 | graphicsSurfaceViewerWidget->show(); | 629 | graphicsSurfaceViewerWidget->show(); |
| 582 | } | 630 | } |
| 583 | 631 | ||
| 632 | void GMainWindow::UpdateStatusBar() { | ||
| 633 | if (emu_thread == nullptr) { | ||
| 634 | status_bar_update_timer.stop(); | ||
| 635 | return; | ||
| 636 | } | ||
| 637 | |||
| 638 | auto results = Core::System::GetInstance().GetAndResetPerfStats(); | ||
| 639 | |||
| 640 | emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); | ||
| 641 | game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); | ||
| 642 | emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); | ||
| 643 | |||
| 644 | emu_speed_label->setVisible(true); | ||
| 645 | game_fps_label->setVisible(true); | ||
| 646 | emu_frametime_label->setVisible(true); | ||
| 647 | } | ||
| 648 | |||
| 584 | bool GMainWindow::ConfirmClose() { | 649 | bool GMainWindow::ConfirmClose() { |
| 585 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | 650 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) |
| 586 | return true; | 651 | return true; |
| @@ -605,7 +670,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) { | |||
| 605 | UISettings::values.microprofile_visible = microProfileDialog->isVisible(); | 670 | UISettings::values.microprofile_visible = microProfileDialog->isVisible(); |
| 606 | #endif | 671 | #endif |
| 607 | UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked(); | 672 | UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked(); |
| 608 | UISettings::values.display_titlebar = ui.actionDisplay_widget_title_bars->isChecked(); | 673 | UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked(); |
| 674 | UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked(); | ||
| 609 | UISettings::values.first_start = false; | 675 | UISettings::values.first_start = false; |
| 610 | 676 | ||
| 611 | game_list->SaveInterfaceLayout(); | 677 | game_list->SaveInterfaceLayout(); |
| @@ -620,6 +686,40 @@ void GMainWindow::closeEvent(QCloseEvent* event) { | |||
| 620 | QWidget::closeEvent(event); | 686 | QWidget::closeEvent(event); |
| 621 | } | 687 | } |
| 622 | 688 | ||
| 689 | static bool IsSingleFileDropEvent(QDropEvent* event) { | ||
| 690 | const QMimeData* mimeData = event->mimeData(); | ||
| 691 | return mimeData->hasUrls() && mimeData->urls().length() == 1; | ||
| 692 | } | ||
| 693 | |||
| 694 | void GMainWindow::dropEvent(QDropEvent* event) { | ||
| 695 | if (IsSingleFileDropEvent(event) && ConfirmChangeGame()) { | ||
| 696 | const QMimeData* mimeData = event->mimeData(); | ||
| 697 | QString filename = mimeData->urls().at(0).toLocalFile(); | ||
| 698 | BootGame(filename); | ||
| 699 | } | ||
| 700 | } | ||
| 701 | |||
| 702 | void GMainWindow::dragEnterEvent(QDragEnterEvent* event) { | ||
| 703 | if (IsSingleFileDropEvent(event)) { | ||
| 704 | event->acceptProposedAction(); | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { | ||
| 709 | event->acceptProposedAction(); | ||
| 710 | } | ||
| 711 | |||
| 712 | bool GMainWindow::ConfirmChangeGame() { | ||
| 713 | if (emu_thread == nullptr) | ||
| 714 | return true; | ||
| 715 | |||
| 716 | auto answer = QMessageBox::question( | ||
| 717 | this, tr("Citra"), | ||
| 718 | tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."), | ||
| 719 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||
| 720 | return answer != QMessageBox::No; | ||
| 721 | } | ||
| 722 | |||
| 623 | #ifdef main | 723 | #ifdef main |
| 624 | #undef main | 724 | #undef main |
| 625 | #endif | 725 | #endif |