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>
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
: QTableWidgetItem(text.simplified()) // simplified() forces single line text
|
||||
: game_list_item(text.simplified()) // simplified() forces single line text
|
||||
{
|
||||
if (sort_role != Qt::DisplayRole)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
#include "game_list_item.h"
|
||||
#include <QTableWidgetItem>
|
||||
|
||||
class custom_table_widget_item : public QTableWidgetItem
|
||||
class custom_table_widget_item : public game_list_item
|
||||
{
|
||||
private:
|
||||
int m_sort_role = Qt::DisplayRole;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "game_list_frame.h"
|
||||
#include "gui_settings.h"
|
||||
#include "custom_table_widget_item.h"
|
||||
#include "qt_utils.h"
|
||||
#include "../emulator/fileFormat/PSF.h"
|
||||
#include <QPainter>
|
||||
#include <unordered_set>
|
||||
|
||||
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> gui_settings, 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));
|
||||
});
|
||||
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
|
||||
}
|
||||
game_list_frame::~game_list_frame() {
|
||||
gui::utils::stop_future_watcher(m_repaint_watcher, true);
|
||||
SaveSettings();
|
||||
}
|
||||
void game_list_frame::FixNarrowColumns() const
|
||||
|
@ -368,7 +379,7 @@ void game_list_frame::PopulateGameList()
|
|||
|
||||
int row = 0;
|
||||
int index = -1;
|
||||
RepaintIcons();//hackish
|
||||
//RepaintIcons();//hackish
|
||||
for (const auto& game : m_game_data)
|
||||
{
|
||||
index++;
|
||||
|
@ -376,7 +387,12 @@ void game_list_frame::PopulateGameList()
|
|||
|
||||
// Icon
|
||||
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(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)
|
||||
{
|
||||
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));
|
||||
game->pxmap = PaintedPixmap(game->icon);
|
||||
//TODO m_icon_color = gui::utils::get_label_color("gamelist_icon_background_color");
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
#include "game_list_table.h"
|
||||
#include "shadps4gui.h"
|
||||
#include "game_list_grid.h"
|
||||
|
||||
#include "game_list_item.h"
|
||||
#include <QHeaderView>
|
||||
#include <QScrollbar>
|
||||
#include <QWidget>
|
||||
#include <deque>
|
||||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent>
|
||||
|
||||
class game_list_frame : public QWidget
|
||||
{
|
||||
|
@ -60,6 +62,7 @@ private:
|
|||
QList<game_info> m_game_data;
|
||||
std::vector<std::string> m_path_list;
|
||||
std::deque<game_info> m_games;
|
||||
QFutureWatcher<game_list_item*> m_repaint_watcher;
|
||||
|
||||
// Icons
|
||||
QSize m_icon_size;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "game_list_grid.h"
|
||||
#include "game_list_grid_delegate.h"
|
||||
|
||||
#include "game_list_item.h"
|
||||
#include <QHeaderView>
|
||||
#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)
|
||||
{
|
||||
const qreal device_pixel_ratio = devicePixelRatioF();
|
||||
|
||||
// define size of expanded image, which is raw image size + margins
|
||||
QSizeF exp_size_f;
|
||||
if (m_text_enabled)
|
||||
game_list_item* item = new game_list_item;
|
||||
item->set_icon_func([this, app, item](int)
|
||||
{
|
||||
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;
|
||||
}
|
||||
const qreal device_pixel_ratio = devicePixelRatioF();
|
||||
|
||||
// define offset for raw image placement
|
||||
QPoint offset(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
|
||||
const QSize exp_size = (exp_size_f * device_pixel_ratio).toSize();
|
||||
// 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));
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_size_f = m_icon_size + m_icon_size * m_margin_factor * 2;
|
||||
}
|
||||
|
||||
// create empty canvas for expanded image
|
||||
QImage exp_img(exp_size, QImage::Format_ARGB32);
|
||||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
exp_img.fill(Qt::transparent);
|
||||
// define offset for raw image placement
|
||||
QPoint offset(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
|
||||
const QSize exp_size = (exp_size_f * device_pixel_ratio).toSize();
|
||||
|
||||
// create background for image
|
||||
QImage bg_img(app->pxmap.size(), QImage::Format_ARGB32);
|
||||
bg_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
bg_img.fill(m_icon_color);
|
||||
// create empty canvas for expanded image
|
||||
QImage exp_img(exp_size, QImage::Format_ARGB32);
|
||||
exp_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
exp_img.fill(Qt::transparent);
|
||||
|
||||
// place raw image inside expanded image
|
||||
QPainter painter(&exp_img);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.drawImage(offset, bg_img);
|
||||
painter.drawPixmap(offset, app->pxmap);
|
||||
app->pxmap = {};
|
||||
painter.end();
|
||||
// create background for image
|
||||
QImage bg_img(app->pxmap.size(), QImage::Format_ARGB32);
|
||||
bg_img.setDevicePixelRatio(device_pixel_ratio);
|
||||
bg_img.fill(m_icon_color);
|
||||
|
||||
// create item with expanded image, title and position
|
||||
QTableWidgetItem* item = new QTableWidgetItem();
|
||||
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
|
||||
// place raw image inside expanded image
|
||||
QPainter painter(&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)
|
||||
{
|
||||
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 <QMouseEvent>
|
||||
#include "../emulator/gameInfo.h"
|
||||
#include "game_list_item.h"
|
||||
|
||||
struct gui_game_info
|
||||
{
|
||||
GameInfo info{};
|
||||
QPixmap icon;
|
||||
QPixmap pxmap;
|
||||
game_list_item* item = nullptr;
|
||||
};
|
||||
|
||||
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_frame.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\gui_save.h" />
|
||||
<QtMoc Include="gui\gui_settings.h" />
|
||||
<QtMoc Include="gui\settings.h" />
|
||||
<ClInclude Include="gui\qt_utils.h" />
|
||||
<ClInclude Include="Types.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
@ -73,12 +75,12 @@
|
|||
</ImportGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
|
||||
<QtInstall>6.4.2</QtInstall>
|
||||
<QtModules>core;gui;widgets</QtModules>
|
||||
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||
<QtBuildConfig>debug</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
|
||||
<QtInstall>6.4.2</QtInstall>
|
||||
<QtModules>core;gui;widgets</QtModules>
|
||||
<QtModules>core;gui;widgets;concurrent</QtModules>
|
||||
<QtBuildConfig>release</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
|
|
Loading…
Reference in a new issue