mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Qt: Refactor background movie handling and improve pixmap scaling
Co-authored-by: KamFretoZ <14798312+kamfretoz@users.noreply.github.com>
This commit is contained in:
parent
d0c54de330
commit
580cf70d06
@ -220,6 +220,8 @@ void GameListWidget::initialize()
|
||||
m_sort_model->setSourceModel(m_model);
|
||||
|
||||
m_ui.setupUi(this);
|
||||
m_ui.stack->installEventFilter(this);
|
||||
m_ui.stack->setAutoFillBackground(false);
|
||||
|
||||
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
|
||||
{
|
||||
@ -353,6 +355,7 @@ void GameListWidget::setCustomBackground()
|
||||
m_background_movie = nullptr;
|
||||
}
|
||||
|
||||
// Get the path to the custom background
|
||||
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
||||
if (!Path::IsAbsolute(path))
|
||||
path = Path::Combine(EmuFolders::DataRoot, path);
|
||||
@ -360,27 +363,26 @@ void GameListWidget::setCustomBackground()
|
||||
// Only try to create background if path are valid
|
||||
if (!path.empty() && FileSystem::FileExists(path.c_str()))
|
||||
{
|
||||
QMovie* new_movie;
|
||||
QString img_path = QString::fromStdString(path);
|
||||
if (img_path.endsWith(".png", Qt::CaseInsensitive))
|
||||
// Use apng plugin
|
||||
new_movie = new QMovie(img_path, "apng", this);
|
||||
else
|
||||
new_movie = new QMovie(img_path, QByteArray(), this);
|
||||
|
||||
if (new_movie->isValid())
|
||||
m_background_movie = new_movie;
|
||||
else
|
||||
const QByteArray format = (img_path.endsWith(".png", Qt::CaseInsensitive)) ? QByteArray("apng") : QByteArray();
|
||||
m_background_movie = new QMovie(img_path, format, this);
|
||||
if (!m_background_movie->isValid())
|
||||
{
|
||||
Console.Warning("Failed to load background movie from: %s", path.c_str());
|
||||
delete new_movie;
|
||||
delete m_background_movie;
|
||||
m_background_movie = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no valid background then reset fallback to default UI state
|
||||
if (!m_background_movie)
|
||||
{
|
||||
m_ui.stack->setPalette(QApplication::palette());
|
||||
m_background_pixmap = QPixmap();
|
||||
m_ui.stack->setAutoFillBackground(true);
|
||||
m_table_view->viewport()->setAutoFillBackground(true);
|
||||
m_list_view->viewport()->setAutoFillBackground(true);
|
||||
|
||||
m_ui.stack->update();
|
||||
m_table_view->setAlternatingRowColors(true);
|
||||
return;
|
||||
}
|
||||
@ -390,7 +392,7 @@ void GameListWidget::setCustomBackground()
|
||||
const std::string ar_value = Host::GetBaseStringSettingValue("UI", "GameListBackgroundMode", InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[static_cast<u8>(QtUtils::ScalingMode::Fit)]);
|
||||
for (u8 i = 0; i < static_cast<u8>(QtUtils::ScalingMode::MaxCount); i++)
|
||||
{
|
||||
if (!(InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i] == nullptr))
|
||||
if (InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i] != nullptr)
|
||||
{
|
||||
if (ar_value == InterfaceSettingsWidget::BACKGROUND_SCALE_NAMES[i])
|
||||
{
|
||||
@ -405,8 +407,13 @@ void GameListWidget::setCustomBackground()
|
||||
|
||||
// Selected Custom background is valid, connect the signals and start animation in gamelist
|
||||
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
|
||||
m_ui.stack->setAutoFillBackground(false);
|
||||
|
||||
m_table_view->viewport()->setAutoFillBackground(false);
|
||||
m_list_view->viewport()->setAutoFillBackground(false);
|
||||
updateCustomBackgroundState(true);
|
||||
m_table_view->setAlternatingRowColors(false);
|
||||
processBackgroundFrames();
|
||||
}
|
||||
|
||||
void GameListWidget::updateCustomBackgroundState(const bool force_start)
|
||||
@ -422,7 +429,7 @@ void GameListWidget::updateCustomBackgroundState(const bool force_start)
|
||||
|
||||
void GameListWidget::processBackgroundFrames()
|
||||
{
|
||||
if (m_background_movie && m_background_movie->isValid())
|
||||
if (m_background_movie && m_background_movie->isValid() && isVisible())
|
||||
{
|
||||
const int widget_width = m_ui.stack->width();
|
||||
const int widget_height = m_ui.stack->height();
|
||||
@ -435,9 +442,8 @@ void GameListWidget::processBackgroundFrames()
|
||||
|
||||
QtUtils::resizeAndScalePixmap(&pm, widget_width, widget_height, dpr, m_background_scaling, m_background_opacity);
|
||||
|
||||
QPalette bg_palette(m_ui.stack->palette());
|
||||
bg_palette.setBrush(QPalette::Base, pm);
|
||||
m_ui.stack->setPalette(bg_palette);
|
||||
m_background_pixmap = std::move(pm);
|
||||
m_ui.stack->update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,6 +731,7 @@ bool GameListWidget::event(QEvent* event)
|
||||
if (event->type() == QEvent::DevicePixelRatioChange)
|
||||
{
|
||||
m_model->setDevicePixelRatio(devicePixelRatioF());
|
||||
processBackgroundFrames();
|
||||
QWidget::event(event);
|
||||
return true;
|
||||
}
|
||||
@ -732,6 +739,25 @@ bool GameListWidget::event(QEvent* event)
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
bool GameListWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
if (watched == m_ui.stack && event->type() == QEvent::Paint)
|
||||
{
|
||||
if (!m_background_pixmap.isNull())
|
||||
{
|
||||
QPainter painter(m_ui.stack);
|
||||
const auto* paint_event = static_cast<QPaintEvent*>(event);
|
||||
painter.save();
|
||||
painter.setClipRect(paint_event->rect());
|
||||
painter.drawTiledPixmap(m_ui.stack->rect(), m_background_pixmap);
|
||||
painter.restore();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void GameListWidget::resizeTableViewColumnsToFit()
|
||||
{
|
||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||
|
||||
@ -10,7 +10,9 @@
|
||||
#include "pcsx2/GameList.h"
|
||||
|
||||
#include <QtGui/QMovie>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtWidgets/QListView>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
#include <QtWidgets/QTableView>
|
||||
|
||||
Q_DECLARE_METATYPE(const GameList::Entry*);
|
||||
@ -101,6 +103,7 @@ protected:
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
private:
|
||||
void loadTableHeaderState();
|
||||
@ -123,6 +126,7 @@ private:
|
||||
GameListRefreshThread* m_refresh_thread = nullptr;
|
||||
|
||||
QMovie* m_background_movie = nullptr;
|
||||
QPixmap m_background_pixmap;
|
||||
QtUtils::ScalingMode m_background_scaling = QtUtils::ScalingMode::Fit;
|
||||
float m_background_opacity = 100.0f;
|
||||
};
|
||||
|
||||
@ -1192,6 +1192,12 @@ void MainWindow::cancelGameListRefresh()
|
||||
m_game_list_widget->cancelRefresh();
|
||||
}
|
||||
|
||||
void MainWindow::updateGameListBackground()
|
||||
{
|
||||
if (m_game_list_widget)
|
||||
m_game_list_widget->setCustomBackground();
|
||||
}
|
||||
|
||||
void MainWindow::reportInfo(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::information(this, title, message);
|
||||
|
||||
@ -116,6 +116,7 @@ public Q_SLOTS:
|
||||
void checkForUpdates(bool display_message, bool force_check);
|
||||
void refreshGameList(bool invalidate_cache, bool popup_on_error);
|
||||
void cancelGameListRefresh();
|
||||
void updateGameListBackground();
|
||||
void reportInfo(const QString& title, const QString& message);
|
||||
void reportError(const QString& title, const QString& message);
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
|
||||
@ -194,6 +194,9 @@ void EmuThread::stopFullscreenUI()
|
||||
{
|
||||
m_run_fullscreen_ui.store(false, std::memory_order_release);
|
||||
emit onFullscreenUIStateChange(false);
|
||||
|
||||
// Resume and refresh background when FullscreenUI exits
|
||||
QMetaObject::invokeMethod(g_main_window, "updateGameListBackground", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -141,9 +141,16 @@ namespace QtUtils
|
||||
|
||||
void resizeAndScalePixmap(QPixmap* pm, const int expected_width, const int expected_height, const qreal dpr, const ScalingMode scaling_mode, const float opacity)
|
||||
{
|
||||
if (!pm || pm->isNull() || pm->width() <= 0 || pm->height() <= 0)
|
||||
if (!pm || pm->width() <= 0 || pm->height() <= 0)
|
||||
return;
|
||||
|
||||
if (dpr <= 0.0)
|
||||
{
|
||||
Console.ErrorFmt("resizeAndScalePixmap: Invalid device pixel ratio ({}) - pixmap will be null", dpr);
|
||||
*pm = QPixmap();
|
||||
return;
|
||||
}
|
||||
|
||||
const int dpr_expected_width = qRound(expected_width * dpr);
|
||||
const int dpr_expected_height = qRound(expected_height * dpr);
|
||||
|
||||
@ -196,8 +203,7 @@ namespace QtUtils
|
||||
qRound(scaledSize.width()),
|
||||
qRound(scaledSize.height()),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation
|
||||
);
|
||||
Qt::SmoothTransformation);
|
||||
|
||||
const QRectF scaledSrcRect(0, 0, pm->width(), pm->height());
|
||||
|
||||
@ -211,16 +217,7 @@ namespace QtUtils
|
||||
}
|
||||
case ScalingMode::Stretch:
|
||||
{
|
||||
*pm = pm->scaled(
|
||||
dpr_expected_width,
|
||||
dpr_expected_height,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation
|
||||
);
|
||||
|
||||
const QRectF scaledSrcRect(0, 0, pm->width(), pm->height());
|
||||
|
||||
painter.drawPixmap(painterRect, *pm, scaledSrcRect);
|
||||
painter.drawPixmap(painterRect, *pm, srcRect);
|
||||
break;
|
||||
}
|
||||
case ScalingMode::Center:
|
||||
@ -229,7 +226,6 @@ namespace QtUtils
|
||||
const qreal pmHeight = pm->height() / dpr;
|
||||
|
||||
QRectF destRect(0, 0, pmWidth, pmHeight);
|
||||
|
||||
destRect.moveCenter(painterRect.center());
|
||||
|
||||
painter.drawPixmap(destRect, *pm, srcRect);
|
||||
@ -243,13 +239,19 @@ namespace QtUtils
|
||||
if (tileWidth <= 0 || tileHeight <= 0)
|
||||
break;
|
||||
|
||||
QPixmap tileSource = pm->scaled(tileWidth, tileHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
tileSource.setDevicePixelRatio(dpr);
|
||||
|
||||
QBrush tileBrush(tileSource);
|
||||
tileBrush.setTextureImage(tileSource.toImage());
|
||||
|
||||
painter.fillRect(painterRect, tileBrush);
|
||||
if (pm->devicePixelRatio() == dpr)
|
||||
{
|
||||
QBrush tileBrush(*pm);
|
||||
painter.fillRect(painterRect, tileBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
QPixmap tileSource = pm->scaled(tileWidth, tileHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
tileSource.setDevicePixelRatio(dpr);
|
||||
QBrush tileBrush(tileSource);
|
||||
tileBrush.setTextureImage(tileSource.toImage());
|
||||
painter.fillRect(painterRect, tileBrush);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@ -266,7 +266,7 @@ void InterfaceSettingsWidget::onSetGameListBackgroundTriggered()
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
std::string relative_path = Path::MakeRelative(QDir::toNativeSeparators(path).toStdString(), EmuFolders::DataRoot);
|
||||
std::string relative_path = Path::MakeRelative(path.toStdString(), EmuFolders::DataRoot);
|
||||
Host::SetBaseStringSettingValue("UI", "GameListBackgroundPath", relative_path.c_str());
|
||||
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user