mirror of https://github.com/PCSX2/pcsx2.git
Frontend: Add fullscreen UI implementation
This commit is contained in:
parent
5b9d197b7d
commit
05bed05afe
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
Binary file not shown.
After Width: | Height: | Size: 202 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "pcsx2/SysForwardDefs.h"
|
||||||
|
|
||||||
#include "AboutDialog.h"
|
#include "AboutDialog.h"
|
||||||
#include "QtHost.h"
|
#include "QtHost.h"
|
||||||
#include "QtUtils.h"
|
#include "QtUtils.h"
|
||||||
|
@ -52,25 +54,25 @@ AboutDialog::~AboutDialog() = default;
|
||||||
|
|
||||||
QString AboutDialog::getWebsiteUrl()
|
QString AboutDialog::getWebsiteUrl()
|
||||||
{
|
{
|
||||||
return QStringLiteral("https://pcsx2.net/");
|
return QString::fromUtf8(PCSX2_WEBSITE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AboutDialog::getSupportForumsUrl()
|
QString AboutDialog::getSupportForumsUrl()
|
||||||
{
|
{
|
||||||
return QStringLiteral("https://forums.pcsx2.net/");
|
return QString::fromUtf8(PCSX2_FORUMS_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AboutDialog::getGitHubRepositoryUrl()
|
QString AboutDialog::getGitHubRepositoryUrl()
|
||||||
{
|
{
|
||||||
return QStringLiteral("https://github.com/PCSX2/pcsx2");
|
return QString::fromUtf8(PCSX2_GITHUB_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AboutDialog::getLicenseUrl()
|
QString AboutDialog::getLicenseUrl()
|
||||||
{
|
{
|
||||||
return QStringLiteral("https://github.com/PCSX2/pcsx2/blob/master/pcsx2/Docs/License.txt");
|
return QString::fromUtf8(PCSX2_LICENSE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AboutDialog::getDiscordServerUrl()
|
QString AboutDialog::getDiscordServerUrl()
|
||||||
{
|
{
|
||||||
return QStringLiteral("https://discord.com/invite/TCz3t9k");
|
return QString::fromUtf8(PCSX2_DISCORD_URL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,24 @@ void DisplayWidget::updateCursor(bool master_enable)
|
||||||
unsetCursor();
|
unsetCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayWidget::handleCloseEvent(QCloseEvent* event)
|
||||||
|
{
|
||||||
|
// Closing the separate widget will either cancel the close, or trigger shutdown.
|
||||||
|
// In the latter case, it's going to destroy us, so don't let Qt do it first.
|
||||||
|
if (QtHost::IsVMValid())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true),
|
||||||
|
Q_ARG(bool, true), Q_ARG(bool, false));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel the event from closing the window.
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayWidget::updateCenterPos()
|
void DisplayWidget::updateCenterPos()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -330,6 +348,7 @@ bool DisplayWidget::event(QEvent* event)
|
||||||
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
||||||
if (event->type() == QEvent::MouseButtonDblClick &&
|
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||||
|
QtHost::IsVMValid() && !QtHost::IsVMPaused() &&
|
||||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||||
{
|
{
|
||||||
|
@ -384,10 +403,7 @@ bool DisplayWidget::event(QEvent* event)
|
||||||
|
|
||||||
case QEvent::Close:
|
case QEvent::Close:
|
||||||
{
|
{
|
||||||
// Closing the separate widget will either cancel the close, or trigger shutdown.
|
handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||||
// In the latter case, it's going to destroy us, so don't let Qt do it first.
|
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true), Q_ARG(bool, true), Q_ARG(bool, false));
|
|
||||||
event->ignore();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,12 +470,9 @@ DisplayWidget* DisplayContainer::removeDisplayWidget()
|
||||||
|
|
||||||
bool DisplayContainer::event(QEvent* event)
|
bool DisplayContainer::event(QEvent* event)
|
||||||
{
|
{
|
||||||
if (event->type() == QEvent::Close)
|
if (event->type() == QEvent::Close && m_display_widget)
|
||||||
{
|
{
|
||||||
// Closing the separate widget will either cancel the close, or trigger shutdown.
|
m_display_widget->handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||||
// In the latter case, it's going to destroy us, so don't let Qt do it first.
|
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true), Q_ARG(bool, true), Q_ARG(bool, false));
|
|
||||||
event->ignore();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class QCloseEvent;
|
||||||
|
|
||||||
class DisplayWidget final : public QWidget
|
class DisplayWidget final : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -41,6 +43,8 @@ public:
|
||||||
void updateRelativeMode(bool master_enable);
|
void updateRelativeMode(bool master_enable);
|
||||||
void updateCursor(bool master_enable);
|
void updateCursor(bool master_enable);
|
||||||
|
|
||||||
|
void handleCloseEvent(QCloseEvent* event);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void windowResizedEvent(int width, int height, float scale);
|
void windowResizedEvent(int width, int height, float scale);
|
||||||
void windowRestoredEvent();
|
void windowRestoredEvent();
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "pcsx2/Counters.h"
|
#include "pcsx2/Counters.h"
|
||||||
#include "pcsx2/Frontend/InputManager.h"
|
#include "pcsx2/Frontend/InputManager.h"
|
||||||
#include "pcsx2/Frontend/ImGuiManager.h"
|
#include "pcsx2/Frontend/ImGuiManager.h"
|
||||||
|
#include "pcsx2/Frontend/FullscreenUI.h"
|
||||||
#include "pcsx2/GS.h"
|
#include "pcsx2/GS.h"
|
||||||
#include "pcsx2/GS/GS.h"
|
#include "pcsx2/GS/GS.h"
|
||||||
#include "pcsx2/GSDumpReplayer.h"
|
#include "pcsx2/GSDumpReplayer.h"
|
||||||
|
@ -87,6 +88,9 @@ void EmuThread::stopInThread()
|
||||||
if (VMManager::HasValidVM())
|
if (VMManager::HasValidVM())
|
||||||
destroyVM();
|
destroyVM();
|
||||||
|
|
||||||
|
if (m_run_fullscreen_ui)
|
||||||
|
stopFullscreenUI();
|
||||||
|
|
||||||
m_event_loop->quit();
|
m_event_loop->quit();
|
||||||
m_shutdown_flag.store(true);
|
m_shutdown_flag.store(true);
|
||||||
}
|
}
|
||||||
|
@ -126,6 +130,53 @@ bool EmuThread::confirmMessage(const QString& title, const QString& message)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuThread::startFullscreenUI(bool fullscreen)
|
||||||
|
{
|
||||||
|
if (!isOnEmuThread())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(this, "startFullscreenUI", Qt::QueuedConnection, Q_ARG(bool, fullscreen));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VMManager::HasValidVM())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_run_fullscreen_ui = true;
|
||||||
|
if (fullscreen)
|
||||||
|
m_is_fullscreen = true;
|
||||||
|
|
||||||
|
if (!GetMTGS().WaitForOpen())
|
||||||
|
{
|
||||||
|
m_run_fullscreen_ui = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll more frequently so we don't lose events
|
||||||
|
stopBackgroundControllerPollTimer();
|
||||||
|
startBackgroundControllerPollTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::stopFullscreenUI()
|
||||||
|
{
|
||||||
|
if (!isOnEmuThread())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(this, &EmuThread::stopFullscreenUI, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// wait until the host display is gone
|
||||||
|
while (s_host_display)
|
||||||
|
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_host_display)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pxAssertRel(!VMManager::HasValidVM(), "VM is not valid at FSUI shutdown time");
|
||||||
|
m_run_fullscreen_ui = false;
|
||||||
|
GetMTGS().WaitForClose();
|
||||||
|
}
|
||||||
|
|
||||||
void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
||||||
{
|
{
|
||||||
if (!isOnEmuThread())
|
if (!isOnEmuThread())
|
||||||
|
@ -136,15 +187,16 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
|
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
|
||||||
loadOurSettings();
|
|
||||||
|
// Only initialize fullscreen/render-to-main when we're not running big picture.
|
||||||
|
if (!m_run_fullscreen_ui)
|
||||||
|
loadOurInitialSettings();
|
||||||
|
|
||||||
|
if (boot_params->fullscreen.has_value())
|
||||||
|
m_is_fullscreen = boot_params->fullscreen.value();
|
||||||
|
|
||||||
emit onVMStarting();
|
emit onVMStarting();
|
||||||
|
|
||||||
// create the display, this may take a while...
|
|
||||||
m_is_fullscreen = boot_params->fullscreen.value_or(Host::GetBaseBoolSettingValue("UI", "StartFullscreen", false));
|
|
||||||
m_is_rendering_to_main = shouldRenderToMain();
|
|
||||||
m_is_surfaceless = false;
|
|
||||||
m_save_state_on_shutdown = false;
|
|
||||||
if (!VMManager::Initialize(*boot_params))
|
if (!VMManager::Initialize(*boot_params))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -265,6 +317,7 @@ void EmuThread::saveStateToSlot(qint32 slot)
|
||||||
|
|
||||||
void EmuThread::run()
|
void EmuThread::run()
|
||||||
{
|
{
|
||||||
|
Threading::SetNameOfCurrentThread("EmuThread");
|
||||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
|
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
|
||||||
m_event_loop = new QEventLoop();
|
m_event_loop = new QEventLoop();
|
||||||
m_started_semaphore.release();
|
m_started_semaphore.release();
|
||||||
|
@ -273,8 +326,13 @@ void EmuThread::run()
|
||||||
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
|
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
|
||||||
pxFailRel("Failed to allocate memory map");
|
pxFailRel("Failed to allocate memory map");
|
||||||
|
|
||||||
// we need input sources ready for binding
|
// We want settings loaded so we choose the correct renderer for big picture mode.
|
||||||
reloadInputSources();
|
// This also sorts out input sources.
|
||||||
|
loadOurSettings();
|
||||||
|
loadOurInitialSettings();
|
||||||
|
VMManager::LoadSettings();
|
||||||
|
|
||||||
|
// Start background polling because the VM won't do it for us.
|
||||||
createBackgroundControllerPollTimer();
|
createBackgroundControllerPollTimer();
|
||||||
startBackgroundControllerPollTimer();
|
startBackgroundControllerPollTimer();
|
||||||
connectSignals();
|
connectSignals();
|
||||||
|
@ -362,7 +420,9 @@ void EmuThread::startBackgroundControllerPollTimer()
|
||||||
if (m_background_controller_polling_timer->isActive())
|
if (m_background_controller_polling_timer->isActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_background_controller_polling_timer->start(BACKGROUND_CONTROLLER_POLLING_INTERVAL);
|
m_background_controller_polling_timer->start(FullscreenUI::IsInitialized() ?
|
||||||
|
FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL :
|
||||||
|
BACKGROUND_CONTROLLER_POLLING_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::stopBackgroundControllerPollTimer()
|
void EmuThread::stopBackgroundControllerPollTimer()
|
||||||
|
@ -397,7 +457,7 @@ void EmuThread::setFullscreen(bool fullscreen)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VMManager::HasValidVM() || m_is_fullscreen == fullscreen)
|
if (!GetMTGS().IsOpen() || m_is_fullscreen == fullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// This will call back to us on the MTGS thread.
|
// This will call back to us on the MTGS thread.
|
||||||
|
@ -417,9 +477,13 @@ void EmuThread::setSurfaceless(bool surfaceless)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VMManager::HasValidVM() || m_is_surfaceless == surfaceless)
|
if (!GetMTGS().IsOpen() || m_is_surfaceless == surfaceless)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// If we went surfaceless and were running the fullscreen UI, stop MTGS running idle.
|
||||||
|
// Otherwise, we'll keep trying to present to nothing.
|
||||||
|
GetMTGS().SetRunIdle(!surfaceless && m_run_fullscreen_ui);
|
||||||
|
|
||||||
// This will call back to us on the MTGS thread.
|
// This will call back to us on the MTGS thread.
|
||||||
m_is_surfaceless = surfaceless;
|
m_is_surfaceless = surfaceless;
|
||||||
GetMTGS().UpdateDisplayWindow();
|
GetMTGS().UpdateDisplayWindow();
|
||||||
|
@ -476,11 +540,19 @@ void EmuThread::connectSignals()
|
||||||
connect(qApp, &QGuiApplication::applicationStateChanged, this, &EmuThread::onApplicationStateChanged);
|
connect(qApp, &QGuiApplication::applicationStateChanged, this, &EmuThread::onApplicationStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuThread::loadOurInitialSettings()
|
||||||
|
{
|
||||||
|
m_is_fullscreen = Host::GetBaseBoolSettingValue("UI", "StartFullscreen", false);
|
||||||
|
m_is_rendering_to_main = shouldRenderToMain();
|
||||||
|
m_is_surfaceless = false;
|
||||||
|
m_save_state_on_shutdown = false;
|
||||||
|
}
|
||||||
|
|
||||||
void EmuThread::checkForSettingChanges()
|
void EmuThread::checkForSettingChanges()
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
|
||||||
|
|
||||||
if (VMManager::HasValidVM())
|
if (s_host_display)
|
||||||
{
|
{
|
||||||
const bool render_to_main = shouldRenderToMain();
|
const bool render_to_main = shouldRenderToMain();
|
||||||
if (!m_is_fullscreen && m_is_rendering_to_main != render_to_main)
|
if (!m_is_fullscreen && m_is_rendering_to_main != render_to_main)
|
||||||
|
@ -772,6 +844,14 @@ HostDisplay* EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api)
|
||||||
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(s_host_display->GetRenderAPI()));
|
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(s_host_display->GetRenderAPI()));
|
||||||
Console.Indent().WriteLn(s_host_display->GetDriverInfo());
|
Console.Indent().WriteLn(s_host_display->GetDriverInfo());
|
||||||
|
|
||||||
|
if (m_run_fullscreen_ui && !FullscreenUI::Initialize())
|
||||||
|
{
|
||||||
|
Console.Error("Failed to initialize fullscreen UI");
|
||||||
|
releaseHostDisplay();
|
||||||
|
m_run_fullscreen_ui = false;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return s_host_display.get();
|
return s_host_display.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,6 +896,7 @@ void Host::EndPresentFrame()
|
||||||
if (GSDumpReplayer::IsReplayingDump())
|
if (GSDumpReplayer::IsReplayingDump())
|
||||||
GSDumpReplayer::RenderUI();
|
GSDumpReplayer::RenderUI();
|
||||||
|
|
||||||
|
FullscreenUI::Render();
|
||||||
ImGuiManager::RenderOSD();
|
ImGuiManager::RenderOSD();
|
||||||
s_host_display->EndPresent();
|
s_host_display->EndPresent();
|
||||||
ImGuiManager::NewFrame();
|
ImGuiManager::NewFrame();
|
||||||
|
@ -1036,14 +1117,15 @@ void Host::RequestExit(bool save_state_if_running)
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state)
|
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
|
||||||
{
|
{
|
||||||
if (!VMManager::HasValidVM())
|
if (!VMManager::HasValidVM())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection,
|
||||||
Q_ARG(bool, allow_confirm), Q_ARG(bool, allow_save_state), Q_ARG(bool, false));
|
Q_ARG(bool, allow_confirm), Q_ARG(bool, allow_save_state),
|
||||||
|
Q_ARG(bool, default_save_state), Q_ARG(bool, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Host::IsFullscreen()
|
bool Host::IsFullscreen()
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
__fi bool isFullscreen() const { return m_is_fullscreen; }
|
__fi bool isFullscreen() const { return m_is_fullscreen; }
|
||||||
__fi bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
__fi bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
||||||
__fi bool isSurfaceless() const { return m_is_surfaceless; }
|
__fi bool isSurfaceless() const { return m_is_surfaceless; }
|
||||||
|
__fi bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
|
||||||
|
|
||||||
bool isOnEmuThread() const;
|
bool isOnEmuThread() const;
|
||||||
|
|
||||||
|
@ -62,6 +63,8 @@ public:
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
bool confirmMessage(const QString& title, const QString& message);
|
bool confirmMessage(const QString& title, const QString& message);
|
||||||
|
void startFullscreenUI(bool fullscreen);
|
||||||
|
void stopFullscreenUI();
|
||||||
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
||||||
void resetVM();
|
void resetVM();
|
||||||
void setVMPaused(bool paused);
|
void setVMPaused(bool paused);
|
||||||
|
@ -133,8 +136,11 @@ protected:
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL =
|
/// Interval at which the controllers are polled when the system is not active.
|
||||||
100; /// Interval at which the controllers are polled when the system is not active.
|
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL = 100;
|
||||||
|
|
||||||
|
/// Poll at half the vsync rate for FSUI to reduce the chance of getting a press+release in the same frame.
|
||||||
|
static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8;
|
||||||
|
|
||||||
void destroyVM();
|
void destroyVM();
|
||||||
void executeVM();
|
void executeVM();
|
||||||
|
@ -143,8 +149,9 @@ private:
|
||||||
|
|
||||||
void createBackgroundControllerPollTimer();
|
void createBackgroundControllerPollTimer();
|
||||||
void destroyBackgroundControllerPollTimer();
|
void destroyBackgroundControllerPollTimer();
|
||||||
void loadOurSettings();
|
|
||||||
void connectSignals();
|
void connectSignals();
|
||||||
|
void loadOurSettings();
|
||||||
|
void loadOurInitialSettings();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void stopInThread();
|
void stopInThread();
|
||||||
|
@ -162,6 +169,7 @@ private:
|
||||||
std::atomic_bool m_shutdown_flag{false};
|
std::atomic_bool m_shutdown_flag{false};
|
||||||
|
|
||||||
bool m_verbose_status = false;
|
bool m_verbose_status = false;
|
||||||
|
bool m_run_fullscreen_ui = false;
|
||||||
bool m_is_rendering_to_main = false;
|
bool m_is_rendering_to_main = false;
|
||||||
bool m_is_fullscreen = false;
|
bool m_is_fullscreen = false;
|
||||||
bool m_is_surfaceless = false;
|
bool m_is_surfaceless = false;
|
||||||
|
|
|
@ -251,8 +251,8 @@ void MainWindow::connectSignals()
|
||||||
connect(m_ui.actionRemoveDisc, &QAction::triggered, this, &MainWindow::onRemoveDiscActionTriggered);
|
connect(m_ui.actionRemoveDisc, &QAction::triggered, this, &MainWindow::onRemoveDiscActionTriggered);
|
||||||
connect(m_ui.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow);
|
connect(m_ui.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow);
|
||||||
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
|
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
|
||||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true); });
|
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true, EmuConfig.SaveStateOnShutdown); });
|
||||||
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false); });
|
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false, false); });
|
||||||
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
|
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()); });
|
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
|
||||||
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||||
|
@ -354,6 +354,8 @@ void MainWindow::connectSignals()
|
||||||
|
|
||||||
void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||||
{
|
{
|
||||||
|
connect(m_ui.actionStartFullscreenUI, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
|
||||||
|
connect(m_ui.actionStartFullscreenUI2, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
|
||||||
connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
|
connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
|
||||||
connect(thread, &EmuThread::onCreateDisplayRequested, this, &MainWindow::createDisplay, Qt::BlockingQueuedConnection);
|
connect(thread, &EmuThread::onCreateDisplayRequested, this, &MainWindow::createDisplay, Qt::BlockingQueuedConnection);
|
||||||
connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection);
|
connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection);
|
||||||
|
@ -387,7 +389,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||||
void MainWindow::recreate()
|
void MainWindow::recreate()
|
||||||
{
|
{
|
||||||
if (s_vm_valid)
|
if (s_vm_valid)
|
||||||
requestShutdown(false, true, true);
|
requestShutdown(false, true, EmuConfig.SaveStateOnShutdown);
|
||||||
|
|
||||||
close();
|
close();
|
||||||
g_main_window = nullptr;
|
g_main_window = nullptr;
|
||||||
|
@ -950,7 +952,7 @@ void MainWindow::switchToGameListView()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_vm_valid)
|
if (m_display_created)
|
||||||
{
|
{
|
||||||
m_was_paused_on_surface_loss = s_vm_paused;
|
m_was_paused_on_surface_loss = s_vm_paused;
|
||||||
if (!s_vm_paused)
|
if (!s_vm_paused)
|
||||||
|
@ -965,7 +967,7 @@ void MainWindow::switchToGameListView()
|
||||||
|
|
||||||
void MainWindow::switchToEmulationView()
|
void MainWindow::switchToEmulationView()
|
||||||
{
|
{
|
||||||
if (!s_vm_valid || !isShowingGameList())
|
if (!m_display_created || !isShowingGameList())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we're no longer surfaceless! this will call back to UpdateDisplay(), which will swap the widget out.
|
// we're no longer surfaceless! this will call back to UpdateDisplay(), which will swap the widget out.
|
||||||
|
@ -1014,14 +1016,14 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */, bool block_until_done /* = false */)
|
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */, bool default_save_to_state /* = true */, bool block_until_done /* = false */)
|
||||||
{
|
{
|
||||||
if (!s_vm_valid)
|
if (!s_vm_valid)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If we don't have a crc, we can't save state.
|
// If we don't have a crc, we can't save state.
|
||||||
allow_save_to_state &= (m_current_game_crc != 0);
|
allow_save_to_state &= (m_current_game_crc != 0);
|
||||||
bool save_state = allow_save_to_state && EmuConfig.SaveStateOnShutdown;
|
bool save_state = allow_save_to_state && default_save_to_state;
|
||||||
|
|
||||||
// Only confirm on UI thread because we need to display a msgbox.
|
// Only confirm on UI thread because we need to display a msgbox.
|
||||||
if (!m_is_closing && allow_confirm && !GSDumpReplayer::IsReplayingDump() && Host::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
|
if (!m_is_closing && allow_confirm && !GSDumpReplayer::IsReplayingDump() && Host::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
|
||||||
|
@ -1081,7 +1083,7 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
||||||
void MainWindow::requestExit()
|
void MainWindow::requestExit()
|
||||||
{
|
{
|
||||||
// this is block, because otherwise closeEvent() will also prompt
|
// this is block, because otherwise closeEvent() will also prompt
|
||||||
if (!requestShutdown(true, true, true))
|
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
|
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
|
||||||
|
@ -1334,7 +1336,7 @@ void MainWindow::onViewGameGridActionTriggered()
|
||||||
|
|
||||||
void MainWindow::onViewSystemDisplayTriggered()
|
void MainWindow::onViewSystemDisplayTriggered()
|
||||||
{
|
{
|
||||||
if (s_vm_valid)
|
if (m_display_created)
|
||||||
switchToEmulationView();
|
switchToEmulationView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1643,7 +1645,7 @@ void MainWindow::showEvent(QShowEvent* event)
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent* event)
|
void MainWindow::closeEvent(QCloseEvent* event)
|
||||||
{
|
{
|
||||||
if (!requestShutdown(true, true, true))
|
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||||
{
|
{
|
||||||
event->ignore();
|
event->ignore();
|
||||||
return;
|
return;
|
||||||
|
@ -1742,6 +1744,8 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_display_created = true;
|
||||||
|
|
||||||
if (is_exclusive_fullscreen)
|
if (is_exclusive_fullscreen)
|
||||||
setDisplayFullscreen(fullscreen_mode);
|
setDisplayFullscreen(fullscreen_mode);
|
||||||
|
|
||||||
|
@ -1750,6 +1754,8 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||||
|
|
||||||
m_ui.actionViewSystemDisplay->setEnabled(true);
|
m_ui.actionViewSystemDisplay->setEnabled(true);
|
||||||
m_ui.actionFullscreen->setEnabled(true);
|
m_ui.actionFullscreen->setEnabled(true);
|
||||||
|
m_ui.actionStartFullscreenUI->setEnabled(false);
|
||||||
|
m_ui.actionStartFullscreenUI2->setEnabled(false);
|
||||||
|
|
||||||
m_display_widget->setShouldHideCursor(shouldHideMouseCursor());
|
m_display_widget->setShouldHideCursor(shouldHideMouseCursor());
|
||||||
m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused);
|
m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused);
|
||||||
|
@ -1940,9 +1946,12 @@ void MainWindow::destroyDisplay()
|
||||||
{
|
{
|
||||||
// Now we can safely destroy the display window.
|
// Now we can safely destroy the display window.
|
||||||
destroyDisplayWidget(true);
|
destroyDisplayWidget(true);
|
||||||
|
m_display_created = false;
|
||||||
|
|
||||||
m_ui.actionViewSystemDisplay->setEnabled(false);
|
m_ui.actionViewSystemDisplay->setEnabled(false);
|
||||||
m_ui.actionFullscreen->setEnabled(false);
|
m_ui.actionFullscreen->setEnabled(false);
|
||||||
|
m_ui.actionStartFullscreenUI->setEnabled(true);
|
||||||
|
m_ui.actionStartFullscreenUI2->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::destroyDisplayWidget(bool show_game_list)
|
void MainWindow::destroyDisplayWidget(bool show_game_list)
|
||||||
|
|
|
@ -104,7 +104,7 @@ public Q_SLOTS:
|
||||||
void reportError(const QString& title, const QString& message);
|
void reportError(const QString& title, const QString& message);
|
||||||
bool confirmMessage(const QString& title, const QString& message);
|
bool confirmMessage(const QString& title, const QString& message);
|
||||||
void runOnUIThread(const std::function<void()>& func);
|
void runOnUIThread(const std::function<void()>& func);
|
||||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool block_until_done = false);
|
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true, bool block_until_done = false);
|
||||||
void requestExit();
|
void requestExit();
|
||||||
void checkForSettingChanges();
|
void checkForSettingChanges();
|
||||||
|
|
||||||
|
@ -258,6 +258,7 @@ private:
|
||||||
QString m_current_game_name;
|
QString m_current_game_name;
|
||||||
quint32 m_current_game_crc;
|
quint32 m_current_game_crc;
|
||||||
|
|
||||||
|
bool m_display_created = false;
|
||||||
bool m_save_states_invalidated = false;
|
bool m_save_states_invalidated = false;
|
||||||
bool m_was_paused_on_surface_loss = false;
|
bool m_was_paused_on_surface_loss = false;
|
||||||
bool m_was_disc_change_request = false;
|
bool m_was_disc_change_request = false;
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
<addaction name="actionStartFile"/>
|
<addaction name="actionStartFile"/>
|
||||||
<addaction name="actionStartDisc"/>
|
<addaction name="actionStartDisc"/>
|
||||||
<addaction name="actionStartBios"/>
|
<addaction name="actionStartBios"/>
|
||||||
|
<addaction name="actionStartFullscreenUI"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionPowerOff"/>
|
<addaction name="actionPowerOff"/>
|
||||||
<addaction name="actionPowerOffWithoutSaving"/>
|
<addaction name="actionPowerOffWithoutSaving"/>
|
||||||
|
@ -225,6 +226,7 @@
|
||||||
<addaction name="actionStartFile"/>
|
<addaction name="actionStartFile"/>
|
||||||
<addaction name="actionStartDisc"/>
|
<addaction name="actionStartDisc"/>
|
||||||
<addaction name="actionStartBios"/>
|
<addaction name="actionStartBios"/>
|
||||||
|
<addaction name="actionStartFullscreenUI2"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionPowerOff"/>
|
<addaction name="actionPowerOff"/>
|
||||||
<addaction name="actionReset"/>
|
<addaction name="actionReset"/>
|
||||||
|
@ -829,6 +831,24 @@
|
||||||
<string>Enable Log Timestamps</string>
|
<string>Enable Log Timestamps</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionStartFullscreenUI">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="tv-2-line">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Start Big Picture Mode</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionStartFullscreenUI2">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="tv-2-line">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Big Picture</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="resources/resources.qrc"/>
|
<include location="resources/resources.qrc"/>
|
||||||
|
|
|
@ -82,6 +82,8 @@ static std::unique_ptr<QTimer> s_settings_save_timer;
|
||||||
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
||||||
static bool s_batch_mode = false;
|
static bool s_batch_mode = false;
|
||||||
static bool s_nogui_mode = false;
|
static bool s_nogui_mode = false;
|
||||||
|
static bool s_start_fullscreen_ui = false;
|
||||||
|
static bool s_start_fullscreen_ui_fullscreen = false;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Initialization/Shutdown
|
// Initialization/Shutdown
|
||||||
|
@ -617,6 +619,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
|
||||||
else if (CHECK_ARG("-fullscreen"))
|
else if (CHECK_ARG("-fullscreen"))
|
||||||
{
|
{
|
||||||
AutoBoot(autoboot)->fullscreen = true;
|
AutoBoot(autoboot)->fullscreen = true;
|
||||||
|
s_start_fullscreen_ui_fullscreen = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (CHECK_ARG("-nofullscreen"))
|
else if (CHECK_ARG("-nofullscreen"))
|
||||||
|
@ -629,6 +632,11 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
|
||||||
Host::InitializeEarlyConsole();
|
Host::InitializeEarlyConsole();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (CHECK_ARG("-bigpicture"))
|
||||||
|
{
|
||||||
|
s_start_fullscreen_ui = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (CHECK_ARG("--"))
|
else if (CHECK_ARG("--"))
|
||||||
{
|
{
|
||||||
no_more_args = true;
|
no_more_args = true;
|
||||||
|
@ -662,7 +670,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
|
||||||
|
|
||||||
// if we don't have autoboot, we definitely don't want batch mode (because that'll skip
|
// if we don't have autoboot, we definitely don't want batch mode (because that'll skip
|
||||||
// scanning the game list).
|
// scanning the game list).
|
||||||
if (s_batch_mode && !autoboot)
|
if (s_batch_mode && !s_start_fullscreen_ui && !autoboot)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(nullptr, QStringLiteral("Error"), s_nogui_mode ?
|
QMessageBox::critical(nullptr, QStringLiteral("Error"), s_nogui_mode ?
|
||||||
QStringLiteral("Cannot use no-gui mode, because no boot filename was specified.") :
|
QStringLiteral("Cannot use no-gui mode, because no boot filename was specified.") :
|
||||||
|
@ -750,10 +758,14 @@ int main(int argc, char* argv[])
|
||||||
if (!s_nogui_mode)
|
if (!s_nogui_mode)
|
||||||
main_window->show();
|
main_window->show();
|
||||||
|
|
||||||
|
// Initialize big picture mode if requested.
|
||||||
|
if (s_start_fullscreen_ui)
|
||||||
|
g_emu_thread->startFullscreenUI(s_start_fullscreen_ui_fullscreen);
|
||||||
|
|
||||||
// Skip the update check if we're booting a game directly.
|
// Skip the update check if we're booting a game directly.
|
||||||
if (autoboot)
|
if (autoboot)
|
||||||
g_emu_thread->startVM(std::move(autoboot));
|
g_emu_thread->startVM(std::move(autoboot));
|
||||||
else
|
else if (!s_nogui_mode)
|
||||||
main_window->startupUpdateCheck();
|
main_window->startupUpdateCheck();
|
||||||
|
|
||||||
// This doesn't return until we exit.
|
// This doesn't return until we exit.
|
||||||
|
|
|
@ -1063,7 +1063,9 @@ endif()
|
||||||
|
|
||||||
if(PCSX2_CORE)
|
if(PCSX2_CORE)
|
||||||
list(APPEND pcsx2FrontendSources
|
list(APPEND pcsx2FrontendSources
|
||||||
|
Frontend/FullscreenUI.cpp
|
||||||
Frontend/GameList.cpp
|
Frontend/GameList.cpp
|
||||||
|
Frontend/ImGuiFullscreen.cpp
|
||||||
Frontend/INISettingsInterface.cpp
|
Frontend/INISettingsInterface.cpp
|
||||||
Frontend/InputManager.cpp
|
Frontend/InputManager.cpp
|
||||||
Frontend/InputSource.cpp
|
Frontend/InputSource.cpp
|
||||||
|
@ -1074,7 +1076,9 @@ if(PCSX2_CORE)
|
||||||
VMManager.cpp
|
VMManager.cpp
|
||||||
)
|
)
|
||||||
list(APPEND pcsx2FrontendHeaders
|
list(APPEND pcsx2FrontendHeaders
|
||||||
|
Frontend/FullscreenUI.h
|
||||||
Frontend/GameList.h
|
Frontend/GameList.h
|
||||||
|
Frontend/ImGuiFullscreen.h
|
||||||
Frontend/INISettingsInterface.h
|
Frontend/INISettingsInterface.h
|
||||||
Frontend/InputManager.h
|
Frontend/InputManager.h
|
||||||
Frontend/InputSource.h
|
Frontend/InputSource.h
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,75 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "common/Pcsx2Defs.h"
|
||||||
|
#include "common/ProgressCallback.h"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class HostDisplayTexture;
|
||||||
|
|
||||||
|
namespace FullscreenUI
|
||||||
|
{
|
||||||
|
bool Initialize();
|
||||||
|
bool IsInitialized();
|
||||||
|
bool HasActiveWindow();
|
||||||
|
void OnVMStarted();
|
||||||
|
void OnVMPaused();
|
||||||
|
void OnVMResumed();
|
||||||
|
void OnVMDestroyed();
|
||||||
|
void OnRunningGameChanged(std::string path, std::string serial, std::string title, u32 crc);
|
||||||
|
void OpenPauseMenu();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
// Returns true if the message has been dismissed.
|
||||||
|
bool DrawErrorWindow(const char* message);
|
||||||
|
bool DrawConfirmWindow(const char* message, bool* result);
|
||||||
|
|
||||||
|
class ProgressCallback final : public BaseProgressCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProgressCallback(std::string name);
|
||||||
|
~ProgressCallback() override;
|
||||||
|
|
||||||
|
void PushState() override;
|
||||||
|
void PopState() override;
|
||||||
|
|
||||||
|
void SetCancellable(bool cancellable) override;
|
||||||
|
void SetTitle(const char* title) override;
|
||||||
|
void SetStatusText(const char* text) override;
|
||||||
|
void SetProgressRange(u32 range) override;
|
||||||
|
void SetProgressValue(u32 value) override;
|
||||||
|
|
||||||
|
void DisplayError(const char* message) override;
|
||||||
|
void DisplayWarning(const char* message) override;
|
||||||
|
void DisplayInformation(const char* message) override;
|
||||||
|
void DisplayDebugMessage(const char* message) override;
|
||||||
|
|
||||||
|
void ModalError(const char* message) override;
|
||||||
|
bool ModalConfirmation(const char* message) override;
|
||||||
|
void ModalInformation(const char* message) override;
|
||||||
|
|
||||||
|
void SetCancelled();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Redraw(bool force);
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
int m_last_progress_percent = -1;
|
||||||
|
};
|
||||||
|
} // namespace FullscreenUI
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,239 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "common/Pcsx2Defs.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class HostDisplayTexture;
|
||||||
|
|
||||||
|
namespace ImGuiFullscreen
|
||||||
|
{
|
||||||
|
#define HEX_TO_IMVEC4(hex, alpha) \
|
||||||
|
ImVec4(static_cast<float>((hex >> 16) & 0xFFu) / 255.0f, static_cast<float>((hex >> 8) & 0xFFu) / 255.0f, \
|
||||||
|
static_cast<float>(hex & 0xFFu) / 255.0f, static_cast<float>(alpha) / 255.0f)
|
||||||
|
|
||||||
|
static constexpr float LAYOUT_SCREEN_WIDTH = 1280.0f;
|
||||||
|
static constexpr float LAYOUT_SCREEN_HEIGHT = 720.0f;
|
||||||
|
static constexpr float LAYOUT_LARGE_FONT_SIZE = 26.0f;
|
||||||
|
static constexpr float LAYOUT_MEDIUM_FONT_SIZE = 16.0f;
|
||||||
|
static constexpr float LAYOUT_SMALL_FONT_SIZE = 10.0f;
|
||||||
|
static constexpr float LAYOUT_MENU_BUTTON_HEIGHT = 50.0f;
|
||||||
|
static constexpr float LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY = 26.0f;
|
||||||
|
static constexpr float LAYOUT_MENU_BUTTON_X_PADDING = 15.0f;
|
||||||
|
static constexpr float LAYOUT_MENU_BUTTON_Y_PADDING = 10.0f;
|
||||||
|
|
||||||
|
extern ImFont* g_standard_font;
|
||||||
|
extern ImFont* g_medium_font;
|
||||||
|
extern ImFont* g_large_font;
|
||||||
|
|
||||||
|
extern float g_layout_scale;
|
||||||
|
extern float g_layout_padding_left;
|
||||||
|
extern float g_layout_padding_top;
|
||||||
|
|
||||||
|
extern ImVec4 UIBackgroundColor;
|
||||||
|
extern ImVec4 UIBackgroundTextColor;
|
||||||
|
extern ImVec4 UIBackgroundLineColor;
|
||||||
|
extern ImVec4 UIBackgroundHighlightColor;
|
||||||
|
extern ImVec4 UIDisabledColor;
|
||||||
|
extern ImVec4 UIPrimaryColor;
|
||||||
|
extern ImVec4 UIPrimaryLightColor;
|
||||||
|
extern ImVec4 UIPrimaryDarkColor;
|
||||||
|
extern ImVec4 UIPrimaryTextColor;
|
||||||
|
extern ImVec4 UITextHighlightColor;
|
||||||
|
extern ImVec4 UIPrimaryLineColor;
|
||||||
|
extern ImVec4 UISecondaryColor;
|
||||||
|
extern ImVec4 UISecondaryLightColor;
|
||||||
|
extern ImVec4 UISecondaryDarkColor;
|
||||||
|
extern ImVec4 UISecondaryTextColor;
|
||||||
|
|
||||||
|
static __fi float DPIScale(float v) { return ImGui::GetIO().DisplayFramebufferScale.x * v; }
|
||||||
|
|
||||||
|
static __fi float DPIScale(int v) { return ImGui::GetIO().DisplayFramebufferScale.x * static_cast<float>(v); }
|
||||||
|
|
||||||
|
static __fi ImVec2 DPIScale(const ImVec2& v)
|
||||||
|
{
|
||||||
|
const ImVec2& fbs = ImGui::GetIO().DisplayFramebufferScale;
|
||||||
|
return ImVec2(v.x * fbs.x, v.y * fbs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __fi float WindowWidthScale(float v) { return ImGui::GetWindowWidth() * v; }
|
||||||
|
|
||||||
|
static __fi float WindowHeightScale(float v) { return ImGui::GetWindowHeight() * v; }
|
||||||
|
|
||||||
|
static __fi float LayoutScale(float v) { return g_layout_scale * v; }
|
||||||
|
|
||||||
|
static __fi ImVec2 LayoutScale(const ImVec2& v) { return ImVec2(v.x * g_layout_scale, v.y * g_layout_scale); }
|
||||||
|
|
||||||
|
static __fi ImVec2 LayoutScale(float x, float y) { return ImVec2(x * g_layout_scale, y * g_layout_scale); }
|
||||||
|
|
||||||
|
static __fi ImVec2 LayoutScaleAndOffset(float x, float y)
|
||||||
|
{
|
||||||
|
return ImVec2(g_layout_padding_left + x * g_layout_scale, g_layout_padding_top + y * g_layout_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __fi ImVec4 ModAlpha(const ImVec4& v, float a)
|
||||||
|
{
|
||||||
|
return ImVec4(v.x, v.y, v.z, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Centers an image within the specified bounds, scaling up or down as needed.
|
||||||
|
ImRect CenterImage(const ImVec2& fit_size, const ImVec2& image_size);
|
||||||
|
ImRect CenterImage(const ImRect& fit_rect, const ImVec2& image_size);
|
||||||
|
|
||||||
|
/// Initializes, setting up any state.
|
||||||
|
bool Initialize(const char* placeholder_image_path);
|
||||||
|
|
||||||
|
void SetTheme();
|
||||||
|
void SetFonts(ImFont* standard_font, ImFont* medium_font, ImFont* large_font);
|
||||||
|
bool UpdateLayoutScale();
|
||||||
|
|
||||||
|
/// Shuts down, clearing all state.
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
/// Texture cache.
|
||||||
|
const std::shared_ptr<HostDisplayTexture>& GetPlaceholderTexture();
|
||||||
|
std::shared_ptr<HostDisplayTexture> LoadTexture(const char* path);
|
||||||
|
HostDisplayTexture* GetCachedTexture(const char* name);
|
||||||
|
HostDisplayTexture* GetCachedTextureAsync(const char* name);
|
||||||
|
bool InvalidateCachedTexture(const std::string& path);
|
||||||
|
void UploadAsyncTextures();
|
||||||
|
|
||||||
|
void BeginLayout();
|
||||||
|
void EndLayout();
|
||||||
|
|
||||||
|
void QueueResetFocus();
|
||||||
|
bool ResetFocusHere();
|
||||||
|
bool WantsToCloseMenu();
|
||||||
|
void ResetCloseMenuIfNeeded();
|
||||||
|
|
||||||
|
void PushPrimaryColor();
|
||||||
|
void PopPrimaryColor();
|
||||||
|
void PushSecondaryColor();
|
||||||
|
void PopSecondaryColor();
|
||||||
|
|
||||||
|
void DrawWindowTitle(const char* title);
|
||||||
|
|
||||||
|
bool BeginFullscreenColumns(const char* title = nullptr);
|
||||||
|
void EndFullscreenColumns();
|
||||||
|
|
||||||
|
bool BeginFullscreenColumnWindow(float start, float end, const char* name, const ImVec4& background = UIBackgroundColor);
|
||||||
|
void EndFullscreenColumnWindow();
|
||||||
|
|
||||||
|
bool BeginFullscreenWindow(float left, float top, float width, float height, const char* name,
|
||||||
|
const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, float padding = 0.0f, ImGuiWindowFlags flags = 0);
|
||||||
|
bool BeginFullscreenWindow(const ImVec2& position, const ImVec2& size, const char* name,
|
||||||
|
const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, float padding = 0.0f, ImGuiWindowFlags flags = 0);
|
||||||
|
void EndFullscreenWindow();
|
||||||
|
|
||||||
|
void BeginMenuButtons(u32 num_items = 0, float y_align = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_X_PADDING,
|
||||||
|
float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float item_height = LAYOUT_MENU_BUTTON_HEIGHT);
|
||||||
|
void EndMenuButtons();
|
||||||
|
bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImVec2* min, ImVec2* max,
|
||||||
|
ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f);
|
||||||
|
void MenuHeading(const char* title, bool draw_line = true);
|
||||||
|
bool MenuHeadingButton(const char* title, const char* value = nullptr, bool enabled = true, bool draw_line = true);
|
||||||
|
bool ActiveButton(const char* title, bool is_active, bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY,
|
||||||
|
ImFont* font = g_large_font);
|
||||||
|
bool MenuButton(const char* title, const char* summary, bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT,
|
||||||
|
ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool MenuButtonWithValue(const char* title, const char* summary, const char* value, bool enabled = true,
|
||||||
|
float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool MenuImageButton(const char* title, const char* summary, ImTextureID user_texture_id, const ImVec2& image_size, bool enabled = true,
|
||||||
|
float height = LAYOUT_MENU_BUTTON_HEIGHT, const ImVec2& uv0 = ImVec2(0.0f, 0.0f), const ImVec2& uv1 = ImVec2(1.0f, 1.0f),
|
||||||
|
ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool FloatingButton(const char* text, float x, float y, float width = -1.0f, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY,
|
||||||
|
float anchor_x = 0.0f, float anchor_y = 0.0f, bool enabled = true, ImFont* font = g_large_font, ImVec2* out_position = nullptr);
|
||||||
|
bool ToggleButton(const char* title, const char* summary, bool* v, bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT,
|
||||||
|
ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool ThreeWayToggleButton(const char* title, const char* summary, std::optional<bool>* v, bool enabled = true,
|
||||||
|
float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool RangeButton(const char* title, const char* summary, s32* value, s32 min, s32 max, s32 increment, const char* format = "%d",
|
||||||
|
bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool RangeButton(const char* title, const char* summary, float* value, float min, float max, float increment, const char* format = "%f",
|
||||||
|
bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, ImFont* summary_font = g_medium_font);
|
||||||
|
bool EnumChoiceButtonImpl(const char* title, const char* summary, s32* value_pointer,
|
||||||
|
const char* (*to_display_name_function)(s32 value, void* opaque), void* opaque, u32 count, bool enabled, float height, ImFont* font,
|
||||||
|
ImFont* summary_font);
|
||||||
|
|
||||||
|
template <typename DataType, typename CountType>
|
||||||
|
static __fi bool EnumChoiceButton(const char* title, const char* summary, DataType* value_pointer,
|
||||||
|
const char* (*to_display_name_function)(DataType value), CountType count, bool enabled = true,
|
||||||
|
float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, ImFont* summary_font = g_medium_font)
|
||||||
|
{
|
||||||
|
s32 value = static_cast<s32>(*value_pointer);
|
||||||
|
auto to_display_name_wrapper = [](s32 value, void* opaque) -> const char* {
|
||||||
|
return (*static_cast<decltype(to_display_name_function)*>(opaque))(static_cast<DataType>(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (EnumChoiceButtonImpl(title, summary, &value, to_display_name_wrapper, &to_display_name_function, static_cast<u32>(count),
|
||||||
|
enabled, height, font, summary_font))
|
||||||
|
{
|
||||||
|
*value_pointer = static_cast<DataType>(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginNavBar(float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING);
|
||||||
|
void EndNavBar();
|
||||||
|
void NavTitle(const char* title, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font);
|
||||||
|
void RightAlignNavButtons(u32 num_items = 0, float item_width = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY,
|
||||||
|
float item_height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
|
||||||
|
bool NavButton(const char* title, bool is_active, bool enabled = true, float width = -1.0f,
|
||||||
|
float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font);
|
||||||
|
|
||||||
|
using FileSelectorCallback = std::function<void(const std::string& path)>;
|
||||||
|
using FileSelectorFilters = std::vector<std::string>;
|
||||||
|
bool IsFileSelectorOpen();
|
||||||
|
void OpenFileSelector(const char* title, bool select_directory, FileSelectorCallback callback,
|
||||||
|
FileSelectorFilters filters = FileSelectorFilters(), std::string initial_directory = std::string());
|
||||||
|
void CloseFileSelector();
|
||||||
|
|
||||||
|
using ChoiceDialogCallback = std::function<void(s32 index, const std::string& title, bool checked)>;
|
||||||
|
using ChoiceDialogOptions = std::vector<std::pair<std::string, bool>>;
|
||||||
|
bool IsChoiceDialogOpen();
|
||||||
|
void OpenChoiceDialog(const char* title, bool checkable, ChoiceDialogOptions options, ChoiceDialogCallback callback);
|
||||||
|
void CloseChoiceDialog();
|
||||||
|
|
||||||
|
using InputStringDialogCallback = std::function<void(std::string text)>;
|
||||||
|
bool IsInputDialogOpen();
|
||||||
|
void OpenInputStringDialog(
|
||||||
|
std::string title, std::string message, std::string caption, std::string ok_button_text, InputStringDialogCallback callback);
|
||||||
|
void CloseInputDialog();
|
||||||
|
|
||||||
|
float GetNotificationVerticalPosition();
|
||||||
|
float GetNotificationVerticalDirection();
|
||||||
|
void SetNotificationVerticalPosition(float position, float direction);
|
||||||
|
|
||||||
|
void OpenBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value);
|
||||||
|
void UpdateBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value);
|
||||||
|
void CloseBackgroundProgressDialog(const char* str_id);
|
||||||
|
|
||||||
|
void AddNotification(float duration, std::string title, std::string text, std::string image_path);
|
||||||
|
void ClearNotifications();
|
||||||
|
|
||||||
|
void ShowToast(std::string title, std::string message, float duration = 10.0f);
|
||||||
|
void ClearToast();
|
||||||
|
} // namespace ImGuiFullscreen
|
|
@ -34,7 +34,6 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Counters.h"
|
#include "Counters.h"
|
||||||
#include "Frontend/ImGuiManager.h"
|
#include "Frontend/ImGuiManager.h"
|
||||||
#include "Frontend/InputManager.h"
|
|
||||||
#include "GS.h"
|
#include "GS.h"
|
||||||
#include "GS/GS.h"
|
#include "GS/GS.h"
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
|
@ -43,6 +42,10 @@
|
||||||
#include "PerformanceMetrics.h"
|
#include "PerformanceMetrics.h"
|
||||||
|
|
||||||
#ifdef PCSX2_CORE
|
#ifdef PCSX2_CORE
|
||||||
|
#include "Frontend/FullscreenUI.h"
|
||||||
|
#include "Frontend/ImGuiManager.h"
|
||||||
|
#include "Frontend/ImGuiFullscreen.h"
|
||||||
|
#include "Frontend/InputManager.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -52,7 +55,7 @@ namespace ImGuiManager
|
||||||
static void SetKeyMap();
|
static void SetKeyMap();
|
||||||
static bool LoadFontData();
|
static bool LoadFontData();
|
||||||
static void UnloadFontData();
|
static void UnloadFontData();
|
||||||
static bool AddImGuiFonts();
|
static bool AddImGuiFonts(bool fullscreen_fonts);
|
||||||
static ImFont* AddTextFont(float size);
|
static ImFont* AddTextFont(float size);
|
||||||
static ImFont* AddFixedFont(float size);
|
static ImFont* AddFixedFont(float size);
|
||||||
static bool AddIconFonts(float size);
|
static bool AddIconFonts(float size);
|
||||||
|
@ -66,6 +69,8 @@ static float s_global_scale = 1.0f;
|
||||||
|
|
||||||
static ImFont* s_standard_font;
|
static ImFont* s_standard_font;
|
||||||
static ImFont* s_fixed_font;
|
static ImFont* s_fixed_font;
|
||||||
|
static ImFont* s_medium_font;
|
||||||
|
static ImFont* s_large_font;
|
||||||
|
|
||||||
static std::vector<u8> s_standard_font_data;
|
static std::vector<u8> s_standard_font_data;
|
||||||
static std::vector<u8> s_fixed_font_data;
|
static std::vector<u8> s_fixed_font_data;
|
||||||
|
@ -111,6 +116,10 @@ bool ImGuiManager::Initialize()
|
||||||
SetKeyMap();
|
SetKeyMap();
|
||||||
SetStyle();
|
SetStyle();
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
pxAssertRel(!FullscreenUI::IsInitialized(), "Fullscreen UI is not initialized on ImGui init");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!display->CreateImGuiContext())
|
if (!display->CreateImGuiContext())
|
||||||
{
|
{
|
||||||
pxFailRel("Failed to create ImGui device context");
|
pxFailRel("Failed to create ImGui device context");
|
||||||
|
@ -120,7 +129,7 @@ bool ImGuiManager::Initialize()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AddImGuiFonts() || !display->UpdateImGuiFontTexture())
|
if (!AddImGuiFonts(false) || !display->UpdateImGuiFontTexture())
|
||||||
{
|
{
|
||||||
pxFailRel("Failed to create ImGui font text");
|
pxFailRel("Failed to create ImGui font text");
|
||||||
display->DestroyImGuiContext();
|
display->DestroyImGuiContext();
|
||||||
|
@ -138,6 +147,10 @@ bool ImGuiManager::Initialize()
|
||||||
|
|
||||||
void ImGuiManager::Shutdown()
|
void ImGuiManager::Shutdown()
|
||||||
{
|
{
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
FullscreenUI::Shutdown();
|
||||||
|
#endif
|
||||||
|
|
||||||
HostDisplay* display = Host::GetHostDisplay();
|
HostDisplay* display = Host::GetHostDisplay();
|
||||||
if (display)
|
if (display)
|
||||||
display->DestroyImGuiContext();
|
display->DestroyImGuiContext();
|
||||||
|
@ -146,6 +159,11 @@ void ImGuiManager::Shutdown()
|
||||||
|
|
||||||
s_standard_font = nullptr;
|
s_standard_font = nullptr;
|
||||||
s_fixed_font = nullptr;
|
s_fixed_font = nullptr;
|
||||||
|
s_medium_font = nullptr;
|
||||||
|
s_large_font = nullptr;
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
ImGuiFullscreen::SetFonts(nullptr, nullptr, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
UnloadFontData();
|
UnloadFontData();
|
||||||
}
|
}
|
||||||
|
@ -172,8 +190,13 @@ void ImGuiManager::UpdateScale()
|
||||||
const float window_scale = display ? display->GetWindowScale() : 1.0f;
|
const float window_scale = display ? display->GetWindowScale() : 1.0f;
|
||||||
const float scale = std::max(window_scale * static_cast<float>(EmuConfig.GS.OsdScale / 100.0), 1.0f);
|
const float scale = std::max(window_scale * static_cast<float>(EmuConfig.GS.OsdScale / 100.0), 1.0f);
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
if (scale == s_global_scale && (!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()))
|
||||||
|
return;
|
||||||
|
#else
|
||||||
if (scale == s_global_scale)
|
if (scale == s_global_scale)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is assumed to be called mid-frame.
|
// This is assumed to be called mid-frame.
|
||||||
ImGui::EndFrame();
|
ImGui::EndFrame();
|
||||||
|
@ -185,7 +208,7 @@ void ImGuiManager::UpdateScale()
|
||||||
SetStyle();
|
SetStyle();
|
||||||
ImGui::GetStyle().ScaleAllSizes(scale);
|
ImGui::GetStyle().ScaleAllSizes(scale);
|
||||||
|
|
||||||
if (!AddImGuiFonts())
|
if (!AddImGuiFonts(HasFullscreenFonts()))
|
||||||
pxFailRel("Failed to create ImGui font text");
|
pxFailRel("Failed to create ImGui font text");
|
||||||
|
|
||||||
if (!display->UpdateImGuiFontTexture())
|
if (!display->UpdateImGuiFontTexture())
|
||||||
|
@ -393,7 +416,7 @@ ImFont* ImGuiManager::AddFixedFont(float size)
|
||||||
|
|
||||||
bool ImGuiManager::AddIconFonts(float size)
|
bool ImGuiManager::AddIconFonts(float size)
|
||||||
{
|
{
|
||||||
static const ImWchar range_fa[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
static constexpr ImWchar range_fa[] = { 0xf001,0xf002,0xf005,0xf005,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf021,0xf025,0xf025,0xf028,0xf028,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf065,0xf065,0xf067,0xf067,0xf071,0xf071,0xf07b,0xf07c,0xf085,0xf085,0xf091,0xf091,0xf0a0,0xf0a0,0xf0ac,0xf0ad,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0d0,0xf0d0,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf11b,0xf11c,0xf121,0xf121,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf188,0xf188,0xf192,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f5,0xf2f5,0xf410,0xf410,0xf466,0xf466,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf65d,0xf65e,0xf756,0xf756,0xf7c2,0xf7c2,0xf815,0xf815,0xf818,0xf818,0xf8cc,0xf8cc,0x0,0x0 };
|
||||||
|
|
||||||
ImFontConfig cfg;
|
ImFontConfig cfg;
|
||||||
cfg.MergeMode = true;
|
cfg.MergeMode = true;
|
||||||
|
@ -406,7 +429,7 @@ bool ImGuiManager::AddIconFonts(float size)
|
||||||
s_icon_font_data.data(), static_cast<int>(s_icon_font_data.size()), size * 0.75f, &cfg, range_fa) != nullptr);
|
s_icon_font_data.data(), static_cast<int>(s_icon_font_data.size()), size * 0.75f, &cfg, range_fa) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGuiManager::AddImGuiFonts()
|
bool ImGuiManager::AddImGuiFonts(bool fullscreen_fonts)
|
||||||
{
|
{
|
||||||
const float standard_font_size = std::ceil(15.0f * s_global_scale);
|
const float standard_font_size = std::ceil(15.0f * s_global_scale);
|
||||||
|
|
||||||
|
@ -421,9 +444,56 @@ bool ImGuiManager::AddImGuiFonts()
|
||||||
if (!s_fixed_font)
|
if (!s_fixed_font)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
if (fullscreen_fonts)
|
||||||
|
{
|
||||||
|
const float medium_font_size = std::ceil(ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE));
|
||||||
|
s_medium_font = AddTextFont(medium_font_size);
|
||||||
|
if (!s_medium_font || !AddIconFonts(medium_font_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const float large_font_size = std::ceil(ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE));
|
||||||
|
s_large_font = AddTextFont(large_font_size);
|
||||||
|
if (!s_large_font || !AddIconFonts(large_font_size))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_medium_font = nullptr;
|
||||||
|
s_large_font = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiFullscreen::SetFonts(s_standard_font, s_medium_font, s_large_font);
|
||||||
|
#endif
|
||||||
|
|
||||||
return io.Fonts->Build();
|
return io.Fonts->Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImGuiManager::AddFullscreenFontsIfMissing()
|
||||||
|
{
|
||||||
|
if (HasFullscreenFonts())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// can't do this in the middle of a frame
|
||||||
|
ImGui::EndFrame();
|
||||||
|
|
||||||
|
if (!AddImGuiFonts(true))
|
||||||
|
{
|
||||||
|
Console.Error("Failed to lazily allocate fullscreen fonts.");
|
||||||
|
AddImGuiFonts(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::GetHostDisplay()->UpdateImGuiFontTexture();
|
||||||
|
NewFrame();
|
||||||
|
|
||||||
|
return HasFullscreenFonts();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiManager::HasFullscreenFonts()
|
||||||
|
{
|
||||||
|
return (s_medium_font && s_large_font);
|
||||||
|
}
|
||||||
|
|
||||||
struct OSDMessage
|
struct OSDMessage
|
||||||
{
|
{
|
||||||
std::string key;
|
std::string key;
|
||||||
|
@ -767,7 +837,13 @@ void ImGuiManager::RenderOSD()
|
||||||
// acquire for IO.MousePos.
|
// acquire for IO.MousePos.
|
||||||
std::atomic_thread_fence(std::memory_order_acquire);
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
// Don't draw OSD when we're just running big picture.
|
||||||
|
if (VMManager::HasValidVM())
|
||||||
|
DrawPerformanceOverlay();
|
||||||
|
#else
|
||||||
DrawPerformanceOverlay();
|
DrawPerformanceOverlay();
|
||||||
|
#endif
|
||||||
|
|
||||||
AcquirePendingOSDMessages();
|
AcquirePendingOSDMessages();
|
||||||
DrawOSDMessages();
|
DrawOSDMessages();
|
||||||
|
@ -788,6 +864,18 @@ ImFont* ImGuiManager::GetFixedFont()
|
||||||
return s_fixed_font;
|
return s_fixed_font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImFont* ImGuiManager::GetMediumFont()
|
||||||
|
{
|
||||||
|
AddFullscreenFontsIfMissing();
|
||||||
|
return s_medium_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImFont* ImGuiManager::GetLargeFont()
|
||||||
|
{
|
||||||
|
AddFullscreenFontsIfMissing();
|
||||||
|
return s_large_font;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PCSX2_CORE
|
#ifdef PCSX2_CORE
|
||||||
|
|
||||||
bool ImGuiManager::WantsTextInput()
|
bool ImGuiManager::WantsTextInput()
|
||||||
|
@ -900,4 +988,5 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // PCSX2_CORE
|
#endif // PCSX2_CORE
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,26 @@ namespace ImGuiManager
|
||||||
/// Returns the scale of all on-screen elements.
|
/// Returns the scale of all on-screen elements.
|
||||||
float GetGlobalScale();
|
float GetGlobalScale();
|
||||||
|
|
||||||
|
/// Returns true if fullscreen fonts are present.
|
||||||
|
bool HasFullscreenFonts();
|
||||||
|
|
||||||
|
/// Allocates/adds fullscreen fonts if they're not loaded.
|
||||||
|
bool AddFullscreenFontsIfMissing();
|
||||||
|
|
||||||
/// Returns the standard font for external drawing.
|
/// Returns the standard font for external drawing.
|
||||||
ImFont* GetStandardFont();
|
ImFont* GetStandardFont();
|
||||||
|
|
||||||
/// Returns the fixed-width font for external drawing.
|
/// Returns the fixed-width font for external drawing.
|
||||||
ImFont* GetFixedFont();
|
ImFont* GetFixedFont();
|
||||||
|
|
||||||
|
/// Returns the medium font for external drawing, scaled by ImGuiFullscreen.
|
||||||
|
/// This font is allocated on demand.
|
||||||
|
ImFont* GetMediumFont();
|
||||||
|
|
||||||
|
/// Returns the large font for external drawing, scaled by ImGuiFullscreen.
|
||||||
|
/// This font is allocated on demand.
|
||||||
|
ImFont* GetLargeFont();
|
||||||
|
|
||||||
#ifdef PCSX2_CORE
|
#ifdef PCSX2_CORE
|
||||||
/// Returns true if imgui wants to intercept text input.
|
/// Returns true if imgui wants to intercept text input.
|
||||||
bool WantsTextInput();
|
bool WantsTextInput();
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "pcsx2/GS.h"
|
#include "pcsx2/GS.h"
|
||||||
#ifdef PCSX2_CORE
|
#ifdef PCSX2_CORE
|
||||||
#include "pcsx2/HostSettings.h"
|
#include "pcsx2/HostSettings.h"
|
||||||
|
#include "pcsx2/Frontend/FullscreenUI.h"
|
||||||
#include "pcsx2/Frontend/InputManager.h"
|
#include "pcsx2/Frontend/InputManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -281,7 +282,13 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
// Don't override the fullscreen UI's vsync choice.
|
||||||
|
if (!FullscreenUI::IsInitialized())
|
||||||
|
display->SetVSync(EmuConfig.GetEffectiveVsyncMode());
|
||||||
|
#else
|
||||||
display->SetVSync(EmuConfig.GetEffectiveVsyncMode());
|
display->SetVSync(EmuConfig.GetEffectiveVsyncMode());
|
||||||
|
#endif
|
||||||
GSConfig.OsdShowGPU = EmuConfig.GS.OsdShowGPU && display->SetGPUTimingEnabled(true);
|
GSConfig.OsdShowGPU = EmuConfig.GS.OsdShowGPU && display->SetGPUTimingEnabled(true);
|
||||||
|
|
||||||
g_gs_renderer->SetRegsMem(basemem);
|
g_gs_renderer->SetRegsMem(basemem);
|
||||||
|
|
|
@ -361,7 +361,8 @@ void PAD::SetDefaultConfig(SettingsInterface& si)
|
||||||
// si.SetStringValue("Hotkeys", "FrameAdvance", "Keyboard"); TBD
|
// si.SetStringValue("Hotkeys", "FrameAdvance", "Keyboard"); TBD
|
||||||
// si.SetStringValue("Hotkeys", "IncreaseSpeed", "Keyboard"); TBD
|
// si.SetStringValue("Hotkeys", "IncreaseSpeed", "Keyboard"); TBD
|
||||||
// si.SetStringValue("Hotkeys", "ResetVM", "Keyboard"); TBD
|
// si.SetStringValue("Hotkeys", "ResetVM", "Keyboard"); TBD
|
||||||
si.SetStringValue("Hotkeys", "ShutdownVM", "Keyboard/Escape");
|
// si.SetStringValue("Hotkeys", "ShutdownVM", "Keyboard"); TBD
|
||||||
|
si.SetStringValue("Hotkeys", "OpenPauseMenu", "Keyboard/Escape");
|
||||||
si.SetStringValue("Hotkeys", "ToggleFrameLimit", "Keyboard/F4");
|
si.SetStringValue("Hotkeys", "ToggleFrameLimit", "Keyboard/F4");
|
||||||
si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space");
|
si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space");
|
||||||
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab");
|
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab");
|
||||||
|
|
|
@ -36,6 +36,12 @@
|
||||||
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
|
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
|
||||||
#define VER_COPYRIGHT_STR "Copyright (C) 2022"
|
#define VER_COPYRIGHT_STR "Copyright (C) 2022"
|
||||||
|
|
||||||
|
#define PCSX2_WEBSITE_URL "https://pcsx2.net/"
|
||||||
|
#define PCSX2_FORUMS_URL "https://forums.pcsx2.net/"
|
||||||
|
#define PCSX2_GITHUB_URL "https://github.com/PCSX2/pcsx2"
|
||||||
|
#define PCSX2_LICENSE_URL "https://github.com/PCSX2/pcsx2/blob/master/pcsx2/Docs/License.txt"
|
||||||
|
#define PCSX2_DISCORD_URL "https://discord.com/invite/TCz3t9k"
|
||||||
|
|
||||||
static const bool PCSX2_isReleaseVersion = 0;
|
static const bool PCSX2_isReleaseVersion = 0;
|
||||||
|
|
||||||
class SysCoreThread;
|
class SysCoreThread;
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "DebugTools/MIPSAnalyst.h"
|
#include "DebugTools/MIPSAnalyst.h"
|
||||||
#include "DebugTools/SymbolMap.h"
|
#include "DebugTools/SymbolMap.h"
|
||||||
|
|
||||||
|
#include "Frontend/FullscreenUI.h"
|
||||||
#include "Frontend/INISettingsInterface.h"
|
#include "Frontend/INISettingsInterface.h"
|
||||||
#include "Frontend/InputManager.h"
|
#include "Frontend/InputManager.h"
|
||||||
#include "Frontend/GameList.h"
|
#include "Frontend/GameList.h"
|
||||||
|
@ -72,7 +73,6 @@
|
||||||
|
|
||||||
namespace VMManager
|
namespace VMManager
|
||||||
{
|
{
|
||||||
static void LoadSettings();
|
|
||||||
static void ApplyGameFixes();
|
static void ApplyGameFixes();
|
||||||
static bool UpdateGameSettingsLayer();
|
static bool UpdateGameSettingsLayer();
|
||||||
static void CheckForConfigChanges(const Pcsx2Config& old_config);
|
static void CheckForConfigChanges(const Pcsx2Config& old_config);
|
||||||
|
@ -137,6 +137,7 @@ static s32 s_current_save_slot = 1;
|
||||||
static u32 s_frame_advance_count = 0;
|
static u32 s_frame_advance_count = 0;
|
||||||
static u32 s_mxcsr_saved;
|
static u32 s_mxcsr_saved;
|
||||||
static std::optional<LimiterModeType> s_limiter_mode_prior_to_hold_interaction;
|
static std::optional<LimiterModeType> s_limiter_mode_prior_to_hold_interaction;
|
||||||
|
static bool s_gs_open_on_initialize = false;
|
||||||
|
|
||||||
bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
||||||
{
|
{
|
||||||
|
@ -200,9 +201,15 @@ void VMManager::SetState(VMState state)
|
||||||
|
|
||||||
SPU2SetOutputPaused(state == VMState::Paused);
|
SPU2SetOutputPaused(state == VMState::Paused);
|
||||||
if (state == VMState::Paused)
|
if (state == VMState::Paused)
|
||||||
|
{
|
||||||
Host::OnVMPaused();
|
Host::OnVMPaused();
|
||||||
|
FullscreenUI::OnVMPaused();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Host::OnVMResumed();
|
Host::OnVMResumed();
|
||||||
|
FullscreenUI::OnVMResumed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +263,12 @@ bool VMManager::Internal::InitializeGlobals()
|
||||||
x86caps.CalculateMHz();
|
x86caps.CalculateMHz();
|
||||||
SysLogMachineCaps();
|
SysLogMachineCaps();
|
||||||
|
|
||||||
|
if (GSinit() != 0)
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync("Error", "Failed to initialize GS (GSinit()).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,6 +696,12 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
|
||||||
GetMTGS().SendGameCRC(new_crc);
|
GetMTGS().SendGameCRC(new_crc);
|
||||||
|
|
||||||
Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, s_game_crc);
|
Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, s_game_crc);
|
||||||
|
if (FullscreenUI::IsInitialized())
|
||||||
|
{
|
||||||
|
GetMTGS().RunOnGSThread([disc_path = s_disc_path, game_serial = s_game_serial, game_name = s_game_name, game_crc = s_game_crc]() {
|
||||||
|
FullscreenUI::OnRunningGameChanged(std::move(disc_path), std::move(game_serial), std::move(game_name), game_crc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// TODO: Enable this when the debugger is added to Qt, and it's active. Otherwise, this is just a waste of time.
|
// TODO: Enable this when the debugger is added to Qt, and it's active. Otherwise, this is just a waste of time.
|
||||||
|
@ -846,8 +865,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
Host::OnVMDestroyed();
|
Host::OnVMDestroyed();
|
||||||
};
|
};
|
||||||
|
|
||||||
LoadSettings();
|
|
||||||
|
|
||||||
std::string state_to_load;
|
std::string state_to_load;
|
||||||
if (!ApplyBootParameters(std::move(boot_params), &state_to_load))
|
if (!ApplyBootParameters(std::move(boot_params), &state_to_load))
|
||||||
return false;
|
return false;
|
||||||
|
@ -870,14 +887,18 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
ScopedGuard close_cdvd = [] { DoCDVDclose(); };
|
ScopedGuard close_cdvd = [] { DoCDVDclose(); };
|
||||||
|
|
||||||
Console.WriteLn("Opening GS...");
|
Console.WriteLn("Opening GS...");
|
||||||
if (!GetMTGS().WaitForOpen())
|
s_gs_open_on_initialize = GetMTGS().IsOpen();
|
||||||
|
if (!s_gs_open_on_initialize && !GetMTGS().WaitForOpen())
|
||||||
{
|
{
|
||||||
// we assume GS is going to report its own error
|
// we assume GS is going to report its own error
|
||||||
Console.WriteLn("Failed to open GS.");
|
Console.WriteLn("Failed to open GS.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedGuard close_gs = []() { GetMTGS().WaitForClose(); };
|
ScopedGuard close_gs = []() {
|
||||||
|
if (!s_gs_open_on_initialize)
|
||||||
|
GetMTGS().WaitForClose();
|
||||||
|
};
|
||||||
|
|
||||||
Console.WriteLn("Opening SPU2...");
|
Console.WriteLn("Opening SPU2...");
|
||||||
if (SPU2init() != 0 || SPU2open() != 0)
|
if (SPU2init() != 0 || SPU2open() != 0)
|
||||||
|
@ -964,6 +985,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
||||||
s_state.store(VMState::Paused, std::memory_order_release);
|
s_state.store(VMState::Paused, std::memory_order_release);
|
||||||
Host::OnVMStarted();
|
Host::OnVMStarted();
|
||||||
|
FullscreenUI::OnVMStarted();
|
||||||
|
|
||||||
UpdateRunningGame(true, false);
|
UpdateRunningGame(true, false);
|
||||||
|
|
||||||
|
@ -1047,7 +1069,14 @@ void VMManager::Shutdown(bool save_resume_state)
|
||||||
DoCDVDclose();
|
DoCDVDclose();
|
||||||
FWclose();
|
FWclose();
|
||||||
FileMcd_EmuClose();
|
FileMcd_EmuClose();
|
||||||
GetMTGS().WaitForClose();
|
|
||||||
|
// If the fullscreen UI is running, do a hardware reset on the GS
|
||||||
|
// so that the texture cache and targets are all cleared.
|
||||||
|
if (s_gs_open_on_initialize)
|
||||||
|
GetMTGS().ResetGS(true);
|
||||||
|
else
|
||||||
|
GetMTGS().WaitForClose();
|
||||||
|
|
||||||
USBshutdown();
|
USBshutdown();
|
||||||
SPU2shutdown();
|
SPU2shutdown();
|
||||||
PADshutdown();
|
PADshutdown();
|
||||||
|
@ -1058,6 +1087,7 @@ void VMManager::Shutdown(bool save_resume_state)
|
||||||
|
|
||||||
s_state.store(VMState::Shutdown, std::memory_order_release);
|
s_state.store(VMState::Shutdown, std::memory_order_release);
|
||||||
Host::OnVMDestroyed();
|
Host::OnVMDestroyed();
|
||||||
|
FullscreenUI::OnVMDestroyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::Reset()
|
void VMManager::Reset()
|
||||||
|
@ -1623,20 +1653,27 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config)
|
||||||
|
|
||||||
void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
||||||
{
|
{
|
||||||
CheckForCPUConfigChanges(old_config);
|
if (HasValidVM())
|
||||||
CheckForGSConfigChanges(old_config);
|
|
||||||
CheckForFramerateConfigChanges(old_config);
|
|
||||||
CheckForPatchConfigChanges(old_config);
|
|
||||||
CheckForSPU2ConfigChanges(old_config);
|
|
||||||
CheckForDEV9ConfigChanges(old_config);
|
|
||||||
CheckForMemoryCardConfigChanges(old_config);
|
|
||||||
|
|
||||||
if (EmuConfig.EnableCheats != old_config.EnableCheats ||
|
|
||||||
EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches ||
|
|
||||||
EmuConfig.EnableNoInterlacingPatches != old_config.EnableNoInterlacingPatches)
|
|
||||||
{
|
{
|
||||||
VMManager::ReloadPatches(true, true);
|
CheckForCPUConfigChanges(old_config);
|
||||||
|
CheckForFramerateConfigChanges(old_config);
|
||||||
|
CheckForPatchConfigChanges(old_config);
|
||||||
|
CheckForSPU2ConfigChanges(old_config);
|
||||||
|
CheckForDEV9ConfigChanges(old_config);
|
||||||
|
CheckForMemoryCardConfigChanges(old_config);
|
||||||
|
|
||||||
|
if (EmuConfig.EnableCheats != old_config.EnableCheats ||
|
||||||
|
EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches ||
|
||||||
|
EmuConfig.EnableNoInterlacingPatches != old_config.EnableNoInterlacingPatches)
|
||||||
|
{
|
||||||
|
VMManager::ReloadPatches(true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For the big picture UI, we still need to update GS settings, since it's running,
|
||||||
|
// and we don't update its config when we start the VM.
|
||||||
|
if (HasValidVM() || GetMTGS().IsOpen())
|
||||||
|
CheckForGSConfigChanges(old_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ApplySettings()
|
void VMManager::ApplySettings()
|
||||||
|
@ -1654,9 +1691,7 @@ void VMManager::ApplySettings()
|
||||||
|
|
||||||
const Pcsx2Config old_config(EmuConfig);
|
const Pcsx2Config old_config(EmuConfig);
|
||||||
LoadSettings();
|
LoadSettings();
|
||||||
|
CheckForConfigChanges(old_config);
|
||||||
if (HasValidVM())
|
|
||||||
CheckForConfigChanges(old_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMManager::ReloadGameSettings()
|
bool VMManager::ReloadGameSettings()
|
||||||
|
@ -1741,6 +1776,10 @@ static void HotkeySaveStateSlot(s32 slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_HOTKEY_LIST(g_vm_manager_hotkeys)
|
BEGIN_HOTKEY_LIST(g_vm_manager_hotkeys)
|
||||||
|
DEFINE_HOTKEY("OpenPauseMenu", "System", "Open Pause Menu", [](s32 pressed) {
|
||||||
|
if (!pressed)
|
||||||
|
FullscreenUI::OpenPauseMenu();
|
||||||
|
})
|
||||||
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
|
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
|
||||||
if (!pressed && VMManager::HasValidVM())
|
if (!pressed && VMManager::HasValidVM())
|
||||||
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
|
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
|
||||||
|
@ -1801,7 +1840,7 @@ DEFINE_HOTKEY("FrameAdvance", "System", "Frame Advance", [](s32 pressed) {
|
||||||
})
|
})
|
||||||
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
|
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
|
||||||
if (!pressed && VMManager::HasValidVM())
|
if (!pressed && VMManager::HasValidVM())
|
||||||
Host::RequestVMShutdown(true, true);
|
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
|
||||||
})
|
})
|
||||||
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
|
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
|
||||||
if (!pressed && VMManager::HasValidVM())
|
if (!pressed && VMManager::HasValidVM())
|
||||||
|
@ -1858,7 +1897,6 @@ DEFINE_HOTKEY_SAVESTATE_X(10)
|
||||||
DEFINE_HOTKEY_LOADSTATE_X(10)
|
DEFINE_HOTKEY_LOADSTATE_X(10)
|
||||||
#undef DEFINE_HOTKEY_SAVESTATE_X
|
#undef DEFINE_HOTKEY_SAVESTATE_X
|
||||||
#undef DEFINE_HOTKEY_LOADSTATE_X
|
#undef DEFINE_HOTKEY_LOADSTATE_X
|
||||||
|
|
||||||
END_HOTKEY_LIST()
|
END_HOTKEY_LIST()
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
|
@ -76,6 +76,9 @@ namespace VMManager
|
||||||
/// Returns the name of the disc/executable currently running.
|
/// Returns the name of the disc/executable currently running.
|
||||||
std::string GetGameName();
|
std::string GetGameName();
|
||||||
|
|
||||||
|
/// Loads global settings (i.e. EmuConfig).
|
||||||
|
void LoadSettings();
|
||||||
|
|
||||||
/// Initializes all system components.
|
/// Initializes all system components.
|
||||||
bool Initialize(VMBootParameters boot_params);
|
bool Initialize(VMBootParameters boot_params);
|
||||||
|
|
||||||
|
@ -249,7 +252,7 @@ namespace Host
|
||||||
void RequestExit(bool save_state_if_running);
|
void RequestExit(bool save_state_if_running);
|
||||||
|
|
||||||
/// Requests shut down of the current virtual machine.
|
/// Requests shut down of the current virtual machine.
|
||||||
void RequestVMShutdown(bool allow_confirm, bool allow_save_state);
|
void RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state);
|
||||||
|
|
||||||
/// Returns true if the hosting application is currently fullscreen.
|
/// Returns true if the hosting application is currently fullscreen.
|
||||||
bool IsFullscreen();
|
bool IsFullscreen();
|
||||||
|
|
|
@ -188,7 +188,9 @@
|
||||||
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
|
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
|
||||||
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
|
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
|
||||||
<ClCompile Include="Frontend\D3D12HostDisplay.cpp" />
|
<ClCompile Include="Frontend\D3D12HostDisplay.cpp" />
|
||||||
|
<ClCompile Include="Frontend\FullscreenUI.cpp" />
|
||||||
<ClCompile Include="Frontend\GameList.cpp" />
|
<ClCompile Include="Frontend\GameList.cpp" />
|
||||||
|
<ClCompile Include="Frontend\ImGuiFullscreen.cpp" />
|
||||||
<ClCompile Include="Frontend\ImGuiManager.cpp" />
|
<ClCompile Include="Frontend\ImGuiManager.cpp" />
|
||||||
<ClCompile Include="Frontend\imgui_impl_dx11.cpp" />
|
<ClCompile Include="Frontend\imgui_impl_dx11.cpp" />
|
||||||
<ClCompile Include="Frontend\imgui_impl_dx12.cpp" />
|
<ClCompile Include="Frontend\imgui_impl_dx12.cpp" />
|
||||||
|
@ -508,7 +510,9 @@
|
||||||
<ClInclude Include="DEV9\Win32\tap.h" />
|
<ClInclude Include="DEV9\Win32\tap.h" />
|
||||||
<ClInclude Include="Frontend\D3D11HostDisplay.h" />
|
<ClInclude Include="Frontend\D3D11HostDisplay.h" />
|
||||||
<ClInclude Include="Frontend\D3D12HostDisplay.h" />
|
<ClInclude Include="Frontend\D3D12HostDisplay.h" />
|
||||||
|
<ClInclude Include="Frontend\FullscreenUI.h" />
|
||||||
<ClInclude Include="Frontend\GameList.h" />
|
<ClInclude Include="Frontend\GameList.h" />
|
||||||
|
<ClInclude Include="Frontend\ImGuiFullscreen.h" />
|
||||||
<ClInclude Include="Frontend\ImGuiManager.h" />
|
<ClInclude Include="Frontend\ImGuiManager.h" />
|
||||||
<ClInclude Include="Frontend\imgui_impl_dx11.h" />
|
<ClInclude Include="Frontend\imgui_impl_dx11.h" />
|
||||||
<ClInclude Include="Frontend\imgui_impl_dx12.h" />
|
<ClInclude Include="Frontend\imgui_impl_dx12.h" />
|
||||||
|
|
|
@ -1275,6 +1275,12 @@
|
||||||
<ClCompile Include="Frontend\LogSink.cpp">
|
<ClCompile Include="Frontend\LogSink.cpp">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Frontend\ImGuiFullscreen.cpp">
|
||||||
|
<Filter>Host</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Frontend\FullscreenUI.cpp">
|
||||||
|
<Filter>Host</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Patch.h">
|
<ClInclude Include="Patch.h">
|
||||||
|
@ -2119,6 +2125,12 @@
|
||||||
<ClInclude Include="Frontend\LogSink.h">
|
<ClInclude Include="Frontend\LogSink.h">
|
||||||
<Filter>Host</Filter>
|
<Filter>Host</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Frontend\ImGuiFullscreen.h">
|
||||||
|
<Filter>Host</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Frontend\FullscreenUI.h">
|
||||||
|
<Filter>Host</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuildStep Include="rdebug\deci2.h">
|
<CustomBuildStep Include="rdebug\deci2.h">
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import functools
|
||||||
|
|
||||||
|
# PCSX2 - PS2 Emulator for PCs
|
||||||
|
# Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||||
|
#
|
||||||
|
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
# ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE. See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
# If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# pylint: disable=bare-except, disable=missing-function-docstring
|
||||||
|
|
||||||
|
src_dirs = [os.path.join(os.path.dirname(__file__), "..", "pcsx2"), os.path.join(os.path.dirname(__file__), "..", "pcsx2-qt")]
|
||||||
|
fa_file = os.path.join(os.path.dirname(__file__), "..", "3rdparty", "include", "IconsFontAwesome5.h")
|
||||||
|
dst_file = os.path.join(os.path.dirname(__file__), "..", "pcsx2", "Frontend", "ImguiManager.cpp")
|
||||||
|
|
||||||
|
all_source_files = list(functools.reduce(lambda prev, src_dir: prev + glob.glob(os.path.join(src_dir, "**", "*.cpp"), recursive=True) + \
|
||||||
|
glob.glob(os.path.join(src_dir, "**", "*.h"), recursive=True) + \
|
||||||
|
glob.glob(os.path.join(src_dir, "**", "*.inl"), recursive=True), src_dirs, []))
|
||||||
|
|
||||||
|
tokens = set()
|
||||||
|
for filename in all_source_files:
|
||||||
|
data = None
|
||||||
|
with open(filename, "r") as f:
|
||||||
|
try:
|
||||||
|
data = f.read()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tokens = tokens.union(set(re.findall("(ICON_FA_[a-zA-Z0-9_]+)", data)))
|
||||||
|
|
||||||
|
print("{} tokens found.".format(len(tokens)))
|
||||||
|
if len(tokens) == 0:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
u8_encodings = {}
|
||||||
|
with open(fa_file, "r") as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
match = re.match("#define (ICON_FA_[^ ]+) \"([^\"]+)\"", line)
|
||||||
|
if match is None:
|
||||||
|
continue
|
||||||
|
u8_encodings[match[1]] = bytes.fromhex(match[2].replace("\\x", ""))
|
||||||
|
|
||||||
|
out_pattern = "(static constexpr ImWchar range_fa\[\] = \{)[0-9A-Z_a-z, \n]+(\};)"
|
||||||
|
|
||||||
|
codepoints = list()
|
||||||
|
for token in tokens:
|
||||||
|
u8_bytes = u8_encodings[token]
|
||||||
|
u8 = str(u8_bytes, "utf-8")
|
||||||
|
u16 = u8.encode("utf-16le")
|
||||||
|
if len(u16) > 2:
|
||||||
|
raise ValueError("{} too long".format(u8_bytes))
|
||||||
|
|
||||||
|
codepoint = int.from_bytes(u16, byteorder="little", signed=False)
|
||||||
|
codepoints.append(codepoint)
|
||||||
|
codepoints.sort()
|
||||||
|
codepoints.append(0) # null terminator
|
||||||
|
|
||||||
|
startc = codepoints[0]
|
||||||
|
endc = None
|
||||||
|
pairs = [startc]
|
||||||
|
for codepoint in codepoints:
|
||||||
|
if endc is not None and (endc + 1) != codepoint:
|
||||||
|
pairs.append(endc)
|
||||||
|
pairs.append(codepoint)
|
||||||
|
startc = codepoint
|
||||||
|
endc = codepoint
|
||||||
|
else:
|
||||||
|
endc = codepoint
|
||||||
|
pairs.append(endc)
|
||||||
|
|
||||||
|
pairs_str = ",".join(map("0x{:x}".format, pairs))
|
||||||
|
|
||||||
|
with open(dst_file, "r") as f:
|
||||||
|
original = f.read()
|
||||||
|
updated = re.sub(out_pattern, "\\1 " + pairs_str + " \\2", original)
|
||||||
|
if original != updated:
|
||||||
|
with open(dst_file, "w") as f:
|
||||||
|
f.write(updated)
|
||||||
|
print("Updated {}".format(dst_file))
|
||||||
|
else:
|
||||||
|
print("Skipping updating {}".format(dst_file))
|
||||||
|
|
Loading…
Reference in New Issue