summaryrefslogtreecommitdiff
path: root/src/citra_qt/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/main.cpp')
-rw-r--r--src/citra_qt/main.cpp242
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
55GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { 55GMainWindow::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
120void 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
143void 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
166void GMainWindow::InitializeRecentFileMenuActions() { 194void 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
222void GMainWindow::ConnectWidgetEvents() { 253void 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*))); 265void 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
255void GMainWindow::OnDisplayTitleBars(bool show) { 288void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -272,7 +305,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
272 } 305 }
273} 306}
274 307
275bool GMainWindow::LoadROM(const std::string& filename) { 308bool 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
338void GMainWindow::BootGame(const std::string& filename) { 372void 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
414void GMainWindow::StoreRecentFile(const std::string& filename) { 456void 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
449void GMainWindow::OnGameListLoadFile(QString game_path) { 491void GMainWindow::OnGameListLoadFile(QString game_path) {
450 BootGame(game_path.toStdString()); 492 BootGame(game_path);
451} 493}
452 494
453void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) { 495void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) {
@@ -466,19 +508,25 @@ void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) {
466} 508}
467 509
468void GMainWindow::OnMenuLoadFile() { 510void 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
479void GMainWindow::OnMenuLoadSymbolMap() { 527void 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
632void 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
584bool GMainWindow::ConfirmClose() { 649bool 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
689static bool IsSingleFileDropEvent(QDropEvent* event) {
690 const QMimeData* mimeData = event->mimeData();
691 return mimeData->hasUrls() && mimeData->urls().length() == 1;
692}
693
694void 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
702void GMainWindow::dragEnterEvent(QDragEnterEvent* event) {
703 if (IsSingleFileDropEvent(event)) {
704 event->acceptProposedAction();
705 }
706}
707
708void GMainWindow::dragMoveEvent(QDragMoveEvent* event) {
709 event->acceptProposedAction();
710}
711
712bool 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