1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-21 18:22:33 +01:00

Qt: implement hover pam in game list

This commit is contained in:
Megamouse 2023-11-23 00:38:40 +01:00
parent aae155e954
commit 4dfda3240c
7 changed files with 169 additions and 34 deletions

View File

@ -22,4 +22,13 @@ struct GameInfo
u32 resolution = 0;
u64 size_on_disk = umax;
std::string get_pam_path() const
{
if (icon_path.empty())
{
return {};
}
return icon_path.substr(0, icon_path.find_last_of("/")) + "/ICON1.PAM";
}
};

View File

@ -19,6 +19,7 @@ struct gui_game_info
bool hasCustomConfig = false;
bool hasCustomPadConfig = false;
bool has_hover_gif = false;
bool has_hover_pam = false;
movie_item_base* item = nullptr;
};

View File

@ -614,6 +614,7 @@ void game_list_frame::OnParsingFinished()
info.hasCustomConfig = fs::is_file(rpcs3::utils::get_custom_config_path(info.info.serial));
info.hasCustomPadConfig = fs::is_file(rpcs3::utils::get_custom_input_config_path(info.info.serial));
info.has_hover_gif = fs::is_file(game_icon_path + info.info.serial + "/hover.gif");
info.has_hover_pam = fs::is_file(info.info.get_pam_path());
m_games.push(std::make_shared<gui_game_info>(std::move(info)));
};

View File

@ -75,16 +75,16 @@ void game_list_grid::populate(
item->setToolTip(tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes));
}
item->set_icon_func([this, item, game](int)
item->set_icon_func([this, item, game](const QVideoFrame& frame)
{
if (!item || !game)
{
return;
}
if (std::shared_ptr<QMovie> movie = item->movie(); movie && item->get_active())
if (const QPixmap pixmap = item->get_movie_image(frame); item->get_active() && !pixmap.isNull())
{
item->set_icon(gui::utils::get_centered_pixmap(movie->currentPixmap(), m_icon_size, 0, 0, 1.0, Qt::FastTransformation));
item->set_icon(gui::utils::get_centered_pixmap(pixmap, m_icon_size, 0, 0, 1.0, Qt::FastTransformation));
}
else
{
@ -92,21 +92,22 @@ void game_list_grid::populate(
item->set_icon(game->pxmap);
if (!game->has_hover_gif)
if (!game->has_hover_gif && !game->has_hover_pam)
{
game->pxmap = {};
}
if (movie)
{
movie->stop();
}
item->stop_movie();
}
});
if (play_hover_movies && game->has_hover_gif)
{
item->init_movie(game_icon_path % serial % "/hover.gif");
item->set_movie_path(game_icon_path % serial % "/hover.gif");
}
else if (play_hover_movies && game->has_hover_pam)
{
item->set_movie_path(QString::fromStdString(game->info.get_pam_path()));
}
if (selected_item_id == game->info.path + game->info.icon_path)

View File

@ -235,16 +235,16 @@ void game_list_table::populate(
custom_table_widget_item* icon_item = new custom_table_widget_item;
game->item = icon_item;
icon_item->set_icon_func([this, icon_item, game](int)
icon_item->set_icon_func([this, icon_item, game](const QVideoFrame& frame)
{
if (!icon_item || !game)
{
return;
}
if (std::shared_ptr<QMovie> movie = icon_item->movie(); movie && icon_item->get_active())
if (const QPixmap pixmap = icon_item->get_movie_image(frame); icon_item->get_active() && !pixmap.isNull())
{
icon_item->setData(Qt::DecorationRole, movie->currentPixmap().scaled(m_icon_size, Qt::KeepAspectRatio));
icon_item->setData(Qt::DecorationRole, pixmap.scaled(m_icon_size, Qt::KeepAspectRatio));
}
else
{
@ -252,15 +252,12 @@ void game_list_table::populate(
icon_item->setData(Qt::DecorationRole, game->pxmap);
if (!game->has_hover_gif)
if (!game->has_hover_gif && !game->has_hover_pam)
{
game->pxmap = {};
}
if (movie)
{
movie->stop();
}
icon_item->stop_movie();
}
});
@ -288,7 +285,11 @@ void game_list_table::populate(
if (play_hover_movies && game->has_hover_gif)
{
icon_item->init_movie(game_icon_path % serial % "/hover.gif");
icon_item->set_movie_path(game_icon_path % serial % "/hover.gif");
}
else if (play_hover_movies && game->has_hover_pam)
{
icon_item->set_movie_path(QString::fromStdString(game->info.get_pam_path()));
}
icon_item->setData(Qt::UserRole, index, true);

View File

@ -1,6 +1,8 @@
#include "stdafx.h"
#include "movie_item_base.h"
#include <QFile>
movie_item_base::movie_item_base()
{
init_pointers();
@ -13,6 +15,11 @@ movie_item_base::~movie_item_base()
m_movie->stop();
}
if (m_media_player)
{
m_media_player->stop();
}
wait_for_icon_loading(true);
wait_for_size_on_disk_loading(true);
}
@ -25,33 +32,136 @@ void movie_item_base::init_pointers()
void movie_item_base::set_active(bool active)
{
if (!std::exchange(m_active, active) && active && m_movie)
if (!std::exchange(m_active, active) && active)
{
m_movie->jumpToFrame(1);
m_movie->start();
init_movie();
if (m_movie)
{
m_movie->jumpToFrame(1);
m_movie->start();
}
if (m_media_player)
{
m_media_player->play();
}
}
}
void movie_item_base::init_movie(const QString& path)
void movie_item_base::init_movie()
{
if (path.isEmpty() || !m_icon_callback) return;
m_movie.reset(new QMovie(path));
if (!m_movie->isValid())
if (m_movie || m_media_player)
{
m_movie.reset();
// Already initialized
return;
}
QObject::connect(m_movie.get(), &QMovie::frameChanged, m_movie.get(), m_icon_callback);
if (!m_icon_callback || m_movie_path.isEmpty() || !QFile::exists(m_movie_path))
{
m_movie_path.clear();
return;
}
const QString lower = m_movie_path.toLower();
if (lower.endsWith(".gif"))
{
m_movie.reset(new QMovie(m_movie_path));
m_movie_path.clear();
if (!m_movie->isValid())
{
m_movie.reset();
return;
}
QObject::connect(m_movie.get(), &QMovie::frameChanged, m_movie.get(), [this](int)
{
m_icon_callback({});
});
return;
}
if (lower.endsWith(".pam"))
{
// We can't set PAM files as source of the video player, so we have to feed them as raw data.
QFile file(m_movie_path);
if (!file.open(QFile::OpenModeFlag::ReadOnly))
{
return;
}
// TODO: Decode the pam properly before pushing it to the player
m_movie_data = file.readAll();
if (m_movie_data.isEmpty())
{
return;
}
m_movie_buffer.reset(new QBuffer(&m_movie_data));
m_movie_buffer->open(QIODevice::ReadOnly);
}
m_video_sink.reset(new QVideoSink());
QObject::connect(m_video_sink.get(), &QVideoSink::videoFrameChanged, m_video_sink.get(), [this](const QVideoFrame& frame)
{
m_icon_callback(frame);
});
m_media_player.reset(new QMediaPlayer());
m_media_player->setVideoSink(m_video_sink.get());
m_media_player->setLoops(QMediaPlayer::Infinite);
if (m_movie_buffer)
{
m_media_player->setSourceDevice(m_movie_buffer.get());
}
else
{
m_media_player->setSource(m_movie_path);
}
}
void movie_item_base::stop_movie()
{
if (m_movie)
{
m_movie->stop();
}
m_video_sink.reset();
m_media_player.reset();
m_movie_buffer.reset();
m_movie_data.clear();
}
QPixmap movie_item_base::get_movie_image(const QVideoFrame& frame) const
{
if (!m_active)
{
return {};
}
if (m_movie)
{
return m_movie->currentPixmap();
}
if (!frame.isValid())
{
return {};
}
// Get image. This usually also converts the image to ARGB32.
return QPixmap::fromImage(frame.toImage());
}
void movie_item_base::call_icon_func() const
{
if (m_icon_callback)
{
m_icon_callback(0);
m_icon_callback({});
}
}

View File

@ -6,11 +6,16 @@
#include <QMovie>
#include <QThread>
#include <QBuffer>
#include <QMediaPlayer>
#include <QVideoSink>
#include <QVideoFrame>
#include <QPixmap>
#include <memory>
#include <functional>
using icon_callback_t = std::function<void(int)>;
using icon_callback_t = std::function<void(const QVideoFrame&)>;
using icon_load_callback_t = std::function<void(int)>;
using size_calc_callback_t = std::function<void()>;
@ -29,12 +34,14 @@ public:
return m_active;
}
[[nodiscard]] std::shared_ptr<QMovie> movie() const
void set_movie_path(QString path)
{
return m_movie;
m_movie_path = std::move(path);
}
void init_movie(const QString& path);
void init_movie();
void stop_movie();
QPixmap get_movie_image(const QVideoFrame& frame) const;
void call_icon_func() const;
void set_icon_func(const icon_callback_t& func);
@ -71,6 +78,11 @@ public:
shared_mutex pixmap_mutex;
protected:
QString m_movie_path;
QByteArray m_movie_data{};
std::unique_ptr<QBuffer> m_movie_buffer;
std::unique_ptr<QMediaPlayer> m_media_player;
std::shared_ptr<QVideoSink> m_video_sink;
std::shared_ptr<QMovie> m_movie;
private: