2019-12-31 06:17:17 +00:00
|
|
|
#include "mainwindow.h"
|
2020-06-19 17:33:57 +00:00
|
|
|
#include "aboutdialog.h"
|
2020-08-06 12:08:22 +00:00
|
|
|
#include "autoupdaterdialog.h"
|
2020-10-19 15:14:49 +00:00
|
|
|
#include "cheatmanagerdialog.h"
|
2020-02-15 15:14:28 +00:00
|
|
|
#include "common/assert.h"
|
2020-06-29 16:46:57 +00:00
|
|
|
#include "core/host_display.h"
|
2019-12-31 06:17:17 +00:00
|
|
|
#include "core/settings.h"
|
2020-03-02 01:08:16 +00:00
|
|
|
#include "core/system.h"
|
2020-12-16 15:18:13 +00:00
|
|
|
#include "debuggerwindow.h"
|
2020-09-01 02:29:22 +00:00
|
|
|
#include "frontend-common/game_list.h"
|
2020-01-24 04:50:53 +00:00
|
|
|
#include "gamelistsettingswidget.h"
|
2019-12-31 06:17:17 +00:00
|
|
|
#include "gamelistwidget.h"
|
2020-05-16 10:02:44 +00:00
|
|
|
#include "gamepropertiesdialog.h"
|
2020-12-17 17:32:29 +00:00
|
|
|
#include "gdbserver.h"
|
2020-09-18 14:28:07 +00:00
|
|
|
#include "memorycardeditordialog.h"
|
2020-03-12 03:53:51 +00:00
|
|
|
#include "qtdisplaywidget.h"
|
2019-12-31 06:17:17 +00:00
|
|
|
#include "qthostinterface.h"
|
2020-06-10 15:48:54 +00:00
|
|
|
#include "qtutils.h"
|
2020-04-16 15:56:11 +00:00
|
|
|
#include "scmversion/scmversion.h"
|
2019-12-31 06:17:17 +00:00
|
|
|
#include "settingsdialog.h"
|
2020-02-04 06:22:56 +00:00
|
|
|
#include "settingwidgetbinder.h"
|
2020-03-12 03:53:58 +00:00
|
|
|
#include <QtCore/QDebug>
|
2020-06-24 15:31:23 +00:00
|
|
|
#include <QtCore/QFile>
|
2020-03-02 01:08:16 +00:00
|
|
|
#include <QtCore/QFileInfo>
|
2020-01-24 04:51:59 +00:00
|
|
|
#include <QtCore/QUrl>
|
2020-03-28 15:12:27 +00:00
|
|
|
#include <QtGui/QCursor>
|
2020-03-22 11:50:49 +00:00
|
|
|
#include <QtGui/QWindowStateChangeEvent>
|
2020-08-06 17:34:40 +00:00
|
|
|
#include <QtWidgets/QActionGroup>
|
2019-12-31 06:17:17 +00:00
|
|
|
#include <QtWidgets/QFileDialog>
|
2020-01-24 04:49:51 +00:00
|
|
|
#include <QtWidgets/QMessageBox>
|
2020-06-29 16:46:57 +00:00
|
|
|
#include <QtWidgets/QStyleFactory>
|
2020-01-24 04:49:47 +00:00
|
|
|
#include <cmath>
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-08-23 12:47:49 +00:00
|
|
|
static constexpr char DISC_IMAGE_FILTER[] = QT_TRANSLATE_NOOP(
|
|
|
|
"MainWindow",
|
2020-11-21 08:41:36 +00:00
|
|
|
"All File Types (*.bin *.img *.iso *.cue *.chd *.exe *.psexe *.psf *.m3u);;Single-Track Raw Images (*.bin *.img "
|
|
|
|
"*.iso);;Cue Sheets (*.cue);;MAME CHD Images (*.chd);;PlayStation Executables (*.exe *.psexe);;Portable Sound Format "
|
2021-01-24 03:17:22 +00:00
|
|
|
"Files (*.psf *.minipsf);;Playlists (*.m3u)");
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-04-16 15:56:11 +00:00
|
|
|
ALWAYS_INLINE static QString getWindowTitle()
|
|
|
|
{
|
|
|
|
return QStringLiteral("DuckStation %1 (%2)").arg(g_scm_tag_str).arg(g_scm_branch_str);
|
|
|
|
}
|
|
|
|
|
2020-07-04 05:54:26 +00:00
|
|
|
MainWindow::MainWindow(QtHostInterface* host_interface)
|
|
|
|
: QMainWindow(nullptr), m_unthemed_style_name(QApplication::style()->objectName()), m_host_interface(host_interface)
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
2020-03-12 05:32:30 +00:00
|
|
|
m_host_interface->setMainWindow(this);
|
|
|
|
|
2020-12-29 06:29:14 +00:00
|
|
|
// force creation of native window
|
|
|
|
winId();
|
|
|
|
}
|
|
|
|
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{
|
|
|
|
Assert(!m_display_widget);
|
|
|
|
m_host_interface->setMainWindow(nullptr);
|
|
|
|
|
|
|
|
Assert(!m_debugger_window);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::initializeAndShow()
|
|
|
|
{
|
2019-12-31 06:17:17 +00:00
|
|
|
m_ui.setupUi(this);
|
|
|
|
setupAdditionalUi();
|
|
|
|
connectSignals();
|
2020-06-24 15:31:23 +00:00
|
|
|
updateTheme();
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-03-22 12:40:29 +00:00
|
|
|
resize(800, 700);
|
2020-09-14 07:58:04 +00:00
|
|
|
|
|
|
|
restoreStateFromConfig();
|
|
|
|
switchToGameListView();
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-12-29 06:29:14 +00:00
|
|
|
show();
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-02-15 15:14:30 +00:00
|
|
|
void MainWindow::reportError(const QString& message)
|
2020-01-24 04:51:30 +00:00
|
|
|
{
|
2020-02-26 09:25:57 +00:00
|
|
|
QMessageBox::critical(this, tr("DuckStation"), message, QMessageBox::Ok);
|
2020-03-12 03:53:58 +00:00
|
|
|
focusDisplayWidget();
|
2020-01-24 04:51:30 +00:00
|
|
|
}
|
|
|
|
|
2020-02-15 15:14:30 +00:00
|
|
|
void MainWindow::reportMessage(const QString& message)
|
2020-01-24 04:51:30 +00:00
|
|
|
{
|
|
|
|
m_ui.statusBar->showMessage(message, 2000);
|
|
|
|
}
|
|
|
|
|
2020-02-26 09:25:57 +00:00
|
|
|
bool MainWindow::confirmMessage(const QString& message)
|
|
|
|
{
|
2020-02-28 07:00:09 +00:00
|
|
|
const int result = QMessageBox::question(this, tr("DuckStation"), message);
|
|
|
|
focusDisplayWidget();
|
2020-03-02 01:08:16 +00:00
|
|
|
|
2020-02-28 07:00:09 +00:00
|
|
|
return (result == QMessageBox::Yes);
|
2020-02-26 09:25:57 +00:00
|
|
|
}
|
|
|
|
|
2020-12-06 14:06:32 +00:00
|
|
|
bool MainWindow::shouldHideCursorInFullscreen() const
|
|
|
|
{
|
|
|
|
return g_host_interface->GetBoolSettingValue("Main", "HideCursorInFullscreen", true);
|
|
|
|
}
|
|
|
|
|
2020-12-26 13:22:24 +00:00
|
|
|
QtDisplayWidget* MainWindow::createDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
2020-04-22 11:13:51 +00:00
|
|
|
Assert(!m_host_display && !m_display_widget);
|
|
|
|
Assert(!fullscreen || !render_to_main);
|
2020-02-15 15:14:28 +00:00
|
|
|
|
2020-11-02 09:52:01 +00:00
|
|
|
m_host_display = m_host_interface->createHostDisplay();
|
|
|
|
if (!m_host_display)
|
|
|
|
{
|
|
|
|
reportError(tr("Failed to create host display."));
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-11-01 14:38:54 +00:00
|
|
|
const std::string fullscreen_mode = m_host_interface->GetStringSettingValue("GPU", "FullscreenMode", "");
|
2020-11-02 09:52:01 +00:00
|
|
|
const bool is_exclusive_fullscreen = (fullscreen && !fullscreen_mode.empty() && m_host_display->SupportsFullscreen());
|
2020-11-01 14:38:54 +00:00
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
m_display_widget = new QtDisplayWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
2020-04-05 12:58:47 +00:00
|
|
|
m_display_widget->setWindowTitle(windowTitle());
|
|
|
|
m_display_widget->setWindowIcon(windowIcon());
|
|
|
|
|
|
|
|
if (fullscreen)
|
|
|
|
{
|
2020-11-01 14:38:54 +00:00
|
|
|
if (!is_exclusive_fullscreen)
|
|
|
|
m_display_widget->showFullScreen();
|
|
|
|
else
|
|
|
|
m_display_widget->showNormal();
|
|
|
|
|
2020-12-28 16:00:31 +00:00
|
|
|
updateMouseMode(System::IsPaused());
|
2020-04-05 12:58:47 +00:00
|
|
|
}
|
|
|
|
else if (!render_to_main)
|
|
|
|
{
|
2020-10-03 02:10:11 +00:00
|
|
|
restoreDisplayWindowGeometryFromConfig();
|
2020-04-05 12:58:47 +00:00
|
|
|
m_display_widget->showNormal();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
|
|
|
switchToEmulationView();
|
|
|
|
}
|
2020-02-15 15:14:28 +00:00
|
|
|
|
|
|
|
// we need the surface visible.. this might be able to be replaced with something else
|
2019-12-31 06:17:17 +00:00
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
|
|
|
if (!wi.has_value())
|
|
|
|
{
|
2020-08-06 09:30:47 +00:00
|
|
|
reportError(QStringLiteral("Failed to get window info from widget"));
|
2020-06-29 16:46:57 +00:00
|
|
|
destroyDisplayWidget();
|
2020-11-02 09:52:01 +00:00
|
|
|
m_host_display = nullptr;
|
2020-06-29 16:46:57 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-12-26 13:22:24 +00:00
|
|
|
if (!m_host_display->CreateRenderDevice(wi.value(), g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
|
|
|
|
g_settings.gpu_threaded_presentation))
|
2020-04-22 11:13:51 +00:00
|
|
|
{
|
|
|
|
reportError(tr("Failed to create host display device context."));
|
2020-06-29 16:46:57 +00:00
|
|
|
destroyDisplayWidget();
|
2020-11-02 09:52:01 +00:00
|
|
|
m_host_display = nullptr;
|
2020-06-29 16:46:57 +00:00
|
|
|
return nullptr;
|
2020-04-22 11:13:51 +00:00
|
|
|
}
|
2020-02-15 15:14:28 +00:00
|
|
|
|
2020-11-01 14:38:54 +00:00
|
|
|
if (is_exclusive_fullscreen)
|
|
|
|
setDisplayFullscreen(fullscreen_mode);
|
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
m_host_display->DoneRenderContextCurrent();
|
|
|
|
return m_display_widget;
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
QtDisplayWidget* MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
|
2020-02-26 09:25:51 +00:00
|
|
|
{
|
2020-04-05 12:58:47 +00:00
|
|
|
const bool is_fullscreen = m_display_widget->isFullScreen();
|
|
|
|
const bool is_rendering_to_main = (!is_fullscreen && m_display_widget->parent());
|
2020-11-01 14:38:54 +00:00
|
|
|
const std::string fullscreen_mode = m_host_interface->GetStringSettingValue("GPU", "FullscreenMode", "");
|
2020-11-02 09:52:01 +00:00
|
|
|
const bool is_exclusive_fullscreen = (fullscreen && !fullscreen_mode.empty() && m_host_display->SupportsFullscreen());
|
2020-04-05 12:58:47 +00:00
|
|
|
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main)
|
2020-06-29 16:46:57 +00:00
|
|
|
return m_display_widget;
|
2020-03-12 03:53:58 +00:00
|
|
|
|
2021-01-20 07:22:18 +00:00
|
|
|
// Skip recreating the surface if we're just transitioning between fullscreen and windowed with render-to-main off.
|
|
|
|
if (!is_rendering_to_main && !render_to_main && !is_exclusive_fullscreen)
|
|
|
|
{
|
|
|
|
qDebug() << "Toggling to" << (fullscreen ? "fullscreen" : "windowed") << "without recreating surface";
|
|
|
|
if (fullscreen)
|
|
|
|
{
|
|
|
|
m_display_widget->showFullScreen();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
restoreDisplayWindowGeometryFromConfig();
|
|
|
|
m_display_widget->showNormal();
|
|
|
|
}
|
|
|
|
|
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
updateMouseMode(System::IsPaused());
|
|
|
|
return m_display_widget;
|
|
|
|
}
|
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
m_host_display->DestroyRenderSurface();
|
2020-04-05 12:58:47 +00:00
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
destroyDisplayWidget();
|
|
|
|
m_display_widget = new QtDisplayWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
2020-04-22 11:13:51 +00:00
|
|
|
m_display_widget->setWindowTitle(windowTitle());
|
|
|
|
m_display_widget->setWindowIcon(windowIcon());
|
|
|
|
|
|
|
|
if (fullscreen)
|
|
|
|
{
|
2020-11-01 14:38:54 +00:00
|
|
|
if (!is_exclusive_fullscreen)
|
|
|
|
m_display_widget->showFullScreen();
|
|
|
|
else
|
|
|
|
m_display_widget->showNormal();
|
2020-12-06 14:06:32 +00:00
|
|
|
|
2020-12-28 16:00:31 +00:00
|
|
|
updateMouseMode(System::IsPaused());
|
2020-04-22 11:13:51 +00:00
|
|
|
}
|
|
|
|
else if (!render_to_main)
|
|
|
|
{
|
2020-10-03 02:10:11 +00:00
|
|
|
restoreDisplayWindowGeometryFromConfig();
|
2020-04-22 11:13:51 +00:00
|
|
|
m_display_widget->showNormal();
|
2020-01-06 06:27:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-22 11:13:51 +00:00
|
|
|
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
|
|
|
switchToEmulationView();
|
2020-01-06 06:27:39 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 11:13:51 +00:00
|
|
|
// we need the surface visible.. this might be able to be replaced with something else
|
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
|
|
|
if (!wi.has_value())
|
|
|
|
{
|
2020-08-06 09:30:47 +00:00
|
|
|
reportError(QStringLiteral("Failed to get new window info from widget"));
|
2020-06-29 16:46:57 +00:00
|
|
|
destroyDisplayWidget();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_host_display->ChangeRenderWindow(wi.value()))
|
2020-04-22 11:13:51 +00:00
|
|
|
Panic("Failed to recreate surface on new widget.");
|
|
|
|
|
2020-11-01 14:38:54 +00:00
|
|
|
if (is_exclusive_fullscreen)
|
|
|
|
setDisplayFullscreen(fullscreen_mode);
|
|
|
|
|
2020-01-06 06:27:39 +00:00
|
|
|
m_display_widget->setFocus();
|
|
|
|
|
|
|
|
QSignalBlocker blocker(m_ui.actionFullscreen);
|
|
|
|
m_ui.actionFullscreen->setChecked(fullscreen);
|
2020-06-29 16:46:57 +00:00
|
|
|
return m_display_widget;
|
2020-04-22 11:13:51 +00:00
|
|
|
}
|
|
|
|
|
2020-11-01 14:38:54 +00:00
|
|
|
void MainWindow::setDisplayFullscreen(const std::string& fullscreen_mode)
|
|
|
|
{
|
|
|
|
u32 width, height;
|
|
|
|
float refresh_rate;
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
if (CommonHostInterface::ParseFullscreenMode(fullscreen_mode, &width, &height, &refresh_rate))
|
|
|
|
{
|
|
|
|
result = m_host_display->SetFullscreen(true, width, height, refresh_rate);
|
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
m_host_interface->AddOSDMessage(
|
|
|
|
m_host_interface->TranslateStdString("OSDMessage", "Failed to acquire exclusive fullscreen."), 20.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-18 13:15:16 +00:00
|
|
|
void MainWindow::displaySizeRequested(qint32 width, qint32 height)
|
|
|
|
{
|
|
|
|
if (!m_display_widget)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!m_display_widget->parent())
|
|
|
|
{
|
|
|
|
// no parent - rendering to separate window. easy.
|
|
|
|
m_display_widget->resize(QSize(std::max<qint32>(width, 1), std::max<qint32>(height, 1)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we are rendering to the main window. we have to add in the extra height from the toolbar/status bar.
|
|
|
|
const s32 extra_height = this->height() - m_display_widget->height();
|
|
|
|
resize(QSize(std::max<qint32>(width, 1), std::max<qint32>(height + extra_height, 1)));
|
|
|
|
}
|
|
|
|
|
2020-04-22 11:13:51 +00:00
|
|
|
void MainWindow::destroyDisplay()
|
|
|
|
{
|
2020-11-30 15:17:26 +00:00
|
|
|
if (!m_host_display)
|
|
|
|
return;
|
|
|
|
|
2020-04-22 11:13:51 +00:00
|
|
|
DebugAssert(m_host_display && m_display_widget);
|
2020-06-29 16:46:57 +00:00
|
|
|
m_host_display = nullptr;
|
|
|
|
destroyDisplayWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::destroyDisplayWidget()
|
|
|
|
{
|
|
|
|
if (!m_display_widget)
|
|
|
|
return;
|
2020-04-22 11:13:51 +00:00
|
|
|
|
|
|
|
if (m_display_widget->parent())
|
|
|
|
{
|
|
|
|
switchToGameListView();
|
2020-06-29 16:46:57 +00:00
|
|
|
m_ui.mainContainer->removeWidget(m_display_widget);
|
2020-04-22 11:13:51 +00:00
|
|
|
}
|
2020-10-03 02:10:11 +00:00
|
|
|
else if (!m_display_widget->isFullScreen())
|
|
|
|
{
|
|
|
|
saveDisplayWindowGeometryToConfig();
|
|
|
|
}
|
2020-04-22 11:13:51 +00:00
|
|
|
|
2020-06-29 16:46:57 +00:00
|
|
|
delete m_display_widget;
|
2020-04-22 11:13:51 +00:00
|
|
|
m_display_widget = nullptr;
|
2020-01-06 06:27:39 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 09:26:14 +00:00
|
|
|
void MainWindow::focusDisplayWidget()
|
|
|
|
{
|
|
|
|
if (m_ui.mainContainer->currentIndex() != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_display_widget->setFocus();
|
|
|
|
}
|
|
|
|
|
2020-12-27 04:08:13 +00:00
|
|
|
void MainWindow::onMouseModeRequested(bool relative_mode, bool hide_cursor)
|
2020-12-28 16:00:31 +00:00
|
|
|
{
|
|
|
|
m_relative_mouse_mode = relative_mode;
|
|
|
|
m_mouse_cursor_hidden = hide_cursor;
|
|
|
|
updateMouseMode(System::IsPaused());
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::updateMouseMode(bool paused)
|
2020-12-27 04:08:13 +00:00
|
|
|
{
|
|
|
|
if (!m_display_widget)
|
|
|
|
return;
|
|
|
|
|
2020-12-28 16:00:31 +00:00
|
|
|
if (paused)
|
|
|
|
{
|
|
|
|
m_display_widget->unsetCursor();
|
|
|
|
m_display_widget->setRelativeMode(false);
|
|
|
|
return;
|
|
|
|
}
|
2020-12-27 04:08:13 +00:00
|
|
|
|
2020-12-28 16:00:31 +00:00
|
|
|
const bool hide_mouse = m_mouse_cursor_hidden || (m_display_widget->isFullScreen() && shouldHideCursorInFullscreen());
|
|
|
|
if (hide_mouse)
|
2020-12-27 04:08:13 +00:00
|
|
|
m_display_widget->setCursor(Qt::BlankCursor);
|
|
|
|
else
|
|
|
|
m_display_widget->unsetCursor();
|
|
|
|
|
2020-12-28 16:00:31 +00:00
|
|
|
m_display_widget->setRelativeMode(m_relative_mouse_mode);
|
2020-12-27 04:08:13 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 17:44:57 +00:00
|
|
|
void MainWindow::onEmulationStarting()
|
2020-01-07 08:55:36 +00:00
|
|
|
{
|
2020-02-15 15:14:28 +00:00
|
|
|
m_emulation_running = true;
|
2020-06-05 17:44:57 +00:00
|
|
|
updateEmulationActions(true, false);
|
|
|
|
|
|
|
|
// ensure it gets updated, since the boot can take a while
|
|
|
|
QGuiApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onEmulationStarted()
|
|
|
|
{
|
2020-02-15 15:14:28 +00:00
|
|
|
updateEmulationActions(false, true);
|
|
|
|
}
|
2020-01-07 08:55:36 +00:00
|
|
|
|
2020-02-15 15:14:28 +00:00
|
|
|
void MainWindow::onEmulationStopped()
|
|
|
|
{
|
|
|
|
m_emulation_running = false;
|
|
|
|
updateEmulationActions(false, false);
|
2020-01-24 04:49:51 +00:00
|
|
|
switchToGameListView();
|
2020-10-19 15:14:49 +00:00
|
|
|
|
|
|
|
if (m_cheat_manager_dialog)
|
|
|
|
{
|
|
|
|
delete m_cheat_manager_dialog;
|
|
|
|
m_cheat_manager_dialog = nullptr;
|
|
|
|
}
|
2020-12-16 15:18:13 +00:00
|
|
|
|
|
|
|
if (m_debugger_window)
|
|
|
|
{
|
|
|
|
delete m_debugger_window;
|
|
|
|
m_debugger_window = nullptr;
|
|
|
|
}
|
2020-02-15 15:14:28 +00:00
|
|
|
}
|
2020-01-07 08:55:36 +00:00
|
|
|
|
2020-02-15 15:14:28 +00:00
|
|
|
void MainWindow::onEmulationPaused(bool paused)
|
|
|
|
{
|
2020-05-30 16:41:31 +00:00
|
|
|
QSignalBlocker blocker(m_ui.actionPause);
|
2020-02-15 15:14:28 +00:00
|
|
|
m_ui.actionPause->setChecked(paused);
|
2020-12-28 16:00:31 +00:00
|
|
|
updateMouseMode(paused);
|
2020-01-07 08:55:36 +00:00
|
|
|
}
|
|
|
|
|
2020-02-15 15:15:18 +00:00
|
|
|
void MainWindow::onStateSaved(const QString& game_code, bool global, qint32 slot)
|
|
|
|
{
|
|
|
|
// don't bother updating for the resume state since we're powering off anyway
|
|
|
|
if (slot < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_host_interface->populateSaveStateMenus(game_code.toStdString().c_str(), m_ui.menuLoadState, m_ui.menuSaveState);
|
|
|
|
}
|
|
|
|
|
2020-02-09 13:16:25 +00:00
|
|
|
void MainWindow::onSystemPerformanceCountersUpdated(float speed, float fps, float vps, float average_frame_time,
|
|
|
|
float worst_frame_time)
|
2020-01-24 04:49:47 +00:00
|
|
|
{
|
|
|
|
m_status_speed_widget->setText(QStringLiteral("%1%").arg(speed, 0, 'f', 0));
|
|
|
|
m_status_fps_widget->setText(
|
|
|
|
QStringLiteral("FPS: %1/%2").arg(std::round(fps), 0, 'f', 0).arg(std::round(vps), 0, 'f', 0));
|
|
|
|
m_status_frame_time_widget->setText(
|
|
|
|
QStringLiteral("%1ms average, %2ms worst").arg(average_frame_time, 0, 'f', 2).arg(worst_frame_time, 0, 'f', 2));
|
|
|
|
}
|
|
|
|
|
2020-02-15 15:14:30 +00:00
|
|
|
void MainWindow::onRunningGameChanged(const QString& filename, const QString& game_code, const QString& game_title)
|
2020-01-24 04:50:46 +00:00
|
|
|
{
|
2020-02-15 15:14:04 +00:00
|
|
|
m_host_interface->populateSaveStateMenus(game_code.toStdString().c_str(), m_ui.menuLoadState, m_ui.menuSaveState);
|
2020-01-24 04:50:46 +00:00
|
|
|
if (game_title.isEmpty())
|
2020-04-16 15:56:11 +00:00
|
|
|
setWindowTitle(getWindowTitle());
|
2020-01-24 04:50:46 +00:00
|
|
|
else
|
|
|
|
setWindowTitle(game_title);
|
2020-04-05 12:58:47 +00:00
|
|
|
|
|
|
|
if (m_display_widget)
|
|
|
|
m_display_widget->setWindowTitle(windowTitle());
|
2020-01-24 04:50:46 +00:00
|
|
|
}
|
|
|
|
|
2020-12-04 14:16:22 +00:00
|
|
|
void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
|
|
|
|
{
|
|
|
|
if (!m_emulation_running || !g_settings.pause_on_focus_loss)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const bool focus_loss = (state != Qt::ApplicationActive);
|
|
|
|
if (focus_loss)
|
|
|
|
{
|
|
|
|
if (!m_was_paused_by_focus_loss && !System::IsPaused())
|
|
|
|
{
|
|
|
|
m_host_interface->pauseSystem(true);
|
|
|
|
m_was_paused_by_focus_loss = true;
|
2020-12-28 16:00:31 +00:00
|
|
|
updateMouseMode(true);
|
2020-12-04 14:16:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_was_paused_by_focus_loss)
|
|
|
|
{
|
|
|
|
if (System::IsPaused())
|
|
|
|
m_host_interface->pauseSystem(false);
|
|
|
|
m_was_paused_by_focus_loss = false;
|
2020-12-28 16:00:31 +00:00
|
|
|
updateMouseMode(false);
|
2020-12-04 14:16:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
void MainWindow::onStartDiscActionTriggered()
|
|
|
|
{
|
|
|
|
QString filename =
|
|
|
|
QFileDialog::getOpenFileName(this, tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr);
|
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2020-09-12 20:01:08 +00:00
|
|
|
m_host_interface->bootSystem(std::make_shared<const SystemBootParameters>(filename.toStdString()));
|
2020-03-02 01:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onStartBIOSActionTriggered()
|
|
|
|
{
|
2020-09-12 20:01:08 +00:00
|
|
|
m_host_interface->bootSystem(std::make_shared<const SystemBootParameters>());
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-01-24 04:50:40 +00:00
|
|
|
void MainWindow::onChangeDiscFromFileActionTriggered()
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
2020-01-24 04:50:40 +00:00
|
|
|
QString filename =
|
|
|
|
QFileDialog::getOpenFileName(this, tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr);
|
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-24 04:50:40 +00:00
|
|
|
m_host_interface->changeDisc(filename);
|
|
|
|
}
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-24 04:50:40 +00:00
|
|
|
void MainWindow::onChangeDiscFromGameListActionTriggered()
|
|
|
|
{
|
|
|
|
m_host_interface->pauseSystem(true);
|
|
|
|
switchToGameListView();
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-08-15 10:39:11 +00:00
|
|
|
void MainWindow::onChangeDiscFromPlaylistMenuAboutToShow()
|
|
|
|
{
|
|
|
|
m_host_interface->populatePlaylistEntryMenu(m_ui.menuChangeDiscFromPlaylist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onChangeDiscFromPlaylistMenuAboutToHide()
|
|
|
|
{
|
|
|
|
m_ui.menuChangeDiscFromPlaylist->clear();
|
|
|
|
}
|
|
|
|
|
2020-09-09 13:44:21 +00:00
|
|
|
void MainWindow::onCheatsMenuAboutToShow()
|
|
|
|
{
|
|
|
|
m_ui.menuCheats->clear();
|
2020-10-23 09:26:19 +00:00
|
|
|
connect(m_ui.menuCheats->addAction(tr("Cheat Manager")), &QAction::triggered, this,
|
|
|
|
&MainWindow::onToolsCheatManagerTriggered);
|
2020-10-19 15:14:49 +00:00
|
|
|
m_ui.menuCheats->addSeparator();
|
2020-09-09 13:44:21 +00:00
|
|
|
m_host_interface->populateCheatsMenu(m_ui.menuCheats);
|
|
|
|
}
|
|
|
|
|
2020-05-19 16:32:19 +00:00
|
|
|
void MainWindow::onRemoveDiscActionTriggered()
|
|
|
|
{
|
|
|
|
m_host_interface->changeDisc(QString());
|
|
|
|
}
|
|
|
|
|
2020-08-20 13:39:29 +00:00
|
|
|
void MainWindow::onViewToolbarActionToggled(bool checked)
|
|
|
|
{
|
|
|
|
m_ui.toolBar->setVisible(checked);
|
2020-09-14 07:58:04 +00:00
|
|
|
saveStateToConfig();
|
2020-08-20 13:39:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onViewStatusBarActionToggled(bool checked)
|
|
|
|
{
|
2020-09-18 14:31:02 +00:00
|
|
|
m_host_interface->SetBoolSettingValue("UI", "ShowStatusBar", checked);
|
2020-08-20 13:39:29 +00:00
|
|
|
m_ui.statusBar->setVisible(checked);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onViewGameListActionTriggered()
|
|
|
|
{
|
|
|
|
if (m_emulation_running)
|
|
|
|
m_host_interface->pauseSystem(true);
|
|
|
|
switchToGameListView();
|
2020-09-23 14:02:13 +00:00
|
|
|
m_game_list_widget->showGameList();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onViewGameGridActionTriggered()
|
|
|
|
{
|
|
|
|
if (m_emulation_running)
|
|
|
|
m_host_interface->pauseSystem(true);
|
|
|
|
switchToGameListView();
|
|
|
|
m_game_list_widget->showGameGrid();
|
2020-08-20 13:39:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onViewSystemDisplayTriggered()
|
|
|
|
{
|
|
|
|
if (m_emulation_running)
|
|
|
|
{
|
|
|
|
switchToEmulationView();
|
|
|
|
m_host_interface->pauseSystem(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-13 13:20:50 +00:00
|
|
|
void MainWindow::onViewGamePropertiesActionTriggered()
|
|
|
|
{
|
|
|
|
const GameListEntry* entry;
|
|
|
|
|
|
|
|
if (m_emulation_running)
|
|
|
|
{
|
|
|
|
const std::string& path = System::GetRunningPath();
|
|
|
|
if (path.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
entry = m_host_interface->getGameList()->GetEntryForPath(path.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry = m_game_list_widget->getSelectedEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry)
|
|
|
|
return;
|
|
|
|
|
|
|
|
GamePropertiesDialog::showForEntry(m_host_interface, entry, this);
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:51:59 +00:00
|
|
|
void MainWindow::onGitHubRepositoryActionTriggered()
|
|
|
|
{
|
2020-05-20 13:25:16 +00:00
|
|
|
QtUtils::OpenURL(this, "https://github.com/stenzek/duckstation/");
|
2020-01-24 04:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onIssueTrackerActionTriggered()
|
|
|
|
{
|
2020-05-20 13:25:16 +00:00
|
|
|
QtUtils::OpenURL(this, "https://github.com/stenzek/duckstation/issues");
|
2020-01-24 04:51:59 +00:00
|
|
|
}
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-04-07 03:54:20 +00:00
|
|
|
void MainWindow::onDiscordServerActionTriggered()
|
|
|
|
{
|
2020-05-20 13:25:16 +00:00
|
|
|
QtUtils::OpenURL(this, "https://discord.gg/Buktv3t");
|
2020-04-07 03:54:20 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 04:36:48 +00:00
|
|
|
void MainWindow::onAboutActionTriggered()
|
|
|
|
{
|
|
|
|
AboutDialog about(this);
|
|
|
|
about.exec();
|
|
|
|
}
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-03-02 01:08:16 +00:00
|
|
|
void MainWindow::onGameListEntrySelected(const GameListEntry* entry)
|
|
|
|
{
|
|
|
|
if (!entry)
|
|
|
|
{
|
|
|
|
m_ui.statusBar->clearMessage();
|
|
|
|
m_host_interface->populateSaveStateMenus("", m_ui.menuLoadState, m_ui.menuSaveState);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ui.statusBar->showMessage(QString::fromStdString(entry->path));
|
|
|
|
m_host_interface->populateSaveStateMenus(entry->code.c_str(), m_ui.menuLoadState, m_ui.menuSaveState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onGameListEntryDoubleClicked(const GameListEntry* entry)
|
|
|
|
{
|
|
|
|
// if we're not running, boot the system, otherwise swap discs
|
|
|
|
QString path = QString::fromStdString(entry->path);
|
|
|
|
if (!m_emulation_running)
|
|
|
|
{
|
2020-07-22 16:44:06 +00:00
|
|
|
if (!entry->code.empty() && m_host_interface->GetBoolSettingValue("Main", "SaveStateOnExit", true))
|
2020-03-02 01:08:16 +00:00
|
|
|
{
|
|
|
|
m_host_interface->resumeSystemFromState(path, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-12 20:01:08 +00:00
|
|
|
m_host_interface->bootSystem(std::make_shared<const SystemBootParameters>(path.toStdString()));
|
2020-03-02 01:08:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_host_interface->changeDisc(path);
|
|
|
|
m_host_interface->pauseSystem(false);
|
|
|
|
switchToEmulationView();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onGameListContextMenuRequested(const QPoint& point, const GameListEntry* entry)
|
|
|
|
{
|
|
|
|
QMenu menu;
|
|
|
|
|
|
|
|
// Hopefully this pointer doesn't disappear... it shouldn't.
|
|
|
|
if (entry)
|
|
|
|
{
|
2020-12-01 14:56:15 +00:00
|
|
|
QAction* action = menu.addAction(tr("Properties..."));
|
|
|
|
action->setEnabled(entry->type == GameListEntryType::Disc);
|
|
|
|
connect(action, &QAction::triggered,
|
2020-08-29 12:42:28 +00:00
|
|
|
[this, entry]() { GamePropertiesDialog::showForEntry(m_host_interface, entry, this); });
|
2020-03-02 01:08:16 +00:00
|
|
|
|
|
|
|
connect(menu.addAction(tr("Open Containing Directory...")), &QAction::triggered, [this, entry]() {
|
|
|
|
const QFileInfo fi(QString::fromStdString(entry->path));
|
2020-05-20 13:25:16 +00:00
|
|
|
QtUtils::OpenURL(this, QUrl::fromLocalFile(fi.absolutePath()));
|
2020-03-02 01:08:16 +00:00
|
|
|
});
|
|
|
|
|
2020-10-03 13:20:48 +00:00
|
|
|
connect(menu.addAction(tr("Set Cover Image...")), &QAction::triggered,
|
|
|
|
[this, entry]() { onGameListSetCoverImageRequested(entry); });
|
|
|
|
|
2020-03-02 01:08:16 +00:00
|
|
|
menu.addSeparator();
|
|
|
|
|
2020-07-23 16:37:09 +00:00
|
|
|
if (!m_emulation_running)
|
2020-03-02 01:08:16 +00:00
|
|
|
{
|
2020-12-01 14:56:31 +00:00
|
|
|
m_host_interface->populateGameListContextMenu(entry, this, &menu);
|
|
|
|
menu.addSeparator();
|
2020-07-23 16:37:09 +00:00
|
|
|
|
2020-09-12 20:01:08 +00:00
|
|
|
connect(menu.addAction(tr("Default Boot")), &QAction::triggered, [this, entry]() {
|
|
|
|
m_host_interface->bootSystem(std::make_shared<const SystemBootParameters>(entry->path));
|
|
|
|
});
|
2020-07-23 16:37:09 +00:00
|
|
|
|
|
|
|
connect(menu.addAction(tr("Fast Boot")), &QAction::triggered, [this, entry]() {
|
2020-09-12 20:01:08 +00:00
|
|
|
auto boot_params = std::make_shared<SystemBootParameters>(entry->path);
|
|
|
|
boot_params->override_fast_boot = true;
|
|
|
|
m_host_interface->bootSystem(std::move(boot_params));
|
2020-07-23 16:37:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
connect(menu.addAction(tr("Full Boot")), &QAction::triggered, [this, entry]() {
|
2020-09-12 20:01:08 +00:00
|
|
|
auto boot_params = std::make_shared<SystemBootParameters>(entry->path);
|
|
|
|
boot_params->override_fast_boot = false;
|
|
|
|
m_host_interface->bootSystem(std::move(boot_params));
|
2020-07-23 16:37:09 +00:00
|
|
|
});
|
2020-12-26 14:40:28 +00:00
|
|
|
|
|
|
|
if (m_ui.menuDebug->menuAction()->isVisible())
|
|
|
|
{
|
|
|
|
connect(menu.addAction(tr("Boot and Debug")), &QAction::triggered, [this, entry]() {
|
|
|
|
m_open_debugger_on_start = true;
|
|
|
|
|
|
|
|
auto boot_params = std::make_shared<SystemBootParameters>(entry->path);
|
|
|
|
boot_params->override_start_paused = true;
|
|
|
|
m_host_interface->bootSystem(std::move(boot_params));
|
|
|
|
});
|
|
|
|
}
|
2020-07-23 16:37:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect(menu.addAction(tr("Change Disc")), &QAction::triggered, [this, entry]() {
|
|
|
|
m_host_interface->changeDisc(QString::fromStdString(entry->path));
|
|
|
|
m_host_interface->pauseSystem(false);
|
|
|
|
switchToEmulationView();
|
|
|
|
});
|
2020-03-02 01:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
menu.addSeparator();
|
|
|
|
}
|
|
|
|
|
|
|
|
connect(menu.addAction(tr("Add Search Directory...")), &QAction::triggered,
|
|
|
|
[this]() { getSettingsDialog()->getGameListSettingsWidget()->addSearchDirectory(this); });
|
|
|
|
|
|
|
|
menu.exec(point);
|
|
|
|
}
|
|
|
|
|
2020-10-03 13:20:48 +00:00
|
|
|
void MainWindow::onGameListSetCoverImageRequested(const GameListEntry* entry)
|
|
|
|
{
|
|
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select Cover Image"), QString(),
|
|
|
|
tr("All Cover Image Types (*.jpg *.jpeg *.png)"));
|
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!m_host_interface->getGameList()->GetCoverImagePathForEntry(entry).empty())
|
|
|
|
{
|
|
|
|
if (QMessageBox::question(this, tr("Cover Already Exists"),
|
|
|
|
tr("A cover image for this game already exists, do you wish to replace it?"),
|
|
|
|
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString new_filename = QString::fromStdString(
|
|
|
|
m_host_interface->getGameList()->GetNewCoverImagePathForEntry(entry, filename.toStdString().c_str()));
|
|
|
|
if (new_filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (QFile::exists(new_filename) && !QFile::remove(new_filename))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to remove existing cover '%1'").arg(new_filename));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!QFile::copy(filename, new_filename))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to copy '%1' to '%2'").arg(filename).arg(new_filename));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_game_list_widget->refreshGridCovers();
|
|
|
|
}
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
void MainWindow::setupAdditionalUi()
|
|
|
|
{
|
2020-04-16 15:56:11 +00:00
|
|
|
setWindowTitle(getWindowTitle());
|
|
|
|
|
2020-09-18 14:31:02 +00:00
|
|
|
const bool status_bar_visible = m_host_interface->GetBoolSettingValue("UI", "ShowStatusBar", true);
|
|
|
|
m_ui.actionViewStatusBar->setChecked(status_bar_visible);
|
|
|
|
m_ui.statusBar->setVisible(status_bar_visible);
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
m_game_list_widget = new GameListWidget(m_ui.mainContainer);
|
|
|
|
m_game_list_widget->initialize(m_host_interface);
|
|
|
|
m_ui.mainContainer->insertWidget(0, m_game_list_widget);
|
|
|
|
m_ui.mainContainer->setCurrentIndex(0);
|
2020-01-07 08:55:36 +00:00
|
|
|
|
2020-01-24 04:49:47 +00:00
|
|
|
m_status_speed_widget = new QLabel(m_ui.statusBar);
|
|
|
|
m_status_speed_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
|
|
m_status_speed_widget->setFixedSize(40, 16);
|
|
|
|
m_status_speed_widget->hide();
|
|
|
|
|
|
|
|
m_status_fps_widget = new QLabel(m_ui.statusBar);
|
|
|
|
m_status_fps_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
|
|
m_status_fps_widget->setFixedSize(80, 16);
|
|
|
|
m_status_fps_widget->hide();
|
|
|
|
|
|
|
|
m_status_frame_time_widget = new QLabel(m_ui.statusBar);
|
|
|
|
m_status_frame_time_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
|
|
m_status_frame_time_widget->setFixedSize(190, 16);
|
|
|
|
m_status_frame_time_widget->hide();
|
|
|
|
|
2020-09-23 14:02:13 +00:00
|
|
|
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
|
|
|
|
|
2020-08-18 14:01:57 +00:00
|
|
|
updateDebugMenuVisibility();
|
|
|
|
|
2020-02-05 08:43:25 +00:00
|
|
|
for (u32 i = 0; i < static_cast<u32>(CPUExecutionMode::Count); i++)
|
|
|
|
{
|
|
|
|
const CPUExecutionMode mode = static_cast<CPUExecutionMode>(i);
|
2020-10-23 09:26:19 +00:00
|
|
|
QAction* action = m_ui.menuCPUExecutionMode->addAction(
|
|
|
|
qApp->translate("CPUExecutionMode", Settings::GetCPUExecutionModeDisplayName(mode)));
|
2020-02-05 08:43:25 +00:00
|
|
|
action->setCheckable(true);
|
|
|
|
connect(action, &QAction::triggered, [this, mode]() {
|
2020-07-21 09:49:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue("CPU", "ExecutionMode", Settings::GetCPUExecutionModeName(mode));
|
2020-02-05 08:43:25 +00:00
|
|
|
m_host_interface->applySettings();
|
|
|
|
updateDebugMenuCPUExecutionMode();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
updateDebugMenuCPUExecutionMode();
|
|
|
|
|
2020-01-07 08:55:36 +00:00
|
|
|
for (u32 i = 0; i < static_cast<u32>(GPURenderer::Count); i++)
|
|
|
|
{
|
|
|
|
const GPURenderer renderer = static_cast<GPURenderer>(i);
|
2020-10-23 09:26:19 +00:00
|
|
|
QAction* action =
|
|
|
|
m_ui.menuRenderer->addAction(qApp->translate("GPURenderer", Settings::GetRendererDisplayName(renderer)));
|
2020-01-07 08:55:36 +00:00
|
|
|
action->setCheckable(true);
|
2020-02-05 08:43:25 +00:00
|
|
|
connect(action, &QAction::triggered, [this, renderer]() {
|
2020-07-21 09:49:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue("GPU", "Renderer", Settings::GetRendererName(renderer));
|
2020-01-24 04:49:49 +00:00
|
|
|
m_host_interface->applySettings();
|
2020-03-14 02:34:39 +00:00
|
|
|
updateDebugMenuGPURenderer();
|
2020-01-07 08:55:36 +00:00
|
|
|
});
|
|
|
|
}
|
2020-01-24 04:49:51 +00:00
|
|
|
updateDebugMenuGPURenderer();
|
2020-07-28 09:14:44 +00:00
|
|
|
|
2020-10-09 07:52:05 +00:00
|
|
|
for (u32 i = 0; i < static_cast<u32>(DisplayCropMode::Count); i++)
|
|
|
|
{
|
|
|
|
const DisplayCropMode crop_mode = static_cast<DisplayCropMode>(i);
|
2020-10-23 09:26:19 +00:00
|
|
|
QAction* action = m_ui.menuCropMode->addAction(
|
|
|
|
qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(crop_mode)));
|
2020-10-09 07:52:05 +00:00
|
|
|
action->setCheckable(true);
|
|
|
|
connect(action, &QAction::triggered, [this, crop_mode]() {
|
|
|
|
m_host_interface->SetStringSettingValue("Display", "CropMode", Settings::GetDisplayCropModeName(crop_mode));
|
|
|
|
m_host_interface->applySettings();
|
|
|
|
updateDebugMenuCropMode();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
updateDebugMenuCropMode();
|
|
|
|
|
2020-07-28 09:14:44 +00:00
|
|
|
const QString current_language(
|
|
|
|
QString::fromStdString(m_host_interface->GetStringSettingValue("Main", "Language", "")));
|
2020-08-06 17:34:40 +00:00
|
|
|
QActionGroup* language_group = new QActionGroup(m_ui.menuSettingsLanguage);
|
2020-07-28 09:14:44 +00:00
|
|
|
for (const std::pair<QString, QString>& it : m_host_interface->getAvailableLanguageList())
|
|
|
|
{
|
2020-08-06 17:34:40 +00:00
|
|
|
QAction* action = language_group->addAction(it.first);
|
2020-07-28 09:14:44 +00:00
|
|
|
action->setCheckable(true);
|
2020-08-06 17:34:40 +00:00
|
|
|
action->setChecked(current_language == it.second);
|
|
|
|
m_ui.menuSettingsLanguage->addAction(action);
|
2020-07-28 09:14:44 +00:00
|
|
|
action->setData(it.second);
|
|
|
|
connect(action, &QAction::triggered, [this, action]() {
|
|
|
|
const QString new_language = action->data().toString();
|
|
|
|
m_host_interface->SetStringSettingValue("Main", "Language", new_language.toUtf8().constData());
|
|
|
|
QMessageBox::information(this, tr("DuckStation"),
|
|
|
|
tr("Language changed. Please restart the application to apply."));
|
|
|
|
});
|
|
|
|
}
|
2020-11-18 13:15:16 +00:00
|
|
|
|
|
|
|
for (u32 scale = 1; scale <= 10; scale++)
|
|
|
|
{
|
|
|
|
QAction* action = m_ui.menuWindowSize->addAction(tr("%1x Scale").arg(scale));
|
|
|
|
connect(action, &QAction::triggered,
|
|
|
|
[scale]() { QtHostInterface::GetInstance()->requestRenderWindowScale(scale); });
|
|
|
|
}
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::updateEmulationActions(bool starting, bool running)
|
|
|
|
{
|
|
|
|
m_ui.actionStartDisc->setDisabled(starting || running);
|
|
|
|
m_ui.actionStartBios->setDisabled(starting || running);
|
2020-05-23 05:03:00 +00:00
|
|
|
m_ui.actionResumeLastState->setDisabled(starting || running);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
|
|
|
m_ui.actionPowerOff->setDisabled(starting || !running);
|
2021-01-08 13:42:17 +00:00
|
|
|
m_ui.actionPowerOffWithoutSaving->setDisabled(starting || !running);
|
2019-12-31 06:17:17 +00:00
|
|
|
m_ui.actionReset->setDisabled(starting || !running);
|
|
|
|
m_ui.actionPause->setDisabled(starting || !running);
|
|
|
|
m_ui.actionChangeDisc->setDisabled(starting || !running);
|
2020-09-09 13:44:21 +00:00
|
|
|
m_ui.actionCheats->setDisabled(starting || !running);
|
2020-03-15 14:06:39 +00:00
|
|
|
m_ui.actionScreenshot->setDisabled(starting || !running);
|
2020-08-20 13:39:29 +00:00
|
|
|
m_ui.actionViewSystemDisplay->setEnabled(starting || running);
|
2020-01-24 04:50:40 +00:00
|
|
|
m_ui.menuChangeDisc->setDisabled(starting || !running);
|
2020-09-09 13:44:21 +00:00
|
|
|
m_ui.menuCheats->setDisabled(starting || !running);
|
2020-10-19 15:14:49 +00:00
|
|
|
m_ui.actionCheatManager->setDisabled(starting || !running);
|
2020-12-16 15:18:13 +00:00
|
|
|
m_ui.actionCPUDebugger->setDisabled(starting || !running);
|
2021-01-13 09:24:41 +00:00
|
|
|
m_ui.actionDumpRAM->setDisabled(starting || !running);
|
|
|
|
m_ui.actionDumpVRAM->setDisabled(starting || !running);
|
|
|
|
m_ui.actionDumpSPURAM->setDisabled(starting || !running);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-24 04:50:42 +00:00
|
|
|
m_ui.actionSaveState->setDisabled(starting || !running);
|
|
|
|
m_ui.menuSaveState->setDisabled(starting || !running);
|
2020-11-18 13:15:16 +00:00
|
|
|
m_ui.menuWindowSize->setDisabled(starting || !running);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
|
|
|
m_ui.actionFullscreen->setDisabled(starting || !running);
|
2020-01-24 04:49:47 +00:00
|
|
|
|
|
|
|
if (running && m_status_speed_widget->isHidden())
|
|
|
|
{
|
|
|
|
m_status_speed_widget->show();
|
|
|
|
m_status_fps_widget->show();
|
|
|
|
m_status_frame_time_widget->show();
|
|
|
|
m_ui.statusBar->addPermanentWidget(m_status_speed_widget);
|
|
|
|
m_ui.statusBar->addPermanentWidget(m_status_fps_widget);
|
|
|
|
m_ui.statusBar->addPermanentWidget(m_status_frame_time_widget);
|
|
|
|
}
|
|
|
|
else if (!running && m_status_speed_widget->isVisible())
|
|
|
|
{
|
|
|
|
m_ui.statusBar->removeWidget(m_status_speed_widget);
|
|
|
|
m_ui.statusBar->removeWidget(m_status_fps_widget);
|
|
|
|
m_ui.statusBar->removeWidget(m_status_frame_time_widget);
|
|
|
|
m_status_speed_widget->hide();
|
|
|
|
m_status_fps_widget->hide();
|
|
|
|
m_status_frame_time_widget->hide();
|
|
|
|
}
|
|
|
|
|
2020-05-23 05:03:15 +00:00
|
|
|
if (starting || running)
|
|
|
|
{
|
|
|
|
if (!m_ui.toolBar->actions().contains(m_ui.actionPowerOff))
|
|
|
|
{
|
|
|
|
m_ui.toolBar->insertAction(m_ui.actionResumeLastState, m_ui.actionPowerOff);
|
|
|
|
m_ui.toolBar->removeAction(m_ui.actionResumeLastState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!m_ui.toolBar->actions().contains(m_ui.actionResumeLastState))
|
|
|
|
{
|
|
|
|
m_ui.toolBar->insertAction(m_ui.actionPowerOff, m_ui.actionResumeLastState);
|
|
|
|
m_ui.toolBar->removeAction(m_ui.actionPowerOff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-26 14:40:28 +00:00
|
|
|
if (m_open_debugger_on_start && running)
|
|
|
|
openCPUDebugger();
|
|
|
|
if ((!starting && !running) || running)
|
|
|
|
m_open_debugger_on_start = false;
|
|
|
|
|
2020-12-26 13:22:24 +00:00
|
|
|
if (g_settings.debugging.enable_gdb_server)
|
|
|
|
{
|
|
|
|
if (starting && !m_gdb_server)
|
|
|
|
{
|
2020-12-17 17:32:29 +00:00
|
|
|
m_gdb_server = new GDBServer(this, g_settings.debugging.gdb_server_port);
|
|
|
|
}
|
2020-12-26 13:22:24 +00:00
|
|
|
else if (!running && m_gdb_server)
|
|
|
|
{
|
2020-12-17 17:32:29 +00:00
|
|
|
delete m_gdb_server;
|
|
|
|
m_gdb_server = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:49:47 +00:00
|
|
|
m_ui.statusBar->clearMessage();
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-23 14:02:13 +00:00
|
|
|
bool MainWindow::isShowingGameList() const
|
|
|
|
{
|
|
|
|
return m_ui.mainContainer->currentIndex() == 0;
|
|
|
|
}
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
void MainWindow::switchToGameListView()
|
|
|
|
{
|
|
|
|
m_ui.mainContainer->setCurrentIndex(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::switchToEmulationView()
|
|
|
|
{
|
2020-04-05 12:58:47 +00:00
|
|
|
if (m_display_widget->parent())
|
|
|
|
m_ui.mainContainer->setCurrentIndex(1);
|
2020-01-06 04:08:00 +00:00
|
|
|
m_display_widget->setFocus();
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::connectSignals()
|
|
|
|
{
|
|
|
|
updateEmulationActions(false, false);
|
|
|
|
onEmulationPaused(false);
|
|
|
|
|
2020-12-04 14:16:22 +00:00
|
|
|
connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onApplicationStateChanged);
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionStartDisc, &QAction::triggered, this, &MainWindow::onStartDiscActionTriggered);
|
2020-03-02 01:08:16 +00:00
|
|
|
connect(m_ui.actionStartBios, &QAction::triggered, this, &MainWindow::onStartBIOSActionTriggered);
|
2020-06-05 17:44:57 +00:00
|
|
|
connect(m_ui.actionResumeLastState, &QAction::triggered, m_host_interface,
|
|
|
|
&QtHostInterface::resumeSystemFromMostRecentState);
|
2020-01-24 04:50:40 +00:00
|
|
|
connect(m_ui.actionChangeDisc, &QAction::triggered, [this] { m_ui.menuChangeDisc->exec(QCursor::pos()); });
|
|
|
|
connect(m_ui.actionChangeDiscFromFile, &QAction::triggered, this, &MainWindow::onChangeDiscFromFileActionTriggered);
|
|
|
|
connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this,
|
|
|
|
&MainWindow::onChangeDiscFromGameListActionTriggered);
|
2020-08-15 10:39:11 +00:00
|
|
|
connect(m_ui.menuChangeDiscFromPlaylist, &QMenu::aboutToShow, this,
|
|
|
|
&MainWindow::onChangeDiscFromPlaylistMenuAboutToShow);
|
|
|
|
connect(m_ui.menuChangeDiscFromPlaylist, &QMenu::aboutToHide, this,
|
|
|
|
&MainWindow::onChangeDiscFromPlaylistMenuAboutToHide);
|
2020-09-09 13:44:21 +00:00
|
|
|
connect(m_ui.menuCheats, &QMenu::aboutToShow, this, &MainWindow::onCheatsMenuAboutToShow);
|
|
|
|
connect(m_ui.actionCheats, &QAction::triggered, [this] { m_ui.menuCheats->exec(QCursor::pos()); });
|
2020-05-19 16:32:19 +00:00
|
|
|
connect(m_ui.actionRemoveDisc, &QAction::triggered, this, &MainWindow::onRemoveDiscActionTriggered);
|
2020-01-24 04:50:53 +00:00
|
|
|
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
|
|
|
|
[this]() { getSettingsDialog()->getGameListSettingsWidget()->addSearchDirectory(this); });
|
2020-02-15 15:14:49 +00:00
|
|
|
connect(m_ui.actionPowerOff, &QAction::triggered, m_host_interface, &QtHostInterface::powerOffSystem);
|
2021-01-08 13:42:17 +00:00
|
|
|
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, m_host_interface,
|
|
|
|
&QtHostInterface::powerOffSystemWithoutSaving);
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionReset, &QAction::triggered, m_host_interface, &QtHostInterface::resetSystem);
|
2020-12-16 15:18:13 +00:00
|
|
|
connect(m_ui.actionPause, &QAction::toggled, [this](bool active) { m_host_interface->pauseSystem(active); });
|
2020-03-15 14:06:39 +00:00
|
|
|
connect(m_ui.actionScreenshot, &QAction::triggered, m_host_interface, &QtHostInterface::saveScreenshot);
|
2020-06-10 15:48:54 +00:00
|
|
|
connect(m_ui.actionScanForNewGames, &QAction::triggered, this,
|
2020-03-22 03:16:20 +00:00
|
|
|
[this]() { m_host_interface->refreshGameList(false, false); });
|
2020-06-10 15:48:54 +00:00
|
|
|
connect(m_ui.actionRescanAllGames, &QAction::triggered, this,
|
|
|
|
[this]() { m_host_interface->refreshGameList(true, false); });
|
2020-01-24 04:50:42 +00:00
|
|
|
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
|
|
|
|
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
|
2020-01-24 04:50:56 +00:00
|
|
|
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
2020-04-05 12:58:47 +00:00
|
|
|
connect(m_ui.actionFullscreen, &QAction::triggered, m_host_interface, &QtHostInterface::toggleFullscreen);
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::Count); });
|
2020-03-22 03:16:32 +00:00
|
|
|
connect(m_ui.actionGeneralSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::GeneralSettings); });
|
2020-09-22 13:08:07 +00:00
|
|
|
connect(m_ui.actionBIOSSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::BIOSSettings); });
|
2020-01-24 04:50:51 +00:00
|
|
|
connect(m_ui.actionConsoleSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::ConsoleSettings); });
|
2021-01-23 07:33:36 +00:00
|
|
|
connect(m_ui.actionEmulationSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::EmulationSettings); });
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionGameListSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::GameListSettings); });
|
2020-01-24 04:50:51 +00:00
|
|
|
connect(m_ui.actionHotkeySettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::HotkeySettings); });
|
2020-05-20 13:26:24 +00:00
|
|
|
connect(m_ui.actionControllerSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::ControllerSettings); });
|
|
|
|
connect(m_ui.actionMemoryCardSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::MemoryCardSettings); });
|
2020-09-10 14:18:12 +00:00
|
|
|
connect(m_ui.actionDisplaySettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::DisplaySettings); });
|
|
|
|
connect(m_ui.actionEnhancementSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::EnhancementSettings); });
|
2020-09-13 12:24:20 +00:00
|
|
|
connect(m_ui.actionPostProcessingSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::PostProcessingSettings); });
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionAudioSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::AudioSettings); });
|
2020-04-30 14:59:31 +00:00
|
|
|
connect(m_ui.actionAdvancedSettings, &QAction::triggered,
|
|
|
|
[this]() { doSettings(SettingsDialog::Category::AdvancedSettings); });
|
2020-08-20 13:39:29 +00:00
|
|
|
connect(m_ui.actionViewToolbar, &QAction::toggled, this, &MainWindow::onViewToolbarActionToggled);
|
|
|
|
connect(m_ui.actionViewStatusBar, &QAction::toggled, this, &MainWindow::onViewStatusBarActionToggled);
|
|
|
|
connect(m_ui.actionViewGameList, &QAction::triggered, this, &MainWindow::onViewGameListActionTriggered);
|
2020-09-23 14:02:13 +00:00
|
|
|
connect(m_ui.actionViewGameGrid, &QAction::triggered, this, &MainWindow::onViewGameGridActionTriggered);
|
2020-08-20 13:39:29 +00:00
|
|
|
connect(m_ui.actionViewSystemDisplay, &QAction::triggered, this, &MainWindow::onViewSystemDisplayTriggered);
|
2020-10-13 13:20:50 +00:00
|
|
|
connect(m_ui.actionViewGameProperties, &QAction::triggered, this, &MainWindow::onViewGamePropertiesActionTriggered);
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionGitHubRepository, &QAction::triggered, this, &MainWindow::onGitHubRepositoryActionTriggered);
|
|
|
|
connect(m_ui.actionIssueTracker, &QAction::triggered, this, &MainWindow::onIssueTrackerActionTriggered);
|
2020-04-07 03:54:20 +00:00
|
|
|
connect(m_ui.actionDiscordServer, &QAction::triggered, this, &MainWindow::onDiscordServerActionTriggered);
|
2020-10-03 08:48:56 +00:00
|
|
|
connect(m_ui.actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
2020-09-14 08:25:51 +00:00
|
|
|
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
2020-09-18 14:28:07 +00:00
|
|
|
connect(m_ui.actionMemory_Card_Editor, &QAction::triggered, this, &MainWindow::onToolsMemoryCardEditorTriggered);
|
2020-10-19 15:14:49 +00:00
|
|
|
connect(m_ui.actionCheatManager, &QAction::triggered, this, &MainWindow::onToolsCheatManagerTriggered);
|
2020-12-26 14:40:28 +00:00
|
|
|
connect(m_ui.actionCPUDebugger, &QAction::triggered, this, &MainWindow::openCPUDebugger);
|
2020-09-23 14:19:54 +00:00
|
|
|
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
2020-09-23 14:02:13 +00:00
|
|
|
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
|
|
|
|
connect(m_ui.actionGridViewZoomIn, &QAction::triggered, m_game_list_widget, [this]() {
|
|
|
|
if (isShowingGameList())
|
2020-09-23 14:08:29 +00:00
|
|
|
m_game_list_widget->gridZoomIn();
|
2020-09-23 14:02:13 +00:00
|
|
|
});
|
|
|
|
connect(m_ui.actionGridViewZoomOut, &QAction::triggered, m_game_list_widget, [this]() {
|
|
|
|
if (isShowingGameList())
|
2020-09-23 14:08:29 +00:00
|
|
|
m_game_list_widget->gridZoomOut();
|
2020-09-23 14:02:13 +00:00
|
|
|
});
|
2020-09-23 14:08:29 +00:00
|
|
|
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget,
|
|
|
|
&GameListWidget::refreshGridCovers);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-24 04:51:30 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::errorReported, this, &MainWindow::reportError,
|
|
|
|
Qt::BlockingQueuedConnection);
|
2020-02-26 09:25:57 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::messageReported, this, &MainWindow::reportMessage);
|
|
|
|
connect(m_host_interface, &QtHostInterface::messageConfirmed, this, &MainWindow::confirmMessage,
|
|
|
|
Qt::BlockingQueuedConnection);
|
2020-04-22 11:13:51 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::createDisplayRequested, this, &MainWindow::createDisplay,
|
2020-02-15 15:14:28 +00:00
|
|
|
Qt::BlockingQueuedConnection);
|
2020-04-22 11:13:51 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::destroyDisplayRequested, this, &MainWindow::destroyDisplay);
|
|
|
|
connect(m_host_interface, &QtHostInterface::updateDisplayRequested, this, &MainWindow::updateDisplay,
|
2020-04-05 12:58:47 +00:00
|
|
|
Qt::BlockingQueuedConnection);
|
2020-11-18 13:15:16 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::displaySizeRequested, this, &MainWindow::displaySizeRequested);
|
2020-02-26 09:26:14 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget);
|
2020-06-05 17:44:57 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::emulationStarting, this, &MainWindow::onEmulationStarting);
|
2019-12-31 06:17:17 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::emulationStarted, this, &MainWindow::onEmulationStarted);
|
|
|
|
connect(m_host_interface, &QtHostInterface::emulationStopped, this, &MainWindow::onEmulationStopped);
|
|
|
|
connect(m_host_interface, &QtHostInterface::emulationPaused, this, &MainWindow::onEmulationPaused);
|
2020-02-15 15:15:18 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::stateSaved, this, &MainWindow::onStateSaved);
|
2020-02-09 13:16:25 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::systemPerformanceCountersUpdated, this,
|
|
|
|
&MainWindow::onSystemPerformanceCountersUpdated);
|
2020-01-24 04:50:46 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
2020-04-13 12:13:46 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::exitRequested, this, &MainWindow::close);
|
2020-12-27 04:08:13 +00:00
|
|
|
connect(m_host_interface, &QtHostInterface::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-03-22 03:10:28 +00:00
|
|
|
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
|
|
|
|
connect(m_game_list_widget, &GameListWidget::entrySelected, this, &MainWindow::onGameListEntrySelected,
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
connect(m_game_list_widget, &GameListWidget::entryDoubleClicked, this, &MainWindow::onGameListEntryDoubleClicked,
|
|
|
|
Qt::QueuedConnection);
|
2020-03-02 01:08:16 +00:00
|
|
|
connect(m_game_list_widget, &GameListWidget::entryContextMenuRequested, this,
|
|
|
|
&MainWindow::onGameListContextMenuRequested);
|
2020-02-04 06:22:56 +00:00
|
|
|
|
2020-02-15 15:14:04 +00:00
|
|
|
m_host_interface->populateSaveStateMenus(nullptr, m_ui.menuLoadState, m_ui.menuSaveState);
|
|
|
|
|
2020-10-09 07:52:05 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDisableInterlacing, "GPU",
|
|
|
|
"DisableInterlacing");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionForceNTSCTimings, "GPU",
|
|
|
|
"ForceNTSCTimings");
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugDumpCPUtoVRAMCopies, "Debug",
|
|
|
|
"DumpCPUToVRAMCopies");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugDumpVRAMtoCPUCopies, "Debug",
|
|
|
|
"DumpVRAMToCPUCopies");
|
2020-03-15 12:04:32 +00:00
|
|
|
connect(m_ui.actionDumpAudio, &QAction::toggled, [this](bool checked) {
|
|
|
|
if (checked)
|
|
|
|
m_host_interface->startDumpingAudio();
|
|
|
|
else
|
|
|
|
m_host_interface->stopDumpingAudio();
|
|
|
|
});
|
2020-08-16 13:20:36 +00:00
|
|
|
connect(m_ui.actionDumpRAM, &QAction::triggered, [this]() {
|
2021-01-13 09:24:41 +00:00
|
|
|
const QString filename =
|
|
|
|
QFileDialog::getSaveFileName(this, tr("Destination File"), QString(), tr("Binary Files (*.bin)"));
|
2020-08-16 13:20:36 +00:00
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_host_interface->dumpRAM(filename);
|
|
|
|
});
|
2021-01-13 09:24:41 +00:00
|
|
|
connect(m_ui.actionDumpVRAM, &QAction::triggered, [this]() {
|
|
|
|
const QString filename = QFileDialog::getSaveFileName(this, tr("Destination File"), QString(),
|
|
|
|
tr("Binary Files (*.bin);;PNG Images (*.png)"));
|
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_host_interface->dumpVRAM(filename);
|
|
|
|
});
|
|
|
|
connect(m_ui.actionDumpSPURAM, &QAction::triggered, [this]() {
|
|
|
|
const QString filename =
|
|
|
|
QFileDialog::getSaveFileName(this, tr("Destination File"), QString(), tr("Binary Files (*.bin)"));
|
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_host_interface->dumpSPURAM(filename);
|
|
|
|
});
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowVRAM, "Debug", "ShowVRAM");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowGPUState, "Debug", "ShowGPUState");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowCDROMState, "Debug",
|
|
|
|
"ShowCDROMState");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowSPUState, "Debug", "ShowSPUState");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowTimersState, "Debug",
|
|
|
|
"ShowTimersState");
|
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowMDECState, "Debug",
|
|
|
|
"ShowMDECState");
|
2020-11-10 13:24:07 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowDMAState, "Debug", "ShowDMAState");
|
2020-06-24 15:31:23 +00:00
|
|
|
|
|
|
|
addThemeToMenu(tr("Default"), QStringLiteral("default"));
|
2020-09-23 14:19:54 +00:00
|
|
|
addThemeToMenu(tr("Fusion"), QStringLiteral("fusion"));
|
|
|
|
addThemeToMenu(tr("Dark Fusion (Gray)"), QStringLiteral("darkfusion"));
|
|
|
|
addThemeToMenu(tr("Dark Fusion (Blue)"), QStringLiteral("darkfusionblue"));
|
2020-06-24 15:32:28 +00:00
|
|
|
addThemeToMenu(tr("QDarkStyle"), QStringLiteral("qdarkstyle"));
|
2020-06-24 15:31:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::addThemeToMenu(const QString& name, const QString& key)
|
|
|
|
{
|
|
|
|
QAction* action = m_ui.menuSettingsTheme->addAction(name);
|
|
|
|
action->setCheckable(true);
|
|
|
|
action->setData(key);
|
|
|
|
connect(action, &QAction::toggled, [this, key](bool) { setTheme(key); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::setTheme(const QString& theme)
|
|
|
|
{
|
2020-07-21 09:49:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue("UI", "Theme", theme.toUtf8().constData());
|
2020-06-24 15:31:23 +00:00
|
|
|
updateTheme();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::updateTheme()
|
|
|
|
{
|
2020-07-21 09:49:04 +00:00
|
|
|
QString theme = QString::fromStdString(m_host_interface->GetStringSettingValue("UI", "Theme", "default"));
|
2020-06-24 15:31:23 +00:00
|
|
|
if (theme == QStringLiteral("qdarkstyle"))
|
|
|
|
{
|
2020-07-04 05:54:26 +00:00
|
|
|
qApp->setStyle(m_unthemed_style_name);
|
|
|
|
qApp->setPalette(QApplication::style()->standardPalette());
|
|
|
|
|
2020-06-24 15:31:23 +00:00
|
|
|
QFile f(QStringLiteral(":qdarkstyle/style.qss"));
|
|
|
|
if (f.open(QFile::ReadOnly | QFile::Text))
|
|
|
|
qApp->setStyleSheet(f.readAll());
|
|
|
|
}
|
2020-09-23 14:19:54 +00:00
|
|
|
else if (theme == QStringLiteral("fusion"))
|
|
|
|
{
|
|
|
|
qApp->setPalette(QApplication::style()->standardPalette());
|
|
|
|
qApp->setStyleSheet(QString());
|
|
|
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
|
|
|
}
|
2020-06-24 15:32:28 +00:00
|
|
|
else if (theme == QStringLiteral("darkfusion"))
|
|
|
|
{
|
|
|
|
// adapted from https://gist.github.com/QuantumCD/6245215
|
|
|
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
|
|
|
|
|
|
|
const QColor lighterGray(75, 75, 75);
|
|
|
|
const QColor darkGray(53, 53, 53);
|
|
|
|
const QColor gray(128, 128, 128);
|
|
|
|
const QColor black(25, 25, 25);
|
|
|
|
const QColor blue(198, 238, 255);
|
|
|
|
|
|
|
|
QPalette darkPalette;
|
|
|
|
darkPalette.setColor(QPalette::Window, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Base, black);
|
|
|
|
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Text, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Button, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Link, blue);
|
|
|
|
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
|
|
|
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
|
|
|
|
|
|
|
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
|
|
|
|
|
|
|
qApp->setPalette(darkPalette);
|
|
|
|
|
|
|
|
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
|
|
|
}
|
2020-09-23 14:19:54 +00:00
|
|
|
else if (theme == QStringLiteral("darkfusionblue"))
|
|
|
|
{
|
|
|
|
// adapted from https://gist.github.com/QuantumCD/6245215
|
|
|
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
|
|
|
|
|
|
|
const QColor lighterGray(75, 75, 75);
|
|
|
|
const QColor darkGray(53, 53, 53);
|
|
|
|
const QColor gray(128, 128, 128);
|
|
|
|
const QColor black(25, 25, 25);
|
|
|
|
const QColor blue(198, 238, 255);
|
|
|
|
const QColor blue2(0, 88, 208);
|
|
|
|
|
|
|
|
QPalette darkPalette;
|
|
|
|
darkPalette.setColor(QPalette::Window, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Base, black);
|
|
|
|
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::ToolTipBase, blue2);
|
|
|
|
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Text, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Button, darkGray);
|
|
|
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
|
|
|
darkPalette.setColor(QPalette::Link, blue);
|
|
|
|
darkPalette.setColor(QPalette::Highlight, blue2);
|
|
|
|
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
|
|
|
|
|
|
|
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
|
|
|
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
|
|
|
|
|
|
|
qApp->setPalette(darkPalette);
|
|
|
|
|
|
|
|
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
|
|
|
}
|
2020-06-24 15:31:23 +00:00
|
|
|
else
|
|
|
|
{
|
2020-06-24 22:12:21 +00:00
|
|
|
qApp->setPalette(QApplication::style()->standardPalette());
|
2020-06-24 15:31:23 +00:00
|
|
|
qApp->setStyleSheet(QString());
|
2020-07-04 05:54:26 +00:00
|
|
|
qApp->setStyle(m_unthemed_style_name);
|
2020-06-24 15:31:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (QObject* obj : m_ui.menuSettingsTheme->children())
|
|
|
|
{
|
|
|
|
QAction* action = qobject_cast<QAction*>(obj);
|
|
|
|
if (action)
|
|
|
|
{
|
|
|
|
QVariant action_data(action->data());
|
|
|
|
if (action_data.isValid())
|
|
|
|
{
|
|
|
|
QSignalBlocker blocker(action);
|
|
|
|
action->setChecked(action_data == theme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 07:58:04 +00:00
|
|
|
void MainWindow::saveStateToConfig()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const QByteArray geometry = saveGeometry();
|
|
|
|
const QByteArray geometry_b64 = geometry.toBase64();
|
|
|
|
const std::string old_geometry_b64 = m_host_interface->GetStringSettingValue("UI", "MainWindowGeometry");
|
2020-09-23 02:18:01 +00:00
|
|
|
if (old_geometry_b64 != geometry_b64.constData())
|
2020-09-14 07:58:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue("UI", "MainWindowGeometry", geometry_b64.constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const QByteArray state = saveState();
|
|
|
|
const QByteArray state_b64 = state.toBase64();
|
|
|
|
const std::string old_state_b64 = m_host_interface->GetStringSettingValue("UI", "MainWindowState");
|
2020-09-23 02:18:01 +00:00
|
|
|
if (old_state_b64 != state_b64.constData())
|
2020-09-14 07:58:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue("UI", "MainWindowState", state_b64.constData());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::restoreStateFromConfig()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::string geometry_b64 = m_host_interface->GetStringSettingValue("UI", "MainWindowGeometry");
|
|
|
|
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
|
|
|
|
if (!geometry.isEmpty())
|
|
|
|
restoreGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const std::string state_b64 = m_host_interface->GetStringSettingValue("UI", "MainWindowState");
|
|
|
|
const QByteArray state = QByteArray::fromBase64(QByteArray::fromStdString(state_b64));
|
|
|
|
if (!state.isEmpty())
|
|
|
|
restoreState(state);
|
|
|
|
|
|
|
|
{
|
|
|
|
QSignalBlocker sb(m_ui.actionViewToolbar);
|
|
|
|
m_ui.actionViewToolbar->setChecked(!m_ui.toolBar->isHidden());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QSignalBlocker sb(m_ui.actionViewStatusBar);
|
|
|
|
m_ui.actionViewStatusBar->setChecked(!m_ui.statusBar->isHidden());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-03 02:10:11 +00:00
|
|
|
void MainWindow::saveDisplayWindowGeometryToConfig()
|
|
|
|
{
|
|
|
|
const QByteArray geometry = m_display_widget->saveGeometry();
|
|
|
|
const QByteArray geometry_b64 = geometry.toBase64();
|
|
|
|
const std::string old_geometry_b64 = m_host_interface->GetStringSettingValue("UI", "DisplayWindowGeometry");
|
|
|
|
if (old_geometry_b64 != geometry_b64.constData())
|
|
|
|
m_host_interface->SetStringSettingValue("UI", "DisplayWindowGeometry", geometry_b64.constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::restoreDisplayWindowGeometryFromConfig()
|
|
|
|
{
|
|
|
|
const std::string geometry_b64 = m_host_interface->GetStringSettingValue("UI", "DisplayWindowGeometry");
|
|
|
|
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
|
|
|
|
if (!geometry.isEmpty())
|
|
|
|
m_display_widget->restoreGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:50:53 +00:00
|
|
|
SettingsDialog* MainWindow::getSettingsDialog()
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
|
|
|
if (!m_settings_dialog)
|
|
|
|
m_settings_dialog = new SettingsDialog(m_host_interface, this);
|
|
|
|
|
2020-01-24 04:50:53 +00:00
|
|
|
return m_settings_dialog;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::doSettings(SettingsDialog::Category category)
|
|
|
|
{
|
|
|
|
SettingsDialog* dlg = getSettingsDialog();
|
|
|
|
if (!dlg->isVisible())
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
2020-01-24 04:50:53 +00:00
|
|
|
dlg->setModal(false);
|
|
|
|
dlg->show();
|
2019-12-31 06:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (category != SettingsDialog::Category::Count)
|
2020-01-24 04:50:53 +00:00
|
|
|
dlg->setCategory(category);
|
2020-01-24 04:49:47 +00:00
|
|
|
}
|
2020-01-24 04:49:51 +00:00
|
|
|
|
2020-02-05 08:43:25 +00:00
|
|
|
void MainWindow::updateDebugMenuCPUExecutionMode()
|
|
|
|
{
|
2020-07-13 16:24:11 +00:00
|
|
|
std::optional<CPUExecutionMode> current_mode =
|
2020-07-21 09:49:04 +00:00
|
|
|
Settings::ParseCPUExecutionMode(m_host_interface->GetStringSettingValue("CPU", "ExecutionMode").c_str());
|
2020-02-05 08:43:25 +00:00
|
|
|
if (!current_mode.has_value())
|
|
|
|
return;
|
|
|
|
|
2020-10-23 09:26:19 +00:00
|
|
|
const QString current_mode_display_name(
|
|
|
|
qApp->translate("CPUExecutionMode", Settings::GetCPUExecutionModeDisplayName(current_mode.value())));
|
2020-02-05 08:43:25 +00:00
|
|
|
for (QObject* obj : m_ui.menuCPUExecutionMode->children())
|
|
|
|
{
|
|
|
|
QAction* action = qobject_cast<QAction*>(obj);
|
|
|
|
if (action)
|
|
|
|
action->setChecked(action->text() == current_mode_display_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:49:51 +00:00
|
|
|
void MainWindow::updateDebugMenuGPURenderer()
|
|
|
|
{
|
|
|
|
// update the menu with the new selected renderer
|
2020-07-13 16:24:11 +00:00
|
|
|
std::optional<GPURenderer> current_renderer =
|
2020-07-21 09:49:04 +00:00
|
|
|
Settings::ParseRendererName(m_host_interface->GetStringSettingValue("GPU", "Renderer").c_str());
|
2020-02-05 08:43:25 +00:00
|
|
|
if (!current_renderer.has_value())
|
|
|
|
return;
|
|
|
|
|
2020-10-23 09:26:19 +00:00
|
|
|
const QString current_renderer_display_name(
|
|
|
|
qApp->translate("GPURenderer", Settings::GetRendererDisplayName(current_renderer.value())));
|
2020-02-05 08:43:25 +00:00
|
|
|
for (QObject* obj : m_ui.menuRenderer->children())
|
2020-01-24 04:49:51 +00:00
|
|
|
{
|
2020-02-05 08:43:25 +00:00
|
|
|
QAction* action = qobject_cast<QAction*>(obj);
|
|
|
|
if (action)
|
|
|
|
action->setChecked(action->text() == current_renderer_display_name);
|
2020-01-24 04:49:51 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 04:50:42 +00:00
|
|
|
|
2020-10-09 07:52:05 +00:00
|
|
|
void MainWindow::updateDebugMenuCropMode()
|
|
|
|
{
|
|
|
|
std::optional<DisplayCropMode> current_crop_mode =
|
|
|
|
Settings::ParseDisplayCropMode(m_host_interface->GetStringSettingValue("Display", "CropMode").c_str());
|
|
|
|
if (!current_crop_mode.has_value())
|
|
|
|
return;
|
|
|
|
|
2020-10-23 09:26:19 +00:00
|
|
|
const QString current_crop_mode_display_name(
|
|
|
|
qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(current_crop_mode.value())));
|
2020-10-09 07:52:05 +00:00
|
|
|
for (QObject* obj : m_ui.menuCropMode->children())
|
|
|
|
{
|
|
|
|
QAction* action = qobject_cast<QAction*>(obj);
|
|
|
|
if (action)
|
|
|
|
action->setChecked(action->text() == current_crop_mode_display_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:50:56 +00:00
|
|
|
void MainWindow::closeEvent(QCloseEvent* event)
|
|
|
|
{
|
2020-02-15 15:14:49 +00:00
|
|
|
m_host_interface->synchronousPowerOffSystem();
|
2020-09-14 07:58:04 +00:00
|
|
|
saveStateToConfig();
|
2020-01-24 04:50:56 +00:00
|
|
|
QMainWindow::closeEvent(event);
|
|
|
|
}
|
2020-03-22 11:50:49 +00:00
|
|
|
|
|
|
|
void MainWindow::changeEvent(QEvent* event)
|
|
|
|
{
|
2020-03-28 15:12:27 +00:00
|
|
|
if (static_cast<QWindowStateChangeEvent*>(event)->oldState() & Qt::WindowMinimized)
|
2020-03-22 11:50:49 +00:00
|
|
|
{
|
|
|
|
// TODO: This should check the render-to-main option.
|
|
|
|
if (m_display_widget)
|
|
|
|
m_host_interface->redrawDisplayWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
QMainWindow::changeEvent(event);
|
|
|
|
}
|
2020-08-06 12:08:22 +00:00
|
|
|
|
|
|
|
void MainWindow::startupUpdateCheck()
|
|
|
|
{
|
|
|
|
if (!m_host_interface->GetBoolSettingValue("AutoUpdater", "CheckAtStartup", true))
|
|
|
|
return;
|
|
|
|
|
|
|
|
checkForUpdates(false);
|
|
|
|
}
|
|
|
|
|
2020-08-18 14:01:57 +00:00
|
|
|
void MainWindow::updateDebugMenuVisibility()
|
|
|
|
{
|
|
|
|
const bool visible = m_host_interface->GetBoolSettingValue("Main", "ShowDebugMenu", false);
|
|
|
|
m_ui.menuDebug->menuAction()->setVisible(visible);
|
|
|
|
}
|
|
|
|
|
2020-09-14 08:25:51 +00:00
|
|
|
void MainWindow::onCheckForUpdatesActionTriggered()
|
|
|
|
{
|
|
|
|
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
|
|
|
m_host_interface->RemoveSettingValue("AutoUpdater", "LastVersion");
|
|
|
|
checkForUpdates(true);
|
|
|
|
}
|
|
|
|
|
2020-11-10 13:24:07 +00:00
|
|
|
void MainWindow::openMemoryCardEditor(const QString& card_a_path, const QString& card_b_path)
|
2020-09-18 14:28:07 +00:00
|
|
|
{
|
|
|
|
if (!m_memory_card_editor_dialog)
|
|
|
|
m_memory_card_editor_dialog = new MemoryCardEditorDialog(this);
|
|
|
|
|
|
|
|
m_memory_card_editor_dialog->setModal(false);
|
|
|
|
m_memory_card_editor_dialog->show();
|
2020-11-10 13:24:07 +00:00
|
|
|
|
|
|
|
if (!card_a_path.isEmpty())
|
|
|
|
{
|
|
|
|
if (!m_memory_card_editor_dialog->setCardA(card_a_path))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(
|
|
|
|
this, tr("Memory Card Not Found"),
|
|
|
|
tr("Memory card '%1' could not be found. Try starting the game and saving to create it.").arg(card_a_path));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!card_b_path.isEmpty())
|
|
|
|
{
|
|
|
|
if (!m_memory_card_editor_dialog->setCardB(card_b_path))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(
|
|
|
|
this, tr("Memory Card Not Found"),
|
|
|
|
tr("Memory card '%1' could not be found. Try starting the game and saving to create it.").arg(card_b_path));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onToolsMemoryCardEditorTriggered()
|
|
|
|
{
|
|
|
|
openMemoryCardEditor(QString(), QString());
|
2020-09-18 14:28:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:14:49 +00:00
|
|
|
void MainWindow::onToolsCheatManagerTriggered()
|
|
|
|
{
|
|
|
|
if (!m_cheat_manager_dialog)
|
|
|
|
m_cheat_manager_dialog = new CheatManagerDialog(this);
|
|
|
|
|
|
|
|
m_cheat_manager_dialog->setModal(false);
|
|
|
|
m_cheat_manager_dialog->show();
|
|
|
|
}
|
|
|
|
|
2020-12-26 14:40:28 +00:00
|
|
|
void MainWindow::openCPUDebugger()
|
2020-12-16 15:18:13 +00:00
|
|
|
{
|
2020-12-26 14:15:12 +00:00
|
|
|
m_host_interface->pauseSystem(true, true);
|
2020-12-26 14:40:28 +00:00
|
|
|
if (!System::IsValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Assert(!m_debugger_window);
|
|
|
|
|
|
|
|
m_debugger_window = new DebuggerWindow();
|
|
|
|
m_debugger_window->setWindowIcon(windowIcon());
|
|
|
|
connect(m_debugger_window, &DebuggerWindow::closed, this, &MainWindow::onCPUDebuggerClosed);
|
2020-12-16 15:18:13 +00:00
|
|
|
m_debugger_window->show();
|
2020-12-26 14:15:12 +00:00
|
|
|
|
|
|
|
// the debugger will miss the pause event above (or we were already paused), so fire it now
|
|
|
|
m_debugger_window->onEmulationPaused(true);
|
2020-12-16 15:18:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onCPUDebuggerClosed()
|
|
|
|
{
|
|
|
|
Assert(m_debugger_window);
|
|
|
|
m_debugger_window->deleteLater();
|
|
|
|
m_debugger_window = nullptr;
|
|
|
|
}
|
|
|
|
|
2020-09-23 14:19:54 +00:00
|
|
|
void MainWindow::onToolsOpenDataDirectoryTriggered()
|
|
|
|
{
|
|
|
|
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_host_interface->getUserDirectoryRelativePath(QString())));
|
|
|
|
}
|
|
|
|
|
2020-08-06 12:08:22 +00:00
|
|
|
void MainWindow::checkForUpdates(bool display_message)
|
|
|
|
{
|
|
|
|
if (!AutoUpdaterDialog::isSupported())
|
|
|
|
{
|
|
|
|
if (display_message)
|
2020-08-06 12:37:30 +00:00
|
|
|
{
|
|
|
|
QMessageBox mbox(this);
|
|
|
|
mbox.setWindowTitle(tr("Updater Error"));
|
|
|
|
mbox.setTextFormat(Qt::RichText);
|
|
|
|
|
|
|
|
QString message;
|
|
|
|
#ifdef WIN32
|
|
|
|
message =
|
|
|
|
tr("<p>Sorry, you are trying to update a DuckStation version which is not an official GitHub release. To "
|
|
|
|
"prevent incompatibilities, the auto-updater is only enabled on official builds.</p>"
|
|
|
|
"<p>To obtain an official build, please follow the instructions under \"Downloading and Running\" at the "
|
|
|
|
"link below:</p>"
|
|
|
|
"<p><a href=\"https://github.com/stenzek/duckstation/\">https://github.com/stenzek/duckstation/</a></p>");
|
|
|
|
#else
|
|
|
|
message = tr("Automatic updating is not supported on the current platform.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mbox.setText(message);
|
|
|
|
mbox.setIcon(QMessageBox::Critical);
|
|
|
|
mbox.exec();
|
|
|
|
}
|
2020-08-06 12:08:22 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_auto_updater_dialog)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_auto_updater_dialog = new AutoUpdaterDialog(m_host_interface, this);
|
|
|
|
connect(m_auto_updater_dialog, &AutoUpdaterDialog::updateCheckCompleted, this, &MainWindow::onUpdateCheckComplete);
|
|
|
|
m_auto_updater_dialog->queueUpdateCheck(display_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::onUpdateCheckComplete()
|
|
|
|
{
|
|
|
|
if (!m_auto_updater_dialog)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_auto_updater_dialog->deleteLater();
|
|
|
|
m_auto_updater_dialog = nullptr;
|
|
|
|
}
|