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.ui
controllersettingwidgetbinder.h
coverdownloaddialog.cpp
coverdownloaddialog.h
coverdownloaddialog.ui
coverdownloadwindow.cpp
coverdownloadwindow.h
coverdownloadwindow.ui
debuggeraddbreakpointdialog.ui
debuggermodels.cpp
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
#include "coverdownloaddialog.h"
#include "coverdownloadwindow.h"
#include "qthost.h"
#include "core/game_list.h"
#include "common/assert.h"
CoverDownloadDialog::CoverDownloadDialog(QWidget* parent /*= nullptr*/) : QDialog(parent)
CoverDownloadWindow::CoverDownloadWindow() : QWidget()
{
m_ui.setupUi(this);
setWindowIcon(QtHost::GetAppIcon());
m_ui.coverIcon->setPixmap(QIcon::fromTheme(QStringLiteral("artboard-2-line")).pixmap(32));
updateEnabled();
QtUtils::RestoreWindowGeometry("CoverDownloadWindow", this);
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadDialog::onStartClicked);
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadDialog::onCloseClicked);
connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadDialog::updateEnabled);
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadWindow::onStartClicked);
connect(m_ui.close, &QPushButton::clicked, this, &CoverDownloadWindow::onCloseClicked);
connect(m_ui.urls, &QTextEdit::textChanged, this, &CoverDownloadWindow::updateEnabled);
}
CoverDownloadDialog::~CoverDownloadDialog()
CoverDownloadWindow::~CoverDownloadWindow()
{
Assert(!m_thread);
}
void CoverDownloadDialog::closeEvent(QCloseEvent* ev)
void CoverDownloadWindow::closeEvent(QCloseEvent* ev)
{
QtUtils::SaveWindowGeometry("CoverDownloadWindow", this);
QWidget::closeEvent(ev);
cancelThread();
emit closed();
}
void CoverDownloadDialog::onDownloadStatus(const QString& text)
void CoverDownloadWindow::onDownloadStatus(const QString& 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.
// 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);
}
void CoverDownloadDialog::onDownloadComplete()
void CoverDownloadWindow::onDownloadComplete()
{
emit coverRefreshRequested();
@ -65,7 +69,7 @@ void CoverDownloadDialog::onDownloadComplete()
m_ui.status->setText(tr("Download complete."));
}
void CoverDownloadDialog::onStartClicked()
void CoverDownloadWindow::onStartClicked()
{
if (m_thread)
cancelThread();
@ -73,15 +77,15 @@ void CoverDownloadDialog::onStartClicked()
startThread();
}
void CoverDownloadDialog::onCloseClicked()
void CoverDownloadWindow::onCloseClicked()
{
if (m_thread)
cancelThread();
reject();
close();
}
void CoverDownloadDialog::updateEnabled()
void CoverDownloadWindow::updateEnabled()
{
const bool running = static_cast<bool>(m_thread);
m_ui.start->setText(running ? tr("Stop") : tr("Start"));
@ -90,18 +94,19 @@ void CoverDownloadDialog::updateEnabled()
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();
connect(m_thread.get(), &CoverDownloadThread::statusUpdated, this, &CoverDownloadDialog::onDownloadStatus);
connect(m_thread.get(), &CoverDownloadThread::progressUpdated, this, &CoverDownloadDialog::onDownloadProgress);
connect(m_thread.get(), &CoverDownloadThread::threadFinished, this, &CoverDownloadDialog::onDownloadComplete);
connect(m_thread.get(), &CoverDownloadThread::statusUpdated, this, &CoverDownloadWindow::onDownloadStatus);
connect(m_thread.get(), &CoverDownloadThread::progressUpdated, this, &CoverDownloadWindow::onDownloadProgress);
connect(m_thread.get(), &CoverDownloadThread::threadFinished, this, &CoverDownloadWindow::onDownloadComplete);
m_thread->start();
updateEnabled();
}
void CoverDownloadDialog::cancelThread()
void CoverDownloadWindow::cancelThread()
{
if (!m_thread)
return;
@ -111,16 +116,16 @@ void CoverDownloadDialog::cancelThread()
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)
{
for (const QString& str : urls.split(QChar('\n')))
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);
}

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
#pragma once
#include "qtprogresscallback.h"
#include "ui_coverdownloadwindow.h"
#include "common/timer.h"
#include "common/types.h"
#include "qtprogresscallback.h"
#include "ui_coverdownloaddialog.h"
#include <QtWidgets/QDialog>
#include <QtWidgets/QWidget>
#include <array>
#include <memory>
#include <string>
class CoverDownloadDialog final : public QDialog
class CoverDownloadWindow final : public QWidget
{
Q_OBJECT
public:
CoverDownloadDialog(QWidget* parent = nullptr);
~CoverDownloadDialog();
CoverDownloadWindow();
~CoverDownloadWindow();
Q_SIGNALS:
void closed();
void coverRefreshRequested();
protected:
@ -51,7 +56,7 @@ private:
void startThread();
void cancelThread();
Ui::CoverDownloadDialog m_ui;
Ui::CoverDownloadWindow m_ui;
std::unique_ptr<CoverDownloadThread> m_thread;
Timer m_last_refresh_time;
};

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
#include "aboutdialog.h"
#include "achievementlogindialog.h"
#include "autoupdaterwindow.h"
#include "coverdownloaddialog.h"
#include "coverdownloadwindow.h"
#include "debuggerwindow.h"
#include "displaywidget.h"
#include "gamelistsettingswidget.h"
@ -834,6 +834,7 @@ void MainWindow::recreate()
void MainWindow::destroySubWindows()
{
QtUtils::CloseAndDeleteWindow(m_cover_download_window);
QtUtils::CloseAndDeleteWindow(m_memory_scanner_window);
QtUtils::CloseAndDeleteWindow(m_debugger_window);
QtUtils::CloseAndDeleteWindow(m_memory_card_editor_window);
@ -2983,10 +2984,26 @@ void MainWindow::onToolsMemoryCardEditorTriggered()
void MainWindow::onToolsCoverDownloaderTriggered()
{
// This can be invoked via big picture, so exit fullscreen.
SystemLock lock(pauseAndLockSystem());
CoverDownloadDialog dlg(lock.getDialogParent());
connect(&dlg, &CoverDownloadDialog::coverRefreshRequested, m_game_list_widget, &GameListWidget::refreshGridCovers);
dlg.exec();
if (isRenderingFullscreen())
{
g_emu_thread->setFullscreen(false, true);
// 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)

View File

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