Qt: Add option to fill custom background

This commit is contained in:
KamFretoZ 2025-09-09 21:26:50 +07:00 committed by Ty
parent fbbd11bc18
commit a635796b12
5 changed files with 52 additions and 32 deletions

View File

@ -304,7 +304,7 @@ void GameListWidget::initialize()
setCustomBackground();
}
static void resizeAndPadImage(QImage* image, int expected_width, int expected_height, bool fill_with_top_left)
static void resizeAndPadImage(QImage* image, int expected_width, int expected_height, bool fill_with_top_left, bool expand_to_fill)
{
const qreal dpr = image->devicePixelRatio();
const int dpr_expected_width = static_cast<int>(static_cast<qreal>(expected_width) * dpr);
@ -313,8 +313,8 @@ static void resizeAndPadImage(QImage* image, int expected_width, int expected_he
return;
// Resize
if ((static_cast<float>(image->width()) / static_cast<float>(image->height())) >=
(static_cast<float>(dpr_expected_width) / static_cast<float>(dpr_expected_height)))
if (((static_cast<float>(image->width()) / static_cast<float>(image->height())) >=
(static_cast<float>(dpr_expected_width) / static_cast<float>(dpr_expected_height))) != expand_to_fill)
{
*image = image->scaledToWidth(dpr_expected_width, Qt::SmoothTransformation);
}
@ -331,9 +331,9 @@ static void resizeAndPadImage(QImage* image, int expected_width, int expected_he
int yoffs = 0;
const int image_width = image->width();
const int image_height = image->height();
if (image_width < dpr_expected_width)
if ((image_width < dpr_expected_width) != expand_to_fill)
xoffs = static_cast<int>(static_cast<qreal>((dpr_expected_width - image_width) / 2) / dpr);
if (image_height < dpr_expected_height)
if ((image_height < dpr_expected_height) != expand_to_fill)
yoffs = static_cast<int>(static_cast<qreal>((dpr_expected_height - image_height) / 2) / dpr);
QImage padded_image(dpr_expected_width, dpr_expected_height, QImage::Format_ARGB32);
@ -348,7 +348,7 @@ static void resizeAndPadImage(QImage* image, int expected_width, int expected_he
const float opacity = Host::GetBaseFloatSettingValue("UI", "GameListBackgroundOpacity");
if (painter.begin(&padded_image))
{
painter.setOpacity((static_cast<float>(opacity / 100.0f))); // Qt expect range from 0.0 to 1.0
painter.setOpacity((static_cast<float>(opacity / 100.0f))); // Qt expects the range to be from 0.0 to 1.0
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(xoffs, yoffs, *image);
painter.end();
@ -361,6 +361,7 @@ void GameListWidget::setCustomBackground(bool force_refresh)
{
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
bool enabled = Host::GetBaseBoolSettingValue("UI", "GameListBackgroundEnabled");
bool fill = Host::GetBaseBoolSettingValue("UI", "GameListBackgroundFill");
// Cleanup old animation if it still exists on gamelist
if (m_background_movie != nullptr)
@ -400,7 +401,7 @@ void GameListWidget::setCustomBackground(bool force_refresh)
}
// Background is valid, connect the signals and start animation in gamelist
connect(m_background_movie, &QMovie::frameChanged, this, [this]() { processBackgroundFrames(); });
connect(m_background_movie, &QMovie::frameChanged, this, [this, fill]() { processBackgroundFrames(fill); });
updateCustomBackgroundState(force_refresh);
m_table_view->setAlternatingRowColors(false);
@ -417,14 +418,14 @@ void GameListWidget::updateCustomBackgroundState(bool force_start)
}
}
void GameListWidget::processBackgroundFrames()
void GameListWidget::processBackgroundFrames(bool fill_area)
{
QImage img = m_background_movie->currentImage();
img.setDevicePixelRatio(devicePixelRatioF());
const int widget_width = m_ui.stack->width();
const int widget_height = m_ui.stack->height();
resizeAndPadImage(&img, widget_width, widget_height, false);
resizeAndPadImage(&img, widget_width, widget_height, false, fill_area);
QPalette new_palette(m_ui.stack->palette());
new_palette.setBrush(QPalette::Base, img);

View File

@ -51,7 +51,7 @@ public:
void reloadThemeSpecificImages();
void setCustomBackground(bool force = false);
void updateCustomBackgroundState(bool force_start = false);
void processBackgroundFrames();
void processBackgroundFrames(bool fill_area);
bool isShowingGameList() const;
bool isShowingGameGrid() const;

View File

@ -1263,7 +1263,7 @@ namespace SettingWidgetBinder
static inline void BindWidgetToFileSetting(SettingsInterface* sif, QLineEdit* widget, QAbstractButton* browse_button,
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
const char* filter, bool allow_pergame = true, bool use_relative = true)
const char* filter, bool allow_pergame = false, bool use_relative = true)
{
using Accessor = SettingAccessor<QLineEdit>;

View File

@ -110,9 +110,11 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.backgroundOpacity, "UI", "GameListBackgroundOpacity", 100);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.backgroundFill, "UI", "GameListBackgroundFill", false);
connect(m_ui.backgroundBrowse, &QPushButton::clicked, [this]() { onSetGameListBackgroundTriggered(); });
connect(m_ui.backgroundReset, &QPushButton::clicked, [this]() { onClearGameListBackgroundTriggered(); });
connect(m_ui.backgroundOpacity, &QSpinBox::valueChanged, [this]() { emit backgroundChanged(); });
connect(m_ui.backgroundFill, &QCheckBox::checkStateChanged, [this]() {emit backgroundChanged(); });
populateLanguages();
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.language, "UI", "Language", QtHost::GetDefaultLanguage());
@ -195,9 +197,18 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
m_ui.startFullscreenUI, tr("Start Big Picture Mode"), tr("Unchecked"),
tr("Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches."));
dialog()->registerWidgetHelp(
m_ui.backgroundBrowse, tr("Game List Background"), tr("Any"),
m_ui.backgroundBrowse, tr("Game List Background"), tr("None"),
tr("Enable an animated / static background on the game list (where you launch your games).<br>"
"This background is only visible in the library and will be hidden once a game is launched. It will also be paused when it's not in focus."));
dialog()->registerWidgetHelp(
m_ui.backgroundReset, tr("Disable/Reset Game List Background"), tr("None"),
tr("Disable and reset the currently applied game list background."));
dialog()->registerWidgetHelp(
m_ui.backgroundOpacity, tr("Game List Background Opacity"), tr("100%"),
tr("Sets the opacity of the custom background."));
dialog()->registerWidgetHelp(
m_ui.backgroundFill, tr("Fill Image"), tr("Unchecked"),
tr("Expand the image to fill all available background area."));
onRenderToSeparateWindowChanged();
}
@ -219,6 +230,7 @@ void InterfaceSettingsWidget::onSetGameListBackgroundTriggered()
{
const QString path = QDir::toNativeSeparators(
QFileDialog::getOpenFileName(this, tr("Select Background Image"), QString(), IMAGE_FILE_FILTER));
if (path.isEmpty())
return;

View File

@ -145,6 +145,19 @@
<string>Appearance</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QComboBox" name="theme"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>Language:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="language"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="themeLabel">
<property name="text">
@ -152,6 +165,13 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="backgroundLabel">
<property name="text">
<string>Game List Background:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="backgroundPathLayout">
<item>
@ -218,28 +238,15 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="backgroundFill">
<property name="text">
<string>Fill Image</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="backgroundLabel">
<property name="text">
<string>Game List Background:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="language"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>Language:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="theme"/>
</item>
</layout>
</widget>
</item>