MainWindow.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // Copyright 2014 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include <QActionGroup>
  5. #include <QDesktopServices>
  6. #include <QFileDialog>
  7. #include <QMessageBox>
  8. #include <QUrl>
  9. #include "ui_MainWindow.h"
  10. #include "Common/StdMakeUnique.h"
  11. #include "Core/BootManager.h"
  12. #include "Core/ConfigManager.h"
  13. #include "Core/HW/ProcessorInterface.h"
  14. #include "DolphinQt/AboutDialog.h"
  15. #include "DolphinQt/MainWindow.h"
  16. #include "DolphinQt/SystemInfo.h"
  17. #include "DolphinQt/Utils/Resources.h"
  18. #include "DolphinQt/Utils/Utils.h"
  19. #include "VideoCommon/VideoConfig.h"
  20. // The "g_main_window" object as defined in MainWindow.h
  21. DMainWindow* g_main_window = nullptr;
  22. DMainWindow::DMainWindow(QWidget* parent_widget)
  23. : QMainWindow(parent_widget)
  24. {
  25. m_ui = std::make_unique<Ui::DMainWindow>();
  26. m_ui->setupUi(this);
  27. Resources::Init();
  28. UpdateIcons();
  29. setWindowIcon(Resources::GetIcon(Resources::DOLPHIN_LOGO));
  30. // Create the GameList
  31. m_game_tracker = new DGameTracker(this);
  32. m_ui->centralWidget->addWidget(m_game_tracker);
  33. m_game_tracker->ScanForGames();
  34. m_game_tracker->SelectLastBootedGame();
  35. // Setup the GameList style switching actions
  36. QActionGroup* gamelistGroup = new QActionGroup(this);
  37. gamelistGroup->addAction(m_ui->actionListView);
  38. gamelistGroup->addAction(m_ui->actionTreeView);
  39. gamelistGroup->addAction(m_ui->actionGridView);
  40. gamelistGroup->addAction(m_ui->actionIconView);
  41. // TODO: save/load this from user prefs!
  42. m_ui->actionListView->setChecked(true);
  43. OnGameListStyleChanged();
  44. // Connect all the signals/slots
  45. connect(this, SIGNAL(CoreStateChanged(Core::EState)), this, SLOT(OnCoreStateChanged(Core::EState)));
  46. connect(m_ui->actionOpen, SIGNAL(triggered()), this, SLOT(OnOpen()));
  47. connect(m_ui->actionBrowse, SIGNAL(triggered()), this, SLOT(OnBrowse()));
  48. connect(m_ui->actionExit, SIGNAL(triggered()), this, SLOT(OnExit()));
  49. connect(m_ui->actionListView, SIGNAL(triggered()), this, SLOT(OnGameListStyleChanged()));
  50. connect(m_ui->actionTreeView, SIGNAL(triggered()), this, SLOT(OnGameListStyleChanged()));
  51. connect(m_ui->actionGridView, SIGNAL(triggered()), this, SLOT(OnGameListStyleChanged()));
  52. connect(m_ui->actionIconView, SIGNAL(triggered()), this, SLOT(OnGameListStyleChanged()));
  53. connect(m_ui->actionPlay, SIGNAL(triggered()), this, SLOT(OnPlay()));
  54. connect(m_ui->actionPlay_mnu, SIGNAL(triggered()), this, SLOT(OnPlay()));
  55. connect(m_game_tracker, SIGNAL(StartGame()), this, SLOT(OnPlay()));
  56. connect(m_ui->actionStop, SIGNAL(triggered()), this, SLOT(OnStop()));
  57. connect(m_ui->actionStop_mnu, SIGNAL(triggered()), this, SLOT(OnStop()));
  58. connect(m_ui->actionReset, SIGNAL(triggered()), this, SLOT(OnReset()));
  59. connect(m_ui->actionWebsite, SIGNAL(triggered()), this, SLOT(OnOpenWebsite()));
  60. connect(m_ui->actionOnlineDocs, SIGNAL(triggered()), this, SLOT(OnOpenDocs()));
  61. connect(m_ui->actionGitHub, SIGNAL(triggered()), this, SLOT(OnOpenGitHub()));
  62. connect(m_ui->actionSystemInfo, SIGNAL(triggered()), this, SLOT(OnOpenSystemInfo()));
  63. connect(m_ui->actionAbout, SIGNAL(triggered()), this, SLOT(OnOpenAbout()));
  64. connect(m_ui->actionAboutQt, SIGNAL(triggered()), this, SLOT(OnOpenAboutQt()));
  65. // Update GUI items
  66. emit CoreStateChanged(Core::CORE_UNINITIALIZED);
  67. // Platform-specific stuff
  68. #ifdef Q_OS_MACX
  69. m_ui->toolbar->setMovable(false);
  70. #endif
  71. }
  72. DMainWindow::~DMainWindow()
  73. {
  74. }
  75. void DMainWindow::closeEvent(QCloseEvent* ce)
  76. {
  77. Stop();
  78. }
  79. // Emulation
  80. void DMainWindow::StartGame(const QString filename)
  81. {
  82. m_render_widget = std::make_unique<DRenderWidget>();
  83. m_render_widget->setWindowTitle(tr("Dolphin")); // TODO
  84. m_render_widget->setWindowIcon(windowIcon());
  85. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen)
  86. {
  87. m_render_widget->setWindowFlags(m_render_widget->windowFlags() | Qt::BypassWindowManagerHint);
  88. g_Config.bFullscreen = !g_Config.bBorderlessFullscreen;
  89. m_render_widget->showFullScreen();
  90. }
  91. else
  92. {
  93. m_ui->centralWidget->addWidget(m_render_widget.get());
  94. m_ui->centralWidget->setCurrentWidget(m_render_widget.get());
  95. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderWindowAutoSize)
  96. {
  97. // Resize main window to fit render
  98. m_render_widget->setMinimumSize(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowWidth,
  99. SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight);
  100. qApp->processEvents(); // Force a redraw so the window has time to resize
  101. m_render_widget->setMinimumSize(0, 0); // Allow the widget to scale down
  102. }
  103. m_render_widget->adjustSize();
  104. }
  105. if (!BootManager::BootCore(filename.toStdString()))
  106. {
  107. QMessageBox::critical(this, tr("Fatal error"), tr("Failed to init Core"), QMessageBox::Ok);
  108. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen)
  109. m_render_widget->close();
  110. else
  111. m_ui->centralWidget->removeWidget(m_render_widget.get());
  112. m_render_widget.reset();
  113. }
  114. else
  115. {
  116. // TODO: Disable screensaver!
  117. emit CoreStateChanged(Core::CORE_RUN);
  118. }
  119. }
  120. QString DMainWindow::RequestBootFilename()
  121. {
  122. // If a game is already selected, just return the filename
  123. if (m_game_tracker->SelectedGame() != nullptr)
  124. return m_game_tracker->SelectedGame()->GetFileName();
  125. return ShowFileDialog();
  126. }
  127. QString DMainWindow::ShowFileDialog()
  128. {
  129. return QFileDialog::getOpenFileName(this, tr("Open File"), QString(),
  130. tr("All supported ROMs (%1);;All files (*)")
  131. .arg(SL("*.gcm *.iso *.ciso *.gcz *.wbfs *.elf *.dol *.dff *.tmd *.wad")));
  132. }
  133. QString DMainWindow::ShowFolderDialog()
  134. {
  135. return QFileDialog::getExistingDirectory(this, tr("Browse for a directory to add"),
  136. QDir::homePath(),
  137. QFileDialog::ShowDirsOnly);
  138. }
  139. void DMainWindow::DoStartPause()
  140. {
  141. if (Core::GetState() == Core::CORE_RUN)
  142. {
  143. Core::SetState(Core::CORE_PAUSE);
  144. emit CoreStateChanged(Core::CORE_PAUSE);
  145. }
  146. else
  147. {
  148. Core::SetState(Core::CORE_RUN);
  149. emit CoreStateChanged(Core::CORE_RUN);
  150. }
  151. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
  152. m_render_widget->setCursor(Qt::BlankCursor);
  153. }
  154. void DMainWindow::OnOpen()
  155. {
  156. QString filename = ShowFileDialog();
  157. if (!filename.isNull())
  158. StartGame(filename);
  159. }
  160. void DMainWindow::OnBrowse()
  161. {
  162. std::string path = ShowFolderDialog().toStdString();
  163. std::vector<std::string>& iso_folder = SConfig::GetInstance().m_ISOFolder;
  164. if (!path.empty())
  165. {
  166. auto itResult = std::find(iso_folder.begin(), iso_folder.end(), path);
  167. if (itResult == iso_folder.end())
  168. {
  169. iso_folder.push_back(path);
  170. SConfig::GetInstance().SaveSettings();
  171. }
  172. }
  173. m_game_tracker->ScanForGames();
  174. }
  175. void DMainWindow::OnExit()
  176. {
  177. close();
  178. if (Core::GetState() == Core::CORE_UNINITIALIZED || m_isStopping)
  179. return;
  180. Stop();
  181. }
  182. void DMainWindow::OnPlay()
  183. {
  184. if (Core::GetState() != Core::CORE_UNINITIALIZED)
  185. {
  186. DoStartPause();
  187. }
  188. else
  189. {
  190. // initialize Core and boot the game
  191. QString filename = RequestBootFilename();
  192. if (!filename.isNull())
  193. StartGame(filename);
  194. }
  195. }
  196. bool DMainWindow::OnStop()
  197. {
  198. if (Core::GetState() == Core::CORE_UNINITIALIZED || m_isStopping)
  199. return true;
  200. // Ask for confirmation in case the user accidentally clicked Stop / Escape
  201. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop)
  202. {
  203. // Pause emulation
  204. Core::SetState(Core::CORE_PAUSE);
  205. emit CoreStateChanged(Core::CORE_PAUSE);
  206. QMessageBox::StandardButton ret = QMessageBox::question(m_render_widget.get(), tr("Please confirm..."),
  207. tr("Do you want to stop the current emulation?"),
  208. QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
  209. if (ret == QMessageBox::No)
  210. {
  211. DoStartPause();
  212. return false;
  213. }
  214. }
  215. return Stop();
  216. }
  217. bool DMainWindow::Stop()
  218. {
  219. m_isStopping = true;
  220. // TODO: Movie stuff
  221. // TODO: Show the author/description dialog here
  222. BootManager::Stop();
  223. // TODO: Allow screensaver again
  224. // TODO: Restore original window title
  225. // TODO:
  226. // If batch mode was specified on the command-line, exit now.
  227. //if (m_bBatchMode)
  228. // Close(true);
  229. if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen)
  230. m_render_widget->close();
  231. else
  232. m_ui->centralWidget->removeWidget(m_render_widget.get());
  233. m_render_widget.reset();
  234. emit CoreStateChanged(Core::CORE_UNINITIALIZED);
  235. m_isStopping = false;
  236. return true;
  237. }
  238. void DMainWindow::OnReset()
  239. {
  240. // TODO: Movie needs to be reset here
  241. ProcessorInterface::ResetButton_Tap();
  242. }
  243. void DMainWindow::OnGameListStyleChanged()
  244. {
  245. if (m_ui->actionListView->isChecked())
  246. m_game_tracker->SetViewStyle(STYLE_LIST);
  247. else if (m_ui->actionTreeView->isChecked())
  248. m_game_tracker->SetViewStyle(STYLE_TREE);
  249. else if (m_ui->actionGridView->isChecked())
  250. m_game_tracker->SetViewStyle(STYLE_GRID);
  251. else if (m_ui->actionIconView->isChecked())
  252. m_game_tracker->SetViewStyle(STYLE_ICON);
  253. }
  254. void DMainWindow::OnCoreStateChanged(Core::EState state)
  255. {
  256. bool is_not_initialized = (state == Core::CORE_UNINITIALIZED);
  257. bool is_running = (state == Core::CORE_RUN);
  258. bool is_paused = (state == Core::CORE_PAUSE);
  259. // Update the toolbar
  260. m_ui->actionPlay->setEnabled(is_not_initialized || is_running || is_paused);
  261. if (is_running)
  262. {
  263. m_ui->actionPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PAUSE));
  264. m_ui->actionPlay->setText(tr("Pause"));
  265. m_ui->actionPlay_mnu->setText(tr("Pause"));
  266. }
  267. else if (is_paused || is_not_initialized)
  268. {
  269. m_ui->actionPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PLAY));
  270. m_ui->actionPlay->setText(tr("Play"));
  271. m_ui->actionPlay_mnu->setText(tr("Play"));
  272. }
  273. m_ui->actionStop->setEnabled(!is_not_initialized);
  274. m_ui->actionOpen->setEnabled(is_not_initialized);
  275. m_game_tracker->setEnabled(is_not_initialized);
  276. }
  277. // Update all the icons used in DMainWindow with fresh ones from
  278. // "Resources". Call this function after changing the icon theme.
  279. void DMainWindow::UpdateIcons()
  280. {
  281. // Play/Pause is handled in OnCoreStateChanged().
  282. m_ui->actionStop->setIcon(Resources::GetIcon(Resources::TOOLBAR_STOP));
  283. }
  284. // Help menu
  285. void DMainWindow::OnOpenWebsite()
  286. {
  287. QDesktopServices::openUrl(QUrl(SL("https://dolphin-emu.org/")));
  288. }
  289. void DMainWindow::OnOpenDocs()
  290. {
  291. QDesktopServices::openUrl(QUrl(SL("https://dolphin-emu.org/docs/guides/")));
  292. }
  293. void DMainWindow::OnOpenGitHub()
  294. {
  295. QDesktopServices::openUrl(QUrl(SL("https://github.com/dolphin-emu/dolphin")));
  296. }
  297. void DMainWindow::OnOpenSystemInfo()
  298. {
  299. DSystemInfo* dlg = new DSystemInfo(this);
  300. dlg->open();
  301. }
  302. void DMainWindow::OnOpenAbout()
  303. {
  304. DAboutDialog* dlg = new DAboutDialog(this);
  305. dlg->open();
  306. }
  307. void DMainWindow::OnOpenAboutQt()
  308. {
  309. QApplication::aboutQt();
  310. }