mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-04-06 06:55:02 +00:00
Qt: add some sorting options to the screenshot manager
This commit is contained in:
parent
3e60bd2aa6
commit
789bab97be
6 changed files with 232 additions and 64 deletions
|
|
@ -3119,9 +3119,9 @@ void main_window::CreateConnects()
|
|||
m_game_list_frame->Refresh(true); // New user may have different games unlocked.
|
||||
});
|
||||
|
||||
connect(ui->actionManage_Screenshots, &QAction::triggered, this, []
|
||||
connect(ui->actionManage_Screenshots, &QAction::triggered, this, [this]
|
||||
{
|
||||
screenshot_manager_dialog* screenshot_manager = new screenshot_manager_dialog();
|
||||
screenshot_manager_dialog* screenshot_manager = new screenshot_manager_dialog(m_game_list_frame ? m_game_list_frame->GetGameInfo() : std::vector<game_info>{});
|
||||
screenshot_manager->show();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -279,6 +279,11 @@ namespace gui
|
|||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
exp_img.fill(Qt::transparent);
|
||||
|
||||
if (pixmap.isNull())
|
||||
{
|
||||
return exp_img;
|
||||
}
|
||||
|
||||
// Load scaled pixmap
|
||||
pixmap = pixmap.scaled(icon_size, Qt::KeepAspectRatio, mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,26 +4,37 @@
|
|||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
screenshot_item::screenshot_item(QWidget* parent)
|
||||
screenshot_item::screenshot_item(QWidget* parent, QSize icon_size, const QString& icon_path, const QPixmap& placeholder)
|
||||
: flow_widget_item(parent)
|
||||
, m_icon_path(icon_path)
|
||||
, m_icon_size(icon_size)
|
||||
{
|
||||
setToolTip(icon_path);
|
||||
|
||||
cb_on_first_visibility = [this]()
|
||||
{
|
||||
m_thread.reset(QThread::create([this]()
|
||||
{
|
||||
thread_base::set_name("Screenshot item");
|
||||
|
||||
const QPixmap pixmap = gui::utils::get_aligned_pixmap(icon_path, icon_size, 1.0, Qt::SmoothTransformation, gui::utils::align_h::center, gui::utils::align_v::center);
|
||||
const QPixmap src_icon = QPixmap(m_icon_path);
|
||||
if (src_icon.isNull()) return;
|
||||
|
||||
const QPixmap pixmap = gui::utils::get_aligned_pixmap(src_icon, m_icon_size, 1.0, Qt::SmoothTransformation, gui::utils::align_h::center, gui::utils::align_v::center);
|
||||
Q_EMIT signal_icon_update(pixmap);
|
||||
}));
|
||||
m_thread->start();
|
||||
};
|
||||
|
||||
label = new QLabel(this);
|
||||
m_label = new QLabel(this);
|
||||
m_label->setPixmap(placeholder);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(m_label);
|
||||
setLayout(layout);
|
||||
|
||||
connect(this, &screenshot_item::signal_icon_update, this, &screenshot_item::update_icon, Qt::ConnectionType::QueuedConnection);
|
||||
}
|
||||
|
||||
screenshot_item::~screenshot_item()
|
||||
|
|
@ -33,3 +44,23 @@ screenshot_item::~screenshot_item()
|
|||
m_thread->wait();
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_item::update_icon(const QPixmap& pixmap)
|
||||
{
|
||||
if (m_label)
|
||||
{
|
||||
m_label->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_item::mouseDoubleClickEvent(QMouseEvent* ev)
|
||||
{
|
||||
flow_widget_item::mouseDoubleClickEvent(ev);
|
||||
|
||||
if (!ev) return;
|
||||
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
{
|
||||
Q_EMIT signal_icon_preview(m_icon_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,29 @@
|
|||
#include "flow_widget_item.h"
|
||||
#include <QLabel>
|
||||
#include <QThread>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class screenshot_item : public flow_widget_item
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
screenshot_item(QWidget* parent);
|
||||
screenshot_item(QWidget* parent, QSize icon_size, const QString& icon_path, const QPixmap& placeholder);
|
||||
virtual ~screenshot_item();
|
||||
|
||||
QString icon_path;
|
||||
QSize icon_size;
|
||||
QLabel* label{};
|
||||
|
||||
private:
|
||||
QLabel* m_label{};
|
||||
QString m_icon_path;
|
||||
QSize m_icon_size;
|
||||
std::unique_ptr<QThread> m_thread;
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent* ev) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void signal_icon_update(const QPixmap& pixmap);
|
||||
void signal_icon_preview(const QString& path);
|
||||
|
||||
public Q_SLOTS:
|
||||
void update_icon(const QPixmap& pixmap);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@
|
|||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QGroupBox>
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent>
|
||||
|
||||
LOG_CHANNEL(gui_log, "GUI");
|
||||
|
||||
screenshot_manager_dialog::screenshot_manager_dialog(QWidget* parent) : QDialog(parent)
|
||||
screenshot_manager_dialog::screenshot_manager_dialog(const std::vector<game_info>& games, QWidget* parent)
|
||||
: QDialog(parent), m_games(games)
|
||||
{
|
||||
setWindowTitle(tr("Screenshots"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
|
@ -28,11 +30,50 @@ screenshot_manager_dialog::screenshot_manager_dialog(QWidget* parent) : QDialog(
|
|||
m_placeholder = QPixmap(m_icon_size);
|
||||
m_placeholder.fill(Qt::gray);
|
||||
|
||||
connect(this, &screenshot_manager_dialog::signal_icon_preview, this, &screenshot_manager_dialog::show_preview);
|
||||
connect(this, &screenshot_manager_dialog::signal_entry_parsed, this, &screenshot_manager_dialog::add_entry);
|
||||
connect(this, &screenshot_manager_dialog::signal_entry_parsed, this, &screenshot_manager_dialog::add_entry, Qt::ConnectionType::QueuedConnection);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
m_combo_sort_filter = new QComboBox();
|
||||
m_combo_sort_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_sort_filter->addItem(tr("Sort by Game"), static_cast<int>(sort_filter::game));
|
||||
m_combo_sort_filter->addItem(tr("Sort by Date"), static_cast<int>(sort_filter::date));
|
||||
connect(m_combo_sort_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
m_combo_type_filter = new QComboBox();
|
||||
m_combo_type_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_type_filter->addItem(tr("All Screenshots"), static_cast<int>(type_filter::all));
|
||||
m_combo_type_filter->addItem(tr("RPCS3 Screenshots"), static_cast<int>(type_filter::rpcs3));
|
||||
m_combo_type_filter->addItem(tr("Cell Screenshots"), static_cast<int>(type_filter::cell));
|
||||
connect(m_combo_type_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
m_combo_game_filter = new QComboBox();
|
||||
m_combo_game_filter->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_combo_game_filter->addItem(tr("All Games"), QString());
|
||||
connect(m_combo_game_filter, &QComboBox::currentIndexChanged, this, [this](int /*index*/){ reload(); });
|
||||
|
||||
QHBoxLayout* sort_layout = new QHBoxLayout();
|
||||
sort_layout->addWidget(m_combo_sort_filter);
|
||||
QGroupBox* gb_sort = new QGroupBox(tr("Sort"));
|
||||
gb_sort->setLayout(sort_layout);
|
||||
|
||||
QHBoxLayout* type_layout = new QHBoxLayout();
|
||||
type_layout->addWidget(m_combo_type_filter);
|
||||
QGroupBox* gb_type = new QGroupBox(tr("Filter Type"));
|
||||
gb_type->setLayout(type_layout);
|
||||
|
||||
QHBoxLayout* game_layout = new QHBoxLayout();
|
||||
game_layout->addWidget(m_combo_game_filter);
|
||||
QGroupBox* gb_game = new QGroupBox(tr("Filter Game"));
|
||||
gb_game->setLayout(game_layout);
|
||||
|
||||
QHBoxLayout* top_layout = new QHBoxLayout();
|
||||
top_layout->addWidget(gb_sort);
|
||||
top_layout->addWidget(gb_type);
|
||||
top_layout->addWidget(gb_game);
|
||||
top_layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum));
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addLayout(top_layout);
|
||||
layout->addWidget(m_flow_widget);
|
||||
setLayout(layout);
|
||||
|
||||
|
|
@ -47,14 +88,8 @@ screenshot_manager_dialog::~screenshot_manager_dialog()
|
|||
|
||||
void screenshot_manager_dialog::add_entry(const QString& path)
|
||||
{
|
||||
screenshot_item* item = new screenshot_item(m_flow_widget);
|
||||
ensure(item->label);
|
||||
item->setToolTip(path);
|
||||
item->installEventFilter(this);
|
||||
item->label->setPixmap(m_placeholder);
|
||||
item->icon_path = path;
|
||||
item->icon_size = m_icon_size;
|
||||
connect(item, &screenshot_item::signal_icon_update, this, &screenshot_manager_dialog::update_icon);
|
||||
screenshot_item* item = new screenshot_item(m_flow_widget, m_icon_size, path, m_placeholder);
|
||||
connect(item, &screenshot_item::signal_icon_preview, this, &screenshot_manager_dialog::show_preview);
|
||||
|
||||
m_flow_widget->add_widget(item);
|
||||
}
|
||||
|
|
@ -65,28 +100,74 @@ void screenshot_manager_dialog::show_preview(const QString& path)
|
|||
preview->show();
|
||||
}
|
||||
|
||||
void screenshot_manager_dialog::update_icon(const QPixmap& pixmap)
|
||||
{
|
||||
if (screenshot_item* item = static_cast<screenshot_item*>(QObject::sender()))
|
||||
{
|
||||
if (item->label)
|
||||
{
|
||||
item->label->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void screenshot_manager_dialog::reload()
|
||||
{
|
||||
m_abort_parsing = true;
|
||||
m_parsing_watcher.disconnect();
|
||||
gui::utils::stop_future_watcher(m_parsing_watcher, true);
|
||||
|
||||
const std::string screenshot_path_qt = fs::get_config_dir() + "screenshots/";
|
||||
const std::string screenshot_path_cell = rpcs3::utils::get_hdd0_dir() + "/photo/";
|
||||
const type_filter t_filter = static_cast<type_filter>(m_combo_type_filter->currentData().toInt());
|
||||
const sort_filter s_filter = static_cast<sort_filter>(m_combo_sort_filter->currentData().toInt());
|
||||
const QString game_filter = m_combo_game_filter->currentData().toString();
|
||||
|
||||
const std::string screenshot_path_rpcs3 = fs::get_config_dir() + "screenshots/";
|
||||
const std::string screenshot_path_cell = rpcs3::utils::get_hdd0_dir() + "/photo/";
|
||||
|
||||
std::vector<std::string> folders;
|
||||
switch (t_filter)
|
||||
{
|
||||
case type_filter::all:
|
||||
folders.push_back(screenshot_path_rpcs3);
|
||||
folders.push_back(screenshot_path_cell);
|
||||
break;
|
||||
case type_filter::rpcs3:
|
||||
folders.push_back(screenshot_path_rpcs3);
|
||||
break;
|
||||
case type_filter::cell:
|
||||
folders.push_back(screenshot_path_cell);
|
||||
break;
|
||||
}
|
||||
|
||||
m_flow_widget->clear();
|
||||
m_game_folders.clear();
|
||||
m_abort_parsing = false;
|
||||
m_parsing_watcher.setFuture(QtConcurrent::map(m_parsing_threads, [this, screenshot_path_qt, screenshot_path_cell](int index)
|
||||
|
||||
connect(&m_parsing_watcher, &QFutureWatcher<void>::finished, this, [this]()
|
||||
{
|
||||
std::vector<std::pair<QString, QString>> games;
|
||||
for (const auto& [dirname, paths] : m_game_folders)
|
||||
{
|
||||
const std::string serial = dirname.toStdString();
|
||||
std::string text = serial;
|
||||
for (const auto& game : m_games)
|
||||
{
|
||||
if (game && game->info.serial == serial)
|
||||
{
|
||||
text = fmt::format("%s (%s)", game->info.name, serial);
|
||||
break;
|
||||
}
|
||||
}
|
||||
games.push_back(std::pair(dirname, QString::fromStdString(text)));
|
||||
}
|
||||
|
||||
std::sort(games.begin(), games.end(), [](const std::pair<QString, QString>& l, const std::pair<QString, QString>& r)
|
||||
{
|
||||
return l.second < r.second;
|
||||
});
|
||||
|
||||
const QString old_filter = m_combo_game_filter->currentData().toString();
|
||||
m_combo_game_filter->blockSignals(true);
|
||||
m_combo_game_filter->clear();
|
||||
m_combo_game_filter->addItem(tr("All Games"), QString());
|
||||
for (const auto& [dirname, text] : games)
|
||||
{
|
||||
m_combo_game_filter->addItem(text, dirname);
|
||||
}
|
||||
m_combo_game_filter->setCurrentIndex(m_combo_game_filter->findData(old_filter));
|
||||
m_combo_game_filter->blockSignals(false);
|
||||
});
|
||||
|
||||
m_parsing_watcher.setFuture(QtConcurrent::map(m_parsing_threads, [this, folders, game_filter, s_filter](int index)
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
|
|
@ -95,26 +176,68 @@ void screenshot_manager_dialog::reload()
|
|||
|
||||
const QStringList filter{ QStringLiteral("*.png") };
|
||||
|
||||
for (const std::string& path : { screenshot_path_qt, screenshot_path_cell })
|
||||
for (const std::string& folder : folders)
|
||||
{
|
||||
if (m_abort_parsing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.empty())
|
||||
if (folder.empty())
|
||||
{
|
||||
gui_log.error("Screenshot manager: Trying to load screenshots from empty path!");
|
||||
continue;
|
||||
}
|
||||
|
||||
QDirIterator dir_iter(QString::fromStdString(path), filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
QDirIterator dir_iter(QString::fromStdString(folder), filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
|
||||
while (dir_iter.hasNext() && !m_abort_parsing)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(dir_iter.next());
|
||||
QFileInfo info(dir_iter.next());
|
||||
const QString dirname = info.dir().dirName();
|
||||
m_game_folders[dirname].push_back(std::move(info));
|
||||
}
|
||||
}
|
||||
|
||||
switch (s_filter)
|
||||
{
|
||||
case sort_filter::game:
|
||||
{
|
||||
for (const auto& [dirname, infos] : m_game_folders)
|
||||
{
|
||||
if (game_filter.isEmpty() || game_filter == dirname)
|
||||
{
|
||||
for (const QFileInfo& info : infos)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(info.filePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sort_filter::date:
|
||||
{
|
||||
std::vector<QFileInfo> sorted_infos;
|
||||
for (const auto& [dirname, infos] : m_game_folders)
|
||||
{
|
||||
if (game_filter.isEmpty() || game_filter == dirname)
|
||||
{
|
||||
sorted_infos.insert(sorted_infos.end(), infos.begin(), infos.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(sorted_infos.begin(), sorted_infos.end(), [](const QFileInfo& a, const QFileInfo& b)
|
||||
{
|
||||
return a.lastModified() < b.lastModified();
|
||||
});
|
||||
|
||||
for (const QFileInfo& info : sorted_infos)
|
||||
{
|
||||
Q_EMIT signal_entry_parsed(info.filePath());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -123,17 +246,3 @@ void screenshot_manager_dialog::showEvent(QShowEvent* event)
|
|||
QDialog::showEvent(event);
|
||||
reload();
|
||||
}
|
||||
|
||||
bool screenshot_manager_dialog::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
if (event && event->type() == QEvent::MouseButtonDblClick && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
|
||||
{
|
||||
if (screenshot_item* item = static_cast<screenshot_item*>(watched))
|
||||
{
|
||||
Q_EMIT signal_icon_preview(item->icon_path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_widget.h"
|
||||
#include "gui_game_info.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFutureWatcher>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
#include <QEvent>
|
||||
#include <QShowEvent>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class screenshot_manager_dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
screenshot_manager_dialog(QWidget* parent = nullptr);
|
||||
screenshot_manager_dialog(const std::vector<game_info>& games, QWidget* parent = nullptr);
|
||||
~screenshot_manager_dialog();
|
||||
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void signal_entry_parsed(const QString& path);
|
||||
void signal_icon_preview(const QString& path);
|
||||
|
||||
public Q_SLOTS:
|
||||
void update_icon(const QPixmap& pixmap);
|
||||
|
||||
private Q_SLOTS:
|
||||
void add_entry(const QString& path);
|
||||
|
|
@ -36,11 +35,28 @@ protected:
|
|||
private:
|
||||
void reload();
|
||||
|
||||
enum class type_filter
|
||||
{
|
||||
all,
|
||||
rpcs3,
|
||||
cell
|
||||
};
|
||||
|
||||
enum class sort_filter
|
||||
{
|
||||
game,
|
||||
date
|
||||
};
|
||||
|
||||
std::vector<game_info> m_games;
|
||||
bool m_abort_parsing = false;
|
||||
const std::array<int, 1> m_parsing_threads{0};
|
||||
QFutureWatcher<void> m_parsing_watcher;
|
||||
flow_widget* m_flow_widget = nullptr;
|
||||
|
||||
QComboBox* m_combo_sort_filter = nullptr;
|
||||
QComboBox* m_combo_game_filter = nullptr;
|
||||
QComboBox* m_combo_type_filter = nullptr;
|
||||
QSize m_icon_size;
|
||||
QPixmap m_placeholder;
|
||||
std::map<QString, std::vector<QFileInfo>> m_game_folders;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue