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 "pcsx2/SysForwardDefs.h"
|
||||
|
||||
#include "AboutDialog.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
@ -52,25 +54,25 @@ AboutDialog::~AboutDialog() = default;
|
|||
|
||||
QString AboutDialog::getWebsiteUrl()
|
||||
{
|
||||
return QStringLiteral("https://pcsx2.net/");
|
||||
return QString::fromUtf8(PCSX2_WEBSITE_URL);
|
||||
}
|
||||
|
||||
QString AboutDialog::getSupportForumsUrl()
|
||||
{
|
||||
return QStringLiteral("https://forums.pcsx2.net/");
|
||||
return QString::fromUtf8(PCSX2_FORUMS_URL);
|
||||
}
|
||||
|
||||
QString AboutDialog::getGitHubRepositoryUrl()
|
||||
{
|
||||
return QStringLiteral("https://github.com/PCSX2/pcsx2");
|
||||
return QString::fromUtf8(PCSX2_GITHUB_URL);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return QStringLiteral("https://discord.com/invite/TCz3t9k");
|
||||
return QString::fromUtf8(PCSX2_DISCORD_URL);
|
||||
}
|
||||
|
|
|
@ -183,6 +183,24 @@ void DisplayWidget::updateCursor(bool master_enable)
|
|||
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()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -330,6 +348,7 @@ bool DisplayWidget::event(QEvent* event)
|
|||
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
||||
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||
QtHost::IsVMValid() && !QtHost::IsVMPaused() &&
|
||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||
{
|
||||
|
@ -384,10 +403,7 @@ bool DisplayWidget::event(QEvent* event)
|
|||
|
||||
case QEvent::Close:
|
||||
{
|
||||
// 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.
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true), Q_ARG(bool, true), Q_ARG(bool, false));
|
||||
event->ignore();
|
||||
handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -454,12 +470,9 @@ DisplayWidget* DisplayContainer::removeDisplayWidget()
|
|||
|
||||
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.
|
||||
// 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();
|
||||
m_display_widget->handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
class DisplayWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -41,6 +43,8 @@ public:
|
|||
void updateRelativeMode(bool master_enable);
|
||||
void updateCursor(bool master_enable);
|
||||
|
||||
void handleCloseEvent(QCloseEvent* event);
|
||||
|
||||
Q_SIGNALS:
|
||||
void windowResizedEvent(int width, int height, float scale);
|
||||
void windowRestoredEvent();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "pcsx2/Counters.h"
|
||||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#include "pcsx2/Frontend/ImGuiManager.h"
|
||||
#include "pcsx2/Frontend/FullscreenUI.h"
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GS/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
|
@ -87,6 +88,9 @@ void EmuThread::stopInThread()
|
|||
if (VMManager::HasValidVM())
|
||||
destroyVM();
|
||||
|
||||
if (m_run_fullscreen_ui)
|
||||
stopFullscreenUI();
|
||||
|
||||
m_event_loop->quit();
|
||||
m_shutdown_flag.store(true);
|
||||
}
|
||||
|
@ -126,6 +130,53 @@ bool EmuThread::confirmMessage(const QString& title, const QString& message)
|
|||
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)
|
||||
{
|
||||
if (!isOnEmuThread())
|
||||
|
@ -136,15 +187,16 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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))
|
||||
return;
|
||||
|
||||
|
@ -265,6 +317,7 @@ void EmuThread::saveStateToSlot(qint32 slot)
|
|||
|
||||
void EmuThread::run()
|
||||
{
|
||||
Threading::SetNameOfCurrentThread("EmuThread");
|
||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
|
||||
m_event_loop = new QEventLoop();
|
||||
m_started_semaphore.release();
|
||||
|
@ -273,8 +326,13 @@ void EmuThread::run()
|
|||
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
|
||||
pxFailRel("Failed to allocate memory map");
|
||||
|
||||
// we need input sources ready for binding
|
||||
reloadInputSources();
|
||||
// We want settings loaded so we choose the correct renderer for big picture mode.
|
||||
// This also sorts out input sources.
|
||||
loadOurSettings();
|
||||
loadOurInitialSettings();
|
||||
VMManager::LoadSettings();
|
||||
|
||||
// Start background polling because the VM won't do it for us.
|
||||
createBackgroundControllerPollTimer();
|
||||
startBackgroundControllerPollTimer();
|
||||
connectSignals();
|
||||
|
@ -362,7 +420,9 @@ void EmuThread::startBackgroundControllerPollTimer()
|
|||
if (m_background_controller_polling_timer->isActive())
|
||||
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()
|
||||
|
@ -397,7 +457,7 @@ void EmuThread::setFullscreen(bool fullscreen)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!VMManager::HasValidVM() || m_is_fullscreen == fullscreen)
|
||||
if (!GetMTGS().IsOpen() || m_is_fullscreen == fullscreen)
|
||||
return;
|
||||
|
||||
// This will call back to us on the MTGS thread.
|
||||
|
@ -417,9 +477,13 @@ void EmuThread::setSurfaceless(bool surfaceless)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!VMManager::HasValidVM() || m_is_surfaceless == surfaceless)
|
||||
if (!GetMTGS().IsOpen() || m_is_surfaceless == surfaceless)
|
||||
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.
|
||||
m_is_surfaceless = surfaceless;
|
||||
GetMTGS().UpdateDisplayWindow();
|
||||
|
@ -476,11 +540,19 @@ void EmuThread::connectSignals()
|
|||
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()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
|
||||
|
||||
if (VMManager::HasValidVM())
|
||||
if (s_host_display)
|
||||
{
|
||||
const bool render_to_main = shouldRenderToMain();
|
||||
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.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();
|
||||
}
|
||||
|
||||
|
@ -816,6 +896,7 @@ void Host::EndPresentFrame()
|
|||
if (GSDumpReplayer::IsReplayingDump())
|
||||
GSDumpReplayer::RenderUI();
|
||||
|
||||
FullscreenUI::Render();
|
||||
ImGuiManager::RenderOSD();
|
||||
s_host_display->EndPresent();
|
||||
ImGuiManager::NewFrame();
|
||||
|
@ -1036,14 +1117,15 @@ void Host::RequestExit(bool save_state_if_running)
|
|||
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())
|
||||
return;
|
||||
|
||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||
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()
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
__fi bool isFullscreen() const { return m_is_fullscreen; }
|
||||
__fi bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
||||
__fi bool isSurfaceless() const { return m_is_surfaceless; }
|
||||
__fi bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
|
||||
|
||||
bool isOnEmuThread() const;
|
||||
|
||||
|
@ -62,6 +63,8 @@ public:
|
|||
|
||||
public Q_SLOTS:
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
void startFullscreenUI(bool fullscreen);
|
||||
void stopFullscreenUI();
|
||||
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
||||
void resetVM();
|
||||
void setVMPaused(bool paused);
|
||||
|
@ -133,8 +136,11 @@ protected:
|
|||
void run();
|
||||
|
||||
private:
|
||||
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL =
|
||||
100; /// Interval at which the controllers are polled when the system is not active.
|
||||
/// 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 executeVM();
|
||||
|
@ -143,8 +149,9 @@ private:
|
|||
|
||||
void createBackgroundControllerPollTimer();
|
||||
void destroyBackgroundControllerPollTimer();
|
||||
void loadOurSettings();
|
||||
void connectSignals();
|
||||
void loadOurSettings();
|
||||
void loadOurInitialSettings();
|
||||
|
||||
private Q_SLOTS:
|
||||
void stopInThread();
|
||||
|
@ -162,6 +169,7 @@ private:
|
|||
std::atomic_bool m_shutdown_flag{false};
|
||||
|
||||
bool m_verbose_status = false;
|
||||
bool m_run_fullscreen_ui = false;
|
||||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = 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.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow);
|
||||
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true); });
|
||||
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false); });
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true, EmuConfig.SaveStateOnShutdown); });
|
||||
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.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||
|
@ -354,6 +354,8 @@ void MainWindow::connectSignals()
|
|||
|
||||
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::onCreateDisplayRequested, this, &MainWindow::createDisplay, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection);
|
||||
|
@ -387,7 +389,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
|||
void MainWindow::recreate()
|
||||
{
|
||||
if (s_vm_valid)
|
||||
requestShutdown(false, true, true);
|
||||
requestShutdown(false, true, EmuConfig.SaveStateOnShutdown);
|
||||
|
||||
close();
|
||||
g_main_window = nullptr;
|
||||
|
@ -950,7 +952,7 @@ void MainWindow::switchToGameListView()
|
|||
return;
|
||||
}
|
||||
|
||||
if (s_vm_valid)
|
||||
if (m_display_created)
|
||||
{
|
||||
m_was_paused_on_surface_loss = s_vm_paused;
|
||||
if (!s_vm_paused)
|
||||
|
@ -965,7 +967,7 @@ void MainWindow::switchToGameListView()
|
|||
|
||||
void MainWindow::switchToEmulationView()
|
||||
{
|
||||
if (!s_vm_valid || !isShowingGameList())
|
||||
if (!m_display_created || !isShowingGameList())
|
||||
return;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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)
|
||||
return true;
|
||||
|
||||
// If we don't have a crc, we can't save state.
|
||||
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.
|
||||
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()
|
||||
{
|
||||
// this is block, because otherwise closeEvent() will also prompt
|
||||
if (!requestShutdown(true, true, true))
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
return;
|
||||
|
||||
// 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()
|
||||
{
|
||||
if (s_vm_valid)
|
||||
if (m_display_created)
|
||||
switchToEmulationView();
|
||||
}
|
||||
|
||||
|
@ -1643,7 +1645,7 @@ void MainWindow::showEvent(QShowEvent* event)
|
|||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!requestShutdown(true, true, true))
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
{
|
||||
event->ignore();
|
||||
return;
|
||||
|
@ -1742,6 +1744,8 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
m_display_created = true;
|
||||
|
||||
if (is_exclusive_fullscreen)
|
||||
setDisplayFullscreen(fullscreen_mode);
|
||||
|
||||
|
@ -1750,6 +1754,8 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
|||
|
||||
m_ui.actionViewSystemDisplay->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->updateRelativeMode(s_vm_valid && !s_vm_paused);
|
||||
|
@ -1940,9 +1946,12 @@ void MainWindow::destroyDisplay()
|
|||
{
|
||||
// Now we can safely destroy the display window.
|
||||
destroyDisplayWidget(true);
|
||||
m_display_created = false;
|
||||
|
||||
m_ui.actionViewSystemDisplay->setEnabled(false);
|
||||
m_ui.actionFullscreen->setEnabled(false);
|
||||
m_ui.actionStartFullscreenUI->setEnabled(true);
|
||||
m_ui.actionStartFullscreenUI2->setEnabled(true);
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplayWidget(bool show_game_list)
|
||||
|
|
|
@ -104,7 +104,7 @@ public Q_SLOTS:
|
|||
void reportError(const QString& title, const QString& message);
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
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 checkForSettingChanges();
|
||||
|
||||
|
@ -258,6 +258,7 @@ private:
|
|||
QString m_current_game_name;
|
||||
quint32 m_current_game_crc;
|
||||
|
||||
bool m_display_created = false;
|
||||
bool m_save_states_invalidated = false;
|
||||
bool m_was_paused_on_surface_loss = false;
|
||||
bool m_was_disc_change_request = false;
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
<addaction name="actionStartFile"/>
|
||||
<addaction name="actionStartDisc"/>
|
||||
<addaction name="actionStartBios"/>
|
||||
<addaction name="actionStartFullscreenUI"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPowerOff"/>
|
||||
<addaction name="actionPowerOffWithoutSaving"/>
|
||||
|
@ -225,6 +226,7 @@
|
|||
<addaction name="actionStartFile"/>
|
||||
<addaction name="actionStartDisc"/>
|
||||
<addaction name="actionStartBios"/>
|
||||
<addaction name="actionStartFullscreenUI2"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPowerOff"/>
|
||||
<addaction name="actionReset"/>
|
||||
|
@ -829,6 +831,24 @@
|
|||
<string>Enable Log Timestamps</string>
|
||||
</property>
|
||||
</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>
|
||||
<resources>
|
||||
<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 bool s_batch_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
|
||||
|
@ -617,6 +619,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
|
|||
else if (CHECK_ARG("-fullscreen"))
|
||||
{
|
||||
AutoBoot(autoboot)->fullscreen = true;
|
||||
s_start_fullscreen_ui_fullscreen = true;
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("-nofullscreen"))
|
||||
|
@ -629,6 +632,11 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
|
|||
Host::InitializeEarlyConsole();
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("-bigpicture"))
|
||||
{
|
||||
s_start_fullscreen_ui = true;
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("--"))
|
||||
{
|
||||
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
|
||||
// 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 ?
|
||||
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)
|
||||
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.
|
||||
if (autoboot)
|
||||
g_emu_thread->startVM(std::move(autoboot));
|
||||
else
|
||||
else if (!s_nogui_mode)
|
||||
main_window->startupUpdateCheck();
|
||||
|
||||
// This doesn't return until we exit.
|
||||
|
|
|
@ -1063,7 +1063,9 @@ endif()
|
|||
|
||||
if(PCSX2_CORE)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/FullscreenUI.cpp
|
||||
Frontend/GameList.cpp
|
||||
Frontend/ImGuiFullscreen.cpp
|
||||
Frontend/INISettingsInterface.cpp
|
||||
Frontend/InputManager.cpp
|
||||
Frontend/InputSource.cpp
|
||||
|
@ -1074,7 +1076,9 @@ if(PCSX2_CORE)
|
|||
VMManager.cpp
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/FullscreenUI.h
|
||||
Frontend/GameList.h
|
||||
Frontend/ImGuiFullscreen.h
|
||||
Frontend/INISettingsInterface.h
|
||||
Frontend/InputManager.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 "Counters.h"
|
||||
#include "Frontend/ImGuiManager.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "GS.h"
|
||||
#include "GS/GS.h"
|
||||
#include "Host.h"
|
||||
|
@ -43,6 +42,10 @@
|
|||
#include "PerformanceMetrics.h"
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
#include "Frontend/FullscreenUI.h"
|
||||
#include "Frontend/ImGuiManager.h"
|
||||
#include "Frontend/ImGuiFullscreen.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "VMManager.h"
|
||||
#endif
|
||||
|
||||
|
@ -52,7 +55,7 @@ namespace ImGuiManager
|
|||
static void SetKeyMap();
|
||||
static bool LoadFontData();
|
||||
static void UnloadFontData();
|
||||
static bool AddImGuiFonts();
|
||||
static bool AddImGuiFonts(bool fullscreen_fonts);
|
||||
static ImFont* AddTextFont(float size);
|
||||
static ImFont* AddFixedFont(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_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_fixed_font_data;
|
||||
|
@ -111,6 +116,10 @@ bool ImGuiManager::Initialize()
|
|||
SetKeyMap();
|
||||
SetStyle();
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
pxAssertRel(!FullscreenUI::IsInitialized(), "Fullscreen UI is not initialized on ImGui init");
|
||||
#endif
|
||||
|
||||
if (!display->CreateImGuiContext())
|
||||
{
|
||||
pxFailRel("Failed to create ImGui device context");
|
||||
|
@ -120,7 +129,7 @@ bool ImGuiManager::Initialize()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!AddImGuiFonts() || !display->UpdateImGuiFontTexture())
|
||||
if (!AddImGuiFonts(false) || !display->UpdateImGuiFontTexture())
|
||||
{
|
||||
pxFailRel("Failed to create ImGui font text");
|
||||
display->DestroyImGuiContext();
|
||||
|
@ -138,6 +147,10 @@ bool ImGuiManager::Initialize()
|
|||
|
||||
void ImGuiManager::Shutdown()
|
||||
{
|
||||
#ifdef PCSX2_CORE
|
||||
FullscreenUI::Shutdown();
|
||||
#endif
|
||||
|
||||
HostDisplay* display = Host::GetHostDisplay();
|
||||
if (display)
|
||||
display->DestroyImGuiContext();
|
||||
|
@ -146,6 +159,11 @@ void ImGuiManager::Shutdown()
|
|||
|
||||
s_standard_font = nullptr;
|
||||
s_fixed_font = nullptr;
|
||||
s_medium_font = nullptr;
|
||||
s_large_font = nullptr;
|
||||
#ifdef PCSX2_CORE
|
||||
ImGuiFullscreen::SetFonts(nullptr, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
UnloadFontData();
|
||||
}
|
||||
|
@ -172,8 +190,13 @@ void ImGuiManager::UpdateScale()
|
|||
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);
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
if (scale == s_global_scale && (!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()))
|
||||
return;
|
||||
#else
|
||||
if (scale == s_global_scale)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// This is assumed to be called mid-frame.
|
||||
ImGui::EndFrame();
|
||||
|
@ -185,7 +208,7 @@ void ImGuiManager::UpdateScale()
|
|||
SetStyle();
|
||||
ImGui::GetStyle().ScaleAllSizes(scale);
|
||||
|
||||
if (!AddImGuiFonts())
|
||||
if (!AddImGuiFonts(HasFullscreenFonts()))
|
||||
pxFailRel("Failed to create ImGui font text");
|
||||
|
||||
if (!display->UpdateImGuiFontTexture())
|
||||
|
@ -393,7 +416,7 @@ ImFont* ImGuiManager::AddFixedFont(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;
|
||||
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);
|
||||
}
|
||||
|
||||
bool ImGuiManager::AddImGuiFonts()
|
||||
bool ImGuiManager::AddImGuiFonts(bool fullscreen_fonts)
|
||||
{
|
||||
const float standard_font_size = std::ceil(15.0f * s_global_scale);
|
||||
|
||||
|
@ -421,9 +444,56 @@ bool ImGuiManager::AddImGuiFonts()
|
|||
if (!s_fixed_font)
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
std::string key;
|
||||
|
@ -767,7 +837,13 @@ void ImGuiManager::RenderOSD()
|
|||
// acquire for IO.MousePos.
|
||||
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();
|
||||
#endif
|
||||
|
||||
AcquirePendingOSDMessages();
|
||||
DrawOSDMessages();
|
||||
|
@ -788,6 +864,18 @@ ImFont* ImGuiManager::GetFixedFont()
|
|||
return s_fixed_font;
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::GetMediumFont()
|
||||
{
|
||||
AddFullscreenFontsIfMissing();
|
||||
return s_medium_font;
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::GetLargeFont()
|
||||
{
|
||||
AddFullscreenFontsIfMissing();
|
||||
return s_large_font;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
bool ImGuiManager::WantsTextInput()
|
||||
|
@ -901,3 +989,4 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
|
|||
}
|
||||
|
||||
#endif // PCSX2_CORE
|
||||
|
||||
|
|
|
@ -43,12 +43,26 @@ namespace ImGuiManager
|
|||
/// Returns the scale of all on-screen elements.
|
||||
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.
|
||||
ImFont* GetStandardFont();
|
||||
|
||||
/// Returns the fixed-width font for external drawing.
|
||||
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
|
||||
/// Returns true if imgui wants to intercept text input.
|
||||
bool WantsTextInput();
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "pcsx2/GS.h"
|
||||
#ifdef PCSX2_CORE
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/Frontend/FullscreenUI.h"
|
||||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#endif
|
||||
|
||||
|
@ -281,7 +282,13 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
|||
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());
|
||||
#endif
|
||||
GSConfig.OsdShowGPU = EmuConfig.GS.OsdShowGPU && display->SetGPUTimingEnabled(true);
|
||||
|
||||
g_gs_renderer->SetRegsMem(basemem);
|
||||
|
|
|
@ -361,7 +361,8 @@ void PAD::SetDefaultConfig(SettingsInterface& si)
|
|||
// si.SetStringValue("Hotkeys", "FrameAdvance", "Keyboard"); TBD
|
||||
// si.SetStringValue("Hotkeys", "IncreaseSpeed", "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", "TogglePause", "Keyboard/Space");
|
||||
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab");
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
|
||||
#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;
|
||||
|
||||
class SysCoreThread;
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "DebugTools/MIPSAnalyst.h"
|
||||
#include "DebugTools/SymbolMap.h"
|
||||
|
||||
#include "Frontend/FullscreenUI.h"
|
||||
#include "Frontend/INISettingsInterface.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "Frontend/GameList.h"
|
||||
|
@ -72,7 +73,6 @@
|
|||
|
||||
namespace VMManager
|
||||
{
|
||||
static void LoadSettings();
|
||||
static void ApplyGameFixes();
|
||||
static bool UpdateGameSettingsLayer();
|
||||
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_mxcsr_saved;
|
||||
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)
|
||||
{
|
||||
|
@ -200,9 +201,15 @@ void VMManager::SetState(VMState state)
|
|||
|
||||
SPU2SetOutputPaused(state == VMState::Paused);
|
||||
if (state == VMState::Paused)
|
||||
{
|
||||
Host::OnVMPaused();
|
||||
FullscreenUI::OnVMPaused();
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::OnVMResumed();
|
||||
FullscreenUI::OnVMResumed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,6 +263,12 @@ bool VMManager::Internal::InitializeGlobals()
|
|||
x86caps.CalculateMHz();
|
||||
SysLogMachineCaps();
|
||||
|
||||
if (GSinit() != 0)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to initialize GS (GSinit()).");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -683,6 +696,12 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
|
|||
GetMTGS().SendGameCRC(new_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
|
||||
// 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();
|
||||
};
|
||||
|
||||
LoadSettings();
|
||||
|
||||
std::string state_to_load;
|
||||
if (!ApplyBootParameters(std::move(boot_params), &state_to_load))
|
||||
return false;
|
||||
|
@ -870,14 +887,18 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
ScopedGuard close_cdvd = [] { DoCDVDclose(); };
|
||||
|
||||
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
|
||||
Console.WriteLn("Failed to open GS.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard close_gs = []() { GetMTGS().WaitForClose(); };
|
||||
ScopedGuard close_gs = []() {
|
||||
if (!s_gs_open_on_initialize)
|
||||
GetMTGS().WaitForClose();
|
||||
};
|
||||
|
||||
Console.WriteLn("Opening SPU2...");
|
||||
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());
|
||||
s_state.store(VMState::Paused, std::memory_order_release);
|
||||
Host::OnVMStarted();
|
||||
FullscreenUI::OnVMStarted();
|
||||
|
||||
UpdateRunningGame(true, false);
|
||||
|
||||
|
@ -1047,7 +1069,14 @@ void VMManager::Shutdown(bool save_resume_state)
|
|||
DoCDVDclose();
|
||||
FWclose();
|
||||
FileMcd_EmuClose();
|
||||
|
||||
// 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();
|
||||
SPU2shutdown();
|
||||
PADshutdown();
|
||||
|
@ -1058,6 +1087,7 @@ void VMManager::Shutdown(bool save_resume_state)
|
|||
|
||||
s_state.store(VMState::Shutdown, std::memory_order_release);
|
||||
Host::OnVMDestroyed();
|
||||
FullscreenUI::OnVMDestroyed();
|
||||
}
|
||||
|
||||
void VMManager::Reset()
|
||||
|
@ -1622,9 +1652,10 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config)
|
|||
}
|
||||
|
||||
void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
||||
{
|
||||
if (HasValidVM())
|
||||
{
|
||||
CheckForCPUConfigChanges(old_config);
|
||||
CheckForGSConfigChanges(old_config);
|
||||
CheckForFramerateConfigChanges(old_config);
|
||||
CheckForPatchConfigChanges(old_config);
|
||||
CheckForSPU2ConfigChanges(old_config);
|
||||
|
@ -1639,6 +1670,12 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
|||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
Console.WriteLn("Applying settings...");
|
||||
|
@ -1654,8 +1691,6 @@ void VMManager::ApplySettings()
|
|||
|
||||
const Pcsx2Config old_config(EmuConfig);
|
||||
LoadSettings();
|
||||
|
||||
if (HasValidVM())
|
||||
CheckForConfigChanges(old_config);
|
||||
}
|
||||
|
||||
|
@ -1741,6 +1776,10 @@ static void HotkeySaveStateSlot(s32 slot)
|
|||
}
|
||||
|
||||
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) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
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) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
Host::RequestVMShutdown(true, true);
|
||||
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
|
||||
})
|
||||
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
|
@ -1858,7 +1897,6 @@ DEFINE_HOTKEY_SAVESTATE_X(10)
|
|||
DEFINE_HOTKEY_LOADSTATE_X(10)
|
||||
#undef DEFINE_HOTKEY_SAVESTATE_X
|
||||
#undef DEFINE_HOTKEY_LOADSTATE_X
|
||||
|
||||
END_HOTKEY_LIST()
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -76,6 +76,9 @@ namespace VMManager
|
|||
/// Returns the name of the disc/executable currently running.
|
||||
std::string GetGameName();
|
||||
|
||||
/// Loads global settings (i.e. EmuConfig).
|
||||
void LoadSettings();
|
||||
|
||||
/// Initializes all system components.
|
||||
bool Initialize(VMBootParameters boot_params);
|
||||
|
||||
|
@ -249,7 +252,7 @@ namespace Host
|
|||
void RequestExit(bool save_state_if_running);
|
||||
|
||||
/// 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.
|
||||
bool IsFullscreen();
|
||||
|
|
|
@ -188,7 +188,9 @@
|
|||
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
|
||||
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\D3D12HostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\FullscreenUI.cpp" />
|
||||
<ClCompile Include="Frontend\GameList.cpp" />
|
||||
<ClCompile Include="Frontend\ImGuiFullscreen.cpp" />
|
||||
<ClCompile Include="Frontend\ImGuiManager.cpp" />
|
||||
<ClCompile Include="Frontend\imgui_impl_dx11.cpp" />
|
||||
<ClCompile Include="Frontend\imgui_impl_dx12.cpp" />
|
||||
|
@ -508,7 +510,9 @@
|
|||
<ClInclude Include="DEV9\Win32\tap.h" />
|
||||
<ClInclude Include="Frontend\D3D11HostDisplay.h" />
|
||||
<ClInclude Include="Frontend\D3D12HostDisplay.h" />
|
||||
<ClInclude Include="Frontend\FullscreenUI.h" />
|
||||
<ClInclude Include="Frontend\GameList.h" />
|
||||
<ClInclude Include="Frontend\ImGuiFullscreen.h" />
|
||||
<ClInclude Include="Frontend\ImGuiManager.h" />
|
||||
<ClInclude Include="Frontend\imgui_impl_dx11.h" />
|
||||
<ClInclude Include="Frontend\imgui_impl_dx12.h" />
|
||||
|
|
|
@ -1275,6 +1275,12 @@
|
|||
<ClCompile Include="Frontend\LogSink.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frontend\ImGuiFullscreen.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frontend\FullscreenUI.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -2119,6 +2125,12 @@
|
|||
<ClInclude Include="Frontend\LogSink.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Frontend\ImGuiFullscreen.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Frontend\FullscreenUI.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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