forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			363 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2014 Dolphin Emulator Project
 | 
						|
// Licensed under GPLv2+
 | 
						|
// Refer to the license.txt file included.
 | 
						|
 | 
						|
#include <memory>
 | 
						|
#include <QActionGroup>
 | 
						|
#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/MainWindow.h"
 | 
						|
#include "DolphinQt/SystemInfo.h"
 | 
						|
#include "DolphinQt/Utils/Resources.h"
 | 
						|
#include "DolphinQt/Utils/Utils.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, &DMainWindow::OnExit);
 | 
						|
 | 
						|
	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_ui->actionPlay_mnu, &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->actionStop_mnu, &QAction::triggered, this, &DMainWindow::OnStop);
 | 
						|
	connect(m_ui->actionReset, &QAction::triggered, this, &DMainWindow::OnReset);
 | 
						|
 | 
						|
	connect(m_ui->actionWebsite, &QAction::triggered, this, [&]() {
 | 
						|
		QDesktopServices::openUrl(QUrl(SL("https://dolphin-emu.org/")));
 | 
						|
	});
 | 
						|
	connect(m_ui->actionOnlineDocs, &QAction::triggered, this, [&]() {
 | 
						|
		QDesktopServices::openUrl(QUrl(SL("https://dolphin-emu.org/docs/guides/")));
 | 
						|
	});
 | 
						|
	connect(m_ui->actionGitHub, &QAction::triggered, this, [&]() {
 | 
						|
		QDesktopServices::openUrl(QUrl(SL("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()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void DMainWindow::closeEvent(QCloseEvent* ce)
 | 
						|
{
 | 
						|
	Stop();
 | 
						|
}
 | 
						|
 | 
						|
// 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(SL("*.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::OnExit()
 | 
						|
{
 | 
						|
	close();
 | 
						|
	if (Core::GetState() == Core::CORE_UNINITIALIZED || m_isStopping)
 | 
						|
		return;
 | 
						|
	Stop();
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
		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)
 | 
						|
		{
 | 
						|
			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"));
 | 
						|
		m_ui->actionPlay_mnu->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->actionPlay_mnu->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));
 | 
						|
}
 |