Play-/Source/ui_unix/mainwindow.cpp

516 lines
16 KiB
C++
Raw Normal View History

2016-09-06 00:12:56 +01:00
#include "mainwindow.h"
2016-08-23 00:54:10 +01:00
#include "settingsdialog.h"
2016-08-10 14:56:16 +01:00
#include "memorycardmanagerdialog.h"
2016-07-01 05:21:58 +03:00
#include "openglwindow.h"
2016-07-26 15:06:37 +01:00
#include <QDateTime>
#include <QFileDialog>
2016-08-23 00:54:10 +01:00
#include <QTimer>
2016-07-01 05:21:58 +03:00
#include <QWindow>
2016-07-26 15:06:37 +01:00
#include <QMessageBox>
2016-09-06 00:03:02 +01:00
#include <QStorageInfo>
2016-07-01 05:21:58 +03:00
#include "GSH_OpenGLQt.h"
2016-08-23 00:54:10 +01:00
#include "tools/PsfPlayer/Source/SH_OpenAL.h"
2016-07-26 15:06:37 +01:00
#include "DiskUtils.h"
#include "PathUtils.h"
2016-08-10 16:29:40 +01:00
#include <zlib.h>
#include <boost/version.hpp>
2016-07-26 15:06:37 +01:00
2016-08-23 00:54:10 +01:00
#include "PreferenceDefs.h"
2017-04-09 06:50:07 +01:00
#include "ScreenShotUtils.h"
2016-09-06 00:12:56 +01:00
#include "ui_mainwindow.h"
2016-09-06 00:03:02 +01:00
#include "vfsmanagerdialog.h"
2016-09-06 00:23:31 +01:00
#include "controllerconfigdialog.h"
2016-09-06 00:12:56 +01:00
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
2016-07-01 05:21:58 +03:00
2016-08-10 16:42:37 +01:00
m_openglpanel = new OpenGLWindow;
QWidget * container = QWidget::createWindowContainer(m_openglpanel);
2016-07-01 05:21:58 +03:00
ui->gridLayout->addWidget(container);
2016-08-10 16:42:37 +01:00
connect(m_openglpanel, SIGNAL(heightChanged(int)), this, SLOT(openGLWindow_resized()));
connect(m_openglpanel, SIGNAL(widthChanged(int)), this, SLOT(openGLWindow_resized()));
2016-07-01 05:21:58 +03:00
2016-08-10 16:42:37 +01:00
connect(m_openglpanel, SIGNAL(keyUp(QKeyEvent*)), this, SLOT(keyReleaseEvent(QKeyEvent*)));
connect(m_openglpanel, SIGNAL(keyDown(QKeyEvent*)), this, SLOT(keyPressEvent(QKeyEvent*)));
2016-07-26 15:06:37 +01:00
2016-08-10 16:42:37 +01:00
connect(m_openglpanel, SIGNAL(focusOut(QFocusEvent*)), this, SLOT(focusOutEvent(QFocusEvent*)));
connect(m_openglpanel, SIGNAL(focusIn(QFocusEvent*)), this, SLOT(focusInEvent(QFocusEvent*)));
2016-07-29 18:31:09 +01:00
2017-04-22 19:46:31 +01:00
connect(m_openglpanel, SIGNAL(doubleClick(QMouseEvent*)), this, SLOT(doubleClickEvent(QMouseEvent*)));
RegisterPreferences();
2016-07-29 18:31:09 +01:00
m_pauseFocusLost = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST);
2018-03-03 21:52:44 +00:00
auto last_path = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_CDROM0_PATH);
if (boost::filesystem::exists(last_path))
{
last_path = last_path.parent_path();
m_lastpath = QString(last_path.native().c_str());
}
2016-07-29 18:31:09 +01:00
2016-08-10 16:42:37 +01:00
CreateStatusBar();
2016-07-27 13:47:50 +01:00
UpdateUI();
2016-07-29 18:31:09 +01:00
2016-09-06 00:12:56 +01:00
}
MainWindow::~MainWindow()
{
2016-07-29 19:18:16 +01:00
CAppConfig::GetInstance().Save();
m_GPDL.reset();
2016-08-23 00:58:47 +01:00
if (g_virtualMachine != nullptr)
{
g_virtualMachine->Pause();
g_virtualMachine->DestroyPadHandler();
g_virtualMachine->DestroyGSHandler();
g_virtualMachine->DestroySoundHandler();
g_virtualMachine->Destroy();
delete g_virtualMachine;
g_virtualMachine = nullptr;
}
delete m_InputBindingManager;
delete ui;
}
void MainWindow::showEvent(QShowEvent* event)
{
QMainWindow::showEvent(event);
2016-08-10 16:42:37 +01:00
InitEmu();
}
2016-08-10 16:42:37 +01:00
void MainWindow::InitEmu()
2016-08-02 02:50:26 +01:00
{
g_virtualMachine = new CPS2VM();
g_virtualMachine->Initialize();
2016-08-10 16:42:37 +01:00
g_virtualMachine->CreateGSHandler(CGSH_OpenGLQt::GetFactoryFunction(m_openglpanel));
SetupSoundHandler();
2016-07-26 00:52:31 +01:00
m_InputBindingManager = new CInputBindingManager(CAppConfig::GetInstance());
g_virtualMachine->CreatePadHandler(CPH_HidUnix::GetFactoryFunction(m_InputBindingManager));
2016-08-23 00:54:10 +01:00
auto onInput = [=](std::array<uint32, 6> device, int code, int value, int type, const input_absinfo *abs)->void
{
if(m_InputBindingManager != nullptr)
{
m_InputBindingManager->OnInputEventReceived(device, code, value);
}
};
m_GPDL = std::make_unique<CGamePadDeviceListener>(onInput);
2016-08-23 00:54:10 +01:00
StatsManager = new CStatsManager();
g_virtualMachine->m_ee->m_gs->OnNewFrame.connect(std::bind(&CStatsManager::OnNewFrame, StatsManager, std::placeholders::_1));
2016-08-23 00:54:10 +01:00
g_virtualMachine->OnRunningStateChange.connect(std::bind(&MainWindow::OnRunningStateChange, this));
g_virtualMachine->m_ee->m_os->OnExecutableChange.connect(std::bind(&MainWindow::OnExecutableChange, this));
}
2016-08-10 16:42:37 +01:00
void MainWindow::SetOpenGlPanelSize()
2016-09-06 00:12:56 +01:00
{
2016-07-01 05:21:58 +03:00
openGLWindow_resized();
}
2016-08-10 16:42:37 +01:00
void MainWindow::SetupSoundHandler()
2016-08-23 00:54:10 +01:00
{
2016-08-02 02:50:26 +01:00
if(g_virtualMachine != nullptr)
{
2016-08-23 00:54:10 +01:00
bool audioEnabled = CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT);
if(audioEnabled)
{
g_virtualMachine->CreateSoundHandler(&CSH_OpenAL::HandlerFactory);
}
else
{
g_virtualMachine->DestroySoundHandler();
}
}
}
2016-07-01 05:21:58 +03:00
void MainWindow::openGLWindow_resized()
{
if (g_virtualMachine != nullptr && g_virtualMachine->m_ee != nullptr && g_virtualMachine->m_ee->m_gs != nullptr )
{
2016-08-10 16:42:37 +01:00
GLint w = m_openglpanel->size().width(), h = m_openglpanel->size().height();
CGSHandler::PRESENTATION_PARAMS presentationParams;
presentationParams.mode = (CGSHandler::PRESENTATION_MODE)CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSHANDLER_PRESENTATION_MODE);
presentationParams.windowWidth = w;
presentationParams.windowHeight = h;
g_virtualMachine->m_ee->m_gs->SetPresentationParams(presentationParams);
g_virtualMachine->m_ee->m_gs->Flip();
}
}
void MainWindow::on_actionOpen_Game_triggered()
{
QFileDialog dialog(this);
dialog.setDirectory(m_lastpath);
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(tr("All supported types(*.iso *.bin *.isz *.cso);;UltraISO Compressed Disk Images (*.isz);;CISO Compressed Disk Images (*.cso);;All files (*.*)"));
if (dialog.exec())
{
auto fileName = dialog.selectedFiles().first();
m_lastpath = QFileInfo(fileName).path();
2018-03-03 21:14:18 +00:00
CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, fileName.toStdString());
2016-07-03 20:55:03 +03:00
if (g_virtualMachine != nullptr)
2016-07-26 15:06:37 +01:00
{
2016-07-03 20:55:03 +03:00
try
{
m_lastOpenCommand = lastOpenCommand(BootType::CD, fileName.toStdString());
2016-07-29 19:19:27 +01:00
BootCDROM();
2016-07-03 20:55:03 +03:00
} catch( const std::exception& e) {
QMessageBox messageBox;
messageBox.critical(0,"Error",e.what());
messageBox.show();
}
2016-07-26 15:06:37 +01:00
}
}
}
void MainWindow::on_actionBoot_ELF_triggered()
{
QFileDialog dialog(this);
dialog.setDirectory(m_lastpath);
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(tr("ELF files (*.elf)"));
if (dialog.exec())
{
auto fileName = dialog.selectedFiles().first();
m_lastpath = QFileInfo(fileName).path();
if (g_virtualMachine != nullptr)
{
2016-07-26 15:06:37 +01:00
try
{
m_lastOpenCommand = lastOpenCommand(BootType::ELF, fileName.toStdString());
2016-07-29 19:19:27 +01:00
BootElf(fileName.toStdString().c_str());
2016-07-26 15:06:37 +01:00
} catch( const std::exception& e) {
QMessageBox messageBox;
messageBox.critical(0,"Error",e.what());
messageBox.show();
}
}
}
}
2016-07-29 19:19:27 +01:00
void MainWindow::BootElf(const char* fileName)
{
g_virtualMachine->Pause();
g_virtualMachine->Reset();
g_virtualMachine->m_ee->m_os->BootFromFile(fileName);
g_virtualMachine->Resume();
}
void MainWindow::BootCDROM()
{
g_virtualMachine->Pause();
g_virtualMachine->Reset();
g_virtualMachine->m_ee->m_os->BootFromCDROM();
g_virtualMachine->Resume();
}
void MainWindow::on_actionExit_triggered()
{
2016-08-23 00:58:47 +01:00
close();
2016-09-06 00:12:56 +01:00
}
2016-07-26 00:52:31 +01:00
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->key() != Qt::Key_Escape && m_InputBindingManager != nullptr)
{
m_InputBindingManager->OnInputEventReceived({0}, event->key(), 1);
}
2016-07-26 00:52:31 +01:00
}
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
2017-04-22 19:46:31 +01:00
if(event->key() == Qt::Key_Escape)
{
if(isFullScreen()) {
toggleFullscreen();
}
return;
}
if(m_InputBindingManager != nullptr)
{
m_InputBindingManager->OnInputEventReceived({0}, event->key(), 0);
}
2016-07-26 00:52:31 +01:00
}
2016-08-23 00:54:10 +01:00
2016-08-10 16:42:37 +01:00
void MainWindow::CreateStatusBar()
2016-08-23 00:54:10 +01:00
{
2017-02-19 15:00:25 +00:00
gameIDLabel = new QLabel(" GameID ");
gameIDLabel->setAlignment(Qt::AlignHCenter);
gameIDLabel->setMinimumSize(gameIDLabel->sizeHint());
2016-08-23 00:54:10 +01:00
fpsLabel = new QLabel(" fps:00 ");
fpsLabel->setAlignment(Qt::AlignHCenter);
fpsLabel->setMinimumSize(fpsLabel->sizeHint());
2016-08-10 16:42:37 +01:00
m_dcLabel = new QLabel(" dc:0000 ");
m_dcLabel->setAlignment(Qt::AlignHCenter);
m_dcLabel->setMinimumSize(m_dcLabel->sizeHint());
2016-08-23 00:54:10 +01:00
2016-08-10 16:42:37 +01:00
m_stateLabel = new QLabel(" Paused ");
m_stateLabel->setAlignment(Qt::AlignHCenter);
m_stateLabel->setMinimumSize(m_dcLabel->sizeHint());
2017-03-25 21:53:28 +00:00
m_msgLabel = new ElidedLabel();
m_msgLabel->setAlignment(Qt::AlignLeft);
QFontMetrics fm(m_msgLabel->font());
m_msgLabel->setMinimumSize(fm.boundingRect("...").size());
m_msgLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
2016-08-10 16:42:37 +01:00
statusBar()->addWidget(m_stateLabel);
2016-08-23 00:54:10 +01:00
statusBar()->addWidget(fpsLabel);
2016-08-10 16:42:37 +01:00
statusBar()->addWidget(m_dcLabel);
2017-03-25 21:53:28 +00:00
statusBar()->addWidget(m_msgLabel, 1);
statusBar()->addWidget(gameIDLabel);
2016-08-10 16:42:37 +01:00
m_fpstimer = new QTimer(this);
connect(m_fpstimer, SIGNAL(timeout()), this, SLOT(setFPS()));
m_fpstimer->start(1000);
2016-08-23 00:54:10 +01:00
}
void MainWindow::setFPS()
{
int frames = StatsManager->GetFrames();
int drawCalls = StatsManager->GetDrawCalls();
int dcpf = (frames != 0) ? (drawCalls / frames) : 0;
//fprintf(stderr, "%d f/s, %d dc/f\n", frames, dcpf);
StatsManager->ClearStats();
fpsLabel->setText(QString(" fps: %1 ").arg(frames));
2016-08-10 16:42:37 +01:00
m_dcLabel->setText(QString(" dc: %1 ").arg(dcpf));
2016-08-23 00:54:10 +01:00
}
void MainWindow::OnRunningStateChange()
{
2016-08-10 16:42:37 +01:00
m_stateLabel->setText(g_virtualMachine->GetStatus() == CVirtualMachine::PAUSED ? "Paused" : "Running");
}
2016-08-23 00:54:10 +01:00
void MainWindow::on_actionSettings_triggered()
{
SettingsDialog sd;
sd.exec();
2016-08-10 16:42:37 +01:00
SetupSoundHandler();
2016-08-23 00:54:10 +01:00
}
2016-07-26 15:06:37 +01:00
2016-08-10 16:42:37 +01:00
void MainWindow::SetupSaveLoadStateSlots()
2016-08-02 02:50:26 +01:00
{
2016-07-26 15:06:37 +01:00
bool enable = (g_virtualMachine != nullptr ? (g_virtualMachine->m_ee->m_os->GetELF() != nullptr) : false);
ui->menuSave_States->clear();
ui->menuLoad_States->clear();
for (int i=1; i <= 10; i++){
2016-08-10 16:42:37 +01:00
QString info = enable ? SaveStateInfo(i) : "Empty";
2016-07-26 15:06:37 +01:00
QAction* saveaction = new QAction(this);
saveaction->setText(QString("Save Slot %1 - %2").arg(i).arg(info));
saveaction->setEnabled(enable);
ui->menuSave_States->addAction(saveaction);
QAction* loadaction = new QAction(this);
loadaction->setText(QString("Load Slot %1 - %2").arg(i).arg(info));
loadaction->setEnabled(enable);
ui->menuLoad_States->addAction(loadaction);
if (enable)
{
2017-02-25 13:12:31 +00:00
connect(saveaction, &QAction::triggered, std::bind(&MainWindow::saveState, this, i));
connect(loadaction, &QAction::triggered, std::bind(&MainWindow::loadState, this, i));
2016-07-26 15:06:37 +01:00
}
}
}
2017-02-27 22:09:05 +00:00
void MainWindow::saveState(int stateSlot)
2016-08-02 02:50:26 +01:00
{
Framework::PathUtils::EnsurePathExists(CPS2VM::GetStateDirectoryPath());
2016-07-26 15:06:37 +01:00
auto stateFilePath = g_virtualMachine->GenerateStatePath(stateSlot);
g_virtualMachine->SaveState(stateFilePath);
2016-07-03 20:55:03 +03:00
2016-07-26 15:06:37 +01:00
QDateTime* dt = new QDateTime;
QString datetime = dt->currentDateTime().toString("hh:mm dd.MM.yyyy");
2017-02-27 22:09:05 +00:00
ui->menuSave_States->actions().at(stateSlot-1)->setText(QString("Save Slot %1 - %2").arg(stateSlot).arg(datetime));
ui->menuLoad_States->actions().at(stateSlot-1)->setText(QString("Load Slot %1 - %2").arg(stateSlot).arg(datetime));
2016-07-26 15:06:37 +01:00
}
2017-02-27 22:09:05 +00:00
void MainWindow::loadState(int stateSlot){
auto stateFilePath = g_virtualMachine->GenerateStatePath(stateSlot);
g_virtualMachine->LoadState(stateFilePath);
2016-07-26 15:06:37 +01:00
g_virtualMachine->Resume();
}
2016-08-02 02:50:26 +01:00
2017-02-27 22:09:05 +00:00
QString MainWindow::SaveStateInfo(int stateSlot)
2016-08-02 02:50:26 +01:00
{
auto stateFilePath = g_virtualMachine->GenerateStatePath(stateSlot);
QFileInfo file(stateFilePath.string().c_str());
2016-07-26 15:06:37 +01:00
if (file.exists() && file.isFile()) {
return file.created().toString("hh:mm dd.MM.yyyy");
} else {
return "Empty";
}
}
void MainWindow::on_actionPause_Resume_triggered()
{
if (g_virtualMachine != nullptr)
{
if (g_virtualMachine->GetStatus() == CVirtualMachine::PAUSED)
{
g_virtualMachine->Resume();
} else {
g_virtualMachine->Pause();
}
}
}
2016-07-26 00:22:08 +01:00
void MainWindow::closeEvent(QCloseEvent *event)
{
QMessageBox::StandardButton resBtn = QMessageBox::question(this, "Close Confirmation?",
tr("Are you sure you want to exit?\nHave you saved your progress?\n"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes);
if (resBtn != QMessageBox::Yes) {
event->ignore();
} else {
event->accept();
}
}
2016-08-10 16:29:40 +01:00
void MainWindow::on_actionAbout_triggered()
{
QMessageBox messageBox;
messageBox.setIconPixmap(QPixmap(":/assets/app_icon.png"));
QString about("Version %1 (%2)\nQt v%3 - zlib v%4 - boost v%5");
QString ver("%1.%2.%3"), boostver,qtver;
boostver = ver.arg(BOOST_VERSION / 100000).arg(BOOST_VERSION / 100 % 1000).arg(BOOST_VERSION % 100);
messageBox.about(this, this->windowTitle(), about.arg(QString(PLAY_VERSION), __DATE__, QT_VERSION_STR, ZLIB_VERSION, boostver));
messageBox.show();
}
2016-07-27 13:47:50 +01:00
void MainWindow::OnExecutableChange()
{
UpdateUI();
2017-02-19 15:00:25 +00:00
gameIDLabel->setText(QString(" %1 ").arg(g_virtualMachine->m_ee->m_os->GetExecutableName()));
2016-07-27 13:47:50 +01:00
}
void MainWindow::UpdateUI()
{
2016-07-29 18:31:09 +01:00
ui->actionPause_when_focus_is_lost->setChecked(m_pauseFocusLost);
ui->actionReset->setEnabled(!m_lastOpenCommand.filename.empty());
2016-08-10 16:42:37 +01:00
SetOpenGlPanelSize();
SetupSaveLoadStateSlots();
2016-07-27 13:47:50 +01:00
}
void MainWindow::RegisterPreferences()
{
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT, true);
2016-07-29 18:31:09 +01:00
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, true);
}
void MainWindow::focusOutEvent(QFocusEvent * event)
{
if (m_pauseFocusLost && g_virtualMachine->GetStatus() == CVirtualMachine::RUNNING)
{
2016-08-10 16:42:37 +01:00
if (!isActiveWindow() && !m_openglpanel->isActive())
2016-07-29 18:31:09 +01:00
{
if (g_virtualMachine != nullptr) {
g_virtualMachine->Pause();
m_deactivatePause = true;
}
}
}
}
void MainWindow::focusInEvent(QFocusEvent * event)
{
if (m_pauseFocusLost && g_virtualMachine->GetStatus() == CVirtualMachine::PAUSED)
{
2016-08-10 16:42:37 +01:00
if (m_deactivatePause && (isActiveWindow() || m_openglpanel->isActive())){
2016-07-29 18:31:09 +01:00
if (g_virtualMachine != nullptr)
{
g_virtualMachine->Resume();
m_deactivatePause = false;
}
}
}
}
2017-04-22 19:46:31 +01:00
void MainWindow::doubleClickEvent(QMouseEvent * ev)
{
if (ev->button() == Qt::LeftButton)
{
toggleFullscreen();
}
}
void MainWindow::toggleFullscreen()
{
if(isFullScreen())
{
showNormal();
statusBar()->show();
menuBar()->show();
}
else
{
showFullScreen();
statusBar()->hide();
menuBar()->hide();
}
}
2016-07-29 18:31:09 +01:00
void MainWindow::on_actionPause_when_focus_is_lost_triggered(bool checked)
{
m_pauseFocusLost = checked;
CAppConfig::GetInstance().SetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, m_pauseFocusLost);
}
2016-07-29 19:19:27 +01:00
void MainWindow::on_actionReset_triggered()
{
if (!m_lastOpenCommand.filename.empty()){
if (m_lastOpenCommand.type == BootType::CD){
2016-07-29 19:19:27 +01:00
BootCDROM();
} else if (m_lastOpenCommand.type == BootType::ELF) {
BootElf(m_lastOpenCommand.filename.c_str());
2016-07-29 19:19:27 +01:00
}
}
}
2016-08-10 14:56:16 +01:00
void MainWindow::on_actionMemory_Card_Manager_triggered()
{
MemoryCardManagerDialog mcm;
mcm.exec();
}
2016-09-06 00:03:02 +01:00
void MainWindow::on_actionVFS_Manager_triggered()
{
VFSManagerDialog vfsmgr;
vfsmgr.exec();
}
2016-09-06 00:23:31 +01:00
void MainWindow::on_actionController_Manager_triggered()
{
ControllerConfigDialog ccd;
ccd.SetInputBindingManager(m_InputBindingManager);
2016-09-06 00:23:31 +01:00
ccd.exec();
2016-09-06 00:23:31 +01:00
}
2017-04-09 06:50:07 +01:00
void MainWindow::on_actionCapture_Screen_triggered()
{
CScreenShotUtils::TriggerGetScreenshot(g_virtualMachine,
[&](int res, const char* msg)->void
{
m_msgLabel->setText(msg);
}
);
}