Qt: Implement render-to-seperate-window and render-to-main toggle
This commit is contained in:
parent
abb87f497f
commit
bf6c1c4866
|
@ -9,6 +9,7 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
|
|||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.pauseOnStart, "Main/StartPaused");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.startFullscreen, "Main/StartFullscreen");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.renderToMain, "Main/RenderToMainWindow");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.saveStateOnExit, "Main/SaveStateOnExit");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.confirmPowerOff, "Main/ConfirmPowerOff");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.showOSDMessages, "Display/ShowOSDMessages");
|
||||
|
@ -29,16 +30,19 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
|
|||
onEnableSpeedLimiterStateChanged();
|
||||
onEmulationSpeedValueChanged(m_ui.emulationSpeed->value());
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnStart, "Pause On Start", "Unchecked",
|
||||
"Pauses the emulator when a game is started.");
|
||||
dialog->registerWidgetHelp(m_ui.startFullscreen, "Start Fullscreen", "Unchecked",
|
||||
"Automatically switches to fullscreen mode when a game is started.");
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnExit, "Save State On Exit", "Checked",
|
||||
"Automatically saves the emulator state when powering down or exiting. You can then "
|
||||
"resume directly from where you left off next time.");
|
||||
dialog->registerWidgetHelp(m_ui.confirmPowerOff, "Confirm Power Off", "Checked",
|
||||
"Determines whether a prompt will be displayed to confirm shutting down the emulator/game "
|
||||
"when the hotkey is pressed.");
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnExit, "Save State On Exit", "Checked",
|
||||
"Automatically saves the emulator state when powering down or exiting. You can then "
|
||||
"resume directly from where you left off next time.");
|
||||
dialog->registerWidgetHelp(m_ui.startFullscreen, "Start Fullscreen", "Unchecked",
|
||||
"Automatically switches to fullscreen mode when a game is started.");
|
||||
dialog->registerWidgetHelp(m_ui.renderToMain, "Render To Main Window", "Checked",
|
||||
"Renders the display of the simulated console to the main window of the application, over "
|
||||
"the game list. If unchecked, the display will render in a seperate window.");
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnStart, "Pause On Start", "Unchecked",
|
||||
"Pauses the emulator when a game is started.");
|
||||
dialog->registerWidgetHelp(m_ui.enableSpeedLimiter, "Enable Speed Limiter", "Checked",
|
||||
"Throttles the emulation speed to the chosen speed above. If unchecked, the emulator will "
|
||||
"run as fast as possible, which may not be playable.");
|
||||
|
|
|
@ -33,30 +33,37 @@
|
|||
</property>
|
||||
<layout class="QGridLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="pauseOnStart">
|
||||
<widget class="QCheckBox" name="confirmPowerOff">
|
||||
<property name="text">
|
||||
<string>Pause On Start</string>
|
||||
<string>Confirm Power Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="startFullscreen">
|
||||
<property name="text">
|
||||
<string>Start Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="saveStateOnExit">
|
||||
<property name="text">
|
||||
<string>Save State On Exit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="confirmPowerOff">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="startFullscreen">
|
||||
<property name="text">
|
||||
<string>Confirm Power Off</string>
|
||||
<string>Start Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="renderToMain">
|
||||
<property name="text">
|
||||
<string>Render To Main Window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="pauseOnStart">
|
||||
<property name="text">
|
||||
<string>Pause On Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -60,18 +60,34 @@ bool MainWindow::confirmMessage(const QString& message)
|
|||
return (result == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_device)
|
||||
void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_device, bool fullscreen,
|
||||
bool render_to_main)
|
||||
{
|
||||
DebugAssert(!m_display_widget);
|
||||
|
||||
m_display_widget = m_host_interface->createDisplayWidget();
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
m_display_widget->setWindowIcon(windowIcon());
|
||||
DebugAssert(m_display_widget);
|
||||
|
||||
m_display_widget->setFocusPolicy(Qt::StrongFocus);
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
m_display_widget->showFullScreen();
|
||||
m_display_widget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
else if (!render_to_main)
|
||||
{
|
||||
m_display_widget->showNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
switchToEmulationView();
|
||||
}
|
||||
|
||||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
switchToEmulationView();
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
m_display_widget->createDeviceContext(worker_thread, use_debug_device);
|
||||
|
@ -81,36 +97,60 @@ void MainWindow::destroyDisplayWindow()
|
|||
{
|
||||
DebugAssert(m_display_widget);
|
||||
|
||||
const bool was_fullscreen = m_display_widget->isFullScreen();
|
||||
if (was_fullscreen)
|
||||
toggleFullscreen();
|
||||
if (m_display_widget->isFullScreen())
|
||||
m_display_widget->showNormal();
|
||||
|
||||
switchToGameListView();
|
||||
if (m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
// recreate the display widget using the potentially-new renderer
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
delete m_display_widget;
|
||||
m_display_widget = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::setFullscreen(bool fullscreen)
|
||||
void MainWindow::updateDisplayWindow(bool fullscreen, bool render_to_main)
|
||||
{
|
||||
if (fullscreen == m_display_widget->isFullScreen())
|
||||
const bool is_fullscreen = m_display_widget->isFullScreen();
|
||||
const bool is_rendering_to_main = (!is_fullscreen && m_display_widget->parent());
|
||||
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main)
|
||||
return;
|
||||
|
||||
if (fullscreen)
|
||||
if (fullscreen || !render_to_main)
|
||||
{
|
||||
m_ui.mainContainer->setCurrentIndex(0);
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
m_display_widget->setParent(nullptr);
|
||||
m_display_widget->showFullScreen();
|
||||
m_display_widget->setCursor(Qt::BlankCursor);
|
||||
if (m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->setCurrentIndex(0);
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
m_display_widget->setParent(nullptr);
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
m_display_widget->showFullScreen();
|
||||
m_display_widget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we don't position it, it ends up in the top-left corner with the title bar obscured
|
||||
m_display_widget->setCursor(QCursor());
|
||||
m_display_widget->showNormal();
|
||||
m_display_widget->move(pos());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// render-to-main
|
||||
if (!m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
m_ui.mainContainer->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
m_display_widget->setCursor(QCursor());
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
m_ui.mainContainer->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
m_display_widget->setFocus();
|
||||
|
@ -119,11 +159,6 @@ void MainWindow::setFullscreen(bool fullscreen)
|
|||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
}
|
||||
|
||||
void MainWindow::toggleFullscreen()
|
||||
{
|
||||
setFullscreen(!m_display_widget->isFullScreen());
|
||||
}
|
||||
|
||||
void MainWindow::focusDisplayWidget()
|
||||
{
|
||||
if (m_ui.mainContainer->currentIndex() != 1)
|
||||
|
@ -176,6 +211,9 @@ void MainWindow::onRunningGameChanged(const QString& filename, const QString& ga
|
|||
setWindowTitle(tr("DuckStation"));
|
||||
else
|
||||
setWindowTitle(game_title);
|
||||
|
||||
if (m_display_widget)
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
}
|
||||
|
||||
void MainWindow::onStartDiscActionTriggered()
|
||||
|
@ -419,7 +457,8 @@ void MainWindow::switchToGameListView()
|
|||
|
||||
void MainWindow::switchToEmulationView()
|
||||
{
|
||||
m_ui.mainContainer->setCurrentIndex(1);
|
||||
if (m_display_widget->parent())
|
||||
m_ui.mainContainer->setCurrentIndex(1);
|
||||
m_display_widget->setFocus();
|
||||
}
|
||||
|
||||
|
@ -445,7 +484,7 @@ void MainWindow::connectSignals()
|
|||
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);
|
||||
connect(m_ui.actionFullscreen, &QAction::triggered, this, &MainWindow::toggleFullscreen);
|
||||
connect(m_ui.actionFullscreen, &QAction::triggered, m_host_interface, &QtHostInterface::toggleFullscreen);
|
||||
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::Count); });
|
||||
connect(m_ui.actionGeneralSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::GeneralSettings); });
|
||||
|
@ -472,8 +511,8 @@ void MainWindow::connectSignals()
|
|||
connect(m_host_interface, &QtHostInterface::createDisplayWindowRequested, this, &MainWindow::createDisplayWindow,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(m_host_interface, &QtHostInterface::destroyDisplayWindowRequested, this, &MainWindow::destroyDisplayWindow);
|
||||
connect(m_host_interface, &QtHostInterface::setFullscreenRequested, this, &MainWindow::setFullscreen);
|
||||
connect(m_host_interface, &QtHostInterface::toggleFullscreenRequested, this, &MainWindow::toggleFullscreen);
|
||||
connect(m_host_interface, &QtHostInterface::updateDisplayWindowRequested, this, &MainWindow::updateDisplayWindow,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(m_host_interface, &QtHostInterface::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget);
|
||||
connect(m_host_interface, &QtHostInterface::emulationStarted, this, &MainWindow::onEmulationStarted);
|
||||
connect(m_host_interface, &QtHostInterface::emulationStopped, this, &MainWindow::onEmulationStopped);
|
||||
|
|
|
@ -28,10 +28,9 @@ private Q_SLOTS:
|
|||
void reportError(const QString& message);
|
||||
void reportMessage(const QString& message);
|
||||
bool confirmMessage(const QString& message);
|
||||
void createDisplayWindow(QThread* worker_thread, bool use_debug_device);
|
||||
void createDisplayWindow(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main);
|
||||
void destroyDisplayWindow();
|
||||
void setFullscreen(bool fullscreen);
|
||||
void toggleFullscreen();
|
||||
void updateDisplayWindow(bool fullscreen, bool render_to_main);
|
||||
void focusDisplayWidget();
|
||||
void onEmulationStarted();
|
||||
void onEmulationStopped();
|
||||
|
|
|
@ -145,6 +145,13 @@ bool QtDisplayWidget::event(QEvent* event)
|
|||
return true;
|
||||
}
|
||||
|
||||
case QEvent::Close:
|
||||
{
|
||||
m_host_interface->synchronousPowerOffSystem();
|
||||
QWidget::event(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
case QEvent::WindowStateChange:
|
||||
{
|
||||
QWidget::event(event);
|
||||
|
|
|
@ -67,11 +67,14 @@ void QtHostInterface::ReportError(const char* message)
|
|||
{
|
||||
HostInterface::ReportError(message);
|
||||
|
||||
emit setFullscreenRequested(false);
|
||||
const bool was_fullscreen = m_is_fullscreen;
|
||||
if (was_fullscreen)
|
||||
SetFullscreen(false);
|
||||
|
||||
emit errorReported(QString::fromLocal8Bit(message));
|
||||
|
||||
if (m_settings.start_fullscreen)
|
||||
emit setFullscreenRequested(true);
|
||||
if (was_fullscreen)
|
||||
SetFullscreen(true);
|
||||
}
|
||||
|
||||
void QtHostInterface::ReportMessage(const char* message)
|
||||
|
@ -83,12 +86,14 @@ void QtHostInterface::ReportMessage(const char* message)
|
|||
|
||||
bool QtHostInterface::ConfirmMessage(const char* message)
|
||||
{
|
||||
emit setFullscreenRequested(false);
|
||||
const bool was_fullscreen = m_is_fullscreen;
|
||||
if (was_fullscreen)
|
||||
SetFullscreen(false);
|
||||
|
||||
const bool result = messageConfirmed(QString::fromLocal8Bit(message));
|
||||
|
||||
if (m_settings.start_fullscreen)
|
||||
emit setFullscreenRequested(true);
|
||||
if (was_fullscreen)
|
||||
SetFullscreen(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -137,6 +142,14 @@ void QtHostInterface::applySettings()
|
|||
QtSettingsInterface si(m_qsettings);
|
||||
UpdateSettings([this, &si]() { m_settings.Load(si); });
|
||||
CommonHostInterface::UpdateInputMap(si);
|
||||
|
||||
// detect when render-to-main flag changes
|
||||
const bool render_to_main = m_qsettings.value("Main/RenderToMainWindow", true).toBool();
|
||||
if (m_system && m_display_widget && !m_is_fullscreen && render_to_main != m_is_rendering_to_main)
|
||||
{
|
||||
m_is_rendering_to_main = render_to_main;
|
||||
emit updateDisplayWindowRequested(false, render_to_main);
|
||||
}
|
||||
}
|
||||
|
||||
void QtHostInterface::loadSettings()
|
||||
|
@ -257,11 +270,25 @@ void QtHostInterface::redrawDisplayWindow()
|
|||
renderDisplay();
|
||||
}
|
||||
|
||||
void QtHostInterface::toggleFullscreen()
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "toggleFullscreen", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
bool QtHostInterface::AcquireHostDisplay()
|
||||
{
|
||||
DebugAssert(!m_display_widget);
|
||||
|
||||
emit createDisplayWindowRequested(m_worker_thread, m_settings.gpu_use_debug_device);
|
||||
m_is_rendering_to_main = getSettingValue("Main/RenderToMainWindow", true).toBool();
|
||||
m_is_fullscreen = m_settings.start_fullscreen;
|
||||
emit createDisplayWindowRequested(m_worker_thread, m_settings.gpu_use_debug_device, m_is_fullscreen,
|
||||
m_is_rendering_to_main);
|
||||
if (!m_display_widget->hasDeviceContext())
|
||||
{
|
||||
m_display_widget = nullptr;
|
||||
|
@ -292,12 +319,17 @@ void QtHostInterface::ReleaseHostDisplay()
|
|||
|
||||
void QtHostInterface::SetFullscreen(bool enabled)
|
||||
{
|
||||
emit setFullscreenRequested(enabled);
|
||||
if (m_is_fullscreen == enabled)
|
||||
return;
|
||||
|
||||
m_is_fullscreen = enabled;
|
||||
emit updateDisplayWindowRequested(m_is_fullscreen, m_is_rendering_to_main);
|
||||
}
|
||||
|
||||
void QtHostInterface::ToggleFullscreen()
|
||||
{
|
||||
emit toggleFullscreenRequested();
|
||||
m_is_fullscreen = !m_is_fullscreen;
|
||||
emit updateDisplayWindowRequested(m_is_fullscreen, m_is_rendering_to_main);
|
||||
}
|
||||
|
||||
std::optional<CommonHostInterface::HostKeyCode> QtHostInterface::GetHostKeyCode(const std::string_view key_code) const
|
||||
|
@ -381,6 +413,13 @@ void QtHostInterface::OnSystemStateSaved(bool global, s32 slot)
|
|||
emit stateSaved(QString::fromStdString(m_system->GetRunningCode()), global, slot);
|
||||
}
|
||||
|
||||
void QtHostInterface::SetDefaultSettings(SettingsInterface& si)
|
||||
{
|
||||
CommonHostInterface::SetDefaultSettings(si);
|
||||
|
||||
si.SetBoolValue("Main", "RenderToMainWindow", true);
|
||||
}
|
||||
|
||||
void QtHostInterface::UpdateInputMap()
|
||||
{
|
||||
updateInputMap();
|
||||
|
|
|
@ -75,10 +75,10 @@ Q_SIGNALS:
|
|||
void emulationPaused(bool paused);
|
||||
void stateSaved(const QString& game_code, bool global, qint32 slot);
|
||||
void gameListRefreshed();
|
||||
void createDisplayWindowRequested(QThread* worker_thread, bool use_debug_device);
|
||||
void createDisplayWindowRequested(QThread* worker_thread, bool use_debug_device, bool fullscreen,
|
||||
bool render_to_main);
|
||||
void destroyDisplayWindowRequested();
|
||||
void setFullscreenRequested(bool fullscreen);
|
||||
void toggleFullscreenRequested();
|
||||
void updateDisplayWindowRequested(bool fullscreen, bool render_to_main);
|
||||
void focusDisplayWidgetRequested();
|
||||
void systemPerformanceCountersUpdated(float speed, float fps, float vps, float avg_frame_time,
|
||||
float worst_frame_time);
|
||||
|
@ -103,6 +103,7 @@ public Q_SLOTS:
|
|||
void stopDumpingAudio();
|
||||
void saveScreenshot();
|
||||
void redrawDisplayWindow();
|
||||
void toggleFullscreen();
|
||||
|
||||
/// Enables controller polling even without a system active. Must be matched by a call to
|
||||
/// disableBackgroundControllerPolling.
|
||||
|
@ -131,6 +132,7 @@ protected:
|
|||
void OnRunningGameChanged() override;
|
||||
void OnSystemStateSaved(bool global, s32 slot) override;
|
||||
|
||||
void SetDefaultSettings(SettingsInterface& si) override;
|
||||
void UpdateInputMap() override;
|
||||
|
||||
private:
|
||||
|
@ -182,4 +184,7 @@ private:
|
|||
|
||||
QTimer* m_background_controller_polling_timer = nullptr;
|
||||
u32 m_background_controller_polling_enable_count = 0;
|
||||
|
||||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = false;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue