mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-22 14:31:39 +00:00
better handling of icons in list mode
This commit is contained in:
parent
85b7251780
commit
8ab05a6e1b
|
@ -3,7 +3,7 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
custom_table_widget_item::custom_table_widget_item(const std::string& text, int sort_role, const QVariant& sort_value)
|
custom_table_widget_item::custom_table_widget_item(const std::string& text, int sort_role, const QVariant& sort_value)
|
||||||
: QTableWidgetItem(QString::fromStdString(text).simplified()) // simplified() forces single line text
|
: game_list_item(QString::fromStdString(text).simplified()) // simplified() forces single line text
|
||||||
{
|
{
|
||||||
if (sort_role != Qt::DisplayRole)
|
if (sort_role != Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ custom_table_widget_item::custom_table_widget_item(const std::string& text, int
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_table_widget_item::custom_table_widget_item(const QString& text, int sort_role, const QVariant& sort_value)
|
custom_table_widget_item::custom_table_widget_item(const QString& text, int sort_role, const QVariant& sort_value)
|
||||||
: QTableWidgetItem(text.simplified()) // simplified() forces single line text
|
: game_list_item(text.simplified()) // simplified() forces single line text
|
||||||
{
|
{
|
||||||
if (sort_role != Qt::DisplayRole)
|
if (sort_role != Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "game_list_item.h"
|
||||||
#include <QTableWidgetItem>
|
#include <QTableWidgetItem>
|
||||||
|
|
||||||
class custom_table_widget_item : public QTableWidgetItem
|
class custom_table_widget_item : public game_list_item
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int m_sort_role = Qt::DisplayRole;
|
int m_sort_role = Qt::DisplayRole;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "game_list_frame.h"
|
#include "game_list_frame.h"
|
||||||
#include "gui_settings.h"
|
#include "gui_settings.h"
|
||||||
#include "custom_table_widget_item.h"
|
#include "custom_table_widget_item.h"
|
||||||
|
#include "qt_utils.h"
|
||||||
#include "../emulator/fileFormat/PSF.h"
|
#include "../emulator/fileFormat/PSF.h"
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, QWidget* parent)
|
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
@ -107,10 +109,19 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, QWi
|
||||||
configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos));
|
configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos));
|
||||||
});
|
});
|
||||||
connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked);
|
connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked);
|
||||||
|
connect(&m_repaint_watcher, &QFutureWatcher<game_list_item*>::resultReadyAt, this, [this](int index)
|
||||||
|
{
|
||||||
|
if (!m_is_list_layout) return;
|
||||||
|
if (game_list_item* item = m_repaint_watcher.resultAt(index))
|
||||||
|
{
|
||||||
|
item->call_icon_func();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Refresh();//TODO remove when watchers added
|
Refresh();//TODO remove when watchers added
|
||||||
}
|
}
|
||||||
game_list_frame::~game_list_frame() {
|
game_list_frame::~game_list_frame() {
|
||||||
|
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
}
|
}
|
||||||
void game_list_frame::FixNarrowColumns() const
|
void game_list_frame::FixNarrowColumns() const
|
||||||
|
@ -368,7 +379,7 @@ void game_list_frame::PopulateGameList()
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
int index = -1;
|
int index = -1;
|
||||||
RepaintIcons();//hackish
|
//RepaintIcons();//hackish
|
||||||
for (const auto& game : m_game_data)
|
for (const auto& game : m_game_data)
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
|
@ -376,7 +387,12 @@ void game_list_frame::PopulateGameList()
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
custom_table_widget_item* icon_item = new custom_table_widget_item;
|
custom_table_widget_item* icon_item = new custom_table_widget_item;
|
||||||
icon_item->setData(Qt::DecorationRole, game->pxmap);
|
game->item = icon_item;
|
||||||
|
icon_item->set_icon_func([this, icon_item, game](int)
|
||||||
|
{
|
||||||
|
icon_item->setData(Qt::DecorationRole, game->pxmap);
|
||||||
|
game->pxmap = {};
|
||||||
|
});
|
||||||
|
|
||||||
icon_item->setData(Qt::UserRole, index, true);
|
icon_item->setData(Qt::UserRole, index, true);
|
||||||
icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game));
|
icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game));
|
||||||
|
@ -448,12 +464,44 @@ std::string game_list_frame::CurrentSelectionPath()
|
||||||
|
|
||||||
void game_list_frame::RepaintIcons(const bool& from_settings)
|
void game_list_frame::RepaintIcons(const bool& from_settings)
|
||||||
{
|
{
|
||||||
for (auto& game : m_game_data)
|
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||||
|
|
||||||
|
if (from_settings)
|
||||||
{
|
{
|
||||||
game->icon.load(QString::fromStdString(game->info.icon_path));
|
//TODO m_icon_color = gui::utils::get_label_color("gamelist_icon_background_color");
|
||||||
game->pxmap = PaintedPixmap(game->icon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_is_list_layout)
|
||||||
|
{
|
||||||
|
QPixmap placeholder(m_icon_size);
|
||||||
|
placeholder.fill(Qt::transparent);
|
||||||
|
|
||||||
|
for (auto& game : m_game_data)
|
||||||
|
{
|
||||||
|
game->pxmap = placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixate vertical header and row height
|
||||||
|
m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height());
|
||||||
|
m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height());
|
||||||
|
|
||||||
|
// Resize the icon column
|
||||||
|
m_game_list->resizeColumnToContents(gui::column_icon);
|
||||||
|
|
||||||
|
// Shorten the last section to remove horizontal scrollbar if possible
|
||||||
|
m_game_list->resizeColumnToContents(gui::column_count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::function func = [this](const game_info& game) -> game_list_item*
|
||||||
|
{
|
||||||
|
if (game->icon.isNull() && (game->info.icon_path.empty() || !game->icon.load(QString::fromStdString(game->info.icon_path))))
|
||||||
|
{
|
||||||
|
//TODO added warning message if no found
|
||||||
|
}
|
||||||
|
game->pxmap = PaintedPixmap(game->icon);
|
||||||
|
return game->item;
|
||||||
|
};
|
||||||
|
m_repaint_watcher.setFuture(QtConcurrent::mapped(m_game_data, func));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const
|
QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
#include "game_list_table.h"
|
#include "game_list_table.h"
|
||||||
#include "shadps4gui.h"
|
#include "shadps4gui.h"
|
||||||
#include "game_list_grid.h"
|
#include "game_list_grid.h"
|
||||||
|
#include "game_list_item.h"
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QScrollbar>
|
#include <QScrollbar>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
|
||||||
class game_list_frame : public QWidget
|
class game_list_frame : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -60,6 +62,7 @@ private:
|
||||||
QList<game_info> m_game_data;
|
QList<game_info> m_game_data;
|
||||||
std::vector<std::string> m_path_list;
|
std::vector<std::string> m_path_list;
|
||||||
std::deque<game_info> m_games;
|
std::deque<game_info> m_games;
|
||||||
|
QFutureWatcher<game_list_item*> m_repaint_watcher;
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
QSize m_icon_size;
|
QSize m_icon_size;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "game_list_grid.h"
|
#include "game_list_grid.h"
|
||||||
#include "game_list_grid_delegate.h"
|
#include "game_list_grid_delegate.h"
|
||||||
|
#include "game_list_item.h"
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
@ -58,45 +58,47 @@ void game_list_grid::setIconSize(const QSize& size) const
|
||||||
|
|
||||||
QTableWidgetItem* game_list_grid::addItem(const game_info& app, const QString& name, const QString& movie_path, const int& row, const int& col)
|
QTableWidgetItem* game_list_grid::addItem(const game_info& app, const QString& name, const QString& movie_path, const int& row, const int& col)
|
||||||
{
|
{
|
||||||
const qreal device_pixel_ratio = devicePixelRatioF();
|
game_list_item* item = new game_list_item;
|
||||||
|
item->set_icon_func([this, app, item](int)
|
||||||
// define size of expanded image, which is raw image size + margins
|
|
||||||
QSizeF exp_size_f;
|
|
||||||
if (m_text_enabled)
|
|
||||||
{
|
{
|
||||||
exp_size_f = m_icon_size + QSizeF(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
|
const qreal device_pixel_ratio = devicePixelRatioF();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exp_size_f = m_icon_size + m_icon_size * m_margin_factor * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// define offset for raw image placement
|
// define size of expanded image, which is raw image size + margins
|
||||||
QPoint offset(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
|
QSizeF exp_size_f;
|
||||||
const QSize exp_size = (exp_size_f * device_pixel_ratio).toSize();
|
if (m_text_enabled)
|
||||||
|
{
|
||||||
|
exp_size_f = m_icon_size + QSizeF(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exp_size_f = m_icon_size + m_icon_size * m_margin_factor * 2;
|
||||||
|
}
|
||||||
|
|
||||||
// create empty canvas for expanded image
|
// define offset for raw image placement
|
||||||
QImage exp_img(exp_size, QImage::Format_ARGB32);
|
QPoint offset(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
|
||||||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
const QSize exp_size = (exp_size_f * device_pixel_ratio).toSize();
|
||||||
exp_img.fill(Qt::transparent);
|
|
||||||
|
|
||||||
// create background for image
|
// create empty canvas for expanded image
|
||||||
QImage bg_img(app->pxmap.size(), QImage::Format_ARGB32);
|
QImage exp_img(exp_size, QImage::Format_ARGB32);
|
||||||
bg_img.setDevicePixelRatio(device_pixel_ratio);
|
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||||
bg_img.fill(m_icon_color);
|
exp_img.fill(Qt::transparent);
|
||||||
|
|
||||||
// place raw image inside expanded image
|
// create background for image
|
||||||
QPainter painter(&exp_img);
|
QImage bg_img(app->pxmap.size(), QImage::Format_ARGB32);
|
||||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
bg_img.setDevicePixelRatio(device_pixel_ratio);
|
||||||
painter.drawImage(offset, bg_img);
|
bg_img.fill(m_icon_color);
|
||||||
painter.drawPixmap(offset, app->pxmap);
|
|
||||||
app->pxmap = {};
|
|
||||||
painter.end();
|
|
||||||
|
|
||||||
// create item with expanded image, title and position
|
// place raw image inside expanded image
|
||||||
QTableWidgetItem* item = new QTableWidgetItem();
|
QPainter painter(&exp_img);
|
||||||
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
painter.drawImage(offset, bg_img);
|
||||||
|
painter.drawPixmap(offset, app->pxmap);
|
||||||
|
app->pxmap = {};
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
// create item with expanded image, title and position
|
||||||
|
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
|
||||||
|
});
|
||||||
if (m_text_enabled)
|
if (m_text_enabled)
|
||||||
{
|
{
|
||||||
item->setData(Qt::ItemDataRole::DisplayRole, name);
|
item->setData(Qt::ItemDataRole::DisplayRole, name);
|
||||||
|
|
44
shadPS4/gui/game_list_item.h
Normal file
44
shadPS4/gui/game_list_item.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QTableWidgetItem>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using icon_callback_t = std::function<void(int)>;
|
||||||
|
|
||||||
|
class game_list_item : public QTableWidgetItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
game_list_item() : QTableWidgetItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
game_list_item(const QString& text, int type = Type) : QTableWidgetItem(text, type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
game_list_item(const QIcon& icon, const QString& text, int type = Type) : QTableWidgetItem(icon, text, type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~game_list_item()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void call_icon_func() const
|
||||||
|
{
|
||||||
|
if (m_icon_callback)
|
||||||
|
{
|
||||||
|
m_icon_callback(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_icon_func(const icon_callback_t& func)
|
||||||
|
{
|
||||||
|
m_icon_callback = func;
|
||||||
|
call_icon_func();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
icon_callback_t m_icon_callback = nullptr;
|
||||||
|
};
|
|
@ -3,12 +3,14 @@
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include "../emulator/gameInfo.h"
|
#include "../emulator/gameInfo.h"
|
||||||
|
#include "game_list_item.h"
|
||||||
|
|
||||||
struct gui_game_info
|
struct gui_game_info
|
||||||
{
|
{
|
||||||
GameInfo info{};
|
GameInfo info{};
|
||||||
QPixmap icon;
|
QPixmap icon;
|
||||||
QPixmap pxmap;
|
QPixmap pxmap;
|
||||||
|
game_list_item* item = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<gui_game_info> game_info;
|
typedef std::shared_ptr<gui_game_info> game_info;
|
||||||
|
|
23
shadPS4/gui/qt_utils.h
Normal file
23
shadPS4/gui/qt_utils.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
|
||||||
|
namespace gui
|
||||||
|
{
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
void stop_future_watcher(QFutureWatcher<T>& watcher, bool cancel)
|
||||||
|
{
|
||||||
|
if (watcher.isStarted() || watcher.isRunning())
|
||||||
|
{
|
||||||
|
if (cancel)
|
||||||
|
{
|
||||||
|
watcher.cancel();
|
||||||
|
}
|
||||||
|
watcher.waitForFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // utils
|
||||||
|
} // gui
|
||||||
|
|
|
@ -45,10 +45,12 @@
|
||||||
<QtMoc Include="gui\game_list_grid.h" />
|
<QtMoc Include="gui\game_list_grid.h" />
|
||||||
<QtMoc Include="gui\game_list_frame.h" />
|
<QtMoc Include="gui\game_list_frame.h" />
|
||||||
<ClInclude Include="gui\game_list_grid_delegate.h" />
|
<ClInclude Include="gui\game_list_grid_delegate.h" />
|
||||||
|
<ClInclude Include="gui\game_list_item.h" />
|
||||||
<ClInclude Include="gui\game_list_table.h" />
|
<ClInclude Include="gui\game_list_table.h" />
|
||||||
<ClInclude Include="gui\gui_save.h" />
|
<ClInclude Include="gui\gui_save.h" />
|
||||||
<QtMoc Include="gui\gui_settings.h" />
|
<QtMoc Include="gui\gui_settings.h" />
|
||||||
<QtMoc Include="gui\settings.h" />
|
<QtMoc Include="gui\settings.h" />
|
||||||
|
<ClInclude Include="gui\qt_utils.h" />
|
||||||
<ClInclude Include="Types.h" />
|
<ClInclude Include="Types.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
|
@ -73,12 +75,12 @@
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
|
||||||
<QtInstall>6.4.2</QtInstall>
|
<QtInstall>6.4.2</QtInstall>
|
||||||
<QtModules>core;gui;widgets</QtModules>
|
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||||
<QtBuildConfig>debug</QtBuildConfig>
|
<QtBuildConfig>debug</QtBuildConfig>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
|
||||||
<QtInstall>6.4.2</QtInstall>
|
<QtInstall>6.4.2</QtInstall>
|
||||||
<QtModules>core;gui;widgets</QtModules>
|
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||||
<QtBuildConfig>release</QtBuildConfig>
|
<QtBuildConfig>release</QtBuildConfig>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||||
|
|
Loading…
Reference in a new issue