game_list_p.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <algorithm>
  6. #include <array>
  7. #include <map>
  8. #include <string>
  9. #include <unordered_map>
  10. #include <utility>
  11. #include <QCoreApplication>
  12. #include <QImage>
  13. #include <QObject>
  14. #include <QStandardItem>
  15. #include <QString>
  16. #include <QWidget>
  17. #include "common/common_types.h"
  18. #include "common/logging/log.h"
  19. #include "common/string_util.h"
  20. #include "yuzu/ui_settings.h"
  21. #include "yuzu/util/util.h"
  22. /**
  23. * Gets the default icon (for games without valid SMDH)
  24. * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
  25. * @return QPixmap default icon
  26. */
  27. static QPixmap GetDefaultIcon(u32 size) {
  28. QPixmap icon(size, size);
  29. icon.fill(Qt::transparent);
  30. return icon;
  31. }
  32. class GameListItem : public QStandardItem {
  33. public:
  34. GameListItem() = default;
  35. explicit GameListItem(const QString& string) : QStandardItem(string) {}
  36. };
  37. /**
  38. * A specialization of GameListItem for path values.
  39. * This class ensures that for every full path value it holds, a correct string representation
  40. * of just the filename (with no extension) will be displayed to the user.
  41. * If this class receives valid SMDH data, it will also display game icons and titles.
  42. */
  43. class GameListItemPath : public GameListItem {
  44. public:
  45. static const int FullPathRole = Qt::UserRole + 1;
  46. static const int TitleRole = Qt::UserRole + 2;
  47. static const int ProgramIdRole = Qt::UserRole + 3;
  48. static const int FileTypeRole = Qt::UserRole + 4;
  49. GameListItemPath() = default;
  50. GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
  51. const QString& game_name, const QString& game_type, u64 program_id) {
  52. setData(game_path, FullPathRole);
  53. setData(game_name, TitleRole);
  54. setData(qulonglong(program_id), ProgramIdRole);
  55. setData(game_type, FileTypeRole);
  56. const u32 size = UISettings::values.icon_size;
  57. QPixmap picture;
  58. if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
  59. picture = GetDefaultIcon(size);
  60. }
  61. picture = picture.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  62. setData(picture, Qt::DecorationRole);
  63. }
  64. QVariant data(int role) const override {
  65. if (role == Qt::DisplayRole) {
  66. std::string filename;
  67. Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
  68. nullptr);
  69. const std::array<QString, 4> row_data{{
  70. QString::fromStdString(filename),
  71. data(FileTypeRole).toString(),
  72. QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())),
  73. data(TitleRole).toString(),
  74. }};
  75. const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
  76. const auto& row2 = row_data.at(UISettings::values.row_2_text_id);
  77. if (row1.isEmpty() || row1 == row2)
  78. return row2;
  79. if (row2.isEmpty())
  80. return row1;
  81. return row1 + "\n " + row2;
  82. }
  83. return GameListItem::data(role);
  84. }
  85. };
  86. class GameListItemCompat : public GameListItem {
  87. Q_DECLARE_TR_FUNCTIONS(GameListItemCompat)
  88. public:
  89. static const int CompatNumberRole = Qt::UserRole + 1;
  90. GameListItemCompat() = default;
  91. explicit GameListItemCompat(const QString& compatibility) {
  92. struct CompatStatus {
  93. QString color;
  94. const char* text;
  95. const char* tooltip;
  96. };
  97. // clang-format off
  98. static const std::map<QString, CompatStatus> status_data = {
  99. {"0", {"#5c93ed", QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}},
  100. {"1", {"#47d35c", QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}},
  101. {"2", {"#94b242", QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}},
  102. {"3", {"#f2d624", QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}},
  103. {"4", {"#FF0000", QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}},
  104. {"5", {"#828282", QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}},
  105. {"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}};
  106. // clang-format on
  107. auto iterator = status_data.find(compatibility);
  108. if (iterator == status_data.end()) {
  109. LOG_WARNING(Frontend, "Invalid compatibility number {}", compatibility.toStdString());
  110. return;
  111. }
  112. const CompatStatus& status = iterator->second;
  113. setData(compatibility, CompatNumberRole);
  114. setText(QObject::tr(status.text));
  115. setToolTip(QObject::tr(status.tooltip));
  116. setData(CreateCirclePixmapFromColor(status.color), Qt::DecorationRole);
  117. }
  118. bool operator<(const QStandardItem& other) const override {
  119. return data(CompatNumberRole) < other.data(CompatNumberRole);
  120. }
  121. };
  122. /**
  123. * A specialization of GameListItem for size values.
  124. * This class ensures that for every numerical size value it holds (in bytes), a correct
  125. * human-readable string representation will be displayed to the user.
  126. */
  127. class GameListItemSize : public GameListItem {
  128. public:
  129. static const int SizeRole = Qt::UserRole + 1;
  130. GameListItemSize() = default;
  131. explicit GameListItemSize(const qulonglong size_bytes) {
  132. setData(size_bytes, SizeRole);
  133. }
  134. void setData(const QVariant& value, int role) override {
  135. // By specializing setData for SizeRole, we can ensure that the numerical and string
  136. // representations of the data are always accurate and in the correct format.
  137. if (role == SizeRole) {
  138. qulonglong size_bytes = value.toULongLong();
  139. GameListItem::setData(ReadableByteSize(size_bytes), Qt::DisplayRole);
  140. GameListItem::setData(value, SizeRole);
  141. } else {
  142. GameListItem::setData(value, role);
  143. }
  144. }
  145. /**
  146. * This operator is, in practice, only used by the TreeView sorting systems.
  147. * Override it so that it will correctly sort by numerical value instead of by string
  148. * representation.
  149. */
  150. bool operator<(const QStandardItem& other) const override {
  151. return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong();
  152. }
  153. };
  154. class GameList;
  155. class QHBoxLayout;
  156. class QTreeView;
  157. class QLabel;
  158. class QLineEdit;
  159. class QToolButton;
  160. class GameListSearchField : public QWidget {
  161. Q_OBJECT
  162. public:
  163. explicit GameListSearchField(GameList* parent = nullptr);
  164. void setFilterResult(int visible, int total);
  165. void clear();
  166. void setFocus();
  167. private:
  168. class KeyReleaseEater : public QObject {
  169. public:
  170. explicit KeyReleaseEater(GameList* gamelist);
  171. private:
  172. GameList* gamelist = nullptr;
  173. QString edit_filter_text_old;
  174. protected:
  175. // EventFilter in order to process systemkeys while editing the searchfield
  176. bool eventFilter(QObject* obj, QEvent* event) override;
  177. };
  178. QHBoxLayout* layout_filter = nullptr;
  179. QTreeView* tree_view = nullptr;
  180. QLabel* label_filter = nullptr;
  181. QLineEdit* edit_filter = nullptr;
  182. QLabel* label_filter_result = nullptr;
  183. QToolButton* button_filter_close = nullptr;
  184. };