diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index dae15de46..c82146a3d 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -226,6 +226,23 @@ void MainWindow::setDisplayFullscreen(const std::string& fullscreen_mode) } } +void MainWindow::displaySizeRequested(qint32 width, qint32 height) +{ + if (!m_display_widget) + return; + + if (!m_display_widget->parent()) + { + // no parent - rendering to separate window. easy. + m_display_widget->resize(QSize(std::max(width, 1), std::max(height, 1))); + return; + } + + // we are rendering to the main window. we have to add in the extra height from the toolbar/status bar. + const s32 extra_height = this->height() - m_display_widget->height(); + resize(QSize(std::max(width, 1), std::max(height + extra_height, 1))); +} + void MainWindow::destroyDisplay() { DebugAssert(m_host_display && m_display_widget); @@ -686,6 +703,13 @@ void MainWindow::setupAdditionalUi() tr("Language changed. Please restart the application to apply.")); }); } + + for (u32 scale = 1; scale <= 10; scale++) + { + QAction* action = m_ui.menuWindowSize->addAction(tr("%1x Scale").arg(scale)); + connect(action, &QAction::triggered, + [scale]() { QtHostInterface::GetInstance()->requestRenderWindowScale(scale); }); + } } void MainWindow::updateEmulationActions(bool starting, bool running) @@ -707,6 +731,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running) m_ui.actionSaveState->setDisabled(starting || !running); m_ui.menuSaveState->setDisabled(starting || !running); + m_ui.menuWindowSize->setDisabled(starting || !running); m_ui.actionFullscreen->setDisabled(starting || !running); @@ -862,6 +887,7 @@ void MainWindow::connectSignals() connect(m_host_interface, &QtHostInterface::destroyDisplayRequested, this, &MainWindow::destroyDisplay); connect(m_host_interface, &QtHostInterface::updateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection); + connect(m_host_interface, &QtHostInterface::displaySizeRequested, this, &MainWindow::displaySizeRequested); connect(m_host_interface, &QtHostInterface::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget); connect(m_host_interface, &QtHostInterface::emulationStarting, this, &MainWindow::onEmulationStarting); connect(m_host_interface, &QtHostInterface::emulationStarted, this, &MainWindow::onEmulationStarted); diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 9c8463474..d0c0519c9 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -45,6 +45,7 @@ private Q_SLOTS: QtDisplayWidget* createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, bool fullscreen, bool render_to_main); QtDisplayWidget* updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main); + void displaySizeRequested(qint32 width, qint32 height); void destroyDisplay(); void focusDisplayWidget(); diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui index 98c9e2de9..4c81bcaa7 100644 --- a/src/duckstation-qt/mainwindow.ui +++ b/src/duckstation-qt/mainwindow.ui @@ -165,7 +165,8 @@ Switch Crop Mode - + + @@ -188,6 +189,11 @@ &View + + + &Window Size + + @@ -196,6 +202,8 @@ + + @@ -344,7 +352,7 @@ - + :/icons/media-flash-2.png:/icons/media-flash-2.png diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index dbad99a0b..501505b3f 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -598,6 +598,15 @@ bool QtHostInterface::SetFullscreen(bool enabled) return true; } +bool QtHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) +{ + if (new_window_width <= 0 || new_window_height <= 0 || m_is_fullscreen || m_is_exclusive_fullscreen) + return false; + + emit displaySizeRequested(new_window_width, new_window_height); + return true; +} + void QtHostInterface::PollAndUpdate() { CommonHostInterface::PollAndUpdate(); @@ -1075,6 +1084,17 @@ void QtHostInterface::reloadPostProcessingShaders() ReloadPostProcessingShaders(); } +void QtHostInterface::requestRenderWindowScale(qreal scale) +{ + if (!isOnWorkerThread()) + { + QMetaObject::invokeMethod(this, "requestRenderWindowScale", Qt::QueuedConnection, Q_ARG(qreal, scale)); + return; + } + + RequestRenderWindowScale(scale); +} + void QtHostInterface::executeOnEmulationThread(std::function callback, bool wait) { if (isOnWorkerThread()) diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index 453b6f12a..aaa5125ad 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -70,6 +70,8 @@ public: TinyString TranslateString(const char* context, const char* str) const override; std::string TranslateStdString(const char* context, const char* str) const override; + bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override; + ALWAYS_INLINE const GameList* getGameList() const { return m_game_list.get(); } ALWAYS_INLINE GameList* getGameList() { return m_game_list.get(); } void refreshGameList(bool invalidate_cache = false, bool invalidate_database = false); @@ -128,6 +130,7 @@ Q_SIGNALS: QtDisplayWidget* createDisplayRequested(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, bool fullscreen, bool render_to_main); QtDisplayWidget* updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main); + void displaySizeRequested(qint32 width, qint32 height); void focusDisplayWidgetRequested(); void destroyDisplayRequested(); void systemPerformanceCountersUpdated(float speed, float fps, float vps, float avg_frame_time, @@ -168,6 +171,7 @@ public Q_SLOTS: void setCheatEnabled(quint32 index, bool enabled); void applyCheat(quint32 index); void reloadPostProcessingShaders(); + void requestRenderWindowScale(qreal scale); void executeOnEmulationThread(std::function callback, bool wait = false); private Q_SLOTS: