Qt: Turn cover downloader into a non-modal window

Same as the others.
This commit is contained in:
Stenzek 2025-07-18 13:04:11 +10:00
parent 3f2b6995bc
commit 0f2ef98747
No known key found for this signature in database
8 changed files with 79 additions and 50 deletions

View File

@ -52,9 +52,9 @@ set(SRCS
controllersettingswindow.h controllersettingswindow.h
controllersettingswindow.ui controllersettingswindow.ui
controllersettingwidgetbinder.h controllersettingwidgetbinder.h
coverdownloaddialog.cpp coverdownloadwindow.cpp
coverdownloaddialog.h coverdownloadwindow.h
coverdownloaddialog.ui coverdownloadwindow.ui
debuggeraddbreakpointdialog.ui debuggeraddbreakpointdialog.ui
debuggermodels.cpp debuggermodels.cpp
debuggermodels.h debuggermodels.h

View File

@ -1,41 +1,45 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 // SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "coverdownloaddialog.h" #include "coverdownloadwindow.h"
#include "qthost.h" #include "qthost.h"
#include "core/game_list.h" #include "core/game_list.h"
#include "common/assert.h" #include "common/assert.h"
CoverDownloadDialog::CoverDownloadDialog(QWidget* parent /*= nullptr*/) : QDialog(parent) CoverDownloadWindow::CoverDownloadWindow() : QWidget()
{ {
m_ui.setupUi(this); m_ui.setupUi(this);
setWindowIcon(QtHost::GetAppIcon()); setWindowIcon(QtHost::GetAppIcon());
m_ui.coverIcon->setPixmap(QIcon::fromTheme(QStringLiteral("artboard-2-line")).pixmap(32)); m_ui.coverIcon->setPixmap(QIcon::fromTheme(QStringLiteral("artboard-2-line")).pixmap(32));
updateEnabled(); updateEnabled();
QtUtils::RestoreWindowGeometry("CoverDownloadWindow", this);
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadDialog::onStartClicked); connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadWindow::onStartClicked);
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadDialog::onCloseClicked); connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadWindow::onCloseClicked);
connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadDialog::updateEnabled); connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadWindow::updateEnabled);
} }
CoverDownloadDialog::~CoverDownloadDialog() CoverDownloadWindow::~CoverDownloadWindow()
{ {
Assert(!m_thread); Assert(!m_thread);
} }
void CoverDownloadDialog::closeEvent(QCloseEvent* ev) void CoverDownloadWindow::closeEvent(QCloseEvent* ev)
{ {
QtUtils::SaveWindowGeometry("CoverDownloadWindow", this);
QWidget::closeEvent(ev);
cancelThread(); cancelThread();
emit closed();
} }
void CoverDownloadDialog::onDownloadStatus(const QString& text) void CoverDownloadWindow::onDownloadStatus(const QString& text)
{ {
m_ui.status->setText(text); m_ui.status->setText(text);
} }
void CoverDownloadDialog::onDownloadProgress(int value, int range) void CoverDownloadWindow::onDownloadProgress(int value, int range)
{ {
// Limit to once every five seconds, otherwise it's way too flickery. // Limit to once every five seconds, otherwise it's way too flickery.
// Ideally in the future we'd have some way to invalidate only a single cover. // Ideally in the future we'd have some way to invalidate only a single cover.
@ -50,7 +54,7 @@ void CoverDownloadDialog::onDownloadProgress(int value, int range)
m_ui.progress->setValue(value); m_ui.progress->setValue(value);
} }
void CoverDownloadDialog::onDownloadComplete() void CoverDownloadWindow::onDownloadComplete()
{ {
emit coverRefreshRequested(); emit coverRefreshRequested();
@ -65,7 +69,7 @@ void CoverDownloadDialog::onDownloadComplete()
m_ui.status->setText(tr("Download complete.")); m_ui.status->setText(tr("Download complete."));
} }
void CoverDownloadDialog::onStartClicked() void CoverDownloadWindow::onStartClicked()
{ {
if (m_thread) if (m_thread)
cancelThread(); cancelThread();
@ -73,15 +77,15 @@ void CoverDownloadDialog::onStartClicked()
startThread(); startThread();
} }
void CoverDownloadDialog::onCloseClicked() void CoverDownloadWindow::onCloseClicked()
{ {
if (m_thread) if (m_thread)
cancelThread(); cancelThread();
reject(); close();
} }
void CoverDownloadDialog::updateEnabled() void CoverDownloadWindow::updateEnabled()
{ {
const bool running = static_cast<bool>(m_thread); const bool running = static_cast<bool>(m_thread);
m_ui.start->setText(running ? tr("Stop") : tr("Start")); m_ui.start->setText(running ? tr("Stop") : tr("Start"));
@ -90,18 +94,19 @@ void CoverDownloadDialog::updateEnabled()
m_ui.urls->setEnabled(!running); m_ui.urls->setEnabled(!running);
} }
void CoverDownloadDialog::startThread() void CoverDownloadWindow::startThread()
{ {
m_thread = std::make_unique<CoverDownloadThread>(this, m_ui.urls->toPlainText(), m_ui.useSerialFileNames->isChecked()); m_thread =
std::make_unique<CoverDownloadThread>(this, m_ui.urls->toPlainText(), m_ui.useSerialFileNames->isChecked());
m_last_refresh_time.Reset(); m_last_refresh_time.Reset();
connect(m_thread.get(), &CoverDownloadThread::statusUpdated, this, &CoverDownloadDialog::onDownloadStatus); connect(m_thread.get(), &CoverDownloadThread::statusUpdated, this, &CoverDownloadWindow::onDownloadStatus);
connect(m_thread.get(), &CoverDownloadThread::progressUpdated, this, &CoverDownloadDialog::onDownloadProgress); connect(m_thread.get(), &CoverDownloadThread::progressUpdated, this, &CoverDownloadWindow::onDownloadProgress);
connect(m_thread.get(), &CoverDownloadThread::threadFinished, this, &CoverDownloadDialog::onDownloadComplete); connect(m_thread.get(), &CoverDownloadThread::threadFinished, this, &CoverDownloadWindow::onDownloadComplete);
m_thread->start(); m_thread->start();
updateEnabled(); updateEnabled();
} }
void CoverDownloadDialog::cancelThread() void CoverDownloadWindow::cancelThread()
{ {
if (!m_thread) if (!m_thread)
return; return;
@ -111,16 +116,16 @@ void CoverDownloadDialog::cancelThread()
m_thread.reset(); m_thread.reset();
} }
CoverDownloadDialog::CoverDownloadThread::CoverDownloadThread(QWidget* parent, const QString& urls, bool use_serials) CoverDownloadWindow::CoverDownloadThread::CoverDownloadThread(QWidget* parent, const QString& urls, bool use_serials)
: QtAsyncProgressThread(parent), m_use_serials(use_serials) : QtAsyncProgressThread(parent), m_use_serials(use_serials)
{ {
for (const QString& str : urls.split(QChar('\n'))) for (const QString& str : urls.split(QChar('\n')))
m_urls.push_back(str.toStdString()); m_urls.push_back(str.toStdString());
} }
CoverDownloadDialog::CoverDownloadThread::~CoverDownloadThread() = default; CoverDownloadWindow::CoverDownloadThread::~CoverDownloadThread() = default;
void CoverDownloadDialog::CoverDownloadThread::runAsync() void CoverDownloadWindow::CoverDownloadThread::runAsync()
{ {
GameList::DownloadCovers(m_urls, m_use_serials, this); GameList::DownloadCovers(m_urls, m_use_serials, this);
} }

View File

@ -1,25 +1,30 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 // SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once #pragma once
#include "qtprogresscallback.h"
#include "ui_coverdownloadwindow.h"
#include "common/timer.h" #include "common/timer.h"
#include "common/types.h" #include "common/types.h"
#include "qtprogresscallback.h"
#include "ui_coverdownloaddialog.h" #include <QtWidgets/QWidget>
#include <QtWidgets/QDialog>
#include <array> #include <array>
#include <memory> #include <memory>
#include <string> #include <string>
class CoverDownloadDialog final : public QDialog class CoverDownloadWindow final : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
CoverDownloadDialog(QWidget* parent = nullptr); CoverDownloadWindow();
~CoverDownloadDialog(); ~CoverDownloadWindow();
Q_SIGNALS: Q_SIGNALS:
void closed();
void coverRefreshRequested(); void coverRefreshRequested();
protected: protected:
@ -51,7 +56,7 @@ private:
void startThread(); void startThread();
void cancelThread(); void cancelThread();
Ui::CoverDownloadDialog m_ui; Ui::CoverDownloadWindow m_ui;
std::unique_ptr<CoverDownloadThread> m_thread; std::unique_ptr<CoverDownloadThread> m_thread;
Timer m_last_refresh_time; Timer m_last_refresh_time;
}; };

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>CoverDownloadDialog</class> <class>CoverDownloadWindow</class>
<widget class="QDialog" name="CoverDownloadDialog"> <widget class="QWidget" name="CoverDownloadWindow">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>

View File

@ -14,7 +14,7 @@
<ClCompile Include="controllerbindingwidgets.cpp" /> <ClCompile Include="controllerbindingwidgets.cpp" />
<ClCompile Include="controllerglobalsettingswidget.cpp" /> <ClCompile Include="controllerglobalsettingswidget.cpp" />
<ClCompile Include="controllersettingswindow.cpp" /> <ClCompile Include="controllersettingswindow.cpp" />
<ClCompile Include="coverdownloaddialog.cpp" /> <ClCompile Include="coverdownloadwindow.cpp" />
<ClCompile Include="emulationsettingswidget.cpp" /> <ClCompile Include="emulationsettingswidget.cpp" />
<ClCompile Include="debuggermodels.cpp" /> <ClCompile Include="debuggermodels.cpp" />
<ClCompile Include="debuggerwindow.cpp" /> <ClCompile Include="debuggerwindow.cpp" />
@ -58,7 +58,7 @@
<QtMoc Include="aboutdialog.h" /> <QtMoc Include="aboutdialog.h" />
<QtMoc Include="audiosettingswidget.h" /> <QtMoc Include="audiosettingswidget.h" />
<QtMoc Include="biossettingswidget.h" /> <QtMoc Include="biossettingswidget.h" />
<QtMoc Include="coverdownloaddialog.h" /> <QtMoc Include="coverdownloadwindow.h" />
<QtMoc Include="memorycardsettingswidget.h" /> <QtMoc Include="memorycardsettingswidget.h" />
<QtMoc Include="memorycardeditorwindow.h" /> <QtMoc Include="memorycardeditorwindow.h" />
<QtMoc Include="displaywidget.h" /> <QtMoc Include="displaywidget.h" />
@ -202,7 +202,7 @@
<QtUi Include="foldersettingswidget.ui"> <QtUi Include="foldersettingswidget.ui">
<FileType>Document</FileType> <FileType>Document</FileType>
</QtUi> </QtUi>
<QtUi Include="coverdownloaddialog.ui"> <QtUi Include="coverdownloadwindow.ui">
<FileType>Document</FileType> <FileType>Document</FileType>
</QtUi> </QtUi>
</ItemGroup> </ItemGroup>
@ -224,7 +224,7 @@
<ClCompile Include="$(IntDir)moc_controllerbindingwidgets.cpp" /> <ClCompile Include="$(IntDir)moc_controllerbindingwidgets.cpp" />
<ClCompile Include="$(IntDir)moc_controllerglobalsettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_controllerglobalsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_controllersettingswindow.cpp" /> <ClCompile Include="$(IntDir)moc_controllersettingswindow.cpp" />
<ClCompile Include="$(IntDir)moc_coverdownloaddialog.cpp" /> <ClCompile Include="$(IntDir)moc_coverdownloadwindow.cpp" />
<ClCompile Include="$(IntDir)moc_displaywidget.cpp" /> <ClCompile Include="$(IntDir)moc_displaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp" />

View File

@ -36,7 +36,7 @@
<ClCompile Include="foldersettingswidget.cpp" /> <ClCompile Include="foldersettingswidget.cpp" />
<ClCompile Include="gamesummarywidget.cpp" /> <ClCompile Include="gamesummarywidget.cpp" />
<ClCompile Include="qttranslations.cpp" /> <ClCompile Include="qttranslations.cpp" />
<ClCompile Include="coverdownloaddialog.cpp" /> <ClCompile Include="coverdownloadwindow.cpp" />
<ClCompile Include="colorpickerbutton.cpp" /> <ClCompile Include="colorpickerbutton.cpp" />
<ClCompile Include="pch.cpp" /> <ClCompile Include="pch.cpp" />
<ClCompile Include="setupwizarddialog.cpp" /> <ClCompile Include="setupwizarddialog.cpp" />
@ -77,7 +77,7 @@
<ClCompile Include="$(IntDir)moc_controllersettingswindow.cpp"> <ClCompile Include="$(IntDir)moc_controllersettingswindow.cpp">
<Filter>moc</Filter> <Filter>moc</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="$(IntDir)moc_coverdownloaddialog.cpp"> <ClCompile Include="$(IntDir)moc_coverdownloadwindow.cpp">
<Filter>moc</Filter> <Filter>moc</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="$(IntDir)moc_debuggermodels.cpp"> <ClCompile Include="$(IntDir)moc_debuggermodels.cpp">
@ -227,7 +227,7 @@
<QtMoc Include="gamelistrefreshthread.h" /> <QtMoc Include="gamelistrefreshthread.h" />
<QtMoc Include="gamesummarywidget.h" /> <QtMoc Include="gamesummarywidget.h" />
<QtMoc Include="foldersettingswidget.h" /> <QtMoc Include="foldersettingswidget.h" />
<QtMoc Include="coverdownloaddialog.h" /> <QtMoc Include="coverdownloadwindow.h" />
<QtMoc Include="colorpickerbutton.h" /> <QtMoc Include="colorpickerbutton.h" />
<QtMoc Include="setupwizarddialog.h" /> <QtMoc Include="setupwizarddialog.h" />
<QtMoc Include="logwindow.h" /> <QtMoc Include="logwindow.h" />
@ -272,7 +272,7 @@
<QtUi Include="controllermacrowidget.ui" /> <QtUi Include="controllermacrowidget.ui" />
<QtUi Include="controllermacroeditwidget.ui" /> <QtUi Include="controllermacroeditwidget.ui" />
<QtUi Include="controllerbindingwidget_mouse.ui" /> <QtUi Include="controllerbindingwidget_mouse.ui" />
<QtUi Include="coverdownloaddialog.ui" /> <QtUi Include="coverdownloadwindow.ui" />
<QtUi Include="setupwizarddialog.ui" /> <QtUi Include="setupwizarddialog.ui" />
<QtUi Include="controllerledsettingsdialog.ui" /> <QtUi Include="controllerledsettingsdialog.ui" />
<QtUi Include="debuggeraddbreakpointdialog.ui" /> <QtUi Include="debuggeraddbreakpointdialog.ui" />

View File

@ -5,7 +5,7 @@
#include "aboutdialog.h" #include "aboutdialog.h"
#include "achievementlogindialog.h" #include "achievementlogindialog.h"
#include "autoupdaterwindow.h" #include "autoupdaterwindow.h"
#include "coverdownloaddialog.h" #include "coverdownloadwindow.h"
#include "debuggerwindow.h" #include "debuggerwindow.h"
#include "displaywidget.h" #include "displaywidget.h"
#include "gamelistsettingswidget.h" #include "gamelistsettingswidget.h"
@ -834,6 +834,7 @@ void MainWindow::recreate()
void MainWindow::destroySubWindows() void MainWindow::destroySubWindows()
{ {
QtUtils::CloseAndDeleteWindow(m_cover_download_window);
QtUtils::CloseAndDeleteWindow(m_memory_scanner_window); QtUtils::CloseAndDeleteWindow(m_memory_scanner_window);
QtUtils::CloseAndDeleteWindow(m_debugger_window); QtUtils::CloseAndDeleteWindow(m_debugger_window);
QtUtils::CloseAndDeleteWindow(m_memory_card_editor_window); QtUtils::CloseAndDeleteWindow(m_memory_card_editor_window);
@ -2983,10 +2984,26 @@ void MainWindow::onToolsMemoryCardEditorTriggered()
void MainWindow::onToolsCoverDownloaderTriggered() void MainWindow::onToolsCoverDownloaderTriggered()
{ {
// This can be invoked via big picture, so exit fullscreen. // This can be invoked via big picture, so exit fullscreen.
SystemLock lock(pauseAndLockSystem()); if (isRenderingFullscreen())
CoverDownloadDialog dlg(lock.getDialogParent()); {
connect(&dlg, &CoverDownloadDialog::coverRefreshRequested, m_game_list_widget, &GameListWidget::refreshGridCovers); g_emu_thread->setFullscreen(false, true);
dlg.exec();
// wait for the fullscreen request to actually go through, otherwise the downloader appears behind the main window.
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents, [this]() { return isRenderingFullscreen(); });
}
if (!m_cover_download_window)
{
m_cover_download_window = new CoverDownloadWindow();
connect(m_cover_download_window, &CoverDownloadWindow::coverRefreshRequested, m_game_list_widget,
&GameListWidget::refreshGridCovers);
connect(m_cover_download_window, &CoverDownloadWindow::closed, this, [this]() {
m_cover_download_window->deleteLater();
m_cover_download_window = nullptr;
});
}
QtUtils::ShowOrRaiseWindow(m_cover_download_window);
} }
void MainWindow::onToolsMediaCaptureToggled(bool checked) void MainWindow::onToolsMediaCaptureToggled(bool checked)

View File

@ -33,6 +33,7 @@ class AutoUpdaterWindow;
class MemoryCardEditorWindow; class MemoryCardEditorWindow;
class DebuggerWindow; class DebuggerWindow;
class MemoryScannerWindow; class MemoryScannerWindow;
class CoverDownloadWindow;
struct SystemBootParameters; struct SystemBootParameters;
@ -339,6 +340,7 @@ private:
MemoryCardEditorWindow* m_memory_card_editor_window = nullptr; MemoryCardEditorWindow* m_memory_card_editor_window = nullptr;
DebuggerWindow* m_debugger_window = nullptr; DebuggerWindow* m_debugger_window = nullptr;
MemoryScannerWindow* m_memory_scanner_window = nullptr; MemoryScannerWindow* m_memory_scanner_window = nullptr;
CoverDownloadWindow* m_cover_download_window = nullptr;
bool m_was_paused_by_focus_loss = false; bool m_was_paused_by_focus_loss = false;
bool m_relative_mouse_mode = false; bool m_relative_mouse_mode = false;