better handling of icons in list mode

This commit is contained in:
georgemoralis 2023-03-14 01:02:06 +02:00
parent f5570a156f
commit 9e4a670be8
9 changed files with 170 additions and 45 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
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

View File

@ -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;

View File

@ -1,6 +1,6 @@
#include "game_list_grid.h"
#include "game_list_grid_delegate.h"
#include "game_list_item.h"
#include <QHeaderView>
#include <QScrollBar>
@ -57,6 +57,9 @@ 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)
{
game_list_item* item = new game_list_item;
item->set_icon_func([this, app, item](int)
{
const qreal device_pixel_ratio = devicePixelRatioF();
@ -94,9 +97,8 @@ QTableWidgetItem* game_list_grid::addItem(const game_info& app, const QString& n
painter.end();
// create item with expanded image, title and position
QTableWidgetItem* item = new QTableWidgetItem();
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
});
if (m_text_enabled)
{
item->setData(Qt::ItemDataRole::DisplayRole, name);

View 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;
};

View File

@ -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
View 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

View File

@ -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')">