Skip to content

Commit a080228

Browse files
committed
Qt: Don't reset model for every scanned game
Make the UI a little more responsive.
1 parent 2669b02 commit a080228

File tree

4 files changed

+58
-74
lines changed

4 files changed

+58
-74
lines changed

src/duckstation-qt/gamelistrefreshthread.cpp

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,30 @@
1414

1515
#include "moc_gamelistrefreshthread.cpp"
1616

17-
AsyncRefreshProgressCallback::AsyncRefreshProgressCallback(GameListRefreshThread* parent) : m_parent(parent)
17+
GameListRefreshThread::GameListRefreshThread(bool invalidate_cache) : QThread(), m_invalidate_cache(invalidate_cache)
1818
{
1919
}
2020

21-
float AsyncRefreshProgressCallback::timeSinceStart() const
22-
{
23-
return m_start_time.GetTimeSeconds();
24-
}
21+
GameListRefreshThread::~GameListRefreshThread() = default;
2522

26-
void AsyncRefreshProgressCallback::Cancel()
23+
void GameListRefreshThread::cancel()
2724
{
2825
// Not atomic, but we don't need to cancel immediately.
2926
m_cancelled = true;
3027
}
3128

32-
void AsyncRefreshProgressCallback::PushState()
29+
void GameListRefreshThread::run()
30+
{
31+
GameList::Refresh(m_invalidate_cache, false, this);
32+
emit refreshComplete();
33+
}
34+
35+
void GameListRefreshThread::PushState()
3336
{
3437
ProgressCallback::PushState();
3538
}
3639

37-
void AsyncRefreshProgressCallback::PopState()
40+
void GameListRefreshThread::PopState()
3841
{
3942
ProgressCallback::PopState();
4043

@@ -46,7 +49,7 @@ void AsyncRefreshProgressCallback::PopState()
4649
fireUpdate();
4750
}
4851

49-
void AsyncRefreshProgressCallback::SetStatusText(const std::string_view text)
52+
void GameListRefreshThread::SetStatusText(const std::string_view text)
5053
{
5154
const QString new_text = QtUtils::StringViewToQString(text);
5255
if (new_text == m_status_text)
@@ -56,7 +59,7 @@ void AsyncRefreshProgressCallback::SetStatusText(const std::string_view text)
5659
fireUpdate();
5760
}
5861

59-
void AsyncRefreshProgressCallback::SetProgressRange(u32 range)
62+
void GameListRefreshThread::SetProgressRange(u32 range)
6063
{
6164
ProgressCallback::SetProgressRange(range);
6265
if (static_cast<int>(m_progress_range) == m_last_range)
@@ -66,7 +69,7 @@ void AsyncRefreshProgressCallback::SetProgressRange(u32 range)
6669
fireUpdate();
6770
}
6871

69-
void AsyncRefreshProgressCallback::SetProgressValue(u32 value)
72+
void GameListRefreshThread::SetProgressValue(u32 value)
7073
{
7174
ProgressCallback::SetProgressValue(value);
7275
if (static_cast<int>(m_progress_value) == m_last_value)
@@ -76,46 +79,24 @@ void AsyncRefreshProgressCallback::SetProgressValue(u32 value)
7679
fireUpdate();
7780
}
7881

79-
void AsyncRefreshProgressCallback::ModalError(const std::string_view message)
82+
void GameListRefreshThread::ModalError(const std::string_view message)
8083
{
8184
QMessageBox::critical(nullptr, QStringLiteral("Error"), QtUtils::StringViewToQString(message));
8285
}
8386

84-
bool AsyncRefreshProgressCallback::ModalConfirmation(const std::string_view message)
87+
bool GameListRefreshThread::ModalConfirmation(const std::string_view message)
8588
{
8689
return QMessageBox::question(nullptr, QStringLiteral("Question"), QtUtils::StringViewToQString(message)) ==
8790
QMessageBox::Yes;
8891
}
8992

90-
void AsyncRefreshProgressCallback::ModalInformation(const std::string_view message)
93+
void GameListRefreshThread::ModalInformation(const std::string_view message)
9194
{
9295
QMessageBox::information(nullptr, QStringLiteral("Information"), QtUtils::StringViewToQString(message));
9396
}
9497

95-
void AsyncRefreshProgressCallback::fireUpdate()
96-
{
97-
m_parent->refreshProgress(m_status_text, m_last_value, m_last_range, m_start_time.GetTimeSeconds());
98-
}
99-
100-
GameListRefreshThread::GameListRefreshThread(bool invalidate_cache)
101-
: QThread(), m_progress(this), m_invalidate_cache(invalidate_cache)
102-
{
103-
}
104-
105-
GameListRefreshThread::~GameListRefreshThread() = default;
106-
107-
float GameListRefreshThread::timeSinceStart() const
98+
void GameListRefreshThread::fireUpdate()
10899
{
109-
return m_progress.timeSinceStart();
110-
}
111-
112-
void GameListRefreshThread::cancel()
113-
{
114-
m_progress.Cancel();
115-
}
116-
117-
void GameListRefreshThread::run()
118-
{
119-
GameList::Refresh(m_invalidate_cache, false, &m_progress);
120-
emit refreshComplete();
100+
emit refreshProgress(m_status_text, m_last_value, m_last_range, static_cast<int>(GameList::GetEntryCount()),
101+
m_start_time.GetTimeSeconds());
121102
}

src/duckstation-qt/gamelistrefreshthread.h

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,26 @@
88
#include "common/progress_callback.h"
99
#include "common/timer.h"
1010

11-
class GameListRefreshThread;
12-
13-
class AsyncRefreshProgressCallback : public ProgressCallback
11+
class GameListRefreshThread final : public QThread, public ProgressCallback
1412
{
13+
Q_OBJECT
14+
1515
public:
16-
explicit AsyncRefreshProgressCallback(GameListRefreshThread* parent);
16+
explicit GameListRefreshThread(bool invalidate_cache);
17+
~GameListRefreshThread();
1718

1819
float timeSinceStart() const;
1920

20-
void Cancel();
21+
void cancel();
22+
23+
Q_SIGNALS:
24+
void refreshProgress(const QString& status, int current, int total, int entry_count, float time);
25+
void refreshComplete();
2126

27+
protected:
28+
void run() final;
29+
30+
private:
2231
void PushState() override;
2332
void PopState() override;
2433

@@ -30,36 +39,11 @@ class AsyncRefreshProgressCallback : public ProgressCallback
3039
bool ModalConfirmation(const std::string_view message) override;
3140
void ModalInformation(const std::string_view message) override;
3241

33-
private:
3442
void fireUpdate();
3543

36-
GameListRefreshThread* m_parent;
3744
Timer m_start_time;
3845
QString m_status_text;
3946
int m_last_range = 1;
4047
int m_last_value = 0;
41-
};
42-
43-
class GameListRefreshThread final : public QThread
44-
{
45-
Q_OBJECT
46-
47-
public:
48-
explicit GameListRefreshThread(bool invalidate_cache);
49-
~GameListRefreshThread();
50-
51-
float timeSinceStart() const;
52-
53-
void cancel();
54-
55-
Q_SIGNALS:
56-
void refreshProgress(const QString& status, int current, int total, float time);
57-
void refreshComplete();
58-
59-
protected:
60-
void run() final;
61-
62-
private:
63-
AsyncRefreshProgressCallback m_progress;
6448
bool m_invalidate_cache;
6549
};

src/duckstation-qt/gamelistwidget.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <QtWidgets/QScrollBar>
3333
#include <QtWidgets/QStyledItemDelegate>
3434
#include <algorithm>
35+
#include <limits>
3536

3637
#include "moc_gamelistwidget.cpp"
3738

@@ -1281,6 +1282,7 @@ void GameListWidget::refresh(bool invalidate_cache)
12811282
Qt::QueuedConnection);
12821283
connect(m_refresh_thread, &GameListRefreshThread::refreshComplete, this, &GameListWidget::onRefreshComplete,
12831284
Qt::QueuedConnection);
1285+
m_refresh_last_entry_count = std::numeric_limits<int>::max(); // force reset on first progress update
12841286
m_refresh_thread->start();
12851287
}
12861288

@@ -1336,12 +1338,25 @@ void GameListWidget::updateBackground(bool reload_image)
13361338
});
13371339
}
13381340

1339-
void GameListWidget::onRefreshProgress(const QString& status, int current, int total, float time)
1341+
void GameListWidget::onRefreshProgress(const QString& status, int current, int total, int entry_count, float time)
13401342
{
13411343
// Avoid spamming the UI on very short refresh (e.g. game exit).
13421344
static constexpr float SHORT_REFRESH_TIME = 0.5f;
13431345
if (!m_model->hasTakenGameList())
1344-
m_model->refresh();
1346+
{
1347+
if (entry_count > m_refresh_last_entry_count)
1348+
{
1349+
m_model->beginInsertRows(QModelIndex(), m_refresh_last_entry_count, entry_count - 1);
1350+
m_model->endInsertRows();
1351+
}
1352+
else
1353+
{
1354+
m_model->beginResetModel();
1355+
m_model->endResetModel();
1356+
}
1357+
1358+
m_refresh_last_entry_count = entry_count;
1359+
}
13451360

13461361
// switch away from the placeholder while we scan, in case we find anything
13471362
if (m_ui.stack->currentIndex() == 2)

src/duckstation-qt/gamelistwidget.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ Q_DECLARE_METATYPE(const GameList::Entry*);
2727

2828
class GameListSortModel;
2929
class GameListRefreshThread;
30+
class GameListWidget;
3031

3132
class GameListModel final : public QAbstractTableModel
3233
{
3334
Q_OBJECT
3435

36+
friend GameListWidget;
37+
3538
public:
3639
enum Column : int
3740
{
@@ -242,7 +245,7 @@ class GameListWidget final : public QWidget
242245
void addGameDirectoryRequested();
243246

244247
private Q_SLOTS:
245-
void onRefreshProgress(const QString& status, int current, int total, float time);
248+
void onRefreshProgress(const QString& status, int current, int total, int entry_count, float time);
246249
void onRefreshComplete();
247250

248251
void onCoverScaleChanged(float scale);
@@ -280,7 +283,8 @@ public Q_SLOTS:
280283
QWidget* m_empty_widget = nullptr;
281284
Ui::EmptyGameListWidget m_empty_ui;
282285

283-
GameListRefreshThread* m_refresh_thread = nullptr;
284-
285286
QImage m_background_image;
287+
288+
GameListRefreshThread* m_refresh_thread = nullptr;
289+
int m_refresh_last_entry_count = 0;
286290
};

0 commit comments

Comments
 (0)