diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index acee714f24..60c49a60d7 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -832,6 +832,7 @@
+
@@ -1671,6 +1672,7 @@
"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DHAVE_SDL3 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\libsdl-org\SDL\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"
+
$(QTDIR)\bin\moc.exe;%(FullPath)
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index 0bb0890b41..582e8ac59b 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -199,6 +199,9 @@
{2bb5cec5-5acb-40c0-a388-68db05dff305}
+
+ {149c596b-83e7-43f8-b5db-6108694434ef}
+
@@ -1182,6 +1185,9 @@
Io\video
+
+ Gui\widgets
+
@@ -1226,9 +1232,6 @@
Gui\utils
-
- Gui
-
Gui\user accounts
@@ -1394,6 +1397,12 @@
Io\video
+
+ Gui\widgets
+
+
+ Gui\widgets
+
diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt
index 66c4fa3144..1c8875c372 100644
--- a/rpcs3/rpcs3qt/CMakeLists.txt
+++ b/rpcs3/rpcs3qt/CMakeLists.txt
@@ -113,6 +113,7 @@ add_library(rpcs3_ui STATIC
vfs_dialog_usb_input.cpp
vfs_dialog_usb_tab.cpp
vfs_tool_dialog.cpp
+ video_label.cpp
welcome_dialog.cpp
about_dialog.ui
diff --git a/rpcs3/rpcs3qt/qt_video_source.cpp b/rpcs3/rpcs3qt/qt_video_source.cpp
index 263c1f2121..2338c09bf8 100644
--- a/rpcs3/rpcs3qt/qt_video_source.cpp
+++ b/rpcs3/rpcs3qt/qt_video_source.cpp
@@ -21,10 +21,16 @@ void qt_video_source::set_video_path(const std::string& path)
void qt_video_source::set_active(bool active)
{
- if (!m_active.exchange(active) && active)
+ if (m_active.exchange(active) == active) return;
+
+ if (active)
{
start_movie();
}
+ else
+ {
+ stop_movie();
+ }
}
void qt_video_source::image_change_callback() const
diff --git a/rpcs3/rpcs3qt/qt_video_source.h b/rpcs3/rpcs3qt/qt_video_source.h
index 44cdebc034..f8b2267e5f 100644
--- a/rpcs3/rpcs3qt/qt_video_source.h
+++ b/rpcs3/rpcs3qt/qt_video_source.h
@@ -23,7 +23,7 @@ public:
void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) override;
bool has_new() const override { return m_has_new; }
- void set_active(bool active);
+ virtual void set_active(bool active);
[[nodiscard]] bool get_active() const
{
return m_active;
diff --git a/rpcs3/rpcs3qt/save_manager_dialog.cpp b/rpcs3/rpcs3qt/save_manager_dialog.cpp
index bdb085d7df..3460a43098 100644
--- a/rpcs3/rpcs3qt/save_manager_dialog.cpp
+++ b/rpcs3/rpcs3qt/save_manager_dialog.cpp
@@ -2,11 +2,13 @@
#include "custom_table_widget_item.h"
#include "qt_utils.h"
+#include "qt_video_source.h"
#include "gui_application.h"
#include "gui_settings.h"
#include "persistent_settings.h"
#include "game_list_delegate.h"
#include "progress_dialog.h"
+#include "video_label.h"
#include "Emu/System.h"
#include "Emu/system_utils.hpp"
@@ -107,7 +109,7 @@ void save_manager_dialog::Init()
push_close->setAutoDefault(true);
// Details
- m_details_icon = new QLabel(this);
+ m_details_icon = new video_label(this);
m_details_icon->setMinimumSize(320, 176);
m_details_title = new QLabel(tr("Select an item to view details"), this);
m_details_title->setWordWrap(true);
@@ -640,7 +642,9 @@ void save_manager_dialog::UpdateDetails()
{
if (const int selected = m_list->selectionModel()->selectedRows().size(); selected != 1)
{
- m_details_icon->setPixmap(QPixmap());
+ m_details_icon->set_thumbnail({});
+ m_details_icon->set_active(false);
+
m_details_subtitle->setText("");
m_details_modified->setText("");
m_details_details->setText("");
@@ -664,7 +668,7 @@ void save_manager_dialog::UpdateDetails()
const int row = m_list->currentRow();
QTableWidgetItem* item = m_list->item(row, SaveColumns::Name);
- QTableWidgetItem* icon_item = m_list->item(row, SaveColumns::Icon);
+ movie_item* icon_item = static_cast(m_list->item(row, SaveColumns::Icon));
if (!item || !icon_item)
{
@@ -674,7 +678,14 @@ void save_manager_dialog::UpdateDetails()
const int idx = item->data(Qt::UserRole).toInt();
const SaveDataEntry& save = ::at32(m_save_entries, idx);
- m_details_icon->setPixmap(icon_item->data(Qt::UserRole).value());
+ if (!icon_item->video_path().isEmpty())
+ {
+ m_details_icon->set_video_path(icon_item->video_path().toStdString());
+ }
+
+ m_details_icon->set_thumbnail(icon_item->data(SaveUserRole::Pixmap).value());
+ m_details_icon->set_active(false);
+
m_details_title->setText(QString::fromStdString(save.title));
m_details_subtitle->setText(QString::fromStdString(save.subtitle));
m_details_modified->setText(tr("Last modified: %1").arg(FormatTimestamp(save.mtime)));
diff --git a/rpcs3/rpcs3qt/save_manager_dialog.h b/rpcs3/rpcs3qt/save_manager_dialog.h
index aa23ccaaef..e685b2b6d5 100644
--- a/rpcs3/rpcs3qt/save_manager_dialog.h
+++ b/rpcs3/rpcs3qt/save_manager_dialog.h
@@ -1,6 +1,7 @@
#pragma once
#include "game_list.h"
+
#include "Emu/Cell/Modules/cellSaveData.h"
#include
@@ -11,6 +12,7 @@
class gui_settings;
class persistent_settings;
+class video_label;
class save_manager_dialog : public QDialog
{
@@ -59,7 +61,7 @@ private:
QSize m_icon_size;
QColor m_icon_color;
- QLabel* m_details_icon = nullptr;
+ video_label* m_details_icon = nullptr;
QLabel* m_details_title = nullptr;
QLabel* m_details_subtitle = nullptr;
QLabel* m_details_modified = nullptr;
diff --git a/rpcs3/rpcs3qt/video_label.cpp b/rpcs3/rpcs3qt/video_label.cpp
new file mode 100644
index 0000000000..bdf36a0e46
--- /dev/null
+++ b/rpcs3/rpcs3qt/video_label.cpp
@@ -0,0 +1,51 @@
+#include "stdafx.h"
+#include "video_label.h"
+
+video_label::video_label(QWidget* parent)
+ : QLabel(parent), qt_video_source()
+{
+}
+
+video_label::~video_label()
+{
+}
+
+void video_label::set_thumbnail(const QPixmap& pxmap)
+{
+ m_current_pixmap = pxmap;
+}
+
+void video_label::set_active(bool active)
+{
+ if (active)
+ {
+ set_image_change_callback([this](const QVideoFrame& frame)
+ {
+ if (const QPixmap pixmap = get_movie_image(frame); get_active() && !pixmap.isNull())
+ {
+ setPixmap(pixmap);
+ }
+ });
+ start_movie();
+ }
+ else
+ {
+ set_image_change_callback({});
+ stop_movie();
+ setPixmap(m_current_pixmap);
+ }
+}
+
+void video_label::enterEvent(QEnterEvent* event)
+{
+ set_active(true);
+
+ QLabel::enterEvent(event);
+}
+
+void video_label::leaveEvent(QEvent* event)
+{
+ set_active(false);
+
+ QLabel::leaveEvent(event);
+}
diff --git a/rpcs3/rpcs3qt/video_label.h b/rpcs3/rpcs3qt/video_label.h
new file mode 100644
index 0000000000..58f0bf8d21
--- /dev/null
+++ b/rpcs3/rpcs3qt/video_label.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "qt_video_source.h"
+#include
+#include
+#include
+
+class video_label : public QLabel, public qt_video_source
+{
+public:
+ video_label(QWidget* parent = nullptr);
+ virtual ~video_label();
+
+ void set_thumbnail(const QPixmap& pxmap);
+ void set_active(bool active) override;
+
+ void enterEvent(QEnterEvent* event) override;
+ void leaveEvent(QEvent* event) override;
+
+private:
+ QPixmap m_current_pixmap;
+};