Play-/Source/ui_qt/mainwindow.cpp

1084 lines
31 KiB
C++
Raw Normal View History

2016-09-06 00:12:56 +01:00
#include "mainwindow.h"
#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"
#ifdef HAS_AMAZON_S3
#include "S3FileBrowser.h"
#endif
2022-09-29 16:02:50 -04:00
#include "ui_shared/ArcadeUtils.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"
#include "QtUtils.h"
#include "openglwindow.h"
#include "GSH_OpenGLQt.h"
2019-12-15 12:38:16 -05:00
#ifdef HAS_GSH_VULKAN
#include "vulkanwindow.h"
#include "GSH_VulkanQt.h"
#include "gs/GSH_Vulkan/GSH_VulkanDeviceInfo.h"
#endif
#include <ctime>
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>
#include <QtGlobal>
#include <QCheckBox>
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
#include "DebugSupport/DebugSupportSettings.h"
#include "DebugSupport/QtDebugger.h"
2020-02-07 07:23:23 +00:00
#include "DebugSupport/FrameDebugger/QtFramedebugger.h"
#include "ui_debugdockmenu.h"
2019-08-31 12:33:24 -04:00
#include "ui_debugmenu.h"
#endif
#include "input/PH_GenericInput.h"
2016-07-26 15:06:37 +01:00
#include "DiskUtils.h"
#include "PathUtils.h"
2022-05-15 22:46:03 +01:00
#include <zstd_zlibwrapper.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-09-06 00:12:56 +01:00
#include "ui_mainwindow.h"
2016-09-06 00:03:02 +01:00
#include "vfsmanagerdialog.h"
#include "ControllerConfig/controllerconfigdialog.h"
#include "QBootablesView.h"
2016-09-06 00:12:56 +01:00
#ifdef __APPLE__
2018-11-19 19:18:37 -05:00
#include "macos/InputProviderMacOsHid.h"
#endif
2018-11-27 13:25:34 -05:00
#ifdef HAS_LIBEVDEV
#include "unix/InputProviderEvDev.h"
#endif
#ifdef WIN32
#include "win32/InputProviderDirectInput.h"
2019-06-19 19:05:45 -04:00
#include "win32/InputProviderXInput.h"
#endif
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
{
ArcadeUtils::RegisterArcadeMachines();
2022-09-30 18:02:29 -04:00
2018-04-30 21:01:23 +01:00
ui->setupUi(this);
buildResizeWindowMenu();
2016-07-01 05:21:58 +03:00
RegisterPreferences();
m_continuationChecker = new CContinuationChecker(this);
#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);
auto lastPath = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_CDROM0_PATH);
std::error_code lastPathExistsErrorCode;
if(fs::exists(lastPath, lastPathExistsErrorCode))
2018-04-30 21:01:23 +01: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();
addAction(ui->actionPause_Resume);
2022-01-13 23:58:16 +00:00
SetupBootableView();
#ifdef HAS_AMAZON_S3
ui->actionBoot_DiscImage_S3->setVisible(S3FileBrowser::IsAvailable());
#endif
InitVirtualMachine();
SetupGsHandler();
SetupDebugger();
2022-01-14 15:03:27 +00:00
m_onRunningStateChangeConnection = m_virtualMachine->OnRunningStateChange.Connect([&] {
if(m_virtualMachine->GetStatus() == CVirtualMachine::RUNNING)
ui->stackedWidget->setCurrentIndex(1);
});
2016-09-06 00:12:56 +01:00
}
MainWindow::~MainWindow()
{
#ifdef DEBUGGER_INCLUDED
m_debugger.reset();
2020-02-02 19:46:03 +00:00
m_frameDebugger.reset();
#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();
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
}
delete ui;
2022-03-16 16:45:30 -04:00
#ifdef DEBUGGER_INCLUDED
delete debugDockMenuUi;
2019-08-31 12:33:24 -04:00
delete debugMenuUi;
#endif
}
void MainWindow::InitVirtualMachine()
2016-08-02 02:50:26 +01:00
{
assert(!m_virtualMachine);
2018-08-01 12:59:11 -04:00
m_virtualMachine = new CPS2VM();
m_virtualMachine->Initialize();
2018-04-30 21:01:23 +01:00
SetupSoundHandler();
2016-07-26 00:52:31 +01: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);
auto& bindingManager = padHandler->GetBindingManager();
2020-02-25 18:47:50 +00:00
bindingManager.Load(profile);
//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>());
#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
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-28 22:32:27 -05:00
#ifdef PROFILE
m_profileFrameDoneConnection = m_virtualMachine->ProfileFrameDone.Connect(std::bind(&CStatsManager::OnProfileFrameDone, &CStatsManager::GetInstance(), std::placeholders::_1));
#endif
2019-08-01 12:44:10 -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));
connect(this, SIGNAL(onExecutableChange()), this, SLOT(HandleOnExecutableChange()));
}
void MainWindow::SetOutputWindowSize()
2016-09-06 00:12:56 +01:00
{
outputWindow_resized();
}
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
{
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();
2022-01-13 23:58:16 +00:00
ui->stackedWidget->addWidget(container);
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:
#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();
2022-01-13 23:58:16 +00:00
ui->stackedWidget->addWidget(container);
2020-02-09 23:05:24 +00:00
m_virtualMachine->CreateGSHandler(CGSH_OpenGLQt::GetFactoryFunction(m_outputwindow));
}
2020-02-11 07:53:35 +00:00
}
2022-01-13 23:58:16 +00:00
if(ui->stackedWidget->count() > 2)
{
auto oldContainer = ui->stackedWidget->widget(1);
ui->stackedWidget->removeWidget(oldContainer);
delete oldContainer;
}
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*)));
m_OnNewFrameConnection = m_virtualMachine->m_ee->m_gs->OnNewFrame.Connect(std::bind(&CStatsManager::OnNewFrame, &CStatsManager::GetInstance(), m_virtualMachine, std::placeholders::_1));
}
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
}
void MainWindow::outputWindow_resized()
{
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
{
uint32 w = m_outputwindow->size().width(), h = m_outputwindow->size().height();
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
}
}
2018-09-28 08:17:24 -04:00
void MainWindow::on_actionBoot_DiscImage_triggered()
{
QStringList filters;
filters.push_back(QtUtils::GetDiscImageFormatsFilter());
filters.push_back("All files (*)");
2018-04-30 21:01:23 +01:00
QFileDialog dialog(this);
dialog.setDirectory(PathToQString(m_lastPath));
2018-04-30 21:01:23 +01:00
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
2018-04-30 21:01:23 +01:00
if(dialog.exec())
{
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
{
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();
}
}
}
}
void MainWindow::on_actionBoot_DiscImage_S3_triggered()
{
#ifdef HAS_AMAZON_S3
S3FileBrowser browser(this);
if(browser.exec())
{
auto filePath = browser.GetSelectedPath();
if(m_virtualMachine != nullptr)
{
try
{
LoadCDROM(filePath);
BootCDROM();
}
catch(const std::exception& e)
{
QMessageBox messageBox;
messageBox.critical(nullptr, "Error", e.what());
messageBox.show();
}
}
}
#endif
}
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();
}
}
void MainWindow::on_actionBoot_ELF_triggered()
{
2018-04-30 21:01:23 +01:00
QFileDialog dialog(this);
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())
{
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
{
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();
}
}
}
}
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);
#ifndef DEBUGGER_INCLUDED
2018-08-01 12:59:11 -04:00
m_virtualMachine->Resume();
#endif
{
TryRegisterBootable(filePath);
TryUpdateLastBootedTime(filePath);
m_lastOpenCommand = LastOpenCommand(BootType::ELF, filePath);
UpdateUI();
}
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();
#ifndef DEBUGGER_INCLUDED
2018-08-01 12:59:11 -04:00
m_virtualMachine->Resume();
#endif
{
auto filePath = CAppConfig::GetInstance().GetPreferencePath(PREF_PS2_CDROM0_PATH);
TryRegisterBootable(filePath);
TryUpdateLastBootedTime(filePath);
m_lastOpenCommand = LastOpenCommand(BootType::CD, filePath);
UpdateUI();
}
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
}
2022-10-08 16:33:19 -04:00
void MainWindow::BootArcadeMachine(fs::path arcadeDefPath)
{
ArcadeUtils::BootArcadeMachine(m_virtualMachine, arcadeDefPath);
m_lastOpenCommand = LastOpenCommand(BootType::ARCADE, arcadeDefPath);
m_msgLabel->setText(QString("Started arcade machine '%1'.").arg(arcadeDefPath.filename().c_str()));
UpdateUI();
}
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
{
if((event->key() != Qt::Key_Escape) && m_qtKeyInputProvider)
2018-04-30 21:01:23 +01: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;
}
if(m_qtKeyInputProvider)
2018-04-30 21:01:23 +01: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
{
m_fpsLabel = new QLabel("");
m_fpsLabel->setAlignment(Qt::AlignHCenter);
m_fpsLabel->setMinimumSize(m_fpsLabel->sizeHint());
m_cpuUsageLabel = new QLabel("");
m_cpuUsageLabel->setAlignment(Qt::AlignHCenter);
m_cpuUsageLabel->setMinimumSize(m_cpuUsageLabel->sizeHint());
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);
statusBar()->addWidget(m_fpsLabel);
statusBar()->addWidget(m_cpuUsageLabel);
2020-02-10 22:11:18 +00:00
#ifdef HAS_GSH_VULKAN
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);
UpdateGSHandlerLabel(gs_index);
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
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);
UpdateCpuUsageLabel();
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();
auto cpuUtilisation = CStatsManager::GetInstance().GetCpuUtilisationInfo();
uint32 dcpf = (frames != 0) ? (drawCalls / frames) : 0;
#ifdef PROFILE
m_profileStatsLabel->setText(QString::fromStdString(CStatsManager::GetInstance().GetProfilingInfo()));
#endif
m_fpsLabel->setText(QString("%1 f/s, %2 dc/f").arg(frames).arg(dcpf));
auto eeUsageRatio = CStatsManager::ComputeCpuUsageRatio(cpuUtilisation.eeIdleTicks, cpuUtilisation.eeTotalTicks);
m_cpuUsageLabel->setText(QString("EE CPU: %1%").arg(static_cast<int>(eeUsageRatio)));
2019-07-24 19:35:46 -04:00
CStatsManager::GetInstance().ClearStats();
}
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)
{
m_virtualMachine->ReloadSpuBlockCount();
2021-02-24 11:55:09 -05:00
m_virtualMachine->ReloadFrameRateLimit();
UpdateCpuUsageLabel();
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)
{
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
{
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);
auto future = m_virtualMachine->SaveState(stateFilePath);
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));
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);
auto future = m_virtualMachine->LoadState(stateFilePath);
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));
#ifndef DEBUGGER_INCLUDED
2018-10-11 12:54:56 -04:00
m_virtualMachine->Resume();
#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);
QFileInfo file(PathToQString(stateFilePath));
2018-04-30 21:01:23 +01:00
if(file.exists() && file.isFile())
{
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
}
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
{
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
{
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)
{
//btnRes is the answer to the "Are you sure you want to exit?" question.
auto resBtn = QMessageBox::Yes;
2022-06-09 14:51:15 -04:00
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREF_UI_SHOWEXITCONFIRMATION))
{
auto message =
2022-06-09 14:51:15 -04:00
[this]() {
if(ui->bootablesView->IsProcessing())
{
return tr("Are you sure you want to exit?\nBootables are currently getting processed.\n");
}
else
{
return tr("Are you sure you want to exit?\nAny progress will be lost if not saved previously.\n");
}
}();
QMessageBox messageBox;
QCheckBox* showAgainCheckBox = new QCheckBox("Show this message next time", &messageBox);
showAgainCheckBox->setChecked(true);
messageBox.setWindowTitle("Close Confirmation");
messageBox.setText(message);
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
messageBox.setDefaultButton(QMessageBox::Yes);
messageBox.setIcon(QMessageBox::Question);
messageBox.setCheckBox(showAgainCheckBox);
resBtn = static_cast<QMessageBox::StandardButton>(messageBox.exec());
CAppConfig::GetInstance().SetPreferenceBoolean(PREF_UI_SHOWEXITCONFIRMATION, showAgainCheckBox->isChecked());
}
2018-04-30 21:01:23 +01:00
if(resBtn != QMessageBox::Yes)
{
event->ignore();
}
else
{
event->accept();
#ifdef DEBUGGER_INCLUDED
m_debugger->close();
m_frameDebugger->close();
#endif
2018-04-30 21:01:23 +01:00
}
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
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));
setWindowTitle(titleString);
ui->bootablesView->AsyncResetModel(true);
2016-07-27 13:47:50 +01: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);
ui->actionReset->setEnabled(!m_lastOpenCommand.path.empty());
ui->actionPause_Resume->setEnabled(IsExecutableLoaded());
SetOutputWindowSize();
2018-04-30 21:01:23 +01:00
SetupSaveLoadStateSlots();
2016-07-27 13:47:50 +01:00
}
void MainWindow::UpdateCpuUsageLabel()
{
bool visible = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_UI_SHOWEECPUUSAGE);
m_cpuUsageLabel->setVisible(visible);
}
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);
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_UI_SHOWEECPUUSAGE, false);
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_UI_SHOWEXITCONFIRMATION, 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
{
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
{
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
}
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
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
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)
{
QAction* scaleAction = new QAction(this);
2020-12-21 18:45:58 -05:00
scaleAction->setText(QString("%1x").arg(scaleRatio));
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);
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);
}
#ifdef DEBUGGER_INCLUDED
void MainWindow::ShowMainWindow()
{
show();
raise();
activateWindow();
}
void MainWindow::ShowDebugger()
{
2019-08-31 12:33:24 -04:00
m_debugger->showMaximized();
m_debugger->raise();
m_debugger->activateWindow();
}
void MainWindow::ShowFrameDebugger()
{
2020-02-02 19:46:03 +00:00
m_frameDebugger->show();
m_frameDebugger->raise();
m_frameDebugger->activateWindow();
}
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."));
});
}
void MainWindow::ToggleGsDraw()
{
auto gs = m_virtualMachine->GetGSHandler();
if(gs == nullptr) return;
bool newState = !gs->GetDrawEnabled();
gs->SetDrawEnabled(newState);
2019-12-18 12:13:34 +00:00
debugMenuUi->actionGsDrawEnabled->setChecked(newState);
m_msgLabel->setText(newState ? QString("GS Draw Enabled") : QString("GS Draw Disabled"));
}
#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-29 19:19:27 +01:00
void MainWindow::on_actionReset_triggered()
{
if(!m_lastOpenCommand.path.empty())
2018-04-30 21:01:23 +01:00
{
2022-10-08 16:33:19 -04:00
switch(m_lastOpenCommand.type)
2018-04-30 21:01:23 +01:00
{
2022-10-08 16:33:19 -04:00
case BootType::CD:
2018-04-30 21:01:23 +01:00
BootCDROM();
2022-10-08 16:33:19 -04:00
break;
case BootType::ELF:
BootElf(m_lastOpenCommand.path);
2022-10-08 16:33:19 -04:00
break;
case BootType::ARCADE:
BootArcadeMachine(m_lastOpenCommand.path);
break;
default:
assert(false);
break;
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()
{
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()
{
auto padHandler = static_cast<CPH_GenericInput*>(m_virtualMachine->GetPadHandler());
if(!padHandler) return;
2018-11-28 22:32:27 -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()
{
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()
{
2022-01-16 15:15:05 +00:00
ui->stackedWidget->setCurrentIndex(1 - ui->stackedWidget->currentIndex());
2019-01-16 20:00:10 +00:00
}
void MainWindow::UpdateGSHandlerLabel(int gs_index)
{
#if HAS_GSH_VULKAN
switch(gs_index)
{
default:
case SettingsDialog::GS_HANDLERS::OPENGL:
m_gsLabel->setText("OpenGL");
break;
case SettingsDialog::GS_HANDLERS::VULKAN:
m_gsLabel->setText("Vulkan");
break;
}
#endif
}
2022-01-13 23:58:16 +00:00
void MainWindow::SetupBootableView()
{
auto showEmu = std::bind(&QStackedWidget::setCurrentIndex, ui->stackedWidget, 1);
QBootablesView* bootablesView = ui->bootablesView;
2022-01-13 23:58:16 +00:00
bootablesView->AddMsgLabel(m_msgLabel);
2022-01-15 01:23:44 +00:00
QBootablesView::BootCallback bootGameCallback = [&, showEmu](fs::path filePath) {
2022-01-13 23:58:16 +00:00
try
{
if(IsBootableDiscImagePath(filePath))
{
LoadCDROM(filePath);
BootCDROM();
}
else if(IsBootableExecutablePath(filePath))
{
BootElf(filePath);
}
2022-09-29 16:02:50 -04:00
else if(IsBootableArcadeDefPath(filePath))
{
2022-10-08 16:33:19 -04:00
BootArcadeMachine(filePath);
2022-09-29 16:02:50 -04:00
}
else
{
QMessageBox messageBox;
QString invalid("Invalid File Format.");
messageBox.critical(this, this->windowTitle(), invalid);
messageBox.show();
}
2022-01-13 23:58:16 +00:00
showEmu();
}
catch(const std::exception& e)
{
QMessageBox messageBox;
messageBox.critical(nullptr, "Error", e.what());
messageBox.show();
}
};
2022-01-15 01:23:44 +00:00
bootablesView->SetupActions(bootGameCallback);
}
void MainWindow::SetupDebugger()
{
#ifdef DEBUGGER_INCLUDED
CDebugSupportSettings::GetInstance().Initialize(&CAppConfig::GetInstance());
m_debugger = std::make_unique<QtDebugger>(*m_virtualMachine);
m_frameDebugger = std::make_unique<QtFramedebugger>();
{
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));
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));
}
2022-05-06 09:21:28 -04:00
#if defined(__APPLE__)
{
auto debugDockMenu = new QMenu(this);
debugDockMenuUi = new Ui::DebugDockMenu();
debugDockMenuUi->setupUi(debugDockMenu);
2022-05-06 09:21:28 -04:00
connect(debugDockMenuUi->actionShowMainWindow, &QAction::triggered, this, std::bind(&MainWindow::ShowMainWindow, this));
connect(debugDockMenuUi->actionShowDebugger, &QAction::triggered, this, std::bind(&MainWindow::ShowDebugger, this));
connect(debugDockMenuUi->actionShowFrameDebugger, &QAction::triggered, this, std::bind(&MainWindow::ShowFrameDebugger, this));
debugDockMenu->setAsDockMenu();
}
2022-05-06 09:21:28 -04:00
#endif //defined(__APPLE__)
#endif //DEBUGGER_INCLUDED
}