From a161c9e74a839174e5b9937960c73dec6d0be909 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 9 Mar 2023 22:18:14 +0200 Subject: [PATCH 01/18] start reworking on adding the new gamelist part1 --- shadPS4/gui/game_list_frame.cpp | 36 +++++++++++++++++++++++++++++++++ shadPS4/gui/game_list_frame.h | 7 ++++++- shadPS4/gui/shadps4gui.cpp | 11 ++++++---- shadPS4/gui/shadps4gui.h | 1 + shadPS4/shadPS4.vcxproj | 5 ++++- shadPS4/shadPS4.vcxproj.filters | 9 ++++++--- 6 files changed, 60 insertions(+), 9 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index f01313e8..2cb10e98 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,7 +1,43 @@ #include "game_list_frame.h" #include "gui_settings.h" +game_list_frame::game_list_frame(QWidget* parent) + : QWidget(parent) +{ + m_game_list = new game_list_table(); + m_game_list->setShowGrid(false); + m_game_list->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_game_list->setSelectionBehavior(QAbstractItemView::SelectRows); + m_game_list->setSelectionMode(QAbstractItemView::SingleSelection); + m_game_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + m_game_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + m_game_list->verticalScrollBar()->installEventFilter(this); + m_game_list->verticalScrollBar()->setSingleStep(20); + m_game_list->horizontalScrollBar()->setSingleStep(20); + m_game_list->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + m_game_list->verticalHeader()->setVisible(false); + m_game_list->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); + m_game_list->horizontalHeader()->setHighlightSections(false); + m_game_list->horizontalHeader()->setSortIndicatorShown(true); + m_game_list->horizontalHeader()->setStretchLastSection(true); + m_game_list->horizontalHeader()->setDefaultSectionSize(150); + m_game_list->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); + m_game_list->setContextMenuPolicy(Qt::CustomContextMenu); + m_game_list->setAlternatingRowColors(true); + m_game_list->installEventFilter(this); + m_game_list->setColumnCount(gui::column_count); + //temp code + QVBoxLayout* layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + QSpacerItem* item = new QSpacerItem(100, 1, QSizePolicy::Expanding, QSizePolicy::Fixed); + layout->addWidget(m_game_list); + setLayout(layout); + //endof temp code +} +game_list_frame::~game_list_frame(){ + +} void game_list_frame::FixNarrowColumns() const { qApp->processEvents(); diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 0443ed9f..48dd7c08 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -4,10 +4,15 @@ #include "shadps4gui.h" #include +#include +#include -class game_list_frame +class game_list_frame : public QWidget { + Q_OBJECT public : + explicit game_list_frame(QWidget* parent = nullptr); + ~game_list_frame(); /** Fix columns with width smaller than the minimal section size */ void FixNarrowColumns() const; diff --git a/shadPS4/gui/shadps4gui.cpp b/shadPS4/gui/shadps4gui.cpp index 3b2b4214..c10d2eb1 100644 --- a/shadPS4/gui/shadps4gui.cpp +++ b/shadPS4/gui/shadps4gui.cpp @@ -12,11 +12,14 @@ shadps4gui::shadps4gui(std::shared_ptr gui_settings, QWidget* pare , m_gui_settings(std::move(gui_settings)) { ui.setupUi(this); - game_list = new GameListViewer(); - game_list->SetGamePath(QDir::currentPath() + "/game/"); - ui.horizontalLayout->addWidget(game_list); + //game_list = new GameListViewer(); + //game_list->SetGamePath(QDir::currentPath() + "/game/"); + //ui.horizontalLayout->addWidget(game_list); + //show(); + //game_list->PopulateAsync(); + game_list_frame* game_list2 = new game_list_frame(); + ui.horizontalLayout->addWidget(game_list2); show(); - game_list->PopulateAsync(); } shadps4gui::~shadps4gui() diff --git a/shadPS4/gui/shadps4gui.h b/shadPS4/gui/shadps4gui.h index 9f65ae78..ed559002 100644 --- a/shadPS4/gui/shadps4gui.h +++ b/shadPS4/gui/shadps4gui.h @@ -4,6 +4,7 @@ #include "ui_shadps4gui.h" #include "GameListViewer.h" #include "gui_settings.h" +#include "game_list_frame.h" class shadps4gui : public QMainWindow { diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 817400ef..802acab7 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -42,12 +42,15 @@ - + + + + {F005E4D9-1FBE-40B3-9FBD-35CEC59081CD} QtVS_v304 diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index 8280e965..7e510f3c 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -90,6 +90,9 @@ gui + + gui + @@ -122,8 +125,8 @@ gui - - gui - + + + \ No newline at end of file From 6d2680d5a3c990dbe2d679086cc8d9a9a46fb077 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 10:42:50 +0200 Subject: [PATCH 02/18] abstracting setting class and more wokr on gamelist class --- shadPS4/gui/game_list_frame.cpp | 48 ++++++++++++++++- shadPS4/gui/game_list_frame.h | 3 +- shadPS4/gui/gui_save.h | 30 +++++++++++ shadPS4/gui/gui_settings.cpp | 16 +++++- shadPS4/gui/gui_settings.h | 40 ++++++++++++-- shadPS4/gui/settings.cpp | 94 +++++++++++++++++++++++++++++++++ shadPS4/gui/settings.h | 48 +++++++++++++++++ shadPS4/gui/shadps4gui.cpp | 2 +- shadPS4/shadPS4.vcxproj | 5 +- shadPS4/shadPS4.vcxproj.filters | 15 ++++-- 10 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 shadPS4/gui/gui_save.h create mode 100644 shadPS4/gui/settings.cpp create mode 100644 shadPS4/gui/settings.h diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 2cb10e98..fd9ca1db 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,8 +1,9 @@ #include "game_list_frame.h" #include "gui_settings.h" -game_list_frame::game_list_frame(QWidget* parent) +game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWidget* parent) : QWidget(parent) + , m_gui_settings(std::move(gui_settings)) { m_game_list = new game_list_table(); m_game_list->setShowGrid(false); @@ -34,6 +35,51 @@ game_list_frame::game_list_frame(QWidget* parent) layout->addWidget(m_game_list); setLayout(layout); //endof temp code + + // Actions regarding showing/hiding columns + auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text) + { + m_game_list->setHorizontalHeaderItem(col, new QTableWidgetItem(header_text)); + m_columnActs.append(new QAction(action_text, this)); + }; + + add_column(gui::column_icon, tr("Icon"), tr("Show Icons")); + add_column(gui::column_name, tr("Name"), tr("Show Names")); + add_column(gui::column_serial, tr("Serial"), tr("Show Serials")); + add_column(gui::column_firmware, tr("Firmware"), tr("Show Firmwares")); + add_column(gui::column_version, tr("Version"), tr("Show Versions")); + add_column(gui::column_category, tr("Category"), tr("Show Categories")); + add_column(gui::column_path, tr("Path"), tr("Show Paths")); + + for (int col = 0; col < m_columnActs.count(); ++col) + { + m_columnActs[col]->setCheckable(true); + + connect(m_columnActs[col], &QAction::triggered, this, [this, col](bool checked) + { + if (!checked) // be sure to have at least one column left so you can call the context menu at all time + { + int c = 0; + for (int i = 0; i < m_columnActs.count(); ++i) + { + if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1) + break; + } + if (c < 2) + { + m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state + return; + } + } + m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show. + m_gui_settings->SetGamelistColVisibility(col, checked); + + if (checked) // handle hidden columns that have zero width after showing them (stuck between others) + { + FixNarrowColumns(); + } + }); + } } game_list_frame::~game_list_frame(){ diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 48dd7c08..4f8e610d 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -11,7 +11,7 @@ class game_list_frame : public QWidget { Q_OBJECT public : - explicit game_list_frame(QWidget* parent = nullptr); + explicit game_list_frame(std::shared_ptr gui_settings,QWidget* parent = nullptr); ~game_list_frame(); /** Fix columns with width smaller than the minimal section size */ void FixNarrowColumns() const; @@ -29,6 +29,7 @@ private: int m_sort_column; // data + std::shared_ptr m_gui_settings; QList m_game_data; // Icons diff --git a/shadPS4/gui/gui_save.h b/shadPS4/gui/gui_save.h new file mode 100644 index 00000000..66970172 --- /dev/null +++ b/shadPS4/gui/gui_save.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +struct gui_save +{ + QString key; + QString name; + QVariant def; + + gui_save() + { + key = ""; + name = ""; + def = QVariant(); + } + + gui_save(const QString& k, const QString& n, const QVariant& d) + { + key = k; + name = n; + def = d; + } + + bool operator==(const gui_save& rhs) const noexcept + { + return key == rhs.key && name == rhs.name && def == rhs.def; + } +}; diff --git a/shadPS4/gui/gui_settings.cpp b/shadPS4/gui/gui_settings.cpp index 4baf9373..3be2dfd1 100644 --- a/shadPS4/gui/gui_settings.cpp +++ b/shadPS4/gui/gui_settings.cpp @@ -3,6 +3,20 @@ gui_settings::gui_settings(QObject* parent) { - m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); + m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); //TODO make the path configurable } +void gui_settings::SetGamelistColVisibility(int col, bool val) const +{ + SetValue(GetGuiSaveForColumn(col), val); +} + +bool gui_settings::GetGamelistColVisibility(int col) const +{ + return GetValue(GetGuiSaveForColumn(col)).toBool(); +} + +gui_save gui_settings::GetGuiSaveForColumn(int col) +{ + return gui_save{ gui::game_list, "visibility_" + gui::get_game_list_column_name(static_cast(col)), true }; +} \ No newline at end of file diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 831b6183..57f5e9b9 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "settings.h" namespace gui { @@ -17,15 +17,47 @@ namespace gui column_count }; + inline QString get_game_list_column_name(game_list_columns col) + { + switch (col) + { + case column_icon: + return "column_icon"; + case column_name: + return "column_name"; + case column_serial: + return "column_serial"; + case column_firmware: + return "column_firmware"; + case column_version: + return "column_version"; + case column_category: + return "column_category"; + case column_path: + return "column_path"; + case column_count: + return ""; + } + + throw std::exception("get_game_list_column_name: Invalid column"); + } + + const QString game_list = "GameList"; + } -class gui_settings +class gui_settings : public settings { + Q_OBJECT public: explicit gui_settings(QObject* parent = nullptr); -private: - std::unique_ptr m_settings; + bool GetGamelistColVisibility(int col) const; + + +public Q_SLOTS: + void SetGamelistColVisibility(int col, bool val) const; + static gui_save GetGuiSaveForColumn(int col); }; diff --git a/shadPS4/gui/settings.cpp b/shadPS4/gui/settings.cpp new file mode 100644 index 00000000..9867b2d7 --- /dev/null +++ b/shadPS4/gui/settings.cpp @@ -0,0 +1,94 @@ +#include "settings.h" + +settings::settings(QObject* parent) : QObject(parent), +m_settings_dir(ComputeSettingsDir()) +{ +} + +settings::~settings() +{ + if (m_settings) + { + m_settings->sync(); + } +} + +QString settings::GetSettingsDir() const +{ + return m_settings_dir.absolutePath(); +} + +QString settings::ComputeSettingsDir() +{ + return ""; //TODO currently we configure same dir , make it configurable +} + +void settings::RemoveValue(const QString& key, const QString& name) const +{ + if (m_settings) + { + m_settings->beginGroup(key); + m_settings->remove(name); + m_settings->endGroup(); + } +} + +void settings::RemoveValue(const gui_save& entry) const +{ + RemoveValue(entry.key, entry.name); +} + +QVariant settings::GetValue(const QString& key, const QString& name, const QVariant& def) const +{ + return m_settings ? m_settings->value(key + "/" + name, def) : def; +} + +QVariant settings::GetValue(const gui_save& entry) const +{ + return GetValue(entry.key, entry.name, entry.def); +} + +QVariant settings::List2Var(const q_pair_list& list) +{ + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << list; + return QVariant(ba); +} + +q_pair_list settings::Var2List(const QVariant& var) +{ + q_pair_list list; + QByteArray ba = var.toByteArray(); + QDataStream stream(&ba, QIODevice::ReadOnly); + stream >> list; + return list; +} + +void settings::SetValue(const gui_save& entry, const QVariant& value) const +{ + if (m_settings) + { + m_settings->beginGroup(entry.key); + m_settings->setValue(entry.name, value); + m_settings->endGroup(); + } +} + +void settings::SetValue(const QString& key, const QVariant& value) const +{ + if (m_settings) + { + m_settings->setValue(key, value); + } +} + +void settings::SetValue(const QString& key, const QString& name, const QVariant& value) const +{ + if (m_settings) + { + m_settings->beginGroup(key); + m_settings->setValue(name, value); + m_settings->endGroup(); + } +} diff --git a/shadPS4/gui/settings.h b/shadPS4/gui/settings.h new file mode 100644 index 00000000..7116edab --- /dev/null +++ b/shadPS4/gui/settings.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "gui_save.h" + +typedef QPair q_string_pair; +typedef QPair q_size_pair; +typedef QList q_pair_list; +typedef QList q_size_list; + +// Parent Class for GUI settings +class settings : public QObject +{ + Q_OBJECT + +public: + explicit settings(QObject* parent = nullptr); + ~settings(); + + QString GetSettingsDir() const; + + QVariant GetValue(const QString& key, const QString& name, const QVariant& def) const; + QVariant GetValue(const gui_save& entry) const; + static QVariant List2Var(const q_pair_list& list); + static q_pair_list Var2List(const QVariant& var); + +public Q_SLOTS: + /** Remove entry */ + void RemoveValue(const QString& key, const QString& name) const; + void RemoveValue(const gui_save& entry) const; + + /** Write value to entry */ + void SetValue(const gui_save& entry, const QVariant& value) const; + void SetValue(const QString& key, const QVariant& value) const; + void SetValue(const QString& key, const QString& name, const QVariant& value) const; + +protected: + static QString ComputeSettingsDir(); + + std::unique_ptr m_settings; + QDir m_settings_dir; +}; \ No newline at end of file diff --git a/shadPS4/gui/shadps4gui.cpp b/shadPS4/gui/shadps4gui.cpp index c10d2eb1..9827e6b9 100644 --- a/shadPS4/gui/shadps4gui.cpp +++ b/shadPS4/gui/shadps4gui.cpp @@ -17,7 +17,7 @@ shadps4gui::shadps4gui(std::shared_ptr gui_settings, QWidget* pare //ui.horizontalLayout->addWidget(game_list); //show(); //game_list->PopulateAsync(); - game_list_frame* game_list2 = new game_list_frame(); + game_list_frame* game_list2 = new game_list_frame(m_gui_settings); ui.horizontalLayout->addWidget(game_list2); show(); } diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 802acab7..3223ef46 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -22,6 +22,7 @@ + @@ -45,7 +46,9 @@ - + + + diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index 7e510f3c..e62e16b6 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -74,6 +74,9 @@ gui + + gui + @@ -93,6 +96,12 @@ gui + + gui + + + gui + @@ -110,9 +119,6 @@ emulator\fileFormat - - gui - Header Files @@ -125,6 +131,9 @@ gui + + gui + From 2809eb7c2cda94b80d993608772bdb9635e6a06b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 10:43:12 +0200 Subject: [PATCH 03/18] Revert "abstracting setting class and more wokr on gamelist class" This reverts commit 794202c785006b020359c0453edab4b9bd89aad4. --- shadPS4/gui/game_list_frame.cpp | 48 +---------------- shadPS4/gui/game_list_frame.h | 3 +- shadPS4/gui/gui_save.h | 30 ----------- shadPS4/gui/gui_settings.cpp | 16 +----- shadPS4/gui/gui_settings.h | 40 ++------------ shadPS4/gui/settings.cpp | 94 --------------------------------- shadPS4/gui/settings.h | 48 ----------------- shadPS4/gui/shadps4gui.cpp | 2 +- shadPS4/shadPS4.vcxproj | 5 +- shadPS4/shadPS4.vcxproj.filters | 15 ++---- 10 files changed, 12 insertions(+), 289 deletions(-) delete mode 100644 shadPS4/gui/gui_save.h delete mode 100644 shadPS4/gui/settings.cpp delete mode 100644 shadPS4/gui/settings.h diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index fd9ca1db..2cb10e98 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,9 +1,8 @@ #include "game_list_frame.h" #include "gui_settings.h" -game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWidget* parent) +game_list_frame::game_list_frame(QWidget* parent) : QWidget(parent) - , m_gui_settings(std::move(gui_settings)) { m_game_list = new game_list_table(); m_game_list->setShowGrid(false); @@ -35,51 +34,6 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWid layout->addWidget(m_game_list); setLayout(layout); //endof temp code - - // Actions regarding showing/hiding columns - auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text) - { - m_game_list->setHorizontalHeaderItem(col, new QTableWidgetItem(header_text)); - m_columnActs.append(new QAction(action_text, this)); - }; - - add_column(gui::column_icon, tr("Icon"), tr("Show Icons")); - add_column(gui::column_name, tr("Name"), tr("Show Names")); - add_column(gui::column_serial, tr("Serial"), tr("Show Serials")); - add_column(gui::column_firmware, tr("Firmware"), tr("Show Firmwares")); - add_column(gui::column_version, tr("Version"), tr("Show Versions")); - add_column(gui::column_category, tr("Category"), tr("Show Categories")); - add_column(gui::column_path, tr("Path"), tr("Show Paths")); - - for (int col = 0; col < m_columnActs.count(); ++col) - { - m_columnActs[col]->setCheckable(true); - - connect(m_columnActs[col], &QAction::triggered, this, [this, col](bool checked) - { - if (!checked) // be sure to have at least one column left so you can call the context menu at all time - { - int c = 0; - for (int i = 0; i < m_columnActs.count(); ++i) - { - if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1) - break; - } - if (c < 2) - { - m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state - return; - } - } - m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show. - m_gui_settings->SetGamelistColVisibility(col, checked); - - if (checked) // handle hidden columns that have zero width after showing them (stuck between others) - { - FixNarrowColumns(); - } - }); - } } game_list_frame::~game_list_frame(){ diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 4f8e610d..48dd7c08 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -11,7 +11,7 @@ class game_list_frame : public QWidget { Q_OBJECT public : - explicit game_list_frame(std::shared_ptr gui_settings,QWidget* parent = nullptr); + explicit game_list_frame(QWidget* parent = nullptr); ~game_list_frame(); /** Fix columns with width smaller than the minimal section size */ void FixNarrowColumns() const; @@ -29,7 +29,6 @@ private: int m_sort_column; // data - std::shared_ptr m_gui_settings; QList m_game_data; // Icons diff --git a/shadPS4/gui/gui_save.h b/shadPS4/gui/gui_save.h deleted file mode 100644 index 66970172..00000000 --- a/shadPS4/gui/gui_save.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include - -struct gui_save -{ - QString key; - QString name; - QVariant def; - - gui_save() - { - key = ""; - name = ""; - def = QVariant(); - } - - gui_save(const QString& k, const QString& n, const QVariant& d) - { - key = k; - name = n; - def = d; - } - - bool operator==(const gui_save& rhs) const noexcept - { - return key == rhs.key && name == rhs.name && def == rhs.def; - } -}; diff --git a/shadPS4/gui/gui_settings.cpp b/shadPS4/gui/gui_settings.cpp index 3be2dfd1..4baf9373 100644 --- a/shadPS4/gui/gui_settings.cpp +++ b/shadPS4/gui/gui_settings.cpp @@ -3,20 +3,6 @@ gui_settings::gui_settings(QObject* parent) { - m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); //TODO make the path configurable + m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); } -void gui_settings::SetGamelistColVisibility(int col, bool val) const -{ - SetValue(GetGuiSaveForColumn(col), val); -} - -bool gui_settings::GetGamelistColVisibility(int col) const -{ - return GetValue(GetGuiSaveForColumn(col)).toBool(); -} - -gui_save gui_settings::GetGuiSaveForColumn(int col) -{ - return gui_save{ gui::game_list, "visibility_" + gui::get_game_list_column_name(static_cast(col)), true }; -} \ No newline at end of file diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 57f5e9b9..831b6183 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -1,6 +1,6 @@ #pragma once -#include "settings.h" +#include namespace gui { @@ -17,47 +17,15 @@ namespace gui column_count }; - inline QString get_game_list_column_name(game_list_columns col) - { - switch (col) - { - case column_icon: - return "column_icon"; - case column_name: - return "column_name"; - case column_serial: - return "column_serial"; - case column_firmware: - return "column_firmware"; - case column_version: - return "column_version"; - case column_category: - return "column_category"; - case column_path: - return "column_path"; - case column_count: - return ""; - } - - throw std::exception("get_game_list_column_name: Invalid column"); - } - - const QString game_list = "GameList"; - } -class gui_settings : public settings +class gui_settings { - Q_OBJECT public: explicit gui_settings(QObject* parent = nullptr); - bool GetGamelistColVisibility(int col) const; - - -public Q_SLOTS: - void SetGamelistColVisibility(int col, bool val) const; - static gui_save GetGuiSaveForColumn(int col); +private: + std::unique_ptr m_settings; }; diff --git a/shadPS4/gui/settings.cpp b/shadPS4/gui/settings.cpp deleted file mode 100644 index 9867b2d7..00000000 --- a/shadPS4/gui/settings.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "settings.h" - -settings::settings(QObject* parent) : QObject(parent), -m_settings_dir(ComputeSettingsDir()) -{ -} - -settings::~settings() -{ - if (m_settings) - { - m_settings->sync(); - } -} - -QString settings::GetSettingsDir() const -{ - return m_settings_dir.absolutePath(); -} - -QString settings::ComputeSettingsDir() -{ - return ""; //TODO currently we configure same dir , make it configurable -} - -void settings::RemoveValue(const QString& key, const QString& name) const -{ - if (m_settings) - { - m_settings->beginGroup(key); - m_settings->remove(name); - m_settings->endGroup(); - } -} - -void settings::RemoveValue(const gui_save& entry) const -{ - RemoveValue(entry.key, entry.name); -} - -QVariant settings::GetValue(const QString& key, const QString& name, const QVariant& def) const -{ - return m_settings ? m_settings->value(key + "/" + name, def) : def; -} - -QVariant settings::GetValue(const gui_save& entry) const -{ - return GetValue(entry.key, entry.name, entry.def); -} - -QVariant settings::List2Var(const q_pair_list& list) -{ - QByteArray ba; - QDataStream stream(&ba, QIODevice::WriteOnly); - stream << list; - return QVariant(ba); -} - -q_pair_list settings::Var2List(const QVariant& var) -{ - q_pair_list list; - QByteArray ba = var.toByteArray(); - QDataStream stream(&ba, QIODevice::ReadOnly); - stream >> list; - return list; -} - -void settings::SetValue(const gui_save& entry, const QVariant& value) const -{ - if (m_settings) - { - m_settings->beginGroup(entry.key); - m_settings->setValue(entry.name, value); - m_settings->endGroup(); - } -} - -void settings::SetValue(const QString& key, const QVariant& value) const -{ - if (m_settings) - { - m_settings->setValue(key, value); - } -} - -void settings::SetValue(const QString& key, const QString& name, const QVariant& value) const -{ - if (m_settings) - { - m_settings->beginGroup(key); - m_settings->setValue(name, value); - m_settings->endGroup(); - } -} diff --git a/shadPS4/gui/settings.h b/shadPS4/gui/settings.h deleted file mode 100644 index 7116edab..00000000 --- a/shadPS4/gui/settings.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -#include "gui_save.h" - -typedef QPair q_string_pair; -typedef QPair q_size_pair; -typedef QList q_pair_list; -typedef QList q_size_list; - -// Parent Class for GUI settings -class settings : public QObject -{ - Q_OBJECT - -public: - explicit settings(QObject* parent = nullptr); - ~settings(); - - QString GetSettingsDir() const; - - QVariant GetValue(const QString& key, const QString& name, const QVariant& def) const; - QVariant GetValue(const gui_save& entry) const; - static QVariant List2Var(const q_pair_list& list); - static q_pair_list Var2List(const QVariant& var); - -public Q_SLOTS: - /** Remove entry */ - void RemoveValue(const QString& key, const QString& name) const; - void RemoveValue(const gui_save& entry) const; - - /** Write value to entry */ - void SetValue(const gui_save& entry, const QVariant& value) const; - void SetValue(const QString& key, const QVariant& value) const; - void SetValue(const QString& key, const QString& name, const QVariant& value) const; - -protected: - static QString ComputeSettingsDir(); - - std::unique_ptr m_settings; - QDir m_settings_dir; -}; \ No newline at end of file diff --git a/shadPS4/gui/shadps4gui.cpp b/shadPS4/gui/shadps4gui.cpp index 9827e6b9..c10d2eb1 100644 --- a/shadPS4/gui/shadps4gui.cpp +++ b/shadPS4/gui/shadps4gui.cpp @@ -17,7 +17,7 @@ shadps4gui::shadps4gui(std::shared_ptr gui_settings, QWidget* pare //ui.horizontalLayout->addWidget(game_list); //show(); //game_list->PopulateAsync(); - game_list_frame* game_list2 = new game_list_frame(m_gui_settings); + game_list_frame* game_list2 = new game_list_frame(); ui.horizontalLayout->addWidget(game_list2); show(); } diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 3223ef46..802acab7 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -22,7 +22,6 @@ - @@ -46,9 +45,7 @@ - - - + diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index e62e16b6..7e510f3c 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -74,9 +74,6 @@ gui - - gui - @@ -96,12 +93,6 @@ gui - - gui - - - gui - @@ -119,6 +110,9 @@ emulator\fileFormat + + gui + Header Files @@ -131,9 +125,6 @@ gui - - gui - From 29a4b249d81cfeafabb90f01c318de6268f8135f Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 10:43:44 +0200 Subject: [PATCH 04/18] Revert "Revert "abstracting setting class and more wokr on gamelist class"" This reverts commit 2809eb7c2cda94b80d993608772bdb9635e6a06b. --- shadPS4/gui/game_list_frame.cpp | 48 ++++++++++++++++- shadPS4/gui/game_list_frame.h | 3 +- shadPS4/gui/gui_save.h | 30 +++++++++++ shadPS4/gui/gui_settings.cpp | 16 +++++- shadPS4/gui/gui_settings.h | 40 ++++++++++++-- shadPS4/gui/settings.cpp | 94 +++++++++++++++++++++++++++++++++ shadPS4/gui/settings.h | 48 +++++++++++++++++ shadPS4/gui/shadps4gui.cpp | 2 +- shadPS4/shadPS4.vcxproj | 5 +- shadPS4/shadPS4.vcxproj.filters | 15 ++++-- 10 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 shadPS4/gui/gui_save.h create mode 100644 shadPS4/gui/settings.cpp create mode 100644 shadPS4/gui/settings.h diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 2cb10e98..fd9ca1db 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,8 +1,9 @@ #include "game_list_frame.h" #include "gui_settings.h" -game_list_frame::game_list_frame(QWidget* parent) +game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWidget* parent) : QWidget(parent) + , m_gui_settings(std::move(gui_settings)) { m_game_list = new game_list_table(); m_game_list->setShowGrid(false); @@ -34,6 +35,51 @@ game_list_frame::game_list_frame(QWidget* parent) layout->addWidget(m_game_list); setLayout(layout); //endof temp code + + // Actions regarding showing/hiding columns + auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text) + { + m_game_list->setHorizontalHeaderItem(col, new QTableWidgetItem(header_text)); + m_columnActs.append(new QAction(action_text, this)); + }; + + add_column(gui::column_icon, tr("Icon"), tr("Show Icons")); + add_column(gui::column_name, tr("Name"), tr("Show Names")); + add_column(gui::column_serial, tr("Serial"), tr("Show Serials")); + add_column(gui::column_firmware, tr("Firmware"), tr("Show Firmwares")); + add_column(gui::column_version, tr("Version"), tr("Show Versions")); + add_column(gui::column_category, tr("Category"), tr("Show Categories")); + add_column(gui::column_path, tr("Path"), tr("Show Paths")); + + for (int col = 0; col < m_columnActs.count(); ++col) + { + m_columnActs[col]->setCheckable(true); + + connect(m_columnActs[col], &QAction::triggered, this, [this, col](bool checked) + { + if (!checked) // be sure to have at least one column left so you can call the context menu at all time + { + int c = 0; + for (int i = 0; i < m_columnActs.count(); ++i) + { + if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1) + break; + } + if (c < 2) + { + m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state + return; + } + } + m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show. + m_gui_settings->SetGamelistColVisibility(col, checked); + + if (checked) // handle hidden columns that have zero width after showing them (stuck between others) + { + FixNarrowColumns(); + } + }); + } } game_list_frame::~game_list_frame(){ diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 48dd7c08..4f8e610d 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -11,7 +11,7 @@ class game_list_frame : public QWidget { Q_OBJECT public : - explicit game_list_frame(QWidget* parent = nullptr); + explicit game_list_frame(std::shared_ptr gui_settings,QWidget* parent = nullptr); ~game_list_frame(); /** Fix columns with width smaller than the minimal section size */ void FixNarrowColumns() const; @@ -29,6 +29,7 @@ private: int m_sort_column; // data + std::shared_ptr m_gui_settings; QList m_game_data; // Icons diff --git a/shadPS4/gui/gui_save.h b/shadPS4/gui/gui_save.h new file mode 100644 index 00000000..66970172 --- /dev/null +++ b/shadPS4/gui/gui_save.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +struct gui_save +{ + QString key; + QString name; + QVariant def; + + gui_save() + { + key = ""; + name = ""; + def = QVariant(); + } + + gui_save(const QString& k, const QString& n, const QVariant& d) + { + key = k; + name = n; + def = d; + } + + bool operator==(const gui_save& rhs) const noexcept + { + return key == rhs.key && name == rhs.name && def == rhs.def; + } +}; diff --git a/shadPS4/gui/gui_settings.cpp b/shadPS4/gui/gui_settings.cpp index 4baf9373..3be2dfd1 100644 --- a/shadPS4/gui/gui_settings.cpp +++ b/shadPS4/gui/gui_settings.cpp @@ -3,6 +3,20 @@ gui_settings::gui_settings(QObject* parent) { - m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); + m_settings.reset(new QSettings("shadps4.ini", QSettings::Format::IniFormat, parent)); //TODO make the path configurable } +void gui_settings::SetGamelistColVisibility(int col, bool val) const +{ + SetValue(GetGuiSaveForColumn(col), val); +} + +bool gui_settings::GetGamelistColVisibility(int col) const +{ + return GetValue(GetGuiSaveForColumn(col)).toBool(); +} + +gui_save gui_settings::GetGuiSaveForColumn(int col) +{ + return gui_save{ gui::game_list, "visibility_" + gui::get_game_list_column_name(static_cast(col)), true }; +} \ No newline at end of file diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 831b6183..57f5e9b9 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "settings.h" namespace gui { @@ -17,15 +17,47 @@ namespace gui column_count }; + inline QString get_game_list_column_name(game_list_columns col) + { + switch (col) + { + case column_icon: + return "column_icon"; + case column_name: + return "column_name"; + case column_serial: + return "column_serial"; + case column_firmware: + return "column_firmware"; + case column_version: + return "column_version"; + case column_category: + return "column_category"; + case column_path: + return "column_path"; + case column_count: + return ""; + } + + throw std::exception("get_game_list_column_name: Invalid column"); + } + + const QString game_list = "GameList"; + } -class gui_settings +class gui_settings : public settings { + Q_OBJECT public: explicit gui_settings(QObject* parent = nullptr); -private: - std::unique_ptr m_settings; + bool GetGamelistColVisibility(int col) const; + + +public Q_SLOTS: + void SetGamelistColVisibility(int col, bool val) const; + static gui_save GetGuiSaveForColumn(int col); }; diff --git a/shadPS4/gui/settings.cpp b/shadPS4/gui/settings.cpp new file mode 100644 index 00000000..9867b2d7 --- /dev/null +++ b/shadPS4/gui/settings.cpp @@ -0,0 +1,94 @@ +#include "settings.h" + +settings::settings(QObject* parent) : QObject(parent), +m_settings_dir(ComputeSettingsDir()) +{ +} + +settings::~settings() +{ + if (m_settings) + { + m_settings->sync(); + } +} + +QString settings::GetSettingsDir() const +{ + return m_settings_dir.absolutePath(); +} + +QString settings::ComputeSettingsDir() +{ + return ""; //TODO currently we configure same dir , make it configurable +} + +void settings::RemoveValue(const QString& key, const QString& name) const +{ + if (m_settings) + { + m_settings->beginGroup(key); + m_settings->remove(name); + m_settings->endGroup(); + } +} + +void settings::RemoveValue(const gui_save& entry) const +{ + RemoveValue(entry.key, entry.name); +} + +QVariant settings::GetValue(const QString& key, const QString& name, const QVariant& def) const +{ + return m_settings ? m_settings->value(key + "/" + name, def) : def; +} + +QVariant settings::GetValue(const gui_save& entry) const +{ + return GetValue(entry.key, entry.name, entry.def); +} + +QVariant settings::List2Var(const q_pair_list& list) +{ + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << list; + return QVariant(ba); +} + +q_pair_list settings::Var2List(const QVariant& var) +{ + q_pair_list list; + QByteArray ba = var.toByteArray(); + QDataStream stream(&ba, QIODevice::ReadOnly); + stream >> list; + return list; +} + +void settings::SetValue(const gui_save& entry, const QVariant& value) const +{ + if (m_settings) + { + m_settings->beginGroup(entry.key); + m_settings->setValue(entry.name, value); + m_settings->endGroup(); + } +} + +void settings::SetValue(const QString& key, const QVariant& value) const +{ + if (m_settings) + { + m_settings->setValue(key, value); + } +} + +void settings::SetValue(const QString& key, const QString& name, const QVariant& value) const +{ + if (m_settings) + { + m_settings->beginGroup(key); + m_settings->setValue(name, value); + m_settings->endGroup(); + } +} diff --git a/shadPS4/gui/settings.h b/shadPS4/gui/settings.h new file mode 100644 index 00000000..7116edab --- /dev/null +++ b/shadPS4/gui/settings.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "gui_save.h" + +typedef QPair q_string_pair; +typedef QPair q_size_pair; +typedef QList q_pair_list; +typedef QList q_size_list; + +// Parent Class for GUI settings +class settings : public QObject +{ + Q_OBJECT + +public: + explicit settings(QObject* parent = nullptr); + ~settings(); + + QString GetSettingsDir() const; + + QVariant GetValue(const QString& key, const QString& name, const QVariant& def) const; + QVariant GetValue(const gui_save& entry) const; + static QVariant List2Var(const q_pair_list& list); + static q_pair_list Var2List(const QVariant& var); + +public Q_SLOTS: + /** Remove entry */ + void RemoveValue(const QString& key, const QString& name) const; + void RemoveValue(const gui_save& entry) const; + + /** Write value to entry */ + void SetValue(const gui_save& entry, const QVariant& value) const; + void SetValue(const QString& key, const QVariant& value) const; + void SetValue(const QString& key, const QString& name, const QVariant& value) const; + +protected: + static QString ComputeSettingsDir(); + + std::unique_ptr m_settings; + QDir m_settings_dir; +}; \ No newline at end of file diff --git a/shadPS4/gui/shadps4gui.cpp b/shadPS4/gui/shadps4gui.cpp index c10d2eb1..9827e6b9 100644 --- a/shadPS4/gui/shadps4gui.cpp +++ b/shadPS4/gui/shadps4gui.cpp @@ -17,7 +17,7 @@ shadps4gui::shadps4gui(std::shared_ptr gui_settings, QWidget* pare //ui.horizontalLayout->addWidget(game_list); //show(); //game_list->PopulateAsync(); - game_list_frame* game_list2 = new game_list_frame(); + game_list_frame* game_list2 = new game_list_frame(m_gui_settings); ui.horizontalLayout->addWidget(game_list2); show(); } diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 802acab7..3223ef46 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -22,6 +22,7 @@ + @@ -45,7 +46,9 @@ - + + + diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index 7e510f3c..e62e16b6 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -74,6 +74,9 @@ gui + + gui + @@ -93,6 +96,12 @@ gui + + gui + + + gui + @@ -110,9 +119,6 @@ emulator\fileFormat - - gui - Header Files @@ -125,6 +131,9 @@ gui + + gui + From c0b2c357ec0a2de51da333f3901707e0a1bf8b3f Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 10:53:05 +0200 Subject: [PATCH 05/18] Load/Save column visability --- shadPS4/gui/game_list_frame.cpp | 22 +++++++++++++++++++++- shadPS4/gui/game_list_frame.h | 6 ++++++ shadPS4/gui/shadps4gui.cpp | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index fd9ca1db..ae6093ae 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -82,7 +82,7 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWid } } game_list_frame::~game_list_frame(){ - + SaveSettings(); } void game_list_frame::FixNarrowColumns() const { @@ -191,4 +191,24 @@ void game_list_frame::SortGameList() const // Shorten the last section to remove horizontal scrollbar if possible m_game_list->resizeColumnToContents(gui::column_count - 1); +} +void game_list_frame::LoadSettings() +{ + for (int col = 0; col < m_columnActs.count(); ++col) + { + const bool vis = m_gui_settings->GetGamelistColVisibility(col); + m_columnActs[col]->setChecked(vis); + m_game_list->setColumnHidden(col, !vis); + } + FixNarrowColumns(); + + m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState()); + +} +void game_list_frame::SaveSettings() +{ + for (int col = 0; col < m_columnActs.count(); ++col) + { + m_gui_settings->SetGamelistColVisibility(col, m_columnActs[col]->isChecked()); + } } \ No newline at end of file diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 4f8e610d..7991d55d 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -16,6 +16,12 @@ public : /** Fix columns with width smaller than the minimal section size */ void FixNarrowColumns() const; + /** Loads from settings. Public so that main frame can easily reset these settings if needed. */ + void LoadSettings(); + + /** Saves settings. Public so that main frame can save this when a caching of column widths is needed for settings backup */ + void SaveSettings(); + /** Resizes the columns to their contents and adds a small spacing */ void ResizeColumnsToContents(int spacing = 20) const; diff --git a/shadPS4/gui/shadps4gui.cpp b/shadPS4/gui/shadps4gui.cpp index 9827e6b9..849aebdb 100644 --- a/shadPS4/gui/shadps4gui.cpp +++ b/shadPS4/gui/shadps4gui.cpp @@ -19,6 +19,7 @@ shadps4gui::shadps4gui(std::shared_ptr gui_settings, QWidget* pare //game_list->PopulateAsync(); game_list_frame* game_list2 = new game_list_frame(m_gui_settings); ui.horizontalLayout->addWidget(game_list2); + game_list2->LoadSettings(); show(); } From fece7bc008a4dc5818e056053ec80c261b396560 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 11:01:02 +0200 Subject: [PATCH 06/18] menu for hide/show colums --- shadPS4/gui/game_list_frame.cpp | 8 ++++++++ shadPS4/shadps4.ini | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 shadPS4/shadps4.ini diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index ae6093ae..a3af8174 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -80,6 +80,14 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWid } }); } + + //events + connect(m_game_list->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, [this](const QPoint& pos) + { + QMenu* configure = new QMenu(this); + configure->addActions(m_columnActs); + configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos)); + }); } game_list_frame::~game_list_frame(){ SaveSettings(); diff --git a/shadPS4/shadps4.ini b/shadPS4/shadps4.ini new file mode 100644 index 00000000..f97319ed --- /dev/null +++ b/shadPS4/shadps4.ini @@ -0,0 +1,8 @@ +[GameList] +visibility_column_path=true +visibility_column_icon=true +visibility_column_name=true +visibility_column_serial=true +visibility_column_firmware=true +visibility_column_version=true +visibility_column_category=true From c60ce7897e39d22f4d5b533a971e6229f5895e07 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 11:14:15 +0200 Subject: [PATCH 07/18] sort columns , and sort order --- shadPS4/gui/game_list_frame.cpp | 40 +++++++++++++++++++++++++++++++-- shadPS4/gui/game_list_frame.h | 2 ++ shadPS4/gui/gui_settings.h | 4 ++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index a3af8174..03cfc12d 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,7 +1,7 @@ #include "game_list_frame.h" #include "gui_settings.h" -game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWidget* parent) +game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWidget* parent) : QWidget(parent) , m_gui_settings(std::move(gui_settings)) { @@ -88,8 +88,9 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings,QWid configure->addActions(m_columnActs); configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos)); }); + connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked); } -game_list_frame::~game_list_frame(){ +game_list_frame::~game_list_frame() { SaveSettings(); } void game_list_frame::FixNarrowColumns() const @@ -200,14 +201,46 @@ void game_list_frame::SortGameList() const // Shorten the last section to remove horizontal scrollbar if possible m_game_list->resizeColumnToContents(gui::column_count - 1); } + +void game_list_frame::OnHeaderColumnClicked(int col) +{ + if (col == 0) return; // Don't "sort" icons. + + if (col == m_sort_column) + { + m_col_sort_order = (m_col_sort_order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder; + } + else + { + m_col_sort_order = Qt::AscendingOrder; + } + m_sort_column = col; + + m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); + m_gui_settings->SetValue(gui::game_list_sortCol, col); + + SortGameList(); +} + void game_list_frame::LoadSettings() { + m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder; + m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt(); + + const QByteArray state = m_gui_settings->GetValue(gui::game_list_state).toByteArray(); + if (!m_game_list->horizontalHeader()->restoreState(state) && m_game_list->rowCount()) + { + // If no settings exist, resize to contents. + ResizeColumnsToContents(); + } + for (int col = 0; col < m_columnActs.count(); ++col) { const bool vis = m_gui_settings->GetGamelistColVisibility(col); m_columnActs[col]->setChecked(vis); m_game_list->setColumnHidden(col, !vis); } + SortGameList(); FixNarrowColumns(); m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState()); @@ -219,4 +252,7 @@ void game_list_frame::SaveSettings() { m_gui_settings->SetGamelistColVisibility(col, m_columnActs[col]->isChecked()); } + m_gui_settings->SetValue(gui::game_list_sortCol, m_sort_column); + m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); + m_gui_settings->SetValue(gui::game_list_state, m_game_list->horizontalHeader()->saveState()); } \ No newline at end of file diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 7991d55d..684d0b47 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -25,6 +25,8 @@ public : /** Resizes the columns to their contents and adds a small spacing */ void ResizeColumnsToContents(int spacing = 20) const; +private Q_SLOTS: + void OnHeaderColumnClicked(int col); private: void SortGameList() const; diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 57f5e9b9..234c6c9c 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -44,6 +44,10 @@ namespace gui const QString game_list = "GameList"; + const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true); + const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1); + const gui_save game_list_state = gui_save(game_list, "state", QByteArray()); + } class gui_settings : public settings From 86be7933067a0fd0a7e55d2068e63e1b3d9d9b60 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 18:12:11 +0200 Subject: [PATCH 08/18] we can now display entries in gamelist view --- shadPS4/gui/game_list_frame.cpp | 186 ++++++++++++++++++++++++++++++++ shadPS4/gui/game_list_frame.h | 19 ++++ shadPS4/gui/gui_settings.h | 18 ++++ shadPS4/shadPS4.vcxproj | 3 - shadPS4/shadps4.ini | 6 ++ 5 files changed, 229 insertions(+), 3 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 03cfc12d..b1aa17bf 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -1,10 +1,27 @@ #include "game_list_frame.h" #include "gui_settings.h" +#include "custom_table_widget_item.h" +#include "../emulator/fileFormat/PSF.h" game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWidget* parent) : QWidget(parent) , m_gui_settings(std::move(gui_settings)) { + m_icon_size = gui::game_list_icon_size_min; // ensure a valid size + m_is_list_layout = m_gui_settings->GetValue(gui::game_list_listMode).toBool(); + m_margin_factor = m_gui_settings->GetValue(gui::game_list_marginFactor).toReal(); + m_text_factor = m_gui_settings->GetValue(gui::game_list_textFactor).toReal(); + m_icon_color = m_gui_settings->GetValue(gui::game_list_iconColor).value(); + m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder; + m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt(); + + m_old_layout_is_list = m_is_list_layout; + + // Save factors for first setup + m_gui_settings->SetValue(gui::game_list_iconColor, m_icon_color); + m_gui_settings->SetValue(gui::game_list_marginFactor, m_margin_factor); + m_gui_settings->SetValue(gui::game_list_textFactor, m_text_factor); + m_game_list = new game_list_table(); m_game_list->setShowGrid(false); m_game_list->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -89,6 +106,8 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi configure->exec(m_game_list->horizontalHeader()->viewport()->mapToGlobal(pos)); }); connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked); + + Refresh();//TODO remove when watchers added } game_list_frame::~game_list_frame() { SaveSettings(); @@ -227,6 +246,8 @@ void game_list_frame::LoadSettings() m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder; m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt(); + Refresh(true); + const QByteArray state = m_gui_settings->GetValue(gui::game_list_state).toByteArray(); if (!m_game_list->horizontalHeader()->restoreState(state) && m_game_list->rowCount()) { @@ -255,4 +276,169 @@ void game_list_frame::SaveSettings() m_gui_settings->SetValue(gui::game_list_sortCol, m_sort_column); m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); m_gui_settings->SetValue(gui::game_list_state, m_game_list->horizontalHeader()->saveState()); +} +void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) +{ + if (from_drive) + { + m_path_list.clear(); + m_game_data.clear(); + + //TODO better ATM manually add path from 1 dir to m_paths_list + m_path_list.emplace_back(QDir::currentPath().toStdString() + "/game/"); + + QDir parent_folder(QString::fromStdString(m_path_list.at(0))); + QFileInfoList fList = parent_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst); + foreach(QFileInfo item, fList) + { + PSF psf; + if (!psf.open(item.absoluteFilePath().toStdString() + "/sce_sys/PARAM.SFO")) + continue;//if we can't open param.sfo go to the next entry + + //TODO std::string test = psf.get_string("TITLE_ID"); + QString iconpath(item.absoluteFilePath() + "/sce_sys/ICON0.PNG"); + + GameInfo game{}; + + game.icon_path = iconpath.toStdString(); + game.name = psf.get_string("TITLE"); + game.serial = psf.get_string("TITLE_ID"); + game.fw = (QString("%1").arg(psf.get_integer("SYSTEM_VER"), 8, 16, QLatin1Char('0'))).mid(1, 3).insert(1, '.').toStdString(); + game.version = psf.get_string("APP_VER"); + game.category = psf.get_string("CATEGORY"); + game.path = item.fileName().toStdString(); + + gui_game_info info{}; + info.info = game; + + m_games.push_back(std::make_shared(std::move(info))); + + + } + } + // Fill Game List / Game Grid + + if (m_is_list_layout) + { + const int scroll_position = m_game_list->verticalScrollBar()->value(); + PopulateGameList(); + SortGameList(); + //RepaintIcons(); + + if (scroll_after) + { + m_game_list->scrollTo(m_game_list->currentIndex(), QAbstractItemView::PositionAtCenter); + } + else + { + m_game_list->verticalScrollBar()->setValue(scroll_position); + } + } + else + { + //RepaintIcons(); + } + + + +} +/** + Cleans and readds entries to table widget in UI. +*/ +void game_list_frame::PopulateGameList() +{ + + //hackinsh + for (auto&& g : m_games) + { + m_game_data.push_back(g); + } + //end of hackinsh + + int selected_row = -1; + + const std::string selected_item = CurrentSelectionPath(); + + // Release old data + //TODO m_game_grid->clear_list(); + //TODO m_game_list->clear_list(); + + m_game_list->setRowCount(m_game_data.size()); + + int row = 0; + int index = -1; + for (const auto& game : m_game_data) + { + index++; + + + // Icon + custom_table_widget_item* icon_item = new custom_table_widget_item; + + icon_item->setData(Qt::UserRole, index, true); + icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game)); + + // Title + custom_table_widget_item* title_item = new custom_table_widget_item(game->info.name); + + // Serial + custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial); + + // Version + QString app_version = QString::fromStdString(game->info.version); + + m_game_list->setItem(row, gui::column_icon, icon_item); + m_game_list->setItem(row, gui::column_name, title_item); + m_game_list->setItem(row, gui::column_serial, serial_item); + m_game_list->setItem(row, gui::column_firmware, new custom_table_widget_item(game->info.fw)); + m_game_list->setItem(row, gui::column_version, new custom_table_widget_item(app_version)); + m_game_list->setItem(row, gui::column_category, new custom_table_widget_item(game->info.category)); + m_game_list->setItem(row, gui::column_path, new custom_table_widget_item(game->info.path)); + + if (selected_item == game->info.path + game->info.icon_path) + { + selected_row = row; + } + + row++; + } + m_game_list->setRowCount(row); + m_game_list->selectRow(selected_row); +} + +std::string game_list_frame::CurrentSelectionPath() +{ + std::string selection; + + QTableWidgetItem* item = nullptr; + + if (m_old_layout_is_list) + { + if (!m_game_list->selectedItems().isEmpty()) + { + item = m_game_list->item(m_game_list->currentRow(), 0); + } + } + else if (m_game_grid) + { + if (!m_game_grid->selectedItems().isEmpty()) + { + item = m_game_grid->currentItem(); + } + } + + if (item) + { + if (const QVariant var = item->data(gui::game_role); var.canConvert()) + { + if (const game_info game = var.value()) + { + selection = game->info.path + game->info.icon_path; + } + } + } + + m_old_layout_is_list = m_is_list_layout; + + return selection; } \ No newline at end of file diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 684d0b47..95e561ff 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -2,10 +2,12 @@ #include "game_list_table.h" #include "shadps4gui.h" +#include "game_list_grid.h" #include #include #include +#include class game_list_frame : public QWidget { @@ -25,10 +27,18 @@ public : /** Resizes the columns to their contents and adds a small spacing */ void ResizeColumnsToContents(int spacing = 20) const; + /** Refresh the gamelist with/without loading game data from files. Public so that main frame can refresh after vfs or install */ + void Refresh(const bool from_drive = false, const bool scroll_after = true); + private Q_SLOTS: void OnHeaderColumnClicked(int col); private: void SortGameList() const; + std::string CurrentSelectionPath(); + void PopulateGameList(); + + // Game Grid + game_list_grid* m_game_grid = nullptr; // Game List game_list_table* m_game_list = nullptr; @@ -36,12 +46,21 @@ private: Qt::SortOrder m_col_sort_order; int m_sort_column; + // List Mode + bool m_is_list_layout = true; + bool m_old_layout_is_list = true; + // data std::shared_ptr m_gui_settings; QList m_game_data; + std::vector m_path_list; + std::deque m_games; // Icons QSize m_icon_size; + QColor m_icon_color; + qreal m_margin_factor; + qreal m_text_factor; }; diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 234c6c9c..7b316862 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -1,9 +1,15 @@ #pragma once #include "settings.h" +#include namespace gui { + enum custom_roles + { + game_role = Qt::UserRole + 1337, + }; + enum game_list_columns { column_icon, @@ -42,11 +48,23 @@ namespace gui throw std::exception("get_game_list_column_name: Invalid column"); } + const QSize game_list_icon_size_min = QSize(40, 22); + const QSize game_list_icon_size_small = QSize(80, 44); + const QSize game_list_icon_size_medium = QSize(160, 88); + const QSize game_list_icon_size_max = QSize(320, 176); + const QString game_list = "GameList"; + const QColor game_list_icon_color = QColor(240, 240, 240, 255); + const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true); const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1); const gui_save game_list_state = gui_save(game_list, "state", QByteArray()); + const gui_save game_list_iconColor = gui_save(game_list, "iconColor", game_list_icon_color); + const gui_save game_list_listMode = gui_save(game_list, "listMode", true); + const gui_save game_list_textFactor = gui_save(game_list, "textFactor", qreal{ 2.0 }); + const gui_save game_list_marginFactor = gui_save(game_list, "marginFactor", qreal{ 0.09 }); + } diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 3223ef46..28e790c5 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -51,9 +51,6 @@ - - - {F005E4D9-1FBE-40B3-9FBD-35CEC59081CD} QtVS_v304 diff --git a/shadPS4/shadps4.ini b/shadPS4/shadps4.ini index f97319ed..325a6916 100644 --- a/shadPS4/shadps4.ini +++ b/shadPS4/shadps4.ini @@ -6,3 +6,9 @@ visibility_column_serial=true visibility_column_firmware=true visibility_column_version=true visibility_column_category=true +sortCol=4 +sortAsc=false +state="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\x4\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3\xfe\0\0\0\a\0\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x96\xff\xff\xff\xff\0\0\0\x1\0\0\0\0\0\0\0\a\0\0\0'\0\0\0\x1\0\0\0\x2\0\0\0\xbc\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\0=\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\x1p\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0\x42\0\0\0\0)" +iconColor=@Variant(\0\0\0\x43\x1\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\0\0) +marginFactor=0.09 +textFactor=2 From 8b9f09442048bf9d87758986ce4e55ae665a4bf6 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 18:30:24 +0200 Subject: [PATCH 09/18] ok we can display icons in columns now --- shadPS4/gui/game_list_frame.cpp | 75 ++++++++++++++++++++++++++++++++- shadPS4/gui/game_list_frame.h | 5 +++ shadPS4/shadps4.ini | 6 +-- 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index b1aa17bf..177f5224 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -2,6 +2,7 @@ #include "gui_settings.h" #include "custom_table_widget_item.h" #include "../emulator/fileFormat/PSF.h" +#include game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWidget* parent) : QWidget(parent) @@ -323,7 +324,7 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) const int scroll_position = m_game_list->verticalScrollBar()->value(); PopulateGameList(); SortGameList(); - //RepaintIcons(); + RepaintIcons(); if (scroll_after) { @@ -336,7 +337,7 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) } else { - //RepaintIcons(); + RepaintIcons(); } @@ -367,6 +368,7 @@ void game_list_frame::PopulateGameList() int row = 0; int index = -1; + RepaintIcons();//hackish for (const auto& game : m_game_data) { index++; @@ -374,6 +376,7 @@ void game_list_frame::PopulateGameList() // Icon custom_table_widget_item* icon_item = new custom_table_widget_item; + icon_item->setData(Qt::DecorationRole, game->pxmap); icon_item->setData(Qt::UserRole, index, true); icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game)); @@ -441,4 +444,72 @@ std::string game_list_frame::CurrentSelectionPath() m_old_layout_is_list = m_is_list_layout; return selection; +} + +void game_list_frame::RepaintIcons(const bool& from_settings) +{ + for (auto& game : m_game_data) + { + game->icon.load(QString::fromStdString(game->info.icon_path)); + game->pxmap = PaintedPixmap(game->icon); + } + +} + +QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const +{ + const qreal device_pixel_ratio = devicePixelRatioF(); + QSize canvas_size(320, 176); + QSize icon_size(icon.size()); + QPoint target_pos; + + if (!icon.isNull()) + { + // Let's upscale the original icon to at least fit into the outer rect of the size of PS3's ICON0.PNG + if (icon_size.width() < 320 || icon_size.height() < 176) + { + icon_size.scale(320, 176, Qt::KeepAspectRatio); + } + + canvas_size = icon_size; + + // Calculate the centered size and position of the icon on our canvas. + if (icon_size.width() != 320 || icon_size.height() != 176) + { + constexpr double target_ratio = 320.0 / 176.0; // aspect ratio 20:11 + + if ((icon_size.width() / static_cast(icon_size.height())) > target_ratio) + { + canvas_size.setHeight(std::ceil(icon_size.width() / target_ratio)); + } + else + { + canvas_size.setWidth(std::ceil(icon_size.height() * target_ratio)); + } + + target_pos.setX(std::max(0, (canvas_size.width() - icon_size.width()) / 2.0)); + target_pos.setY(std::max(0, (canvas_size.height() - icon_size.height()) / 2.0)); + } + } + + // Create a canvas large enough to fit our entire scaled icon + QPixmap canvas(canvas_size * device_pixel_ratio); + canvas.setDevicePixelRatio(device_pixel_ratio); + canvas.fill(m_icon_color); + + // Create a painter for our canvas + QPainter painter(&canvas); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + + // Draw the icon onto our canvas + if (!icon.isNull()) + { + painter.drawPixmap(target_pos.x(), target_pos.y(), icon_size.width(), icon_size.height(), icon); + } + + // Finish the painting + painter.end(); + + // Scale and return our final image + return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation); } \ No newline at end of file diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 95e561ff..29ad1ee6 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -30,9 +30,14 @@ public : /** Refresh the gamelist with/without loading game data from files. Public so that main frame can refresh after vfs or install */ void Refresh(const bool from_drive = false, const bool scroll_after = true); + /** Repaint Gamelist Icons with new background color */ + void RepaintIcons(const bool& from_settings = false); + + private Q_SLOTS: void OnHeaderColumnClicked(int col); private: + QPixmap PaintedPixmap(const QPixmap& icon) const; void SortGameList() const; std::string CurrentSelectionPath(); void PopulateGameList(); diff --git a/shadPS4/shadps4.ini b/shadPS4/shadps4.ini index 325a6916..2160d85d 100644 --- a/shadPS4/shadps4.ini +++ b/shadPS4/shadps4.ini @@ -6,9 +6,9 @@ visibility_column_serial=true visibility_column_firmware=true visibility_column_version=true visibility_column_category=true -sortCol=4 -sortAsc=false -state="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\x4\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3\xfe\0\0\0\a\0\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x96\xff\xff\xff\xff\0\0\0\x1\0\0\0\0\0\0\0\a\0\0\0'\0\0\0\x1\0\0\0\x2\0\0\0\xbc\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\0=\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\x1p\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0\x42\0\0\0\0)" +sortCol=1 +sortAsc=true +state="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2\xe1\0\0\0\a\0\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x96\xff\xff\xff\xff\0\0\0\x1\0\0\0\0\0\0\0\a\0\0\0.\0\0\0\x1\0\0\0\x2\0\0\0\xc6\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\0=\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0\x42\0\0\0\0)" iconColor=@Variant(\0\0\0\x43\x1\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\0\0) marginFactor=0.09 textFactor=2 From f5570a156f75eea89ffac79290e8323995281659 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 10 Mar 2023 18:37:04 +0200 Subject: [PATCH 10/18] ingnore ini files --- .gitignore | 1 + shadPS4/shadps4.ini | 14 -------------- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 shadPS4/shadps4.ini diff --git a/.gitignore b/.gitignore index ba8935de..517c46c6 100644 --- a/.gitignore +++ b/.gitignore @@ -400,3 +400,4 @@ FodyWeavers.xsd /shadPS4/psf.txt /tools/pkg extractor/game/* /tools/pkg extractor/*.pkg +/shadPS4/shadps4.ini diff --git a/shadPS4/shadps4.ini b/shadPS4/shadps4.ini deleted file mode 100644 index 2160d85d..00000000 --- a/shadPS4/shadps4.ini +++ /dev/null @@ -1,14 +0,0 @@ -[GameList] -visibility_column_path=true -visibility_column_icon=true -visibility_column_name=true -visibility_column_serial=true -visibility_column_firmware=true -visibility_column_version=true -visibility_column_category=true -sortCol=1 -sortAsc=true -state="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2\xe1\0\0\0\a\0\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x96\xff\xff\xff\xff\0\0\0\x1\0\0\0\0\0\0\0\a\0\0\0.\0\0\0\x1\0\0\0\x2\0\0\0\xc6\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\0=\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x96\0\0\0\x1\0\0\0\0\0\0\0\x42\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0\x42\0\0\0\0)" -iconColor=@Variant(\0\0\0\x43\x1\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\0\0) -marginFactor=0.09 -textFactor=2 From 9e4a670be820b0787fec970aeb57e60080bf731b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Tue, 14 Mar 2023 01:02:06 +0200 Subject: [PATCH 11/18] better handling of icons in list mode --- shadPS4/gui/custom_table_widget_item.cpp | 4 +- shadPS4/gui/custom_table_widget_item.h | 3 +- shadPS4/gui/game_list_frame.cpp | 60 ++++++++++++++++++--- shadPS4/gui/game_list_frame.h | 5 +- shadPS4/gui/game_list_grid.cpp | 68 ++++++++++++------------ shadPS4/gui/game_list_item.h | 44 +++++++++++++++ shadPS4/gui/game_list_table.h | 2 + shadPS4/gui/qt_utils.h | 23 ++++++++ shadPS4/shadPS4.vcxproj | 6 ++- 9 files changed, 170 insertions(+), 45 deletions(-) create mode 100644 shadPS4/gui/game_list_item.h create mode 100644 shadPS4/gui/qt_utils.h diff --git a/shadPS4/gui/custom_table_widget_item.cpp b/shadPS4/gui/custom_table_widget_item.cpp index 6b418046..26a78815 100644 --- a/shadPS4/gui/custom_table_widget_item.cpp +++ b/shadPS4/gui/custom_table_widget_item.cpp @@ -3,7 +3,7 @@ #include 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) { diff --git a/shadPS4/gui/custom_table_widget_item.h b/shadPS4/gui/custom_table_widget_item.h index 00ffc18a..0ca88e48 100644 --- a/shadPS4/gui/custom_table_widget_item.h +++ b/shadPS4/gui/custom_table_widget_item.h @@ -1,7 +1,8 @@ #pragma once +#include "game_list_item.h" #include -class custom_table_widget_item : public QTableWidgetItem +class custom_table_widget_item : public game_list_item { private: int m_sort_role = Qt::DisplayRole; diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 177f5224..409a5441 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -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 +#include game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWidget* parent) : QWidget(parent) @@ -107,10 +109,19 @@ game_list_frame::game_list_frame(std::shared_ptr 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::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 diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 29ad1ee6..16af942c 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -3,11 +3,13 @@ #include "game_list_table.h" #include "shadps4gui.h" #include "game_list_grid.h" - +#include "game_list_item.h" #include #include #include #include +#include +#include class game_list_frame : public QWidget { @@ -60,6 +62,7 @@ private: QList m_game_data; std::vector m_path_list; std::deque m_games; + QFutureWatcher m_repaint_watcher; // Icons QSize m_icon_size; diff --git a/shadPS4/gui/game_list_grid.cpp b/shadPS4/gui/game_list_grid.cpp index aeef3e50..d6b0f23b 100644 --- a/shadPS4/gui/game_list_grid.cpp +++ b/shadPS4/gui/game_list_grid.cpp @@ -1,6 +1,6 @@ #include "game_list_grid.h" #include "game_list_grid_delegate.h" - +#include "game_list_item.h" #include #include @@ -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); diff --git a/shadPS4/gui/game_list_item.h b/shadPS4/gui/game_list_item.h new file mode 100644 index 00000000..e000be0a --- /dev/null +++ b/shadPS4/gui/game_list_item.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include + +using icon_callback_t = std::function; + +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; +}; diff --git a/shadPS4/gui/game_list_table.h b/shadPS4/gui/game_list_table.h index 3678a08c..26a16bf7 100644 --- a/shadPS4/gui/game_list_table.h +++ b/shadPS4/gui/game_list_table.h @@ -3,12 +3,14 @@ #include #include #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 game_info; diff --git a/shadPS4/gui/qt_utils.h b/shadPS4/gui/qt_utils.h new file mode 100644 index 00000000..00ad829b --- /dev/null +++ b/shadPS4/gui/qt_utils.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace gui +{ + namespace utils + { + template + void stop_future_watcher(QFutureWatcher& watcher, bool cancel) + { + if (watcher.isStarted() || watcher.isRunning()) + { + if (cancel) + { + watcher.cancel(); + } + watcher.waitForFinished(); + } + } + } // utils +} // gui + diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 28e790c5..5338f302 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -45,10 +45,12 @@ + + @@ -73,12 +75,12 @@ 6.4.2 - core;gui;widgets + core;gui;widgets;concurrent debug 6.4.2 - core;gui;widgets + core;gui;widgets;concurrent release From 583298211d9a10e0549a2bd716d50571d2958b8b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Tue, 14 Mar 2023 10:10:44 +0200 Subject: [PATCH 12/18] some more work on game_list repainter --- shadPS4/gui/game_list_frame.cpp | 33 ++++++++++++++++++++++++++++----- shadPS4/gui/game_list_frame.h | 1 + 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 409a5441..1344fb44 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -110,13 +110,14 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi }); connect(m_game_list->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnHeaderColumnClicked); connect(&m_repaint_watcher, &QFutureWatcher::resultReadyAt, this, [this](int index) + { + if (!m_is_list_layout) return; + if (game_list_item* item = m_repaint_watcher.resultAt(index)) { - if (!m_is_list_layout) return; - if (game_list_item* item = m_repaint_watcher.resultAt(index)) - { item->call_icon_func(); - } - }); + } + }); + connect(&m_repaint_watcher, &QFutureWatcher::finished, this, &game_list_frame::OnRepaintFinished); Refresh();//TODO remove when watchers added } @@ -279,6 +280,28 @@ void game_list_frame::LoadSettings() m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState()); } + +void game_list_frame::OnRepaintFinished() +{ + if (m_is_list_layout) + { + // 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); + } + else + { + // The game grid needs to be recreated from scratch + //TODO !! + } +} + void game_list_frame::SaveSettings() { for (int col = 0; col < m_columnActs.count(); ++col) diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 16af942c..e5b399b8 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -38,6 +38,7 @@ public : private Q_SLOTS: void OnHeaderColumnClicked(int col); + void OnRepaintFinished(); private: QPixmap PaintedPixmap(const QPixmap& icon) const; void SortGameList() const; From 4612305bd65e1948d9c676cee2b9e58c1a7eba21 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 15 Mar 2023 08:41:27 +0200 Subject: [PATCH 13/18] more work on game_list --- shadPS4/gui/game_list_frame.cpp | 310 +++++++++++++++++--------------- shadPS4/gui/game_list_frame.h | 2 + 2 files changed, 167 insertions(+), 145 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index 1344fb44..d5c5d25e 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -76,29 +76,29 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi m_columnActs[col]->setCheckable(true); connect(m_columnActs[col], &QAction::triggered, this, [this, col](bool checked) + { + if (!checked) // be sure to have at least one column left so you can call the context menu at all time { - if (!checked) // be sure to have at least one column left so you can call the context menu at all time + int c = 0; + for (int i = 0; i < m_columnActs.count(); ++i) { - int c = 0; - for (int i = 0; i < m_columnActs.count(); ++i) - { - if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1) - break; - } - if (c < 2) - { - m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state - return; - } + if (m_gui_settings->GetGamelistColVisibility(i) && ++c > 1) + break; } - m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show. - m_gui_settings->SetGamelistColVisibility(col, checked); + if (c < 2) + { + m_columnActs[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state + return; + } + } + m_game_list->setColumnHidden(col, !checked); // Negate because it's a set col hidden and we have menu say show. + m_gui_settings->SetGamelistColVisibility(col, checked); - if (checked) // handle hidden columns that have zero width after showing them (stuck between others) - { - FixNarrowColumns(); - } - }); + if (checked) // handle hidden columns that have zero width after showing them (stuck between others) + { + FixNarrowColumns(); + } + }); } //events @@ -119,139 +119,27 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi }); connect(&m_repaint_watcher, &QFutureWatcher::finished, this, &game_list_frame::OnRepaintFinished); + connect(&m_refresh_watcher, &QFutureWatcher::finished, this, &game_list_frame::OnRefreshFinished); + connect(&m_refresh_watcher, &QFutureWatcher::canceled, this, [this]() + { + gui::utils::stop_future_watcher(m_repaint_watcher, true); + + m_path_list.clear(); + m_game_data.clear(); + m_games.clear(); + }); + Refresh();//TODO remove when watchers added } game_list_frame::~game_list_frame() { gui::utils::stop_future_watcher(m_repaint_watcher, true); + gui::utils::stop_future_watcher(m_refresh_watcher, true); SaveSettings(); } -void game_list_frame::FixNarrowColumns() const + +void game_list_frame::OnRefreshFinished() { - qApp->processEvents(); - // handle columns (other than the icon column) that have zero width after showing them (stuck between others) - for (int col = 1; col < m_columnActs.count(); ++col) - { - if (m_game_list->isColumnHidden(col)) - { - continue; - } - - if (m_game_list->columnWidth(col) <= m_game_list->horizontalHeader()->minimumSectionSize()) - { - m_game_list->setColumnWidth(col, m_game_list->horizontalHeader()->minimumSectionSize()); - } - } -} - -void game_list_frame::ResizeColumnsToContents(int spacing) const -{ - if (!m_game_list) - { - return; - } - - m_game_list->verticalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents); - m_game_list->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents); - - // Make non-icon columns slighty bigger for better visuals - for (int i = 1; i < m_game_list->columnCount(); i++) - { - if (m_game_list->isColumnHidden(i)) - { - continue; - } - - const int size = m_game_list->horizontalHeader()->sectionSize(i) + spacing; - m_game_list->horizontalHeader()->resizeSection(i, size); - } -} - -void game_list_frame::SortGameList() const -{ - // Back-up old header sizes to handle unwanted column resize in case of zero search results - QList column_widths; - const int old_row_count = m_game_list->rowCount(); - const int old_game_count = m_game_data.count(); - - for (int i = 0; i < m_game_list->columnCount(); i++) - { - column_widths.append(m_game_list->columnWidth(i)); - } - - // Sorting resizes hidden columns, so unhide them as a workaround - QList columns_to_hide; - - for (int i = 0; i < m_game_list->columnCount(); i++) - { - if (m_game_list->isColumnHidden(i)) - { - m_game_list->setColumnHidden(i, false); - columns_to_hide << i; - } - } - - // Sort the list by column and sort order - m_game_list->sortByColumn(m_sort_column, m_col_sort_order); - - // Hide columns again - for (auto i : columns_to_hide) - { - m_game_list->setColumnHidden(i, true); - } - - // Don't resize the columns if no game is shown to preserve the header settings - if (!m_game_list->rowCount()) - { - for (int i = 0; i < m_game_list->columnCount(); i++) - { - m_game_list->setColumnWidth(i, column_widths[i]); - } - - m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed); - return; - } - - // Fixate vertical header and row height - m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height()); - m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height()); - m_game_list->resizeRowsToContents(); - - // Resize columns if the game list was empty before - if (!old_row_count && !old_game_count) - { - ResizeColumnsToContents(); - } - else - { - m_game_list->resizeColumnToContents(gui::column_icon); - } - - // Fixate icon column - m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed); - - // Shorten the last section to remove horizontal scrollbar if possible - m_game_list->resizeColumnToContents(gui::column_count - 1); -} - -void game_list_frame::OnHeaderColumnClicked(int col) -{ - if (col == 0) return; // Don't "sort" icons. - - if (col == m_sort_column) - { - m_col_sort_order = (m_col_sort_order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder; - } - else - { - m_col_sort_order = Qt::AscendingOrder; - } - m_sort_column = col; - - m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); - m_gui_settings->SetValue(gui::game_list_sortCol, col); - - SortGameList(); } void game_list_frame::LoadSettings() @@ -314,6 +202,9 @@ void game_list_frame::SaveSettings() } void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) { + gui::utils::stop_future_watcher(m_repaint_watcher, true); + gui::utils::stop_future_watcher(m_refresh_watcher, from_drive); + if (from_drive) { m_path_list.clear(); @@ -527,6 +418,135 @@ void game_list_frame::RepaintIcons(const bool& from_settings) m_repaint_watcher.setFuture(QtConcurrent::mapped(m_game_data, func)); } +void game_list_frame::FixNarrowColumns() const +{ + qApp->processEvents(); + + // handle columns (other than the icon column) that have zero width after showing them (stuck between others) + for (int col = 1; col < m_columnActs.count(); ++col) + { + if (m_game_list->isColumnHidden(col)) + { + continue; + } + + if (m_game_list->columnWidth(col) <= m_game_list->horizontalHeader()->minimumSectionSize()) + { + m_game_list->setColumnWidth(col, m_game_list->horizontalHeader()->minimumSectionSize()); + } + } +} + +void game_list_frame::ResizeColumnsToContents(int spacing) const +{ + if (!m_game_list) + { + return; + } + + m_game_list->verticalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents); + m_game_list->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents); + + // Make non-icon columns slighty bigger for better visuals + for (int i = 1; i < m_game_list->columnCount(); i++) + { + if (m_game_list->isColumnHidden(i)) + { + continue; + } + + const int size = m_game_list->horizontalHeader()->sectionSize(i) + spacing; + m_game_list->horizontalHeader()->resizeSection(i, size); + } +} + +void game_list_frame::OnHeaderColumnClicked(int col) +{ + if (col == 0) return; // Don't "sort" icons. + + if (col == m_sort_column) + { + m_col_sort_order = (m_col_sort_order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder; + } + else + { + m_col_sort_order = Qt::AscendingOrder; + } + m_sort_column = col; + + m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); + m_gui_settings->SetValue(gui::game_list_sortCol, col); + + SortGameList(); +} + +void game_list_frame::SortGameList() const +{ + // Back-up old header sizes to handle unwanted column resize in case of zero search results + QList column_widths; + const int old_row_count = m_game_list->rowCount(); + const int old_game_count = m_game_data.count(); + + for (int i = 0; i < m_game_list->columnCount(); i++) + { + column_widths.append(m_game_list->columnWidth(i)); + } + + // Sorting resizes hidden columns, so unhide them as a workaround + QList columns_to_hide; + + for (int i = 0; i < m_game_list->columnCount(); i++) + { + if (m_game_list->isColumnHidden(i)) + { + m_game_list->setColumnHidden(i, false); + columns_to_hide << i; + } + } + + // Sort the list by column and sort order + m_game_list->sortByColumn(m_sort_column, m_col_sort_order); + + // Hide columns again + for (auto i : columns_to_hide) + { + m_game_list->setColumnHidden(i, true); + } + + // Don't resize the columns if no game is shown to preserve the header settings + if (!m_game_list->rowCount()) + { + for (int i = 0; i < m_game_list->columnCount(); i++) + { + m_game_list->setColumnWidth(i, column_widths[i]); + } + + m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed); + return; + } + + // Fixate vertical header and row height + m_game_list->verticalHeader()->setMinimumSectionSize(m_icon_size.height()); + m_game_list->verticalHeader()->setMaximumSectionSize(m_icon_size.height()); + m_game_list->resizeRowsToContents(); + + // Resize columns if the game list was empty before + if (!old_row_count && !old_game_count) + { + ResizeColumnsToContents(); + } + else + { + m_game_list->resizeColumnToContents(gui::column_icon); + } + + // Fixate icon column + m_game_list->horizontalHeader()->setSectionResizeMode(gui::column_icon, QHeaderView::Fixed); + + // Shorten the last section to remove horizontal scrollbar if possible + m_game_list->resizeColumnToContents(gui::column_count - 1); +} + QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const { const qreal device_pixel_ratio = devicePixelRatioF(); @@ -583,4 +603,4 @@ QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const // Scale and return our final image return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation); -} \ No newline at end of file +} diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index e5b399b8..75e4a17a 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -39,6 +39,7 @@ public : private Q_SLOTS: void OnHeaderColumnClicked(int col); void OnRepaintFinished(); + void OnRefreshFinished(); private: QPixmap PaintedPixmap(const QPixmap& icon) const; void SortGameList() const; @@ -64,6 +65,7 @@ private: std::vector m_path_list; std::deque m_games; QFutureWatcher m_repaint_watcher; + QFutureWatcher m_refresh_watcher; // Icons QSize m_icon_size; From e3ebcff4a58be775314c8b3c331b2f9368a06a94 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 15 Mar 2023 21:39:39 +0200 Subject: [PATCH 14/18] refactoring main window (still not functional) --- shadPS4/gui/custom_dock_widget.h | 67 +++++++ shadPS4/gui/game_list_frame.cpp | 21 ++- shadPS4/gui/game_list_frame.h | 10 +- shadPS4/gui/gui_settings.h | 5 + shadPS4/gui/main_window.cpp | 73 ++++++++ shadPS4/gui/main_window.h | 43 +++++ shadPS4/gui/main_window.ui | 297 +++++++++++++++++++++++++++++++ shadPS4/shadPS4.vcxproj | 4 + shadPS4/shadPS4.vcxproj.filters | 21 ++- 9 files changed, 529 insertions(+), 12 deletions(-) create mode 100644 shadPS4/gui/custom_dock_widget.h create mode 100644 shadPS4/gui/main_window.cpp create mode 100644 shadPS4/gui/main_window.h create mode 100644 shadPS4/gui/main_window.ui diff --git a/shadPS4/gui/custom_dock_widget.h b/shadPS4/gui/custom_dock_widget.h new file mode 100644 index 00000000..ece514c1 --- /dev/null +++ b/shadPS4/gui/custom_dock_widget.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +class custom_dock_widget : public QDockWidget +{ +private: + std::shared_ptr m_title_bar_widget; + bool m_is_title_bar_visible = true; + +public: + explicit custom_dock_widget(const QString& title, QWidget* parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()) + : QDockWidget(title, parent, flags) + { + m_title_bar_widget.reset(titleBarWidget()); + + connect(this, &QDockWidget::topLevelChanged, [this](bool/* topLevel*/) + { + SetTitleBarVisible(m_is_title_bar_visible); + style()->unpolish(this); + style()->polish(this); + }); + } + + void SetTitleBarVisible(bool visible) + { + if (visible || isFloating()) + { + if (m_title_bar_widget.get() != titleBarWidget()) + { + setTitleBarWidget(m_title_bar_widget.get()); + QMargins margins = widget()->contentsMargins(); + margins.setTop(0); + widget()->setContentsMargins(margins); + } + } + else + { + setTitleBarWidget(new QWidget()); + QMargins margins = widget()->contentsMargins(); + margins.setTop(1); + widget()->setContentsMargins(margins); + } + + m_is_title_bar_visible = visible; + } + +protected: + void paintEvent(QPaintEvent* event) override + { + // We need to repaint the dock widgets as plain widgets in floating mode. + // Source: https://stackoverflow.com/questions/10272091/cannot-add-a-background-image-to-a-qdockwidget + if (isFloating()) + { + QStyleOption opt; + opt.initFrom(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + return; + } + + // Use inherited method for docked mode because otherwise the dock would lose the title etc. + QDockWidget::paintEvent(event); + } +}; diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index d5c5d25e..ba38d44b 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -7,7 +7,7 @@ #include game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWidget* parent) - : QWidget(parent) + : custom_dock_widget(tr("Game List"), parent) , m_gui_settings(std::move(gui_settings)) { m_icon_size = gui::game_list_icon_size_min; // ensure a valid size @@ -25,6 +25,12 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi m_gui_settings->SetValue(gui::game_list_marginFactor, m_margin_factor); m_gui_settings->SetValue(gui::game_list_textFactor, m_text_factor); + m_game_dock = new QMainWindow(this); + m_game_dock->setWindowFlags(Qt::Widget); + setWidget(m_game_dock); + + m_game_grid = new game_list_grid(QSize(), m_icon_color, m_margin_factor, m_text_factor, false); + m_game_list = new game_list_table(); m_game_list->setShowGrid(false); m_game_list->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -48,13 +54,12 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi m_game_list->installEventFilter(this); m_game_list->setColumnCount(gui::column_count); - //temp code - QVBoxLayout* layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - QSpacerItem* item = new QSpacerItem(100, 1, QSizePolicy::Expanding, QSizePolicy::Fixed); - layout->addWidget(m_game_list); - setLayout(layout); - //endof temp code + m_central_widget = new QStackedWidget(this); + m_central_widget->addWidget(m_game_list); + m_central_widget->addWidget(m_game_grid); + m_central_widget->setCurrentWidget(m_is_list_layout ? m_game_list : m_game_grid); + + m_game_dock->setCentralWidget(m_central_widget); // Actions regarding showing/hiding columns auto add_column = [this](gui::game_list_columns col, const QString& header_text, const QString& action_text) diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 75e4a17a..4182ba7d 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -1,17 +1,19 @@ #pragma once #include "game_list_table.h" +#include "custom_dock_widget.h" #include "shadps4gui.h" #include "game_list_grid.h" #include "game_list_item.h" #include #include +#include #include #include #include #include -class game_list_frame : public QWidget +class game_list_frame : public custom_dock_widget { Q_OBJECT public : @@ -40,12 +42,18 @@ private Q_SLOTS: void OnHeaderColumnClicked(int col); void OnRepaintFinished(); void OnRefreshFinished(); +Q_SIGNALS: + void GameListFrameClosed(); private: QPixmap PaintedPixmap(const QPixmap& icon) const; void SortGameList() const; std::string CurrentSelectionPath(); void PopulateGameList(); + // Which widget we are displaying depends on if we are in grid or list mode. + QMainWindow* m_game_dock = nullptr; + QStackedWidget* m_central_widget = nullptr; + // Game Grid game_list_grid* m_game_grid = nullptr; diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 7b316862..ca2af497 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -53,10 +53,15 @@ namespace gui const QSize game_list_icon_size_medium = QSize(160, 88); const QSize game_list_icon_size_max = QSize(320, 176); + const int game_list_max_slider_pos = 100; + + const QString main_window = "main_window"; const QString game_list = "GameList"; const QColor game_list_icon_color = QColor(240, 240, 240, 255); + const gui_save main_window_gamelist_visible = gui_save(main_window, "gamelistVisible", true); + const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true); const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1); const gui_save game_list_state = gui_save(game_list, "state", QByteArray()); diff --git a/shadPS4/gui/main_window.cpp b/shadPS4/gui/main_window.cpp new file mode 100644 index 00000000..a98f78bd --- /dev/null +++ b/shadPS4/gui/main_window.cpp @@ -0,0 +1,73 @@ +#include "game_list_frame.h" +#include "main_window.h" +#include "gui_settings.h" +#include "ui_main_window.h" + +main_window::main_window(std::shared_ptr gui_settings, QWidget* parent) + : QMainWindow(parent) + , ui(new Ui::main_window) +{ + + ui->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose); +} + +main_window::~main_window() +{ + +} + +bool main_window::Init() +{ + // add toolbar widgets + ui->toolBar->setObjectName("mw_toolbar"); + ui->sizeSlider->setRange(0, gui::game_list_max_slider_pos); + ui->toolBar->addWidget(ui->sizeSliderContainer); + ui->toolBar->addWidget(ui->mw_searchbar); + + CreateActions(); + CreateDockWindows(); + + return true; +} + +void main_window::CreateActions() +{ + //create action group for icon size + m_icon_size_act_group = new QActionGroup(this); + m_icon_size_act_group->addAction(ui->setIconSizeTinyAct); + m_icon_size_act_group->addAction(ui->setIconSizeSmallAct); + m_icon_size_act_group->addAction(ui->setIconSizeMediumAct); + m_icon_size_act_group->addAction(ui->setIconSizeLargeAct); + + //create action group for list mode + m_list_mode_act_group = new QActionGroup(this); + m_list_mode_act_group->addAction(ui->setlistModeListAct); + m_list_mode_act_group->addAction(ui->setlistModeGridAct); + +} + +void main_window::CreateDockWindows() +{ + m_main_window = new QMainWindow(); + m_main_window->setContextMenuPolicy(Qt::PreventContextMenu); + + m_game_list_frame = new game_list_frame(m_gui_settings,m_main_window); + m_game_list_frame->setObjectName("gamelist"); + + m_main_window->addDockWidget(Qt::LeftDockWidgetArea, m_game_list_frame); + + m_main_window->setDockNestingEnabled(true); + + setCentralWidget(m_main_window); + + connect(m_game_list_frame, &game_list_frame::GameListFrameClosed, this, [this]() + { + if (ui->showGameListAct->isChecked()) + { + ui->showGameListAct->setChecked(false); + m_gui_settings->SetValue(gui::main_window_gamelist_visible, false); + } + }); +} diff --git a/shadPS4/gui/main_window.h b/shadPS4/gui/main_window.h new file mode 100644 index 00000000..3e6e856f --- /dev/null +++ b/shadPS4/gui/main_window.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +class gui_settings; +class game_list_frame; + +namespace Ui +{ + class main_window; +} + +class main_window : public QMainWindow +{ + Q_OBJECT + + std::unique_ptr ui; + + bool m_is_list_mode = true; + bool m_save_slider_pos = false; + int m_other_slider_pos = 0; + +public: + explicit main_window(std::shared_ptr gui_settings,QWidget* parent = nullptr); + ~main_window(); + bool Init(); + +private: + void CreateActions(); + void CreateDockWindows(); + + QActionGroup* m_icon_size_act_group = nullptr; + QActionGroup* m_list_mode_act_group = nullptr; + + // Dockable widget frames + QMainWindow* m_main_window = nullptr; + game_list_frame* m_game_list_frame = nullptr; + + std::shared_ptr m_gui_settings; + +}; + diff --git a/shadPS4/gui/main_window.ui b/shadPS4/gui/main_window.ui new file mode 100644 index 00000000..bbe343a4 --- /dev/null +++ b/shadPS4/gui/main_window.ui @@ -0,0 +1,297 @@ + + + main_window + + + + 0 + 0 + 1058 + 580 + + + + + 0 + 0 + + + + + 4 + 0 + + + + RPCS3 + + + false + + + true + + + true + + + QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::GroupedDragging + + + + + 0 + 0 + + + + + + 480 + 10 + 251 + 31 + + + + + 0 + 0 + + + + + 10 + false + + + + Qt::ClickFocus + + + false + + + Search... + + + false + + + + + + 280 + 10 + 181 + 31 + + + + + 0 + 0 + + + + + 0 + + + 14 + + + 0 + + + 14 + + + 0 + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + false + + + Qt::Horizontal + + + QSlider::NoTicks + + + + + + + + + + 0 + 0 + 1058 + 22 + + + + Qt::PreventContextMenu + + + + File + + + + + + + + View + + + + Game List Icons + + + + + + + + + Game List Mode + + + + + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + Install Packages (PKG) + + + Install application from a .pkg file + + + + + Install Firmware + + + Install firmware from PS3UPDAT.PUP + + + + + Exit + + + Exit RPCS3 + + + Exit the application. + + + + + true + + + Show Game List + + + + + Game List Refresh + + + + + true + + + Tiny + + + + + true + + + true + + + Small + + + + + true + + + Medium + + + + + true + + + Large + + + + + true + + + true + + + List View + + + + + true + + + Grid View + + + + + + + + + diff --git a/shadPS4/shadPS4.vcxproj b/shadPS4/shadPS4.vcxproj index 5338f302..86b503fa 100644 --- a/shadPS4/shadPS4.vcxproj +++ b/shadPS4/shadPS4.vcxproj @@ -22,6 +22,7 @@ + @@ -30,6 +31,7 @@ + @@ -41,6 +43,7 @@ + @@ -50,6 +53,7 @@ + diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index e62e16b6..87bb22e0 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -77,11 +77,17 @@ gui + + Source Files + Form Files + + Form Files + @@ -102,6 +108,9 @@ gui + + Header Files + @@ -134,8 +143,14 @@ gui - - - + + Header Files + + + Header Files + + + gui + \ No newline at end of file From 4306dce221397e8e8105b35a1de690d4ef1d6363 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 16 Mar 2023 10:46:11 +0200 Subject: [PATCH 15/18] more work on main window --- shadPS4/gui/game_list_frame.cpp | 37 ++++++++++ shadPS4/gui/game_list_frame.h | 15 +++++ shadPS4/gui/gui_settings.cpp | 4 ++ shadPS4/gui/gui_settings.h | 10 +++ shadPS4/gui/main_window.cpp | 116 ++++++++++++++++++++++++++++++++ shadPS4/gui/main_window.h | 5 ++ 6 files changed, 187 insertions(+) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index ba38d44b..ee2b28f7 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -609,3 +609,40 @@ QPixmap game_list_frame::PaintedPixmap(const QPixmap& icon) const // Scale and return our final image return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation); } +void game_list_frame::SetListMode(const bool& is_list) +{ + m_old_layout_is_list = m_is_list_layout; + m_is_list_layout = is_list; + + m_gui_settings->SetValue(gui::game_list_listMode, is_list); + + Refresh(true); + + m_central_widget->setCurrentWidget(m_is_list_layout ? m_game_list : m_game_grid); +} +void game_list_frame::SetSearchText(const QString& text) +{ + m_search_text = text; + Refresh(); +} +void game_list_frame::closeEvent(QCloseEvent* event) +{ + QDockWidget::closeEvent(event); + Q_EMIT GameListFrameClosed(); +} + +void game_list_frame::resizeEvent(QResizeEvent* event) +{ + if (!m_is_list_layout) + { + Refresh(false, m_game_grid->selectedItems().count()); + } + QDockWidget::resizeEvent(event); +} +void game_list_frame::ResizeIcons(const int& slider_pos) +{ + m_icon_size_index = slider_pos; + m_icon_size = gui_settings::SizeFromSlider(slider_pos); + + RepaintIcons(); +} \ No newline at end of file diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 4182ba7d..411e140e 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -37,13 +37,22 @@ public : /** Repaint Gamelist Icons with new background color */ void RepaintIcons(const bool& from_settings = false); + /** Resize Gamelist Icons to size given by slider position */ + void ResizeIcons(const int& slider_pos); +public Q_SLOTS: + void SetSearchText(const QString& text); + void SetListMode(const bool& is_list); private Q_SLOTS: void OnHeaderColumnClicked(int col); void OnRepaintFinished(); void OnRefreshFinished(); Q_SIGNALS: void GameListFrameClosed(); + void RequestIconSizeChange(const int& val); +protected: + void closeEvent(QCloseEvent* event) override; + void resizeEvent(QResizeEvent* event) override; private: QPixmap PaintedPixmap(const QPixmap& icon) const; void SortGameList() const; @@ -75,6 +84,12 @@ private: QFutureWatcher m_repaint_watcher; QFutureWatcher m_refresh_watcher; + // Search + QString m_search_text; + + // Icon Size + int m_icon_size_index = 0; + // Icons QSize m_icon_size; QColor m_icon_color; diff --git a/shadPS4/gui/gui_settings.cpp b/shadPS4/gui/gui_settings.cpp index 3be2dfd1..d3353631 100644 --- a/shadPS4/gui/gui_settings.cpp +++ b/shadPS4/gui/gui_settings.cpp @@ -19,4 +19,8 @@ bool gui_settings::GetGamelistColVisibility(int col) const gui_save gui_settings::GetGuiSaveForColumn(int col) { return gui_save{ gui::game_list, "visibility_" + gui::get_game_list_column_name(static_cast(col)), true }; +} +QSize gui_settings::SizeFromSlider(int pos) +{ + return gui::game_list_icon_size_min + (gui::game_list_icon_size_max - gui::game_list_icon_size_min) * (1.f * pos / gui::game_list_max_slider_pos); } \ No newline at end of file diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index ca2af497..7b99bf4c 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -55,6 +55,13 @@ namespace gui const int game_list_max_slider_pos = 100; + inline int get_Index(const QSize& current) + { + const int size_delta = game_list_icon_size_max.width() - game_list_icon_size_min.width(); + const int current_delta = current.width() - game_list_icon_size_min.width(); + return game_list_max_slider_pos * current_delta / size_delta; + } + const QString main_window = "main_window"; const QString game_list = "GameList"; @@ -65,6 +72,8 @@ namespace gui const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true); const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1); const gui_save game_list_state = gui_save(game_list, "state", QByteArray()); + const gui_save game_list_iconSize = gui_save(game_list, "iconSize", get_Index(game_list_icon_size_small)); + const gui_save game_list_iconSizeGrid = gui_save(game_list, "iconSizeGrid", get_Index(game_list_icon_size_small)); const gui_save game_list_iconColor = gui_save(game_list, "iconColor", game_list_icon_color); const gui_save game_list_listMode = gui_save(game_list, "listMode", true); const gui_save game_list_textFactor = gui_save(game_list, "textFactor", qreal{ 2.0 }); @@ -86,5 +95,6 @@ public: public Q_SLOTS: void SetGamelistColVisibility(int col, bool val) const; static gui_save GetGuiSaveForColumn(int col); + static QSize SizeFromSlider(int pos); }; diff --git a/shadPS4/gui/main_window.cpp b/shadPS4/gui/main_window.cpp index a98f78bd..252073c5 100644 --- a/shadPS4/gui/main_window.cpp +++ b/shadPS4/gui/main_window.cpp @@ -28,6 +28,12 @@ bool main_window::Init() CreateActions(); CreateDockWindows(); + CreateConnects(); + + setMinimumSize(350, minimumSizeHint().height()); + setWindowTitle(QString::fromStdString("ShadPS4 v0.0.2")); + + ConfigureGuiFromSettings(); return true; } @@ -71,3 +77,113 @@ void main_window::CreateDockWindows() } }); } +void main_window::CreateConnects() +{ + connect(ui->exitAct, &QAction::triggered, this, &QWidget::close); + + connect(ui->showGameListAct, &QAction::triggered, this, [this](bool checked) + { + checked ? m_game_list_frame->show() : m_game_list_frame->hide(); + m_gui_settings->SetValue(gui::main_window_gamelist_visible, checked); + }); + connect(ui->refreshGameListAct, &QAction::triggered, this, [this] + { + m_game_list_frame->Refresh(true); + }); + + connect(m_icon_size_act_group, &QActionGroup::triggered, this, [this](QAction* act) + { + static const int index_small = gui::get_Index(gui::game_list_icon_size_small); + static const int index_medium = gui::get_Index(gui::game_list_icon_size_medium); + + int index; + + if (act == ui->setIconSizeTinyAct) + index = 0; + else if (act == ui->setIconSizeSmallAct) + index = index_small; + else if (act == ui->setIconSizeMediumAct) + index = index_medium; + else + index = gui::game_list_max_slider_pos; + + m_save_slider_pos = true; + ResizeIcons(index); + }); + connect(m_game_list_frame, &game_list_frame::RequestIconSizeChange, this, [this](const int& val) + { + const int idx = ui->sizeSlider->value() + val; + m_save_slider_pos = true; + ResizeIcons(idx); + }); + + connect(m_list_mode_act_group, &QActionGroup::triggered, this, [this](QAction* act) + { + const bool is_list_act = act == ui->setlistModeListAct; + if (is_list_act == m_is_list_mode) + return; + + const int slider_pos = ui->sizeSlider->sliderPosition(); + ui->sizeSlider->setSliderPosition(m_other_slider_pos); + SetIconSizeActions(m_other_slider_pos); + m_other_slider_pos = slider_pos; + + m_is_list_mode = is_list_act; + m_game_list_frame->SetListMode(m_is_list_mode); + }); + connect(ui->sizeSlider, &QSlider::valueChanged, this, &main_window::ResizeIcons); + connect(ui->sizeSlider, &QSlider::sliderReleased, this, [this] + { + const int index = ui->sizeSlider->value(); + m_gui_settings->SetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid, index); + SetIconSizeActions(index); + }); + connect(ui->sizeSlider, &QSlider::actionTriggered, this, [this](int action) + { + if (action != QAbstractSlider::SliderNoAction && action != QAbstractSlider::SliderMove) + { // we only want to save on mouseclicks or slider release (the other connect handles this) + m_save_slider_pos = true; // actionTriggered happens before the value was changed + } + }); + + connect(ui->mw_searchbar, &QLineEdit::textChanged, m_game_list_frame, &game_list_frame::SetSearchText); +} + +void main_window::SetIconSizeActions(int idx) const +{ + static const int threshold_tiny = gui::get_Index((gui::game_list_icon_size_small + gui::game_list_icon_size_min) / 2); + static const int threshold_small = gui::get_Index((gui::game_list_icon_size_medium + gui::game_list_icon_size_small) / 2); + static const int threshold_medium = gui::get_Index((gui::game_list_icon_size_max + gui::game_list_icon_size_medium) / 2); + + if (idx < threshold_tiny) + ui->setIconSizeTinyAct->setChecked(true); + else if (idx < threshold_small) + ui->setIconSizeSmallAct->setChecked(true); + else if (idx < threshold_medium) + ui->setIconSizeMediumAct->setChecked(true); + else + ui->setIconSizeLargeAct->setChecked(true); +} +void main_window::ResizeIcons(int index) +{ + if (ui->sizeSlider->value() != index) + { + ui->sizeSlider->setSliderPosition(index); + return; // ResizeIcons will be triggered again by setSliderPosition, so return here + } + + if (m_save_slider_pos) + { + m_save_slider_pos = false; + m_gui_settings->SetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid, index); + + // this will also fire when we used the actions, but i didn't want to add another boolean member + SetIconSizeActions(index); + } + + m_game_list_frame->ResizeIcons(index); +} +void main_window::ConfigureGuiFromSettings() +{ + +} \ No newline at end of file diff --git a/shadPS4/gui/main_window.h b/shadPS4/gui/main_window.h index 3e6e856f..e12c5c14 100644 --- a/shadPS4/gui/main_window.h +++ b/shadPS4/gui/main_window.h @@ -26,9 +26,14 @@ public: ~main_window(); bool Init(); +private Q_SLOTS: + void ConfigureGuiFromSettings(); + void SetIconSizeActions(int idx) const; + void ResizeIcons(int index); private: void CreateActions(); void CreateDockWindows(); + void CreateConnects(); QActionGroup* m_icon_size_act_group = nullptr; QActionGroup* m_list_mode_act_group = nullptr; From 9962cf333c1e81a8f6834a3adbdb646ea369a5c6 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 16 Mar 2023 19:51:22 +0200 Subject: [PATCH 16/18] new main window working --- shadPS4/gui/gui_settings.h | 3 ++ shadPS4/gui/main_window.cpp | 45 ++++++++++++++++++++- shadPS4/gui/main_window.h | 1 + shadPS4/main.cpp | 8 +++- shadPS4/shadPS4.vcxproj.filters | 70 ++++++++++++++++++--------------- 5 files changed, 92 insertions(+), 35 deletions(-) diff --git a/shadPS4/gui/gui_settings.h b/shadPS4/gui/gui_settings.h index 7b99bf4c..6ddb2d31 100644 --- a/shadPS4/gui/gui_settings.h +++ b/shadPS4/gui/gui_settings.h @@ -68,6 +68,9 @@ namespace gui const QColor game_list_icon_color = QColor(240, 240, 240, 255); const gui_save main_window_gamelist_visible = gui_save(main_window, "gamelistVisible", true); + const gui_save main_window_geometry = gui_save(main_window, "geometry", QByteArray()); + const gui_save main_window_windowState = gui_save(main_window, "windowState", QByteArray()); + const gui_save main_window_mwState = gui_save(main_window, "mwState", QByteArray()); const gui_save game_list_sortAsc = gui_save(game_list, "sortAsc", true); const gui_save game_list_sortCol = gui_save(game_list, "sortCol", 1); diff --git a/shadPS4/gui/main_window.cpp b/shadPS4/gui/main_window.cpp index 252073c5..fb6b1700 100644 --- a/shadPS4/gui/main_window.cpp +++ b/shadPS4/gui/main_window.cpp @@ -6,6 +6,7 @@ main_window::main_window(std::shared_ptr gui_settings, QWidget* parent) : QMainWindow(parent) , ui(new Ui::main_window) + , m_gui_settings(std::move(gui_settings)) { ui->setupUi(this); @@ -15,7 +16,7 @@ main_window::main_window(std::shared_ptr gui_settings, QWidget* pa main_window::~main_window() { - + SaveWindowState(); } bool main_window::Init() @@ -35,6 +36,11 @@ bool main_window::Init() ConfigureGuiFromSettings(); + show(); + + // Fix possible hidden game list columns. The game list has to be visible already. Use this after show() + m_game_list_frame->FixNarrowColumns(); + return true; } @@ -185,5 +191,42 @@ void main_window::ResizeIcons(int index) } void main_window::ConfigureGuiFromSettings() { + // Restore GUI state if needed. We need to if they exist. + if (!restoreGeometry(m_gui_settings->GetValue(gui::main_window_geometry).toByteArray())) + { + resize(QGuiApplication::primaryScreen()->availableSize() * 0.7); + } + restoreState(m_gui_settings->GetValue(gui::main_window_windowState).toByteArray()); + m_main_window->restoreState(m_gui_settings->GetValue(gui::main_window_mwState).toByteArray()); + + ui->showGameListAct->setChecked(m_gui_settings->GetValue(gui::main_window_gamelist_visible).toBool()); + + m_game_list_frame->setVisible(ui->showGameListAct->isChecked()); + + // handle icon size options + m_is_list_mode = m_gui_settings->GetValue(gui::game_list_listMode).toBool(); + if (m_is_list_mode) + ui->setlistModeListAct->setChecked(true); + else + ui->setlistModeGridAct->setChecked(true); + + const int icon_size_index = m_gui_settings->GetValue(m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid).toInt(); + m_other_slider_pos = m_gui_settings->GetValue(!m_is_list_mode ? gui::game_list_iconSize : gui::game_list_iconSizeGrid).toInt(); + ui->sizeSlider->setSliderPosition(icon_size_index); + SetIconSizeActions(icon_size_index); + + // Gamelist + m_game_list_frame->LoadSettings(); +} + +void main_window::SaveWindowState() const +{ + // Save gui settings + m_gui_settings->SetValue(gui::main_window_geometry, saveGeometry()); + m_gui_settings->SetValue(gui::main_window_windowState, saveState()); + m_gui_settings->SetValue(gui::main_window_mwState, m_main_window->saveState()); + + // Save column settings + m_game_list_frame->SaveSettings(); } \ No newline at end of file diff --git a/shadPS4/gui/main_window.h b/shadPS4/gui/main_window.h index e12c5c14..9a945e34 100644 --- a/shadPS4/gui/main_window.h +++ b/shadPS4/gui/main_window.h @@ -30,6 +30,7 @@ private Q_SLOTS: void ConfigureGuiFromSettings(); void SetIconSizeActions(int idx) const; void ResizeIcons(int index); + void SaveWindowState() const; private: void CreateActions(); void CreateDockWindows(); diff --git a/shadPS4/main.cpp b/shadPS4/main.cpp index baaf71a0..3b5c816a 100644 --- a/shadPS4/main.cpp +++ b/shadPS4/main.cpp @@ -1,13 +1,17 @@ #include "gui/shadps4gui.h" #include #include "gui/gui_settings.h" +#include "gui/main_window.h" int main(int argc, char* argv[]) { QApplication a(argc, argv); std::shared_ptr m_gui_settings; m_gui_settings.reset(new gui_settings()); - shadps4gui w(m_gui_settings,nullptr); - w.show(); + //shadps4gui w(m_gui_settings,nullptr); + //w.show(); + main_window* m_main_window = new main_window(m_gui_settings, nullptr); + m_main_window->Init(); + return a.exec(); } \ No newline at end of file diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index 87bb22e0..829c9d37 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -33,6 +33,12 @@ {ed31734c-f010-4590-9f01-18e0b2497ffb} + + {b4b58418-b124-41bb-96ef-610faa1c8812} + + + {731089fd-7d11-4f10-8f55-4854c2e42e9e} + @@ -59,26 +65,26 @@ gui - - gui - - - gui - - - gui - - - gui - - - gui - gui + + gui\game list + + + gui\game list + + + gui\game list + + + gui\game list + + + gui\game list + - Source Files + gui\main window @@ -96,20 +102,20 @@ gui - - gui - - - gui - gui gui + + gui\game list + + + gui\game list + - Header Files + gui\main window @@ -131,15 +137,6 @@ Header Files - - gui - - - gui - - - gui - gui @@ -152,5 +149,14 @@ gui + + gui\game list + + + gui\game list + + + gui\game list + \ No newline at end of file From 07c7152d5472d45a95aaf8155b18951cf74cb218 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 17 Mar 2023 11:35:44 +0200 Subject: [PATCH 17/18] game_list and game grid are now working --- shadPS4/gui/game_list_frame.cpp | 281 ++++++++++++++++++++++++-------- shadPS4/gui/game_list_frame.h | 4 + shadPS4/gui/game_list_grid.cpp | 2 +- shadPS4/gui/game_list_grid.h | 2 +- shadPS4/main.cpp | 2 - shadPS4/shadPS4.vcxproj.filters | 2 +- 6 files changed, 219 insertions(+), 74 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index ee2b28f7..b32eaeae 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -133,8 +133,6 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, QWi m_game_data.clear(); m_games.clear(); }); - - Refresh();//TODO remove when watchers added } game_list_frame::~game_list_frame() { gui::utils::stop_future_watcher(m_repaint_watcher, true); @@ -144,34 +142,23 @@ game_list_frame::~game_list_frame() { void game_list_frame::OnRefreshFinished() { - -} - -void game_list_frame::LoadSettings() -{ - m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder; - m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt(); - - Refresh(true); - - const QByteArray state = m_gui_settings->GetValue(gui::game_list_state).toByteArray(); - if (!m_game_list->horizontalHeader()->restoreState(state) && m_game_list->rowCount()) + gui::utils::stop_future_watcher(m_repaint_watcher, true); + for (auto&& g : m_games) { - // If no settings exist, resize to contents. - ResizeColumnsToContents(); + m_game_data.push_back(g); } - - for (int col = 0; col < m_columnActs.count(); ++col) + m_games.clear(); + // Sort by name at the very least. + std::sort(m_game_data.begin(), m_game_data.end(), [&](const game_info& game1, const game_info& game2) { - const bool vis = m_gui_settings->GetGamelistColVisibility(col); - m_columnActs[col]->setChecked(vis); - m_game_list->setColumnHidden(col, !vis); - } - SortGameList(); - FixNarrowColumns(); + const QString title1 = m_titles.value(QString::fromStdString(game1->info.serial), QString::fromStdString(game1->info.name)); + const QString title2 = m_titles.value(QString::fromStdString(game2->info.serial), QString::fromStdString(game2->info.name)); + return title1.toLower() < title2.toLower(); + }); - m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState()); + m_path_list.clear(); + Refresh(); } void game_list_frame::OnRepaintFinished() @@ -191,19 +178,114 @@ void game_list_frame::OnRepaintFinished() else { // The game grid needs to be recreated from scratch - //TODO !! + int games_per_row = 0; + + if (m_icon_size.width() > 0 && m_icon_size.height() > 0) + { + games_per_row = width() / (m_icon_size.width() + m_icon_size.width() * m_game_grid->getMarginFactor() * 2); + } + + const int scroll_position = m_game_grid->verticalScrollBar()->value(); + //TODO add connections + PopulateGameGrid(games_per_row, m_icon_size, m_icon_color); + m_central_widget->addWidget(m_game_grid); + m_central_widget->setCurrentWidget(m_game_grid); + m_game_grid->verticalScrollBar()->setValue(scroll_position); } } -void game_list_frame::SaveSettings() +bool game_list_frame::IsEntryVisible(const game_info& game) { - for (int col = 0; col < m_columnActs.count(); ++col) + const QString serial = QString::fromStdString(game->info.serial); + return SearchMatchesApp(QString::fromStdString(game->info.name), serial); +} + +void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color) +{ + int r = 0; + int c = 0; + + const std::string selected_item = CurrentSelectionPath(); + + // Release old data + m_game_list->clear_list(); + m_game_grid->deleteLater(); + + const bool show_text = m_icon_size_index > gui::game_list_max_slider_pos * 2 / 5; + + if (m_icon_size_index < gui::game_list_max_slider_pos * 2 / 3) { - m_gui_settings->SetGamelistColVisibility(col, m_columnActs[col]->isChecked()); + m_game_grid = new game_list_grid(image_size, image_color, m_margin_factor, m_text_factor * 2, show_text); } - m_gui_settings->SetValue(gui::game_list_sortCol, m_sort_column); - m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); - m_gui_settings->SetValue(gui::game_list_state, m_game_list->horizontalHeader()->saveState()); + else + { + m_game_grid = new game_list_grid(image_size, image_color, m_margin_factor, m_text_factor, show_text); + } + + // Get list of matching apps + QList matching_apps; + + for (const auto& app : m_game_data) + { + if (IsEntryVisible(app)) + { + matching_apps.push_back(app); + } + } + + const int entries = matching_apps.count(); + + // Edge cases! + if (entries == 0) + { // For whatever reason, 0%x is division by zero. Absolute nonsense by definition of modulus. But, I'll acquiesce. + return; + } + + maxCols = std::clamp(maxCols, 1, entries); + + const int needs_extra_row = (entries % maxCols) != 0; + const int max_rows = needs_extra_row + entries / maxCols; + m_game_grid->setRowCount(max_rows); + m_game_grid->setColumnCount(maxCols); + + for (const auto& app : matching_apps) + { + const QString serial = QString::fromStdString(app->info.serial); + const QString title = m_titles.value(serial, QString::fromStdString(app->info.name)); + + game_list_item* item = m_game_grid->addItem(app, title, r, c); + app->item = item; + item->setData(gui::game_role, QVariant::fromValue(app)); + + item->setToolTip(tr("%0 [%1]").arg(title).arg(serial)); + + + if (selected_item == app->info.path + app->info.icon_path) + { + m_game_grid->setCurrentItem(item); + } + + if (++c >= maxCols) + { + c = 0; + r++; + } + } + + if (c != 0) + { // if left over games exist -- if empty entries exist + for (int col = c; col < maxCols; ++col) + { + game_list_item* empty_item = new game_list_item(); + empty_item->setFlags(Qt::NoItemFlags); + m_game_grid->setItem(r, col, empty_item); + } + } + + m_game_grid->resizeColumnsToContents(); + m_game_grid->resizeRowsToContents(); + m_game_grid->installEventFilter(this); + m_game_grid->verticalScrollBar()->installEventFilter(this); } void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) { @@ -214,38 +296,41 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) { m_path_list.clear(); m_game_data.clear(); + m_games.clear(); //TODO better ATM manually add path from 1 dir to m_paths_list - m_path_list.emplace_back(QDir::currentPath().toStdString() + "/game/"); - - QDir parent_folder(QString::fromStdString(m_path_list.at(0))); + QDir parent_folder(QString::fromStdString(QDir::currentPath().toStdString() + "/game/")); QFileInfoList fList = parent_folder.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::DirsFirst); foreach(QFileInfo item, fList) { - PSF psf; - if (!psf.open(item.absoluteFilePath().toStdString() + "/sce_sys/PARAM.SFO")) - continue;//if we can't open param.sfo go to the next entry - - //TODO std::string test = psf.get_string("TITLE_ID"); - QString iconpath(item.absoluteFilePath() + "/sce_sys/ICON0.PNG"); - - GameInfo game{}; - - game.icon_path = iconpath.toStdString(); - game.name = psf.get_string("TITLE"); - game.serial = psf.get_string("TITLE_ID"); - game.fw = (QString("%1").arg(psf.get_integer("SYSTEM_VER"), 8, 16, QLatin1Char('0'))).mid(1, 3).insert(1, '.').toStdString(); - game.version = psf.get_string("APP_VER"); - game.category = psf.get_string("CATEGORY"); - game.path = item.fileName().toStdString(); - - gui_game_info info{}; - info.info = game; - - m_games.push_back(std::make_shared(std::move(info))); - - + m_path_list.emplace_back(item.absoluteFilePath().toStdString()); } + + m_refresh_watcher.setFuture(QtConcurrent::map(m_path_list, [this](const std::string& dir) + { + GameInfo game{}; + game.path = dir; + PSF psf; + if (psf.open(game.path + "/sce_sys/PARAM.SFO")) + { + QString iconpath(QString::fromStdString(game.path) + "/sce_sys/ICON0.PNG"); + game.icon_path = iconpath.toStdString(); + game.name = psf.get_string("TITLE"); + game.serial = psf.get_string("TITLE_ID"); + game.fw = (QString("%1").arg(psf.get_integer("SYSTEM_VER"), 8, 16, QLatin1Char('0'))).mid(1, 3).insert(1, '.').toStdString(); + game.version = psf.get_string("APP_VER"); + game.category = psf.get_string("CATEGORY"); + + m_titles.insert(QString::fromStdString(game.serial), QString::fromStdString(game.name)); + + gui_game_info info{}; + info.info = game; + + m_games.push_back(std::make_shared(std::move(info))); + } + + })); + return; } // Fill Game List / Game Grid @@ -279,11 +364,11 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) void game_list_frame::PopulateGameList() { - //hackinsh - for (auto&& g : m_games) - { - m_game_data.push_back(g); - } + //hackinsh TODO remove + //for (auto&& g : m_games) + //{ + // m_game_data.push_back(g); + //} //end of hackinsh int selected_row = -1; @@ -291,18 +376,25 @@ void game_list_frame::PopulateGameList() const std::string selected_item = CurrentSelectionPath(); // Release old data - //TODO m_game_grid->clear_list(); - //TODO m_game_list->clear_list(); + m_game_grid->clear_list(); + m_game_list->clear_list(); m_game_list->setRowCount(m_game_data.size()); int row = 0; int index = -1; - //RepaintIcons();//hackish for (const auto& game : m_game_data) { index++; + if (!IsEntryVisible(game)) + { + game->item = nullptr; + continue; + } + + const QString serial = QString::fromStdString(game->info.serial); + const QString title = m_titles.value(serial, QString::fromStdString(game->info.name)); // Icon custom_table_widget_item* icon_item = new custom_table_widget_item; @@ -317,10 +409,10 @@ void game_list_frame::PopulateGameList() icon_item->setData(gui::custom_roles::game_role, QVariant::fromValue(game)); // Title - custom_table_widget_item* title_item = new custom_table_widget_item(game->info.name); + custom_table_widget_item* title_item = new custom_table_widget_item(title); // Serial - custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial); + custom_table_widget_item* serial_item = new custom_table_widget_item(serial); // Version QString app_version = QString::fromStdString(game->info.version); @@ -645,4 +737,55 @@ void game_list_frame::ResizeIcons(const int& slider_pos) m_icon_size = gui_settings::SizeFromSlider(slider_pos); RepaintIcons(); -} \ No newline at end of file +} + +void game_list_frame::LoadSettings() +{ + m_col_sort_order = m_gui_settings->GetValue(gui::game_list_sortAsc).toBool() ? Qt::AscendingOrder : Qt::DescendingOrder; + m_sort_column = m_gui_settings->GetValue(gui::game_list_sortCol).toInt(); + + Refresh(true); + + const QByteArray state = m_gui_settings->GetValue(gui::game_list_state).toByteArray(); + if (!m_game_list->horizontalHeader()->restoreState(state) && m_game_list->rowCount()) + { + // If no settings exist, resize to contents. + ResizeColumnsToContents(); + } + + for (int col = 0; col < m_columnActs.count(); ++col) + { + const bool vis = m_gui_settings->GetGamelistColVisibility(col); + m_columnActs[col]->setChecked(vis); + m_game_list->setColumnHidden(col, !vis); + } + SortGameList(); + FixNarrowColumns(); + + m_game_list->horizontalHeader()->restoreState(m_game_list->horizontalHeader()->saveState()); + +} + +void game_list_frame::SaveSettings() +{ + for (int col = 0; col < m_columnActs.count(); ++col) + { + m_gui_settings->SetGamelistColVisibility(col, m_columnActs[col]->isChecked()); + } + m_gui_settings->SetValue(gui::game_list_sortCol, m_sort_column); + m_gui_settings->SetValue(gui::game_list_sortAsc, m_col_sort_order == Qt::AscendingOrder); + m_gui_settings->SetValue(gui::game_list_state, m_game_list->horizontalHeader()->saveState()); +} + +/** +* Returns false if the game should be hidden because it doesn't match search term in toolbar. +*/ +bool game_list_frame::SearchMatchesApp(const QString& name, const QString& serial) const +{ + if (!m_search_text.isEmpty()) + { + const QString search_text = m_search_text.toLower(); + return m_titles.value(serial, name).toLower().contains(search_text) || serial.toLower().contains(search_text); + } + return true; +} diff --git a/shadPS4/gui/game_list_frame.h b/shadPS4/gui/game_list_frame.h index 411e140e..b9e76785 100644 --- a/shadPS4/gui/game_list_frame.h +++ b/shadPS4/gui/game_list_frame.h @@ -58,6 +58,9 @@ private: void SortGameList() const; std::string CurrentSelectionPath(); void PopulateGameList(); + void PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color); + bool SearchMatchesApp(const QString& name, const QString& serial) const; + bool IsEntryVisible(const game_info& game); // Which widget we are displaying depends on if we are in grid or list mode. QMainWindow* m_game_dock = nullptr; @@ -71,6 +74,7 @@ private: QList m_columnActs; Qt::SortOrder m_col_sort_order; int m_sort_column; + QMap m_titles; // List Mode bool m_is_list_layout = true; diff --git a/shadPS4/gui/game_list_grid.cpp b/shadPS4/gui/game_list_grid.cpp index d6b0f23b..bc090b99 100644 --- a/shadPS4/gui/game_list_grid.cpp +++ b/shadPS4/gui/game_list_grid.cpp @@ -56,7 +56,7 @@ 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* game_list_grid::addItem(const game_info& app, const QString& name,const int& row, const int& col) { game_list_item* item = new game_list_item; item->set_icon_func([this, app, item](int) diff --git a/shadPS4/gui/game_list_grid.h b/shadPS4/gui/game_list_grid.h index 179c2cf7..b403da5f 100644 --- a/shadPS4/gui/game_list_grid.h +++ b/shadPS4/gui/game_list_grid.h @@ -19,7 +19,7 @@ public: void enableText(const bool& enabled); void setIconSize(const QSize& size) const; - QTableWidgetItem* addItem(const game_info& app, const QString& name, const QString& movie_path, const int& row, const int& col); + game_list_item* addItem(const game_info& app, const QString& name,const int& row, const int& col); [[nodiscard]] qreal getMarginFactor() const; diff --git a/shadPS4/main.cpp b/shadPS4/main.cpp index 3b5c816a..ebed39f5 100644 --- a/shadPS4/main.cpp +++ b/shadPS4/main.cpp @@ -8,8 +8,6 @@ int main(int argc, char* argv[]) QApplication a(argc, argv); std::shared_ptr m_gui_settings; m_gui_settings.reset(new gui_settings()); - //shadps4gui w(m_gui_settings,nullptr); - //w.show(); main_window* m_main_window = new main_window(m_gui_settings, nullptr); m_main_window->Init(); diff --git a/shadPS4/shadPS4.vcxproj.filters b/shadPS4/shadPS4.vcxproj.filters index 829c9d37..eff56824 100644 --- a/shadPS4/shadPS4.vcxproj.filters +++ b/shadPS4/shadPS4.vcxproj.filters @@ -92,7 +92,7 @@ Form Files - Form Files + gui\main window From 109d0ce9dec361d1308c3a1e41867cbe43083e23 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 17 Mar 2023 11:36:18 +0200 Subject: [PATCH 18/18] remove dummy code --- shadPS4/gui/game_list_frame.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/shadPS4/gui/game_list_frame.cpp b/shadPS4/gui/game_list_frame.cpp index b32eaeae..f5a10083 100644 --- a/shadPS4/gui/game_list_frame.cpp +++ b/shadPS4/gui/game_list_frame.cpp @@ -363,14 +363,6 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after) */ void game_list_frame::PopulateGameList() { - - //hackinsh TODO remove - //for (auto&& g : m_games) - //{ - // m_game_data.push_back(g); - //} - //end of hackinsh - int selected_row = -1; const std::string selected_item = CurrentSelectionPath();