Skip to content

Commit cde908a

Browse files
committed
Qt: Add Custom background support
1 parent c1f1761 commit cde908a

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

pcsx2-qt/GameList/GameListWidget.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212

1313
#include "common/Assertions.h"
1414
#include "common/Console.h"
15+
#include "common/Path.h"
1516
#include "common/StringUtil.h"
1617

1718
#include "fmt/format.h"
1819

1920
#include <QtCore/QSortFilterProxyModel>
21+
#include <QtCore/QDir>
22+
#include <QtCore/QString>
2023
#include <QtGui/QPainter>
2124
#include <QtGui/QPixmap>
2225
#include <QtGui/QPixmapCache>
2326
#include <QtGui/QWheelEvent>
2427
#include <QtWidgets/QApplication>
28+
#include <QtWidgets/QFileDialog>
2529
#include <QtWidgets/QHeaderView>
2630
#include <QtWidgets/QMenu>
2731
#include <QtWidgets/QScrollBar>
@@ -280,6 +284,92 @@ void GameListWidget::initialize()
280284

281285
updateToolbar();
282286
resizeTableViewColumnsToFit();
287+
setCustomBackground(false);
288+
}
289+
290+
static void resizeAndPadImage(QImage* image, int expected_width, int expected_height, bool fill_with_top_left)
291+
{
292+
const qreal dpr = image->devicePixelRatio();
293+
const int dpr_expected_width = static_cast<int>(static_cast<qreal>(expected_width) * dpr);
294+
const int dpr_expected_height = static_cast<int>(static_cast<qreal>(expected_height) * dpr);
295+
if (image->width() == dpr_expected_width && image->height() == dpr_expected_height)
296+
return;
297+
298+
if ((static_cast<float>(image->width()) / static_cast<float>(image->height())) >=
299+
(static_cast<float>(dpr_expected_width) / static_cast<float>(dpr_expected_height)))
300+
{
301+
*image = image->scaledToWidth(dpr_expected_width, Qt::SmoothTransformation);
302+
}
303+
else
304+
{
305+
*image = image->scaledToHeight(dpr_expected_height, Qt::SmoothTransformation);
306+
}
307+
308+
if (image->width() == dpr_expected_width && image->height() == dpr_expected_height)
309+
return;
310+
311+
int xoffs = 0;
312+
int yoffs = 0;
313+
const int image_width = image->width();
314+
const int image_height = image->height();
315+
if (image_width < dpr_expected_width)
316+
xoffs = static_cast<int>(static_cast<qreal>((dpr_expected_width - image_width) / 2) / dpr);
317+
if (image_height < dpr_expected_height)
318+
yoffs = static_cast<int>(static_cast<qreal>((dpr_expected_height - image_height) / 2) / dpr);
319+
320+
QImage padded_image(dpr_expected_width, dpr_expected_height, QImage::Format_ARGB32);
321+
padded_image.setDevicePixelRatio(dpr);
322+
if (fill_with_top_left)
323+
padded_image.fill(image->pixel(0, 0));
324+
else
325+
padded_image.fill(Qt::transparent);
326+
327+
QPainter painter;
328+
if (painter.begin(&padded_image))
329+
{
330+
painter.setCompositionMode(QPainter::CompositionMode_Source);
331+
painter.drawImage(xoffs, yoffs, *image);
332+
painter.end();
333+
}
334+
335+
*image = std::move(padded_image);
336+
}
337+
338+
void GameListWidget::setCustomBackground(bool reload)
339+
{
340+
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
341+
if (path.empty())
342+
return;
343+
344+
if (!Path::IsAbsolute(path))
345+
path = Path::Combine(EmuFolders::DataRoot, path);
346+
347+
if (reload)
348+
{
349+
m_background_image = QImage();
350+
if (!path.empty() && m_background_image.load(path.c_str()))
351+
m_background_image.setDevicePixelRatio(devicePixelRatio());
352+
}
353+
354+
if (m_background_image.isNull() || path.empty())
355+
{
356+
m_ui.stack->setPalette(QApplication::palette());
357+
m_table_view->setAlternatingRowColors(true);
358+
return;
359+
}
360+
361+
int widget_width = m_ui.stack->width();
362+
int widget_height = m_ui.stack->height();
363+
364+
resizeAndPadImage(&m_background_image, widget_width, widget_height, false);
365+
366+
if (widget_width != m_ui.stack->width() || widget_height != m_ui.stack->height())
367+
return;
368+
369+
m_table_view->setAlternatingRowColors(false);
370+
QPalette new_palette(m_ui.stack->palette());
371+
new_palette.setBrush(QPalette::Base, QPixmap::fromImage(m_background_image));
372+
m_ui.stack->setPalette(new_palette);
283373
}
284374

285375
bool GameListWidget::isShowingGameList() const
@@ -467,6 +557,28 @@ void GameListWidget::refreshGridCovers()
467557
m_model->refreshCovers();
468558
}
469559

560+
void GameListWidget::onViewSetGameListBackgroundTriggered()
561+
{
562+
const QString path = QDir::toNativeSeparators(
563+
QFileDialog::getOpenFileName(this, tr("Select Background Image"), QString(), tr("Supported Image Types (*.jpg *.jpeg *.png *.webp)")));
564+
if (path.isEmpty())
565+
return;
566+
567+
std::string relative_path = Path::MakeRelative(QDir::toNativeSeparators(path).toStdString(), EmuFolders::DataRoot);
568+
Host::SetBaseStringSettingValue("UI", "GameListBackgroundPath", relative_path.c_str());
569+
Host::CommitBaseSettingChanges();
570+
setCustomBackground(true);
571+
}
572+
573+
void GameListWidget::onViewClearGameListBackgroundTriggered()
574+
{
575+
Host::RemoveBaseSettingValue("UI", "GameListBackgroundPath");
576+
Host::CommitBaseSettingChanges();
577+
updateToolbar();
578+
resizeTableViewColumnsToFit();
579+
setCustomBackground(true);
580+
}
581+
470582
void GameListWidget::showGameList()
471583
{
472584
if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
@@ -545,6 +657,7 @@ void GameListWidget::resizeEvent(QResizeEvent* event)
545657
QWidget::resizeEvent(event);
546658
resizeTableViewColumnsToFit();
547659
m_model->updateCacheSize(width(), height());
660+
setCustomBackground(true);
548661
}
549662

550663
void GameListWidget::resizeTableViewColumnsToFit()

pcsx2-qt/GameList/GameListWidget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class GameListWidget : public QWidget
4848
void refresh(bool invalidate_cache);
4949
void cancelRefresh();
5050
void reloadThemeSpecificImages();
51+
void setCustomBackground(bool reload);
5152

5253
bool isShowingGameList() const;
5354
bool isShowingGameGrid() const;
@@ -90,6 +91,8 @@ public Q_SLOTS:
9091
void gridZoomOut();
9192
void gridIntScale(int int_scale);
9293
void refreshGridCovers();
94+
void onViewSetGameListBackgroundTriggered();
95+
void onViewClearGameListBackgroundTriggered();
9396

9497
protected:
9598
void resizeEvent(QResizeEvent* event);
@@ -114,4 +117,6 @@ public Q_SLOTS:
114117
Ui::EmptyGameListWidget m_empty_ui;
115118

116119
GameListRefreshThread* m_refresh_thread = nullptr;
120+
121+
QImage m_background_image;
117122
};

pcsx2-qt/MainWindow.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ void MainWindow::connectSignals()
385385
m_game_list_widget->gridZoomOut();
386386
});
387387
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers);
388+
connect(m_ui.actionSetGameListBackground, &QAction::triggered, m_game_list_widget, &GameListWidget::onViewSetGameListBackgroundTriggered);
389+
connect(m_ui.actionClearGameListBackground, &QAction::triggered, m_game_list_widget, &GameListWidget::onViewClearGameListBackgroundTriggered);
388390
connect(m_game_list_widget, &GameListWidget::layoutChange, this, [this]() {
389391
QSignalBlocker sb(m_ui.actionGridViewShowTitles);
390392
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());

pcsx2-qt/MainWindow.ui

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<x>0</x>
3232
<y>0</y>
3333
<width>1050</width>
34-
<height>27</height>
34+
<height>28</height>
3535
</rect>
3636
</property>
3737
<widget class="QMenu" name="menuSystem">
@@ -176,6 +176,9 @@
176176
<addaction name="actionGridViewZoomIn"/>
177177
<addaction name="actionGridViewZoomOut"/>
178178
<addaction name="actionGridViewRefreshCovers"/>
179+
<addaction name="separator"/>
180+
<addaction name="actionSetGameListBackground"/>
181+
<addaction name="actionClearGameListBackground"/>
179182
</widget>
180183
<widget class="QMenu" name="menuTools">
181184
<property name="title">
@@ -1056,6 +1059,22 @@
10561059
<string>Edit &amp;Patches...</string>
10571060
</property>
10581061
</action>
1062+
<action name="actionSetGameListBackground">
1063+
<property name="text">
1064+
<string>Set Custom Background</string>
1065+
</property>
1066+
<property name="icon">
1067+
<iconset theme="artboard-2-line"/>
1068+
</property>
1069+
</action>
1070+
<action name="actionClearGameListBackground">
1071+
<property name="text">
1072+
<string>Clear Custom Background</string>
1073+
</property>
1074+
<property name="icon">
1075+
<iconset theme="trash-fill"/>
1076+
</property>
1077+
</action>
10591078
</widget>
10601079
<resources>
10611080
<include location="resources/resources.qrc"/>

0 commit comments

Comments
 (0)