2016-09-06 00:12:56 +01:00
|
|
|
#include "mainwindow.h"
|
2018-09-24 12:34:54 -04:00
|
|
|
#include "QStringUtils.h"
|
2016-08-23 00:54:10 +01:00
|
|
|
#include "settingsdialog.h"
|
2016-08-10 14:56:16 +01:00
|
|
|
#include "memorycardmanagerdialog.h"
|
2018-10-16 13:08:52 -04:00
|
|
|
#include "S3FileBrowser.h"
|
2019-01-16 20:00:10 +00:00
|
|
|
#include "ui_shared/BootablesProcesses.h"
|
2019-07-25 12:43:24 -04:00
|
|
|
#include "ui_shared/StatsManager.h"
|
2020-10-04 11:47:32 -04:00
|
|
|
#include "QtUtils.h"
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2019-12-17 09:37:30 -05:00
|
|
|
#include "openglwindow.h"
|
|
|
|
#include "GSH_OpenGLQt.h"
|
|
|
|
|
2019-12-15 12:38:16 -05:00
|
|
|
#ifdef HAS_GSH_VULKAN
|
2019-09-12 15:28:40 -04:00
|
|
|
#include "vulkanwindow.h"
|
|
|
|
#include "GSH_VulkanQt.h"
|
2020-04-25 20:42:42 -04:00
|
|
|
#include "gs/GSH_Vulkan/GSH_VulkanDeviceInfo.h"
|
2019-09-12 15:28:40 -04:00
|
|
|
#endif
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2016-07-26 15:06:37 +01:00
|
|
|
#include <QDateTime>
|
2016-07-26 15:20:18 +01:00
|
|
|
#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>
|
2019-01-16 20:00:10 +00:00
|
|
|
#include <ctime>
|
2020-04-10 05:31:49 +01:00
|
|
|
#include <QtGlobal>
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2019-03-25 12:41:48 -04:00
|
|
|
#include "StdStreamUtils.h"
|
|
|
|
#include "string_format.h"
|
|
|
|
|
2018-10-18 08:20:35 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include "../../tools/PsfPlayer/Source/win32_ui/SH_WaveOut.h"
|
|
|
|
#else
|
2016-08-23 00:54:10 +01:00
|
|
|
#include "tools/PsfPlayer/Source/SH_OpenAL.h"
|
2019-12-10 13:42:18 +00:00
|
|
|
#endif
|
2019-08-31 12:33:24 -04:00
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2019-12-09 19:07:36 +00:00
|
|
|
#include "DebugSupport/QtDebugger.h"
|
2019-08-31 12:33:24 -04:00
|
|
|
#include "ui_debugmenu.h"
|
|
|
|
#endif
|
2018-11-19 13:20:46 -05:00
|
|
|
#include "input/PH_GenericInput.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>
|
2016-07-26 15:06:37 +01:00
|
|
|
|
2019-01-16 20:00:10 +00:00
|
|
|
#include "CoverUtils.h"
|
2016-08-23 00:54:10 +01:00
|
|
|
#include "PreferenceDefs.h"
|
2019-03-04 22:19:20 -05:00
|
|
|
#include "PS2VM_Preferences.h"
|
2017-04-09 06:50:07 +01:00
|
|
|
#include "ScreenShotUtils.h"
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2016-09-06 00:12:56 +01:00
|
|
|
#include "ui_mainwindow.h"
|
2016-09-06 00:03:02 +01:00
|
|
|
#include "vfsmanagerdialog.h"
|
2019-01-16 20:00:10 +00:00
|
|
|
#include "bootablelistdialog.h"
|
2018-07-31 18:43:01 -04:00
|
|
|
#include "ControllerConfig/controllerconfigdialog.h"
|
2016-09-06 00:12:56 +01:00
|
|
|
|
2018-11-19 13:20:46 -05:00
|
|
|
#ifdef __APPLE__
|
2018-11-19 19:18:37 -05:00
|
|
|
#include "macos/InputProviderMacOsHid.h"
|
2018-11-19 13:20:46 -05:00
|
|
|
#endif
|
2018-11-27 13:25:34 -05:00
|
|
|
#ifdef HAS_LIBEVDEV
|
|
|
|
#include "unix/InputProviderEvDev.h"
|
|
|
|
#endif
|
2019-03-02 20:18:52 -05:00
|
|
|
#ifdef WIN32
|
|
|
|
#include "win32/InputProviderDirectInput.h"
|
2019-06-19 19:05:45 -04:00
|
|
|
#include "win32/InputProviderXInput.h"
|
2019-03-02 20:18:52 -05:00
|
|
|
#endif
|
2018-11-19 13:20:46 -05:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
MainWindow::MainWindow(QWidget* parent)
|
|
|
|
: QMainWindow(parent)
|
|
|
|
, ui(new Ui::MainWindow)
|
2016-09-06 00:12:56 +01:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
ui->setupUi(this);
|
2020-12-20 19:22:04 -05:00
|
|
|
buildResizeWindowMenu();
|
2016-07-01 05:21:58 +03:00
|
|
|
|
2019-12-17 09:37:30 -05:00
|
|
|
RegisterPreferences();
|
|
|
|
|
2018-10-05 13:35:24 -04:00
|
|
|
m_continuationChecker = new CContinuationChecker(this);
|
|
|
|
|
2019-07-25 12:50:25 -04:00
|
|
|
#ifdef PROFILE
|
|
|
|
{
|
|
|
|
m_profileStatsLabel = new QLabel(this);
|
|
|
|
QFont courierFont("Courier");
|
|
|
|
m_profileStatsLabel->setFont(courierFont);
|
|
|
|
m_profileStatsLabel->setAlignment(Qt::AlignTop);
|
|
|
|
ui->gridLayout->addWidget(m_profileStatsLabel, 0, 1);
|
|
|
|
}
|
|
|
|
#endif
|
2019-08-01 12:44:10 -04:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
m_pauseFocusLost = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST);
|
2018-09-24 12:34:54 -04:00
|
|
|
auto lastPath = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_CDROM0_PATH);
|
2019-10-31 13:20:02 -04:00
|
|
|
std::error_code lastPathExistsErrorCode;
|
|
|
|
if(fs::exists(lastPath, lastPathExistsErrorCode))
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-09-24 12:34:54 -04:00
|
|
|
m_lastPath = lastPath.parent_path();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_lastPath = QStringToPath(QDir::homePath());
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2016-07-29 18:31:09 +01:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
CreateStatusBar();
|
|
|
|
UpdateUI();
|
2020-11-16 14:49:47 -05:00
|
|
|
addAction(ui->actionPause_Resume);
|
2019-05-13 12:49:37 -04:00
|
|
|
ui->actionBoot_DiscImage_S3->setVisible(S3FileBrowser::IsAvailable());
|
2018-08-01 13:05:38 -04:00
|
|
|
|
|
|
|
InitVirtualMachine();
|
2020-02-09 23:03:33 +00:00
|
|
|
SetupGsHandler();
|
2019-03-21 17:52:43 -04:00
|
|
|
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2019-12-09 19:07:36 +00:00
|
|
|
m_debugger = std::make_unique<QtDebugger>(this, *m_virtualMachine);
|
2019-03-21 17:52:43 -04:00
|
|
|
m_frameDebugger = std::make_unique<CFrameDebugger>();
|
2020-01-02 20:33:11 +00:00
|
|
|
m_frameDebugger->Show(SW_SHOWMAXIMIZED);
|
2019-03-21 17:52:43 -04:00
|
|
|
|
|
|
|
auto debugMenu = new QMenu(this);
|
|
|
|
debugMenuUi = new Ui::DebugMenu();
|
|
|
|
debugMenuUi->setupUi(debugMenu);
|
|
|
|
ui->menuBar->insertMenu(ui->menuHelp->menuAction(), debugMenu);
|
|
|
|
|
|
|
|
connect(debugMenuUi->actionShowDebugger, &QAction::triggered, this, std::bind(&MainWindow::ShowDebugger, this));
|
2019-08-31 12:33:24 -04:00
|
|
|
//connect(debugMenuUi->actionShowFrameDebugger, &QAction::triggered, this, std::bind(&MainWindow::ShowFrameDebugger, this));
|
|
|
|
//connect(debugMenuUi->actionDumpNextFrame, &QAction::triggered, this, std::bind(&MainWindow::DumpNextFrame, this));
|
|
|
|
//connect(debugMenuUi->actionGsDrawEnabled, &QAction::triggered, this, std::bind(&MainWindow::ToggleGsDraw, this));
|
2019-03-21 17:52:43 -04:00
|
|
|
#endif
|
2016-09-06 00:12:56 +01:00
|
|
|
}
|
|
|
|
|
2016-06-26 23:42:21 -04:00
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{
|
2019-03-21 17:52:43 -04:00
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2019-08-31 12:33:24 -04:00
|
|
|
//m_debugger.reset();
|
|
|
|
//m_frameDebugger.reset();
|
2019-03-21 17:52:43 -04:00
|
|
|
#endif
|
2018-04-30 21:01:23 +01:00
|
|
|
CAppConfig::GetInstance().Save();
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Pause();
|
2018-11-19 13:20:46 -05:00
|
|
|
m_qtKeyInputProvider.reset();
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->DestroyPadHandler();
|
|
|
|
m_virtualMachine->DestroyGSHandler();
|
|
|
|
m_virtualMachine->DestroySoundHandler();
|
|
|
|
m_virtualMachine->Destroy();
|
|
|
|
delete m_virtualMachine;
|
|
|
|
m_virtualMachine = nullptr;
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2019-08-31 12:33:24 -04:00
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2018-04-30 21:01:23 +01:00
|
|
|
delete ui;
|
2019-08-31 12:33:24 -04:00
|
|
|
delete debugMenuUi;
|
|
|
|
#endif
|
2016-06-26 23:42:21 -04:00
|
|
|
}
|
|
|
|
|
2018-08-01 13:05:38 -04:00
|
|
|
void MainWindow::InitVirtualMachine()
|
2016-08-02 02:50:26 +01:00
|
|
|
{
|
2018-08-01 13:05:38 -04:00
|
|
|
assert(!m_virtualMachine);
|
|
|
|
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine = new CPS2VM();
|
|
|
|
m_virtualMachine->Initialize();
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
SetupSoundHandler();
|
2016-07-26 00:52:31 +01:00
|
|
|
|
2018-11-19 13:20:46 -05:00
|
|
|
{
|
|
|
|
m_virtualMachine->CreatePadHandler(CPH_GenericInput::GetFactoryFunction());
|
|
|
|
auto padHandler = static_cast<CPH_GenericInput*>(m_virtualMachine->GetPadHandler());
|
2020-02-25 18:47:50 +00:00
|
|
|
auto profile = CAppConfig::GetInstance().GetPreferenceString(PREF_INPUT_PAD1_PROFILE);
|
|
|
|
|
2018-11-19 13:20:46 -05:00
|
|
|
auto& bindingManager = padHandler->GetBindingManager();
|
2020-02-25 18:47:50 +00:00
|
|
|
bindingManager.Load(profile);
|
2018-11-19 13:20:46 -05:00
|
|
|
|
|
|
|
//Create QtKeyInputProvider
|
|
|
|
m_qtKeyInputProvider = std::make_shared<CInputProviderQtKey>();
|
|
|
|
bindingManager.RegisterInputProvider(m_qtKeyInputProvider);
|
|
|
|
#ifdef __APPLE__
|
|
|
|
bindingManager.RegisterInputProvider(std::make_shared<CInputProviderMacOsHid>());
|
|
|
|
#endif
|
2018-11-27 13:25:34 -05:00
|
|
|
#ifdef HAS_LIBEVDEV
|
|
|
|
bindingManager.RegisterInputProvider(std::make_shared<CInputProviderEvDev>());
|
2019-03-02 20:18:52 -05:00
|
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
|
|
bindingManager.RegisterInputProvider(std::make_shared<CInputProviderDirectInput>());
|
2019-06-20 18:21:46 -04:00
|
|
|
bindingManager.RegisterInputProvider(std::make_shared<CInputProviderXInput>());
|
2018-11-27 13:25:34 -05:00
|
|
|
#endif
|
2018-11-19 13:20:46 -05:00
|
|
|
if(!bindingManager.HasBindings())
|
2018-10-23 01:40:35 +01:00
|
|
|
{
|
2020-09-14 19:43:25 -04:00
|
|
|
ControllerConfigDialog::AutoConfigureKeyboard(0, &bindingManager);
|
2018-10-23 01:40:35 +01:00
|
|
|
}
|
2018-11-19 13:20:46 -05:00
|
|
|
}
|
2018-11-28 22:32:27 -05:00
|
|
|
|
2019-07-25 12:50:25 -04:00
|
|
|
#ifdef PROFILE
|
2019-08-15 20:46:21 -04:00
|
|
|
m_profileFrameDoneConnection = m_virtualMachine->ProfileFrameDone.Connect(std::bind(&CStatsManager::OnProfileFrameDone, &CStatsManager::GetInstance(), m_virtualMachine, std::placeholders::_1));
|
2019-07-25 12:50:25 -04:00
|
|
|
#endif
|
2019-08-01 12:44:10 -04:00
|
|
|
|
2019-04-04 19:14:16 -04:00
|
|
|
//OnExecutableChange might be called from another thread, we need to wrap it around a Qt signal
|
2019-07-01 13:11:23 +01:00
|
|
|
m_OnExecutableChangeConnection = m_virtualMachine->m_ee->m_os->OnExecutableChange.Connect(std::bind(&MainWindow::EmitOnExecutableChange, this));
|
2019-04-04 19:14:16 -04:00
|
|
|
connect(this, SIGNAL(onExecutableChange()), this, SLOT(HandleOnExecutableChange()));
|
2016-07-26 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2019-09-12 15:11:52 -04:00
|
|
|
void MainWindow::SetOutputWindowSize()
|
2016-09-06 00:12:56 +01:00
|
|
|
{
|
2019-09-12 15:11:52 -04:00
|
|
|
outputWindow_resized();
|
2016-07-26 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2018-08-01 13:05:38 -04:00
|
|
|
void MainWindow::SetupGsHandler()
|
|
|
|
{
|
|
|
|
assert(m_virtualMachine);
|
2020-02-11 07:53:35 +00:00
|
|
|
switch(CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER))
|
|
|
|
{
|
2019-12-15 12:38:16 -05:00
|
|
|
#ifdef HAS_GSH_VULKAN
|
2020-02-11 07:53:35 +00:00
|
|
|
case SettingsDialog::GS_HANDLERS::VULKAN:
|
2020-02-09 23:05:24 +00:00
|
|
|
{
|
2020-04-25 20:42:42 -04:00
|
|
|
assert(GSH_Vulkan::CDeviceInfo::GetInstance().HasAvailableDevices());
|
2020-02-10 22:11:18 +00:00
|
|
|
m_outputwindow = new VulkanWindow;
|
|
|
|
QWidget* container = QWidget::createWindowContainer(m_outputwindow);
|
|
|
|
m_outputwindow->create();
|
|
|
|
ui->gridLayout->addWidget(container, 0, 0);
|
2020-02-09 23:05:24 +00:00
|
|
|
m_virtualMachine->CreateGSHandler(CGSH_VulkanQt::GetFactoryFunction(m_outputwindow));
|
|
|
|
}
|
2020-02-11 07:53:35 +00:00
|
|
|
break;
|
|
|
|
case SettingsDialog::GS_HANDLERS::OPENGL:
|
2019-09-12 15:28:40 -04:00
|
|
|
#endif
|
2020-02-11 07:53:35 +00:00
|
|
|
default:
|
2020-02-09 23:05:24 +00:00
|
|
|
{
|
2020-02-10 22:11:18 +00:00
|
|
|
m_outputwindow = new OpenGLWindow;
|
|
|
|
QWidget* container = QWidget::createWindowContainer(m_outputwindow);
|
|
|
|
m_outputwindow->create();
|
|
|
|
ui->gridLayout->addWidget(container, 0, 0);
|
2020-02-09 23:05:24 +00:00
|
|
|
m_virtualMachine->CreateGSHandler(CGSH_OpenGLQt::GetFactoryFunction(m_outputwindow));
|
2018-08-01 13:05:38 -04:00
|
|
|
}
|
2020-02-11 07:53:35 +00:00
|
|
|
}
|
2020-02-10 22:11:18 +00:00
|
|
|
|
|
|
|
connect(m_outputwindow, SIGNAL(heightChanged(int)), this, SLOT(outputWindow_resized()));
|
|
|
|
connect(m_outputwindow, SIGNAL(widthChanged(int)), this, SLOT(outputWindow_resized()));
|
|
|
|
|
|
|
|
connect(m_outputwindow, SIGNAL(keyUp(QKeyEvent*)), this, SLOT(keyReleaseEvent(QKeyEvent*)));
|
|
|
|
connect(m_outputwindow, SIGNAL(keyDown(QKeyEvent*)), this, SLOT(keyPressEvent(QKeyEvent*)));
|
|
|
|
|
|
|
|
connect(m_outputwindow, SIGNAL(focusOut(QFocusEvent*)), this, SLOT(focusOutEvent(QFocusEvent*)));
|
|
|
|
connect(m_outputwindow, SIGNAL(focusIn(QFocusEvent*)), this, SLOT(focusInEvent(QFocusEvent*)));
|
|
|
|
|
|
|
|
connect(m_outputwindow, SIGNAL(doubleClick(QMouseEvent*)), this, SLOT(doubleClickEvent(QMouseEvent*)));
|
|
|
|
|
2020-02-09 23:05:24 +00:00
|
|
|
m_OnNewFrameConnection = m_virtualMachine->m_ee->m_gs->OnNewFrame.Connect(std::bind(&CStatsManager::OnNewFrame, &CStatsManager::GetInstance(), std::placeholders::_1));
|
2018-08-01 13:05:38 -04:00
|
|
|
}
|
|
|
|
|
2016-08-10 16:42:37 +01:00
|
|
|
void MainWindow::SetupSoundHandler()
|
2016-08-23 00:54:10 +01:00
|
|
|
{
|
2018-08-01 13:01:48 -04:00
|
|
|
assert(m_virtualMachine);
|
|
|
|
bool audioEnabled = CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT);
|
|
|
|
if(audioEnabled)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-10-18 08:20:35 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
m_virtualMachine->CreateSoundHandler(&CSH_WaveOut::HandlerFactory);
|
|
|
|
#else
|
2018-08-01 13:01:48 -04:00
|
|
|
m_virtualMachine->CreateSoundHandler(&CSH_OpenAL::HandlerFactory);
|
2018-10-18 08:20:35 -04:00
|
|
|
#endif
|
2018-08-01 13:01:48 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_virtualMachine->DestroySoundHandler();
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2016-08-23 00:54:10 +01:00
|
|
|
}
|
|
|
|
|
2019-09-12 15:11:52 -04:00
|
|
|
void MainWindow::outputWindow_resized()
|
2016-07-26 15:20:18 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr && m_virtualMachine->m_ee != nullptr && m_virtualMachine->m_ee->m_gs != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2019-09-12 15:11:52 -04:00
|
|
|
uint32 w = m_outputwindow->size().width(), h = m_outputwindow->size().height();
|
2016-07-26 15:20:18 +01:00
|
|
|
|
2020-04-10 05:31:49 +01:00
|
|
|
qreal scale = 1.0;
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
|
|
|
scale = devicePixelRatioF();
|
2020-04-10 15:39:04 -04:00
|
|
|
#endif
|
2018-04-30 21:01:23 +01:00
|
|
|
CGSHandler::PRESENTATION_PARAMS presentationParams;
|
2018-08-08 12:21:41 -04:00
|
|
|
presentationParams.mode = static_cast<CGSHandler::PRESENTATION_MODE>(CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSHANDLER_PRESENTATION_MODE));
|
2018-05-23 03:12:05 +03:00
|
|
|
presentationParams.windowWidth = w * scale;
|
|
|
|
presentationParams.windowHeight = h * scale;
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->m_ee->m_gs->SetPresentationParams(presentationParams);
|
2020-10-24 11:16:09 -04:00
|
|
|
if(m_virtualMachine->GetStatus() == CVirtualMachine::PAUSED)
|
|
|
|
{
|
|
|
|
m_virtualMachine->m_ee->m_gs->Flip(true);
|
|
|
|
}
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2016-07-26 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2018-09-28 08:17:24 -04:00
|
|
|
void MainWindow::on_actionBoot_DiscImage_triggered()
|
2016-07-26 15:20:18 +01:00
|
|
|
{
|
2020-10-04 11:47:32 -04:00
|
|
|
QStringList filters;
|
|
|
|
filters.push_back(QtUtils::GetDiscImageFormatsFilter());
|
|
|
|
filters.push_back("All files (*)");
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
QFileDialog dialog(this);
|
2018-09-24 12:34:54 -04:00
|
|
|
dialog.setDirectory(PathToQString(m_lastPath));
|
2018-04-30 21:01:23 +01:00
|
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
2020-10-04 11:47:32 -04:00
|
|
|
dialog.setNameFilters(filters);
|
2018-04-30 21:01:23 +01:00
|
|
|
if(dialog.exec())
|
|
|
|
{
|
2018-09-24 12:34:54 -04:00
|
|
|
auto filePath = QStringToPath(dialog.selectedFiles().first());
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2020-12-15 13:52:36 -05:00
|
|
|
LoadCDROM(filePath);
|
2018-04-30 21:01:23 +01:00
|
|
|
BootCDROM();
|
|
|
|
}
|
|
|
|
catch(const std::exception& e)
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
2018-07-31 18:47:14 -04:00
|
|
|
messageBox.critical(nullptr, "Error", e.what());
|
2018-04-30 21:01:23 +01:00
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-26 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2018-10-16 13:08:52 -04:00
|
|
|
void MainWindow::on_actionBoot_DiscImage_S3_triggered()
|
|
|
|
{
|
|
|
|
S3FileBrowser browser(this);
|
|
|
|
if(browser.exec())
|
|
|
|
{
|
|
|
|
auto filePath = browser.GetSelectedPath();
|
|
|
|
if(m_virtualMachine != nullptr)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2020-12-15 13:52:36 -05:00
|
|
|
LoadCDROM(filePath);
|
2018-10-16 13:08:52 -04:00
|
|
|
BootCDROM();
|
|
|
|
}
|
|
|
|
catch(const std::exception& e)
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
|
|
|
messageBox.critical(nullptr, "Error", e.what());
|
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-28 12:00:02 -04:00
|
|
|
void MainWindow::on_actionBoot_cdrom0_triggered()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BootCDROM();
|
|
|
|
}
|
|
|
|
catch(const std::exception& e)
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
|
|
|
messageBox.critical(nullptr, "Error", e.what());
|
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 15:20:18 +01:00
|
|
|
void MainWindow::on_actionBoot_ELF_triggered()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
QFileDialog dialog(this);
|
2018-09-24 12:34:54 -04:00
|
|
|
dialog.setDirectory(PathToQString(m_lastPath));
|
2018-04-30 21:01:23 +01:00
|
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
|
|
dialog.setNameFilter(tr("ELF files (*.elf)"));
|
|
|
|
if(dialog.exec())
|
|
|
|
{
|
2018-09-24 12:34:54 -04:00
|
|
|
auto filePath = QStringToPath(dialog.selectedFiles().first());
|
|
|
|
m_lastPath = filePath.parent_path();
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2018-09-24 12:34:54 -04:00
|
|
|
BootElf(filePath);
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
|
|
|
catch(const std::exception& e)
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
2018-07-31 18:47:14 -04:00
|
|
|
messageBox.critical(nullptr, "Error", e.what());
|
2018-04-30 21:01:23 +01:00
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-26 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2019-10-16 20:51:11 -04:00
|
|
|
void MainWindow::BootElf(fs::path filePath)
|
2016-07-29 19:19:27 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Pause();
|
|
|
|
m_virtualMachine->Reset();
|
2018-09-22 21:42:03 -04:00
|
|
|
m_virtualMachine->m_ee->m_os->BootFromFile(filePath);
|
2019-03-21 17:52:43 -04:00
|
|
|
#ifndef DEBUGGER_INCLUDED
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Resume();
|
2019-03-21 17:52:43 -04:00
|
|
|
#endif
|
2020-12-15 13:52:36 -05:00
|
|
|
{
|
|
|
|
TryRegisterBootable(filePath);
|
|
|
|
TryUpdateLastBootedTime(filePath);
|
|
|
|
m_lastOpenCommand = LastOpenCommand(BootType::ELF, filePath);
|
2020-12-17 15:58:19 -05:00
|
|
|
UpdateUI();
|
2020-12-15 13:52:36 -05:00
|
|
|
}
|
2018-08-08 12:21:12 -04:00
|
|
|
m_msgLabel->setText(QString("Loaded executable '%1'.")
|
2018-08-09 12:28:42 -04:00
|
|
|
.arg(m_virtualMachine->m_ee->m_os->GetExecutableName()));
|
2016-07-29 19:19:27 +01:00
|
|
|
}
|
|
|
|
|
2019-10-16 20:51:11 -04:00
|
|
|
void MainWindow::LoadCDROM(fs::path filePath)
|
2018-10-08 02:43:23 +01:00
|
|
|
{
|
2018-10-08 02:44:23 +01:00
|
|
|
m_lastPath = filePath.parent_path();
|
2018-10-08 02:43:23 +01:00
|
|
|
CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, filePath);
|
|
|
|
}
|
|
|
|
|
2016-07-29 19:19:27 +01:00
|
|
|
void MainWindow::BootCDROM()
|
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Pause();
|
|
|
|
m_virtualMachine->Reset();
|
|
|
|
m_virtualMachine->m_ee->m_os->BootFromCDROM();
|
2019-03-21 17:52:43 -04:00
|
|
|
#ifndef DEBUGGER_INCLUDED
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Resume();
|
2019-03-21 17:52:43 -04:00
|
|
|
#endif
|
2020-12-15 13:52:36 -05:00
|
|
|
{
|
|
|
|
auto filePath = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_CDROM0_PATH);
|
|
|
|
TryRegisterBootable(filePath);
|
|
|
|
TryUpdateLastBootedTime(filePath);
|
|
|
|
m_lastOpenCommand = LastOpenCommand(BootType::CD, filePath);
|
2020-12-17 15:58:19 -05:00
|
|
|
UpdateUI();
|
2020-12-15 13:52:36 -05:00
|
|
|
}
|
2018-08-08 12:21:12 -04:00
|
|
|
m_msgLabel->setText(QString("Loaded executable '%1' from cdrom0.")
|
2018-08-09 12:28:42 -04:00
|
|
|
.arg(m_virtualMachine->m_ee->m_os->GetExecutableName()));
|
2016-07-29 19:19:27 +01:00
|
|
|
}
|
|
|
|
|
2016-07-26 15:20:18 +01:00
|
|
|
void MainWindow::on_actionExit_triggered()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
close();
|
2016-09-06 00:12:56 +01:00
|
|
|
}
|
2016-07-26 00:52:31 +01:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::keyPressEvent(QKeyEvent* event)
|
2016-07-26 00:52:31 +01:00
|
|
|
{
|
2018-11-19 13:20:46 -05:00
|
|
|
if((event->key() != Qt::Key_Escape) && m_qtKeyInputProvider)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-11-19 13:20:46 -05:00
|
|
|
m_qtKeyInputProvider->OnKeyPress(event->key());
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2016-07-26 00:52:31 +01:00
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::keyReleaseEvent(QKeyEvent* event)
|
2016-07-26 00:52:31 +01:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
if(event->key() == Qt::Key_Escape)
|
|
|
|
{
|
|
|
|
if(isFullScreen())
|
|
|
|
{
|
|
|
|
toggleFullscreen();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2018-11-19 13:20:46 -05:00
|
|
|
if(m_qtKeyInputProvider)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-11-19 13:20:46 -05:00
|
|
|
m_qtKeyInputProvider->OnKeyRelease(event->key());
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
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
|
|
|
{
|
2018-08-02 08:56:07 -04:00
|
|
|
m_fpsLabel = new QLabel("");
|
|
|
|
m_fpsLabel->setAlignment(Qt::AlignHCenter);
|
|
|
|
m_fpsLabel->setMinimumSize(m_fpsLabel->sizeHint());
|
2016-07-26 00:49:24 +01:00
|
|
|
|
2018-04-30 21:01:23 +01: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);
|
2017-03-25 21:53:28 +00:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
statusBar()->addWidget(m_msgLabel, 1);
|
2018-08-02 08:56:07 -04:00
|
|
|
statusBar()->addWidget(m_fpsLabel);
|
2020-02-10 22:11:18 +00:00
|
|
|
#ifdef HAS_GSH_VULKAN
|
2020-04-25 20:42:42 -04:00
|
|
|
if(GSH_Vulkan::CDeviceInfo::GetInstance().HasAvailableDevices())
|
|
|
|
{
|
|
|
|
m_gsLabel = new QLabel("");
|
2020-02-10 22:11:18 +00:00
|
|
|
auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER);
|
2020-02-12 17:29:37 +00:00
|
|
|
UpdateGSHandlerLabel(gs_index);
|
2020-04-25 20:42:42 -04:00
|
|
|
|
|
|
|
m_gsLabel->setAlignment(Qt::AlignHCenter);
|
|
|
|
m_gsLabel->setMinimumSize(m_gsLabel->sizeHint());
|
|
|
|
//QLabel have no click event, so we're using ContextMenu event aka rightClick to toggle GS
|
|
|
|
m_gsLabel->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(m_gsLabel, &QLabel::customContextMenuRequested, [&]() {
|
|
|
|
auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER);
|
|
|
|
gs_index = (gs_index + 1) % SettingsDialog::GS_HANDLERS::MAX_HANDLER;
|
|
|
|
CAppConfig::GetInstance().SetPreferenceInteger(PREF_VIDEO_GS_HANDLER, gs_index);
|
|
|
|
SetupGsHandler();
|
|
|
|
UpdateGSHandlerLabel(gs_index);
|
|
|
|
});
|
|
|
|
statusBar()->addWidget(m_gsLabel);
|
|
|
|
}
|
2020-02-10 22:11:18 +00:00
|
|
|
#endif
|
2018-08-07 22:41:02 -04:00
|
|
|
m_msgLabel->setText(QString("Play! v%1 - %2").arg(PLAY_VERSION).arg(__DATE__));
|
|
|
|
|
2018-08-07 19:17:28 -04:00
|
|
|
m_fpsTimer = new QTimer(this);
|
2019-07-24 19:35:46 -04:00
|
|
|
connect(m_fpsTimer, SIGNAL(timeout()), this, SLOT(updateStats()));
|
2018-08-07 19:17:28 -04:00
|
|
|
m_fpsTimer->start(1000);
|
2016-08-23 00:54:10 +01:00
|
|
|
}
|
|
|
|
|
2019-07-24 19:35:46 -04:00
|
|
|
void MainWindow::updateStats()
|
2016-08-23 00:54:10 +01:00
|
|
|
{
|
2019-07-24 19:35:46 -04:00
|
|
|
uint32 frames = CStatsManager::GetInstance().GetFrames();
|
|
|
|
uint32 drawCalls = CStatsManager::GetInstance().GetDrawCalls();
|
2018-08-02 08:56:07 -04:00
|
|
|
uint32 dcpf = (frames != 0) ? (drawCalls / frames) : 0;
|
2019-07-25 12:50:25 -04:00
|
|
|
#ifdef PROFILE
|
|
|
|
m_profileStatsLabel->setText(QString::fromStdString(CStatsManager::GetInstance().GetProfilingInfo()));
|
|
|
|
#endif
|
2018-08-02 08:56:07 -04:00
|
|
|
m_fpsLabel->setText(QString("%1 f/s, %2 dc/f").arg(frames).arg(dcpf));
|
2019-07-24 19:35:46 -04:00
|
|
|
CStatsManager::GetInstance().ClearStats();
|
2016-07-26 00:49:24 +01:00
|
|
|
}
|
|
|
|
|
2016-08-23 00:54:10 +01:00
|
|
|
void MainWindow::on_actionSettings_triggered()
|
|
|
|
{
|
2020-02-10 22:11:18 +00:00
|
|
|
auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER);
|
2018-04-30 21:01:23 +01:00
|
|
|
SettingsDialog sd;
|
|
|
|
sd.exec();
|
|
|
|
SetupSoundHandler();
|
2019-03-30 14:43:25 +00:00
|
|
|
if(m_virtualMachine != nullptr)
|
|
|
|
{
|
2019-10-12 10:58:54 +01:00
|
|
|
m_virtualMachine->ReloadSpuBlockCount();
|
2020-02-10 22:11:18 +00:00
|
|
|
auto new_gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER);
|
|
|
|
if(gs_index != new_gs_index)
|
|
|
|
{
|
2020-02-12 17:29:37 +00:00
|
|
|
UpdateGSHandlerLabel(new_gs_index);
|
2020-02-10 22:11:18 +00:00
|
|
|
SetupGsHandler();
|
|
|
|
}
|
|
|
|
else
|
2019-03-30 14:43:25 +00:00
|
|
|
{
|
2020-02-10 22:11:18 +00:00
|
|
|
outputWindow_resized();
|
|
|
|
auto gsHandler = m_virtualMachine->GetGSHandler();
|
|
|
|
if(gsHandler)
|
|
|
|
{
|
|
|
|
gsHandler->NotifyPreferencesChanged();
|
|
|
|
}
|
2019-03-30 14:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
{
|
2020-05-20 11:11:19 -04:00
|
|
|
bool enable = IsExecutableLoaded();
|
2018-04-30 21:01:23 +01:00
|
|
|
ui->menuSave_States->clear();
|
|
|
|
ui->menuLoad_States->clear();
|
2019-03-13 12:30:21 -04:00
|
|
|
for(int i = 0; i < 10; i++)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2019-03-13 12:30:21 -04:00
|
|
|
QString info = enable ? GetSaveStateInfo(i) : "Empty";
|
2016-07-26 15:06:37 +01:00
|
|
|
|
2018-04-30 21:01:23 +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);
|
2016-07-26 15:06:37 +01:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
QAction* loadaction = new QAction(this);
|
|
|
|
loadaction->setText(QString("Load Slot %1 - %2").arg(i).arg(info));
|
|
|
|
loadaction->setEnabled(enable);
|
|
|
|
ui->menuLoad_States->addAction(loadaction);
|
2016-07-26 15:06:37 +01:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
if(enable)
|
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
auto stateFilePath = m_virtualMachine->GenerateStatePath(stateSlot);
|
2018-08-07 19:18:19 -04:00
|
|
|
auto future = m_virtualMachine->SaveState(stateFilePath);
|
2018-10-05 13:35:24 -04:00
|
|
|
m_continuationChecker->GetContinuationManager().Register(std::move(future),
|
2018-10-11 12:54:56 -04:00
|
|
|
[this, stateSlot = stateSlot](const bool& succeeded) {
|
|
|
|
if(succeeded)
|
|
|
|
{
|
|
|
|
m_msgLabel->setText(QString("Saved state to slot %1.").arg(stateSlot));
|
2019-03-25 12:41:15 -04:00
|
|
|
QString datetime = GetSaveStateInfo(stateSlot);
|
2019-03-13 12:30:21 -04:00
|
|
|
ui->menuSave_States->actions().at(stateSlot)->setText(QString("Save Slot %1 - %2").arg(stateSlot).arg(datetime));
|
|
|
|
ui->menuLoad_States->actions().at(stateSlot)->setText(QString("Load Slot %1 - %2").arg(stateSlot).arg(datetime));
|
2018-10-11 12:54:56 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_msgLabel->setText(QString("Error saving state to slot %1.").arg(stateSlot));
|
|
|
|
}
|
|
|
|
});
|
2016-07-26 15:06:37 +01:00
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::loadState(int stateSlot)
|
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
auto stateFilePath = m_virtualMachine->GenerateStatePath(stateSlot);
|
2018-08-07 19:18:19 -04:00
|
|
|
auto future = m_virtualMachine->LoadState(stateFilePath);
|
2018-10-05 13:35:24 -04:00
|
|
|
m_continuationChecker->GetContinuationManager().Register(std::move(future),
|
2018-10-11 12:54:56 -04:00
|
|
|
[this, stateSlot = stateSlot](const bool& succeeded) {
|
|
|
|
if(succeeded)
|
|
|
|
{
|
|
|
|
m_msgLabel->setText(QString("Loaded state from slot %1.").arg(stateSlot));
|
2019-05-12 10:02:50 -04:00
|
|
|
#ifndef DEBUGGER_INCLUDED
|
2018-10-11 12:54:56 -04:00
|
|
|
m_virtualMachine->Resume();
|
2019-05-12 10:02:50 -04:00
|
|
|
#endif
|
2018-10-11 12:54:56 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_msgLabel->setText(QString("Error loading state from slot %1.").arg(stateSlot));
|
|
|
|
}
|
|
|
|
});
|
2016-07-26 15:06:37 +01:00
|
|
|
}
|
2016-08-02 02:50:26 +01:00
|
|
|
|
2019-03-13 12:30:21 -04:00
|
|
|
QString MainWindow::GetSaveStateInfo(int stateSlot)
|
2016-08-02 02:50:26 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
auto stateFilePath = m_virtualMachine->GenerateStatePath(stateSlot);
|
2019-03-13 12:28:38 -04:00
|
|
|
QFileInfo file(PathToQString(stateFilePath));
|
2018-04-30 21:01:23 +01:00
|
|
|
if(file.exists() && file.isFile())
|
|
|
|
{
|
2019-03-25 12:41:15 -04:00
|
|
|
return file.lastModified().toString("hh:mm dd.MM.yyyy");
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return "Empty";
|
|
|
|
}
|
2016-07-26 15:06:37 +01:00
|
|
|
}
|
|
|
|
|
2016-07-26 00:49:24 +01:00
|
|
|
void MainWindow::on_actionPause_Resume_triggered()
|
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine->GetStatus() == CVirtualMachine::PAUSED)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-07 13:22:38 -04:00
|
|
|
m_msgLabel->setText("Virtual machine resumed.");
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Resume();
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-08-07 13:22:38 -04:00
|
|
|
m_msgLabel->setText("Virtual machine paused.");
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Pause();
|
2018-04-30 21:01:23 +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-07-26 00:22:08 +01:00
|
|
|
}
|
2016-08-10 16:29:40 +01:00
|
|
|
|
|
|
|
void MainWindow::on_actionAbout_triggered()
|
|
|
|
{
|
2019-10-29 19:50:46 -04:00
|
|
|
auto about = QString("Version %1 (%2)\nQt v%3 - zlib v%4")
|
|
|
|
.arg(QString(PLAY_VERSION), __DATE__, QT_VERSION_STR, ZLIB_VERSION);
|
2019-03-04 20:07:38 -05:00
|
|
|
QMessageBox::about(this, this->windowTitle(), about);
|
2016-08-10 16:29:40 +01:00
|
|
|
}
|
2016-07-27 13:47:50 +01:00
|
|
|
|
2019-04-04 19:14:16 -04:00
|
|
|
void MainWindow::EmitOnExecutableChange()
|
|
|
|
{
|
|
|
|
emit onExecutableChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::HandleOnExecutableChange()
|
2016-07-27 13:47:50 +01:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
UpdateUI();
|
2019-07-22 14:56:37 +01:00
|
|
|
auto titleString = QString("Play! - [ %1 ] - %2").arg(m_virtualMachine->m_ee->m_os->GetExecutableName(), QString(PLAY_VERSION));
|
2018-08-02 08:56:07 -04:00
|
|
|
setWindowTitle(titleString);
|
2016-07-27 13:47:50 +01:00
|
|
|
}
|
|
|
|
|
2020-05-20 11:11:19 -04:00
|
|
|
bool MainWindow::IsExecutableLoaded() const
|
|
|
|
{
|
|
|
|
return (m_virtualMachine != nullptr ? (m_virtualMachine->m_ee->m_os->GetELF() != nullptr) : false);
|
|
|
|
}
|
|
|
|
|
2016-07-27 13:47:50 +01:00
|
|
|
void MainWindow::UpdateUI()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
ui->actionPause_when_focus_is_lost->setChecked(m_pauseFocusLost);
|
2018-09-22 22:30:15 -04:00
|
|
|
ui->actionReset->setEnabled(!m_lastOpenCommand.path.empty());
|
2020-05-20 11:11:19 -04:00
|
|
|
ui->actionPause_Resume->setEnabled(IsExecutableLoaded());
|
2019-09-12 15:11:52 -04:00
|
|
|
SetOutputWindowSize();
|
2018-04-30 21:01:23 +01:00
|
|
|
SetupSaveLoadStateSlots();
|
2016-07-27 13:47:50 +01:00
|
|
|
}
|
2016-07-27 14:10:28 +01:00
|
|
|
|
|
|
|
void MainWindow::RegisterPreferences()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT, true);
|
|
|
|
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, true);
|
2020-02-11 07:53:35 +00:00
|
|
|
CAppConfig::GetInstance().RegisterPreferenceInteger(PREF_VIDEO_GS_HANDLER, SettingsDialog::GS_HANDLERS::OPENGL);
|
2020-02-25 18:47:50 +00:00
|
|
|
CAppConfig::GetInstance().RegisterPreferenceString(PREF_INPUT_PAD1_PROFILE, "default");
|
2016-07-29 18:31:09 +01:00
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::focusOutEvent(QFocusEvent* event)
|
2016-07-29 18:31:09 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_pauseFocusLost && m_virtualMachine->GetStatus() == CVirtualMachine::RUNNING)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2019-09-12 15:11:52 -04:00
|
|
|
if(!isActiveWindow() && !m_outputwindow->isActive())
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Pause();
|
2018-04-30 21:01:23 +01:00
|
|
|
m_deactivatePause = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-29 18:31:09 +01:00
|
|
|
}
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::focusInEvent(QFocusEvent* event)
|
2016-07-29 18:31:09 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_pauseFocusLost && m_virtualMachine->GetStatus() == CVirtualMachine::PAUSED)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2019-09-12 15:11:52 -04:00
|
|
|
if(m_deactivatePause && (isActiveWindow() || m_outputwindow->isActive()))
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
if(m_virtualMachine != nullptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
2018-08-01 12:59:11 -04:00
|
|
|
m_virtualMachine->Resume();
|
2018-04-30 21:01:23 +01:00
|
|
|
m_deactivatePause = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-29 18:31:09 +01:00
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
void MainWindow::doubleClickEvent(QMouseEvent* ev)
|
2017-04-22 19:46:31 +01:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
if(ev->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
toggleFullscreen();
|
|
|
|
}
|
2017-04-22 19:46:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::toggleFullscreen()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
if(isFullScreen())
|
|
|
|
{
|
|
|
|
showNormal();
|
|
|
|
statusBar()->show();
|
|
|
|
menuBar()->show();
|
2020-11-13 17:00:58 -05:00
|
|
|
m_outputwindow->DismissFullScreenCursor();
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
showFullScreen();
|
|
|
|
statusBar()->hide();
|
|
|
|
menuBar()->hide();
|
2020-11-13 17:00:58 -05:00
|
|
|
m_outputwindow->ShowFullScreenCursor();
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
2017-04-22 19:46:31 +01:00
|
|
|
}
|
2018-11-19 13:20:46 -05:00
|
|
|
|
2020-12-20 19:22:04 -05:00
|
|
|
void MainWindow::buildResizeWindowMenu()
|
|
|
|
{
|
|
|
|
struct VIDEO_MODE
|
|
|
|
{
|
|
|
|
const char* name;
|
|
|
|
unsigned int width;
|
|
|
|
unsigned int height;
|
|
|
|
};
|
2020-12-31 19:06:20 -05:00
|
|
|
// clang-format off
|
2020-12-20 19:22:04 -05:00
|
|
|
static const VIDEO_MODE videoModes[] =
|
|
|
|
{
|
|
|
|
{ "NTSC", 640, 448 },
|
|
|
|
{ "PAL", 640, 512 },
|
|
|
|
{ "HDTV (1080)", 1920, 1080 }
|
|
|
|
};
|
2020-12-21 18:45:58 -05:00
|
|
|
static const float scaleRatios[] =
|
|
|
|
{
|
|
|
|
0.5f,
|
|
|
|
1.0f,
|
|
|
|
2.0f
|
|
|
|
};
|
2020-12-31 19:06:20 -05:00
|
|
|
// clang-format on
|
2020-12-20 19:22:04 -05:00
|
|
|
for(const auto& videoMode : videoModes)
|
|
|
|
{
|
|
|
|
auto videoModeDesc = QString("%1 - %2x%3").arg(videoMode.name).arg(videoMode.width).arg(videoMode.height);
|
|
|
|
QMenu* videoModeMenu = ui->menuResizeWindow->addMenu(videoModeDesc);
|
2020-12-31 19:06:20 -05:00
|
|
|
|
2020-12-21 18:45:58 -05:00
|
|
|
for(const auto& scaleRatio : scaleRatios)
|
2020-12-20 19:22:04 -05:00
|
|
|
{
|
|
|
|
QAction* scaleAction = new QAction(this);
|
2020-12-21 18:45:58 -05:00
|
|
|
scaleAction->setText(QString("%1x").arg(scaleRatio));
|
2020-12-20 19:22:04 -05:00
|
|
|
videoModeMenu->addAction(scaleAction);
|
2020-12-31 19:06:20 -05:00
|
|
|
|
2020-12-21 18:45:58 -05:00
|
|
|
auto width = static_cast<uint32>(static_cast<float>(videoMode.width) * scaleRatio);
|
|
|
|
auto height = static_cast<uint32>(static_cast<float>(videoMode.height) * scaleRatio);
|
2020-12-20 19:22:04 -05:00
|
|
|
connect(scaleAction, &QAction::triggered, std::bind(&MainWindow::resizeWindow, this, width, height));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::resizeWindow(unsigned int width, unsigned int height)
|
|
|
|
{
|
|
|
|
ui->centralWidget->resize(width, height);
|
|
|
|
ui->centralWidget->setMinimumSize(width, height);
|
|
|
|
adjustSize();
|
|
|
|
ui->centralWidget->setMinimumSize(0, 0);
|
|
|
|
}
|
|
|
|
|
2019-03-21 17:52:43 -04:00
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2019-08-31 12:33:24 -04:00
|
|
|
//bool MainWindow::nativeEventFilter(const QByteArray&, void* message, long* result)
|
|
|
|
//{
|
|
|
|
// auto msg = reinterpret_cast<MSG*>(message);
|
|
|
|
// HWND activeWnd = GetActiveWindow();
|
|
|
|
// if(m_debugger && (activeWnd == m_debugger->m_hWnd) &&
|
|
|
|
// TranslateAccelerator(m_debugger->m_hWnd, m_debugger->GetAccelerators(), msg))
|
|
|
|
// {
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
// if(m_frameDebugger && (activeWnd == m_frameDebugger->m_hWnd) &&
|
|
|
|
// TranslateAccelerator(m_frameDebugger->m_hWnd, m_frameDebugger->GetAccelerators(), msg))
|
|
|
|
// {
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
// return false;
|
|
|
|
//}
|
2019-03-21 17:52:43 -04:00
|
|
|
|
|
|
|
void MainWindow::ShowDebugger()
|
|
|
|
{
|
2019-08-31 12:33:24 -04:00
|
|
|
m_debugger->showMaximized();
|
|
|
|
//SetForegroundWindow(*m_debugger);
|
2019-03-21 17:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::ShowFrameDebugger()
|
|
|
|
{
|
2019-08-31 12:33:24 -04:00
|
|
|
//m_frameDebugger->Show(SW_SHOWMAXIMIZED);
|
|
|
|
//SetForegroundWindow(*m_frameDebugger);
|
2019-03-21 17:52:43 -04:00
|
|
|
}
|
2019-03-25 12:41:48 -04:00
|
|
|
|
2019-10-16 20:51:11 -04:00
|
|
|
fs::path MainWindow::GetFrameDumpDirectoryPath()
|
2019-03-25 12:41:48 -04:00
|
|
|
{
|
2019-10-16 20:51:11 -04:00
|
|
|
return CAppConfig::GetBasePath() / fs::path("framedumps/");
|
2019-03-25 12:41:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::DumpNextFrame()
|
|
|
|
{
|
|
|
|
m_virtualMachine->TriggerFrameDump(
|
|
|
|
[&](const CFrameDump& frameDump) {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto frameDumpDirectoryPath = GetFrameDumpDirectoryPath();
|
|
|
|
Framework::PathUtils::EnsurePathExists(frameDumpDirectoryPath);
|
|
|
|
for(unsigned int i = 0; i < UINT_MAX; i++)
|
|
|
|
{
|
|
|
|
auto frameDumpFileName = string_format("framedump_%08d.dmp.zip", i);
|
2019-10-16 20:51:11 -04:00
|
|
|
auto frameDumpPath = frameDumpDirectoryPath / fs::path(frameDumpFileName);
|
|
|
|
if(!fs::exists(frameDumpPath))
|
2019-03-25 12:41:48 -04:00
|
|
|
{
|
|
|
|
auto dumpStream = Framework::CreateOutputStdStream(frameDumpPath.native());
|
|
|
|
frameDump.Write(dumpStream);
|
|
|
|
m_msgLabel->setText(QString("Dumped frame to '%1'.").arg(frameDumpFileName.c_str()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
m_msgLabel->setText(QString("Failed to dump frame."));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-25 12:57:31 -04:00
|
|
|
void MainWindow::ToggleGsDraw()
|
|
|
|
{
|
|
|
|
auto gs = m_virtualMachine->GetGSHandler();
|
|
|
|
if(gs == nullptr) return;
|
|
|
|
bool newState = !gs->GetDrawEnabled();
|
|
|
|
gs->SetDrawEnabled(newState);
|
2019-08-31 12:33:24 -04:00
|
|
|
//debugMenuUi->actionGsDrawEnabled->setChecked(newState);
|
2019-03-25 12:57:31 -04:00
|
|
|
m_msgLabel->setText(newState ? QString("GS Draw Enabled") : QString("GS Draw Disabled"));
|
|
|
|
}
|
|
|
|
|
2019-03-21 17:52:43 -04:00
|
|
|
#endif
|
|
|
|
|
2016-07-29 18:31:09 +01:00
|
|
|
void MainWindow::on_actionPause_when_focus_is_lost_triggered(bool checked)
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
m_pauseFocusLost = checked;
|
|
|
|
CAppConfig::GetInstance().SetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, m_pauseFocusLost);
|
2016-07-27 14:10:28 +01:00
|
|
|
}
|
2016-07-29 19:19:27 +01:00
|
|
|
|
|
|
|
void MainWindow::on_actionReset_triggered()
|
|
|
|
{
|
2018-09-22 22:30:15 -04:00
|
|
|
if(!m_lastOpenCommand.path.empty())
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
if(m_lastOpenCommand.type == BootType::CD)
|
|
|
|
{
|
|
|
|
BootCDROM();
|
|
|
|
}
|
|
|
|
else if(m_lastOpenCommand.type == BootType::ELF)
|
|
|
|
{
|
2018-09-22 22:30:15 -04:00
|
|
|
BootElf(m_lastOpenCommand.path);
|
2018-04-30 21:01:23 +01:00
|
|
|
}
|
|
|
|
}
|
2016-07-29 19:19:27 +01:00
|
|
|
}
|
2016-08-10 14:56:16 +01:00
|
|
|
|
|
|
|
void MainWindow::on_actionMemory_Card_Manager_triggered()
|
|
|
|
{
|
2019-01-07 20:05:40 -05:00
|
|
|
MemoryCardManagerDialog mcm(this);
|
2018-04-30 21:01:23 +01:00
|
|
|
mcm.exec();
|
2016-08-10 14:56:16 +01:00
|
|
|
}
|
2016-09-06 00:03:02 +01:00
|
|
|
|
|
|
|
void MainWindow::on_actionVFS_Manager_triggered()
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
VFSManagerDialog vfsmgr;
|
|
|
|
vfsmgr.exec();
|
2016-09-06 00:03:02 +01:00
|
|
|
}
|
2016-09-06 00:23:31 +01:00
|
|
|
|
|
|
|
void MainWindow::on_actionController_Manager_triggered()
|
|
|
|
{
|
2018-11-19 13:20:46 -05:00
|
|
|
auto padHandler = static_cast<CPH_GenericInput*>(m_virtualMachine->GetPadHandler());
|
|
|
|
if(!padHandler) return;
|
2018-11-28 22:32:27 -05:00
|
|
|
|
2018-11-19 13:20:46 -05:00
|
|
|
ControllerConfigDialog ccd(&padHandler->GetBindingManager(), m_qtKeyInputProvider.get(), this);
|
2018-04-30 21:01:23 +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()
|
|
|
|
{
|
2019-08-16 08:27:30 -04:00
|
|
|
m_screenShotCompleteConnection = CScreenShotUtils::TriggerGetScreenshot(m_virtualMachine,
|
2019-08-19 19:05:35 -04:00
|
|
|
[&](int res, const char* msg) -> void {
|
|
|
|
m_msgLabel->setText(msg);
|
|
|
|
});
|
2017-04-09 06:50:07 +01:00
|
|
|
}
|
2019-01-16 20:00:10 +00:00
|
|
|
|
|
|
|
void MainWindow::on_actionList_Bootables_triggered()
|
|
|
|
{
|
|
|
|
BootableListDialog dialog(this);
|
|
|
|
if(dialog.exec())
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BootablesDb::Bootable bootable = dialog.getResult();
|
|
|
|
if(IsBootableDiscImagePath(bootable.path))
|
|
|
|
{
|
|
|
|
LoadCDROM(bootable.path);
|
|
|
|
BootCDROM();
|
|
|
|
}
|
|
|
|
else if(IsBootableExecutablePath(bootable.path))
|
|
|
|
{
|
|
|
|
BootElf(bootable.path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
|
|
|
QString invalid("Invalid File Format.");
|
|
|
|
messageBox.critical(this, this->windowTitle(), invalid);
|
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(const std::exception& e)
|
|
|
|
{
|
|
|
|
QMessageBox messageBox;
|
|
|
|
messageBox.critical(nullptr, "Error", e.what());
|
|
|
|
messageBox.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 17:29:37 +00:00
|
|
|
|
|
|
|
void MainWindow::UpdateGSHandlerLabel(int gs_index)
|
|
|
|
{
|
|
|
|
switch(gs_index)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case SettingsDialog::GS_HANDLERS::OPENGL:
|
|
|
|
m_gsLabel->setText("OpenGL");
|
|
|
|
break;
|
|
|
|
#ifdef HAS_GSH_VULKAN
|
|
|
|
case SettingsDialog::GS_HANDLERS::VULKAN:
|
|
|
|
m_gsLabel->setText("Vulkan");
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2020-04-10 05:31:49 +01:00
|
|
|
}
|