mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
380 lines
10 KiB
C++
380 lines
10 KiB
C++
// Copyright 2014 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <memory>
|
|
#include <QActionGroup>
|
|
#include <QCloseEvent>
|
|
#include <QDesktopServices>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QUrl>
|
|
|
|
#include "ui_MainWindow.h"
|
|
|
|
#include "Core/BootManager.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/HW/ProcessorInterface.h"
|
|
|
|
#include "DolphinQt/AboutDialog.h"
|
|
#include "DolphinQt/Host.h"
|
|
#include "DolphinQt/MainWindow.h"
|
|
#include "DolphinQt/SystemInfo.h"
|
|
#include "DolphinQt/Utils/Resources.h"
|
|
|
|
#include "VideoCommon/VideoConfig.h"
|
|
|
|
// The "g_main_window" object as defined in MainWindow.h
|
|
DMainWindow* g_main_window = nullptr;
|
|
|
|
DMainWindow::DMainWindow(QWidget* parent_widget)
|
|
: QMainWindow(parent_widget)
|
|
{
|
|
m_ui = std::make_unique<Ui::DMainWindow>();
|
|
m_ui->setupUi(this);
|
|
|
|
Resources::Init();
|
|
UpdateIcons();
|
|
setWindowIcon(Resources::GetIcon(Resources::DOLPHIN_LOGO));
|
|
|
|
// Create the GameList
|
|
m_game_tracker = new DGameTracker(this);
|
|
m_ui->centralWidget->addWidget(m_game_tracker);
|
|
m_game_tracker->ScanForGames();
|
|
m_game_tracker->SelectLastBootedGame();
|
|
|
|
// Setup the GameList style switching actions
|
|
QActionGroup* gamelistGroup = new QActionGroup(this);
|
|
gamelistGroup->addAction(m_ui->actionListView);
|
|
gamelistGroup->addAction(m_ui->actionTreeView);
|
|
gamelistGroup->addAction(m_ui->actionGridView);
|
|
gamelistGroup->addAction(m_ui->actionIconView);
|
|
|
|
// TODO: save/load this from user prefs!
|
|
m_ui->actionListView->setChecked(true);
|
|
OnGameListStyleChanged();
|
|
|
|
// Connect all the signals/slots
|
|
connect(this, &DMainWindow::CoreStateChanged, this, &DMainWindow::OnCoreStateChanged);
|
|
|
|
connect(m_ui->actionOpen, &QAction::triggered, this, [&]() {
|
|
QString filename = ShowFileDialog();
|
|
if (!filename.isNull())
|
|
StartGame(filename);
|
|
});
|
|
connect(m_ui->actionBrowse, &QAction::triggered, this, &DMainWindow::OnBrowse);
|
|
connect(m_ui->actionExit, &QAction::triggered, this, [&]() {
|
|
close();
|
|
});
|
|
|
|
connect(m_ui->actionListView, &QAction::triggered, this, &DMainWindow::OnGameListStyleChanged);
|
|
connect(m_ui->actionTreeView, &QAction::triggered, this, &DMainWindow::OnGameListStyleChanged);
|
|
connect(m_ui->actionGridView, &QAction::triggered, this, &DMainWindow::OnGameListStyleChanged);
|
|
connect(m_ui->actionIconView, &QAction::triggered, this, &DMainWindow::OnGameListStyleChanged);
|
|
|
|
connect(m_ui->actionPlay, &QAction::triggered, this, &DMainWindow::OnPlay);
|
|
connect(m_game_tracker, &DGameTracker::StartGame, this, &DMainWindow::OnPlay);
|
|
connect(m_ui->actionStop, &QAction::triggered, this, &DMainWindow::OnStop);
|
|
connect(m_ui->actionReset, &QAction::triggered, this, &DMainWindow::OnReset);
|
|
connect(m_ui->actionScreenshot, &QAction::triggered, this, []() {
|
|
Core::SaveScreenShot();
|
|
});
|
|
|
|
connect(m_ui->actionWebsite, &QAction::triggered, this, []() {
|
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/")));
|
|
});
|
|
connect(m_ui->actionOnlineDocs, &QAction::triggered, this, []() {
|
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/docs/guides/")));
|
|
});
|
|
connect(m_ui->actionGitHub, &QAction::triggered, this, []() {
|
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/dolphin-emu/dolphin")));
|
|
});
|
|
connect(m_ui->actionSystemInfo, &QAction::triggered, this, [&]() {
|
|
DSystemInfo* dlg = new DSystemInfo(this);
|
|
dlg->open();
|
|
});
|
|
connect(m_ui->actionAbout, &QAction::triggered, this, [&]() {
|
|
DAboutDialog* dlg = new DAboutDialog(this);
|
|
dlg->open();
|
|
});
|
|
connect(m_ui->actionAboutQt, &QAction::triggered, this, [&]() {
|
|
QApplication::aboutQt();
|
|
});
|
|
|
|
// Update GUI items
|
|
emit CoreStateChanged(Core::CORE_UNINITIALIZED);
|
|
|
|
// Platform-specific stuff
|
|
#ifdef Q_OS_MACX
|
|
m_ui->toolbar->setMovable(false);
|
|
#endif
|
|
}
|
|
|
|
DMainWindow::~DMainWindow()
|
|
{
|
|
}
|
|
|
|
bool DMainWindow::event(QEvent* e)
|
|
{
|
|
if (e->type() == HostEvent::TitleEvent)
|
|
{
|
|
HostTitleEvent* htev = (HostTitleEvent*)e;
|
|
m_ui->statusbar->showMessage(QString::fromStdString(htev->m_title), 1500);
|
|
return true;
|
|
}
|
|
return QMainWindow::event(e);
|
|
}
|
|
|
|
void DMainWindow::closeEvent(QCloseEvent* ce)
|
|
{
|
|
if (!OnStop())
|
|
ce->ignore();
|
|
else
|
|
QMainWindow::closeEvent(ce);
|
|
}
|
|
|
|
// Emulation
|
|
|
|
void DMainWindow::StartGame(const QString filename)
|
|
{
|
|
m_render_widget = std::make_unique<DRenderWidget>();
|
|
m_render_widget->setWindowTitle(tr("Dolphin")); // TODO
|
|
m_render_widget->setWindowIcon(windowIcon());
|
|
|
|
if (SConfig::GetInstance().bFullscreen)
|
|
{
|
|
m_render_widget->setWindowFlags(m_render_widget->windowFlags() | Qt::BypassWindowManagerHint);
|
|
g_Config.bFullscreen = !g_Config.bBorderlessFullscreen;
|
|
m_render_widget->showFullScreen();
|
|
}
|
|
else
|
|
{
|
|
m_ui->centralWidget->addWidget(m_render_widget.get());
|
|
m_ui->centralWidget->setCurrentWidget(m_render_widget.get());
|
|
|
|
if (SConfig::GetInstance().bRenderWindowAutoSize)
|
|
{
|
|
// Resize main window to fit render
|
|
m_render_widget->setMinimumSize(SConfig::GetInstance().iRenderWindowWidth,
|
|
SConfig::GetInstance().iRenderWindowHeight);
|
|
qApp->processEvents(); // Force a redraw so the window has time to resize
|
|
m_render_widget->setMinimumSize(0, 0); // Allow the widget to scale down
|
|
}
|
|
m_render_widget->adjustSize();
|
|
}
|
|
|
|
if (!BootManager::BootCore(filename.toStdString()))
|
|
{
|
|
QMessageBox::critical(this, tr("Fatal error"), tr("Failed to init Core"), QMessageBox::Ok);
|
|
if (SConfig::GetInstance().bFullscreen)
|
|
m_render_widget->close();
|
|
else
|
|
m_ui->centralWidget->removeWidget(m_render_widget.get());
|
|
m_render_widget.reset();
|
|
}
|
|
else
|
|
{
|
|
DisableScreensaver();
|
|
emit CoreStateChanged(Core::CORE_RUN);
|
|
}
|
|
}
|
|
|
|
void DMainWindow::DisableScreensaver()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
// Prevents Windows from sleeping or turning off the display
|
|
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
|
|
#endif
|
|
}
|
|
|
|
void DMainWindow::EnableScreensaver()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
// Allows Windows to sleep and turn off the display
|
|
SetThreadExecutionState(ES_CONTINUOUS);
|
|
#endif
|
|
}
|
|
|
|
QString DMainWindow::RequestBootFilename()
|
|
{
|
|
// If a game is already selected, just return the filename
|
|
if (m_game_tracker->SelectedGame() != nullptr)
|
|
return m_game_tracker->SelectedGame()->GetFileName();
|
|
|
|
return ShowFileDialog();
|
|
}
|
|
|
|
QString DMainWindow::ShowFileDialog()
|
|
{
|
|
return QFileDialog::getOpenFileName(this, tr("Open File"), QString(),
|
|
tr("All supported ROMs (%1);;All files (*)")
|
|
.arg(QStringLiteral("*.gcm *.iso *.ciso *.gcz *.wbfs *.elf *.dol *.dff *.tmd *.wad")));
|
|
}
|
|
|
|
QString DMainWindow::ShowFolderDialog()
|
|
{
|
|
return QFileDialog::getExistingDirectory(this, tr("Browse for a directory to add"),
|
|
QDir::homePath(), QFileDialog::ShowDirsOnly);
|
|
}
|
|
|
|
void DMainWindow::DoStartPause()
|
|
{
|
|
if (Core::GetState() == Core::CORE_RUN)
|
|
{
|
|
Core::SetState(Core::CORE_PAUSE);
|
|
emit CoreStateChanged(Core::CORE_PAUSE);
|
|
}
|
|
else
|
|
{
|
|
Core::SetState(Core::CORE_RUN);
|
|
emit CoreStateChanged(Core::CORE_RUN);
|
|
}
|
|
if (SConfig::GetInstance().bHideCursor)
|
|
m_render_widget->setCursor(Qt::BlankCursor);
|
|
}
|
|
|
|
void DMainWindow::OnBrowse()
|
|
{
|
|
std::string path = ShowFolderDialog().toStdString();
|
|
std::vector<std::string>& iso_folder = SConfig::GetInstance().m_ISOFolder;
|
|
if (!path.empty())
|
|
{
|
|
auto itResult = std::find(iso_folder.begin(), iso_folder.end(), path);
|
|
|
|
if (itResult == iso_folder.end())
|
|
{
|
|
iso_folder.push_back(path);
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|
|
}
|
|
m_game_tracker->ScanForGames();
|
|
}
|
|
|
|
void DMainWindow::OnPlay()
|
|
{
|
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
|
{
|
|
DoStartPause();
|
|
}
|
|
else
|
|
{
|
|
// initialize Core and boot the game
|
|
QString filename = RequestBootFilename();
|
|
if (!filename.isNull())
|
|
StartGame(filename);
|
|
}
|
|
}
|
|
|
|
bool DMainWindow::OnStop()
|
|
{
|
|
if (Core::GetState() == Core::CORE_UNINITIALIZED || m_isStopping)
|
|
return true;
|
|
|
|
// Ask for confirmation in case the user accidentally clicked Stop / Escape
|
|
if (SConfig::GetInstance().bConfirmStop)
|
|
{
|
|
// Pause emulation if it isn't already
|
|
bool wasPaused = false;
|
|
if (Core::GetState() == Core::CORE_PAUSE)
|
|
{
|
|
wasPaused = true;
|
|
}
|
|
else
|
|
{
|
|
Core::SetState(Core::CORE_PAUSE);
|
|
emit CoreStateChanged(Core::CORE_PAUSE);
|
|
}
|
|
|
|
QMessageBox::StandardButton ret = QMessageBox::question(m_render_widget.get(), tr("Please confirm..."),
|
|
tr("Do you want to stop the current emulation?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
|
|
if (ret == QMessageBox::No)
|
|
{
|
|
if (!wasPaused)
|
|
DoStartPause();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return Stop();
|
|
}
|
|
|
|
bool DMainWindow::Stop()
|
|
{
|
|
m_isStopping = true;
|
|
|
|
// TODO: Movie stuff
|
|
// TODO: Show the author/description dialog here
|
|
|
|
BootManager::Stop();
|
|
EnableScreensaver();
|
|
// TODO: Restore original window title
|
|
|
|
// TODO:
|
|
// If batch mode was specified on the command-line, exit now.
|
|
//if (m_bBatchMode)
|
|
// Close(true);
|
|
|
|
if (SConfig::GetInstance().bFullscreen)
|
|
m_render_widget->close();
|
|
else
|
|
m_ui->centralWidget->removeWidget(m_render_widget.get());
|
|
m_render_widget.reset();
|
|
|
|
emit CoreStateChanged(Core::CORE_UNINITIALIZED);
|
|
m_isStopping = false;
|
|
return true;
|
|
}
|
|
|
|
void DMainWindow::OnReset()
|
|
{
|
|
// TODO: Movie needs to be reset here
|
|
ProcessorInterface::ResetButton_Tap();
|
|
}
|
|
|
|
void DMainWindow::OnGameListStyleChanged()
|
|
{
|
|
if (m_ui->actionListView->isChecked())
|
|
m_game_tracker->SetViewStyle(STYLE_LIST);
|
|
else if (m_ui->actionTreeView->isChecked())
|
|
m_game_tracker->SetViewStyle(STYLE_TREE);
|
|
else if (m_ui->actionGridView->isChecked())
|
|
m_game_tracker->SetViewStyle(STYLE_GRID);
|
|
else if (m_ui->actionIconView->isChecked())
|
|
m_game_tracker->SetViewStyle(STYLE_ICON);
|
|
}
|
|
|
|
void DMainWindow::OnCoreStateChanged(Core::EState state)
|
|
{
|
|
bool is_not_initialized = (state == Core::CORE_UNINITIALIZED);
|
|
bool is_running = (state == Core::CORE_RUN);
|
|
bool is_paused = (state == Core::CORE_PAUSE);
|
|
|
|
// Update the toolbar
|
|
m_ui->actionPlay->setEnabled(is_not_initialized || is_running || is_paused);
|
|
if (is_running)
|
|
{
|
|
m_ui->actionPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PAUSE));
|
|
m_ui->actionPlay->setText(tr("Pause"));
|
|
}
|
|
else if (is_paused || is_not_initialized)
|
|
{
|
|
m_ui->actionPlay->setIcon(Resources::GetIcon(Resources::TOOLBAR_PLAY));
|
|
m_ui->actionPlay->setText(tr("Play"));
|
|
}
|
|
|
|
m_ui->actionStop->setEnabled(!is_not_initialized);
|
|
m_ui->actionOpen->setEnabled(is_not_initialized);
|
|
m_game_tracker->setEnabled(is_not_initialized);
|
|
}
|
|
|
|
// Update all the icons used in DMainWindow with fresh ones from
|
|
// "Resources". Call this function after changing the icon theme.
|
|
void DMainWindow::UpdateIcons()
|
|
{
|
|
// Play/Pause is handled in OnCoreStateChanged().
|
|
m_ui->actionStop->setIcon(Resources::GetIcon(Resources::TOOLBAR_STOP));
|
|
m_ui->actionScreenshot->setIcon(Resources::GetIcon(Resources::TOOLBAR_SCREENSHOT));
|
|
}
|