diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index ef33068716..4088192f8c 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -517,6 +517,16 @@
true
true
+
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+
true
true
@@ -742,6 +752,16 @@
true
true
+
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+
true
true
@@ -987,6 +1007,16 @@
true
true
+
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+
true
true
@@ -1212,6 +1242,16 @@
true
true
+
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+
true
true
@@ -1276,6 +1316,8 @@
+
+
@@ -1932,6 +1974,42 @@
.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB "-DBRANCH=$(BRANCH)" -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\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"
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\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"
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+
+
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB "-DBRANCH=$(BRANCH)" -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\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"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\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"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index 472cbd3b55..1ef9787ac5 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -125,6 +125,9 @@
ts
false
+
+ {b227bdd4-16f5-4f6e-a8b2-8b1f4bdc606a}
+
@@ -886,6 +889,36 @@
rpcs3
+
+ Gui\screenshot manager
+
+
+ Generated Files\Release - LLVM
+
+
+ Generated Files\Debug
+
+
+ Generated Files\Release
+
+
+ Generated Files\Debug - LLVM
+
+
+ Gui\screenshot manager
+
+
+ Generated Files\Release - LLVM
+
+
+ Generated Files\Debug
+
+
+ Generated Files\Release
+
+
+ Generated Files\Debug - LLVM
+
@@ -1169,6 +1202,12 @@
Gui\settings
+
+ Gui\screenshot manager
+
+
+ Gui\screenshot manager
+
diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt
index 19a5694b85..99fbd7e497 100644
--- a/rpcs3/rpcs3qt/CMakeLists.txt
+++ b/rpcs3/rpcs3qt/CMakeLists.txt
@@ -42,6 +42,8 @@
save_data_info_dialog.cpp
save_data_list_dialog.cpp
save_manager_dialog.cpp
+ screenshot_manager_dialog.cpp
+ screenshot_preview.cpp
settings.cpp
settings_dialog.cpp
skylander_dialog.cpp
diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp
index 61bb0a7862..fe28bc48a9 100644
--- a/rpcs3/rpcs3qt/main_window.cpp
+++ b/rpcs3/rpcs3qt/main_window.cpp
@@ -6,6 +6,7 @@
#include "save_manager_dialog.h"
#include "trophy_manager_dialog.h"
#include "user_manager_dialog.h"
+#include "screenshot_manager_dialog.h"
#include "kernel_explorer.h"
#include "game_list_frame.h"
#include "debugger_frame.h"
@@ -1518,6 +1519,12 @@ void main_window::CreateConnects()
m_game_list_frame->Refresh(true); // New user may have different games unlocked.
});
+ connect(ui->actionManage_Screenshots, &QAction::triggered, [this]
+ {
+ screenshot_manager_dialog* screenshot_manager = new screenshot_manager_dialog();
+ screenshot_manager->show();
+ });
+
connect(ui->toolsCgDisasmAct, &QAction::triggered, [this]
{
cg_disasm_window* cgdw = new cg_disasm_window(m_gui_settings);
diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui
index f1ca2ad765..ada8433dd1 100644
--- a/rpcs3/rpcs3qt/main_window.ui
+++ b/rpcs3/rpcs3qt/main_window.ui
@@ -229,6 +229,7 @@
+
diff --git a/rpcs3/rpcs3qt/screenshot_manager_dialog.cpp b/rpcs3/rpcs3qt/screenshot_manager_dialog.cpp
new file mode 100644
index 0000000000..0f8df5511e
--- /dev/null
+++ b/rpcs3/rpcs3qt/screenshot_manager_dialog.cpp
@@ -0,0 +1,59 @@
+#include "screenshot_manager_dialog.h"
+#include "screenshot_preview.h"
+#include "qt_utils.h"
+#include "Utilities/File.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+screenshot_manager_dialog::screenshot_manager_dialog(QWidget* parent) : QDialog(parent)
+{
+ setWindowTitle(tr("Screenshots"));
+
+ m_grid = new QListWidget(this);
+ m_grid->setViewMode(QListWidget::IconMode);
+ m_grid->setMovement(QListWidget::Static);
+ m_grid->setResizeMode(QListWidget::Adjust);
+ m_grid->setIconSize(QSize(160, 90));
+ m_grid->setGridSize(m_grid->iconSize() + QSize(10, 10));
+
+ const std::string screen_path = fs::get_config_dir() + "/screenshots/";
+ const QStringList filter{ QStringLiteral("*.png") };
+ QDirIterator dir_iter(QString::fromStdString(screen_path), filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
+
+ while (dir_iter.hasNext())
+ {
+ const QString filepath = dir_iter.next();
+
+ QListWidgetItem* item = new QListWidgetItem;
+ item->setData(Qt::UserRole, filepath);
+ item->setIcon(QIcon(filepath));
+ item->setToolTip(filepath);
+
+ m_grid->addItem(item);
+ }
+
+ connect(m_grid, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item)
+ {
+ if (!item)
+ {
+ return;
+ }
+
+ const QString filepath = item->data(Qt::UserRole).toString();
+
+ screenshot_preview* preview = new screenshot_preview(filepath);
+ preview->show();
+ });
+
+ QVBoxLayout* layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(m_grid);
+ setLayout(layout);
+
+ resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
+}
diff --git a/rpcs3/rpcs3qt/screenshot_manager_dialog.h b/rpcs3/rpcs3qt/screenshot_manager_dialog.h
new file mode 100644
index 0000000000..f5b9e3ba4e
--- /dev/null
+++ b/rpcs3/rpcs3qt/screenshot_manager_dialog.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+
+class QListWidget;
+
+class screenshot_manager_dialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ screenshot_manager_dialog(QWidget* parent = nullptr);
+
+private:
+ QListWidget* m_grid = nullptr;
+};
diff --git a/rpcs3/rpcs3qt/screenshot_preview.cpp b/rpcs3/rpcs3qt/screenshot_preview.cpp
new file mode 100644
index 0000000000..979f38ebbc
--- /dev/null
+++ b/rpcs3/rpcs3qt/screenshot_preview.cpp
@@ -0,0 +1,64 @@
+#include "screenshot_preview.h"
+#include "qt_utils.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+screenshot_preview::screenshot_preview(const QString& filepath, QWidget* parent)
+ : QLabel(parent)
+ , m_filepath(filepath)
+{
+ QImageReader reader(filepath);
+ reader.setAutoTransform(true);
+
+ m_image = reader.read();
+
+ setWindowTitle(tr("Screenshot Preview"));
+ setObjectName("screenshot_preview");
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ setPixmap(QPixmap::fromImage(m_image));
+ setMinimumSize(160, 90);
+
+ connect(this, &screenshot_preview::customContextMenuRequested, this, &screenshot_preview::show_context_menu);
+}
+#include
+
+void screenshot_preview::show_context_menu(const QPoint & pos)
+{
+ QMenu* menu = new QMenu();
+ menu->addAction(tr("&Copy"), [this]() { QGuiApplication::clipboard()->setImage(m_image); });
+ menu->addSeparator();
+
+ QAction* reset_act = menu->addAction(tr("To &Normal Size"), [this]() { scale(m_image.size()); });
+ reset_act->setEnabled(pixmap()->size() != m_image.size());
+
+ QAction* stretch_act = menu->addAction(tr("&Stretch to size"), [this]() { m_stretch = !m_stretch; scale(size()); });
+ stretch_act->setCheckable(true);
+ stretch_act->setChecked(m_stretch);
+
+ menu->addSeparator();
+ menu->addAction(tr("E&xit"), this, &QLabel::close);
+ menu->exec(mapToGlobal(pos));
+}
+
+void screenshot_preview::scale(const QSize& new_size)
+{
+ if (new_size != size())
+ {
+ resize(new_size);
+ }
+
+ setPixmap(QPixmap::fromImage(m_image.scaled(new_size, m_stretch ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio, Qt::SmoothTransformation)));
+}
+
+void screenshot_preview::resizeEvent(QResizeEvent* event)
+{
+ scale(event->size());
+ event->ignore();
+}
diff --git a/rpcs3/rpcs3qt/screenshot_preview.h b/rpcs3/rpcs3qt/screenshot_preview.h
new file mode 100644
index 0000000000..f9a813997a
--- /dev/null
+++ b/rpcs3/rpcs3qt/screenshot_preview.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+#include
+
+class screenshot_preview : public QLabel
+{
+ Q_OBJECT
+
+public:
+ screenshot_preview(const QString& filepath, QWidget* parent = nullptr);
+
+protected:
+ void resizeEvent(QResizeEvent* event);
+
+private Q_SLOTS:
+ void show_context_menu(const QPoint& pos);
+
+private:
+ void scale(const QSize& size);
+
+ QString m_filepath;
+ QImage m_image;
+ double m_factor = 1.0;
+ bool m_stretch = false;
+};