diff options
Diffstat (limited to '')
| -rw-r--r-- | dist/license.md | 3 | ||||
| -rw-r--r-- | dist/qt_themes/colorful/icons/48x48/star.png | bin | 0 -> 1248 bytes | |||
| -rw-r--r-- | dist/qt_themes/colorful/style.qrc | 1 | ||||
| -rw-r--r-- | dist/qt_themes/default/default.qrc | 1 | ||||
| -rw-r--r-- | dist/qt_themes/default/icons/48x48/star.png | bin | 0 -> 686 bytes | |||
| -rw-r--r-- | dist/qt_themes/qdarkstyle/icons/48x48/star.png | bin | 0 -> 725 bytes | |||
| -rw-r--r-- | dist/qt_themes/qdarkstyle/style.qrc | 1 | ||||
| -rw-r--r-- | dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png | bin | 0 -> 725 bytes | |||
| -rw-r--r-- | dist/qt_themes/qdarkstyle_midnight_blue/style.qrc | 1 | ||||
| -rw-r--r-- | license.txt | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 14 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 103 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 5 | ||||
| -rw-r--r-- | src/yuzu/game_list_p.h | 26 | ||||
| -rw-r--r-- | src/yuzu/uisettings.h | 1 |
15 files changed, 152 insertions, 5 deletions
diff --git a/dist/license.md b/dist/license.md index e9bc87656..7bdebfec1 100644 --- a/dist/license.md +++ b/dist/license.md | |||
| @@ -12,6 +12,7 @@ qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com | |||
| 12 | qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com | 12 | qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com |
| 13 | qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team | 13 | qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team |
| 14 | qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com | 14 | qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com |
| 15 | qt_themes/default/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com | ||
| 15 | qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com | 16 | qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com |
| 16 | qt_themes/qdarkstyle/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io | 17 | qt_themes/qdarkstyle/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io |
| 17 | qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com | 18 | qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com |
| @@ -20,6 +21,7 @@ qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com | |||
| 20 | qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com | 21 | qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com |
| 21 | qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team | 22 | qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team |
| 22 | qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com | 23 | qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com |
| 24 | qt_themes/qdarkstyle/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com | ||
| 23 | qt_themes/colorful/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com | 25 | qt_themes/colorful/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com |
| 24 | qt_themes/colorful/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io | 26 | qt_themes/colorful/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io |
| 25 | qt_themes/colorful/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com | 27 | qt_themes/colorful/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com |
| @@ -28,5 +30,6 @@ qt_themes/colorful/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com | |||
| 28 | qt_themes/colorful/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com | 30 | qt_themes/colorful/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com |
| 29 | qt_themes/colorful/icons/48x48/plus.png | CC BY-ND 3.0 | https://icons8.com | 31 | qt_themes/colorful/icons/48x48/plus.png | CC BY-ND 3.0 | https://icons8.com |
| 30 | qt_themes/colorful/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com | 32 | qt_themes/colorful/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com |
| 33 | qt_themes/colorful/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com | ||
| 31 | 34 | ||
| 32 | <!-- TODO: Add the license of the yuzu icon --> \ No newline at end of file | 35 | <!-- TODO: Add the license of the yuzu icon --> \ No newline at end of file |
diff --git a/dist/qt_themes/colorful/icons/48x48/star.png b/dist/qt_themes/colorful/icons/48x48/star.png new file mode 100644 index 000000000..43b5d52ed --- /dev/null +++ b/dist/qt_themes/colorful/icons/48x48/star.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/colorful/style.qrc b/dist/qt_themes/colorful/style.qrc index 36735519a..18b10869e 100644 --- a/dist/qt_themes/colorful/style.qrc +++ b/dist/qt_themes/colorful/style.qrc | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 7 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 8 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> | 8 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> |
| 9 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 9 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 10 | <file alias="48x48/star.png">icons/48x48/star.png</file> | ||
| 10 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 11 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
| 11 | </qresource> | 12 | </qresource> |
| 12 | <qresource prefix="colorful"> | 13 | <qresource prefix="colorful"> |
diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/default.qrc index 2182f33f3..b195747a3 100644 --- a/dist/qt_themes/default/default.qrc +++ b/dist/qt_themes/default/default.qrc | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 10 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 11 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> | 11 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> |
| 12 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 12 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 13 | <file alias="48x48/star.png">icons/48x48/star.png</file> | ||
| 13 | <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file> | 14 | <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file> |
| 14 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 15 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
| 15 | </qresource> | 16 | </qresource> |
diff --git a/dist/qt_themes/default/icons/48x48/star.png b/dist/qt_themes/default/icons/48x48/star.png new file mode 100644 index 000000000..740f7f3e7 --- /dev/null +++ b/dist/qt_themes/default/icons/48x48/star.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/qdarkstyle/icons/48x48/star.png b/dist/qt_themes/qdarkstyle/icons/48x48/star.png new file mode 100644 index 000000000..90d423a1d --- /dev/null +++ b/dist/qt_themes/qdarkstyle/icons/48x48/star.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/style.qrc index 2b91204f3..34e872d25 100644 --- a/dist/qt_themes/qdarkstyle/style.qrc +++ b/dist/qt_themes/qdarkstyle/style.qrc | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 8 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 9 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> | 9 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> |
| 10 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 10 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 11 | <file alias="48x48/star.png">icons/48x48/star.png</file> | ||
| 11 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 12 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
| 12 | </qresource> | 13 | </qresource> |
| 13 | <qresource prefix="qss_icons"> | 14 | <qresource prefix="qss_icons"> |
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png new file mode 100644 index 000000000..90d423a1d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc index 579e73ece..142dd3288 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 8 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 9 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> | 9 | <file alias="48x48/plus.png">icons/48x48/plus.png</file> |
| 10 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 10 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 11 | <file alias="48x48/star.png">icons/48x48/star.png</file> | ||
| 11 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 12 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
| 12 | </qresource> | 13 | </qresource> |
| 13 | <qresource prefix="qss_icons"> | 14 | <qresource prefix="qss_icons"> |
diff --git a/license.txt b/license.txt index 86e7b3c1b..495f3e676 100644 --- a/license.txt +++ b/license.txt | |||
| @@ -358,6 +358,7 @@ chip.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | |||
| 358 | folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | 358 | folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com |
| 359 | plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | 359 | plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com |
| 360 | sd_card.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | 360 | sd_card.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com |
| 361 | star.png | CC BY-ND 3.0 | https://icons8.com | ||
| 361 | 362 | ||
| 362 | Note: | 363 | Note: |
| 363 | Some icons are different in different themes, and they are separately listed | 364 | Some icons are different in different themes, and they are separately listed |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 50ea15e2a..ff6a6e961 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -934,6 +934,13 @@ void Config::ReadUIGamelistValues() { | |||
| 934 | UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt(); | 934 | UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt(); |
| 935 | UISettings::values.cache_game_list = | 935 | UISettings::values.cache_game_list = |
| 936 | ReadSetting(QStringLiteral("cache_game_list"), true).toBool(); | 936 | ReadSetting(QStringLiteral("cache_game_list"), true).toBool(); |
| 937 | const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); | ||
| 938 | for (int i = 0; i < favorites_size; i++) { | ||
| 939 | qt_config->setArrayIndex(i); | ||
| 940 | UISettings::values.favorited_ids.append( | ||
| 941 | ReadSetting(QStringLiteral("program_id")).toULongLong()); | ||
| 942 | } | ||
| 943 | qt_config->endArray(); | ||
| 937 | 944 | ||
| 938 | qt_config->endGroup(); | 945 | qt_config->endGroup(); |
| 939 | } | 946 | } |
| @@ -1476,6 +1483,13 @@ void Config::SaveUIGamelistValues() { | |||
| 1476 | WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3); | 1483 | WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3); |
| 1477 | WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2); | 1484 | WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2); |
| 1478 | WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true); | 1485 | WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true); |
| 1486 | qt_config->beginWriteArray(QStringLiteral("favorites")); | ||
| 1487 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | ||
| 1488 | qt_config->setArrayIndex(i); | ||
| 1489 | WriteSetting(QStringLiteral("program_id"), | ||
| 1490 | QVariant::fromValue(UISettings::values.favorited_ids[i])); | ||
| 1491 | } | ||
| 1492 | qt_config->endArray(); | ||
| 1479 | 1493 | ||
| 1480 | qt_config->endGroup(); | 1494 | qt_config->endGroup(); |
| 1481 | } | 1495 | } |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 9afd5b45f..48b78d65f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <QJsonDocument> | 11 | #include <QJsonDocument> |
| 12 | #include <QJsonObject> | 12 | #include <QJsonObject> |
| 13 | #include <QKeyEvent> | 13 | #include <QKeyEvent> |
| 14 | #include <QList> | ||
| 14 | #include <QMenu> | 15 | #include <QMenu> |
| 15 | #include <QThreadPool> | 16 | #include <QThreadPool> |
| 16 | #include <fmt/format.h> | 17 | #include <fmt/format.h> |
| @@ -84,6 +85,10 @@ void GameListSearchField::setFilterResult(int visible, int total) { | |||
| 84 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); | 85 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 88 | bool GameListSearchField::isEmpty() const { | ||
| 89 | return edit_filter->text().isEmpty(); | ||
| 90 | } | ||
| 91 | |||
| 87 | QString GameList::GetLastFilterResultItem() const { | 92 | QString GameList::GetLastFilterResultItem() const { |
| 88 | QString file_path; | 93 | QString file_path; |
| 89 | const int folder_count = item_model->rowCount(); | 94 | const int folder_count = item_model->rowCount(); |
| @@ -187,7 +192,9 @@ void GameList::OnTextChanged(const QString& new_text) { | |||
| 187 | // If the searchfield is empty every item is visible | 192 | // If the searchfield is empty every item is visible |
| 188 | // Otherwise the filter gets applied | 193 | // Otherwise the filter gets applied |
| 189 | if (edit_filter_text.isEmpty()) { | 194 | if (edit_filter_text.isEmpty()) { |
| 190 | for (int i = 0; i < folder_count; ++i) { | 195 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), |
| 196 | UISettings::values.favorited_ids.size() == 0); | ||
| 197 | for (int i = 1; i < folder_count; ++i) { | ||
| 191 | folder = item_model->item(i, 0); | 198 | folder = item_model->item(i, 0); |
| 192 | const QModelIndex folder_index = folder->index(); | 199 | const QModelIndex folder_index = folder->index(); |
| 193 | const int children_count = folder->rowCount(); | 200 | const int children_count = folder->rowCount(); |
| @@ -198,8 +205,9 @@ void GameList::OnTextChanged(const QString& new_text) { | |||
| 198 | } | 205 | } |
| 199 | search_field->setFilterResult(children_total, children_total); | 206 | search_field->setFilterResult(children_total, children_total); |
| 200 | } else { | 207 | } else { |
| 208 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true); | ||
| 201 | int result_count = 0; | 209 | int result_count = 0; |
| 202 | for (int i = 0; i < folder_count; ++i) { | 210 | for (int i = 1; i < folder_count; ++i) { |
| 203 | folder = item_model->item(i, 0); | 211 | folder = item_model->item(i, 0); |
| 204 | const QModelIndex folder_index = folder->index(); | 212 | const QModelIndex folder_index = folder->index(); |
| 205 | const int children_count = folder->rowCount(); | 213 | const int children_count = folder->rowCount(); |
| @@ -280,6 +288,13 @@ void GameList::OnUpdateThemedIcons() { | |||
| 280 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 288 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), |
| 281 | Qt::DecorationRole); | 289 | Qt::DecorationRole); |
| 282 | break; | 290 | break; |
| 291 | case GameListItemType::Favorites: | ||
| 292 | child->setData( | ||
| 293 | QIcon::fromTheme(QStringLiteral("star")) | ||
| 294 | .pixmap(icon_size) | ||
| 295 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||
| 296 | Qt::DecorationRole); | ||
| 297 | break; | ||
| 283 | default: | 298 | default: |
| 284 | break; | 299 | break; |
| 285 | } | 300 | } |
| @@ -427,6 +442,13 @@ void GameList::DonePopulating(const QStringList& watch_list) { | |||
| 427 | emit ShowList(!IsEmpty()); | 442 | emit ShowList(!IsEmpty()); |
| 428 | 443 | ||
| 429 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); | 444 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); |
| 445 | item_model->invisibleRootItem()->insertRow(0, new GameListFavorites()); | ||
| 446 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), | ||
| 447 | UISettings::values.favorited_ids.size() == 0); | ||
| 448 | tree_view->expand(item_model->invisibleRootItem()->child(0)->index()); | ||
| 449 | for (const auto id : UISettings::values.favorited_ids) { | ||
| 450 | AddFavorite(id); | ||
| 451 | } | ||
| 430 | 452 | ||
| 431 | // Clear out the old directories to watch for changes and add the new ones | 453 | // Clear out the old directories to watch for changes and add the new ones |
| 432 | auto watch_dirs = watcher->directories(); | 454 | auto watch_dirs = watcher->directories(); |
| @@ -446,7 +468,7 @@ void GameList::DonePopulating(const QStringList& watch_list) { | |||
| 446 | tree_view->setEnabled(true); | 468 | tree_view->setEnabled(true); |
| 447 | const int folder_count = tree_view->model()->rowCount(); | 469 | const int folder_count = tree_view->model()->rowCount(); |
| 448 | int children_total = 0; | 470 | int children_total = 0; |
| 449 | for (int i = 0; i < folder_count; ++i) { | 471 | for (int i = 1; i < folder_count; ++i) { |
| 450 | children_total += item_model->item(i, 0)->rowCount(); | 472 | children_total += item_model->item(i, 0)->rowCount(); |
| 451 | } | 473 | } |
| 452 | search_field->setFilterResult(children_total, children_total); | 474 | search_field->setFilterResult(children_total, children_total); |
| @@ -478,6 +500,9 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { | |||
| 478 | case GameListItemType::SysNandDir: | 500 | case GameListItemType::SysNandDir: |
| 479 | AddPermDirPopup(context_menu, selected); | 501 | AddPermDirPopup(context_menu, selected); |
| 480 | break; | 502 | break; |
| 503 | case GameListItemType::Favorites: | ||
| 504 | AddFavoritesPopup(context_menu); | ||
| 505 | break; | ||
| 481 | default: | 506 | default: |
| 482 | break; | 507 | break; |
| 483 | } | 508 | } |
| @@ -485,6 +510,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { | |||
| 485 | } | 510 | } |
| 486 | 511 | ||
| 487 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { | 512 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { |
| 513 | QAction* favorite = context_menu.addAction(tr("Favorite")); | ||
| 514 | context_menu.addSeparator(); | ||
| 488 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); | 515 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); |
| 489 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); | 516 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); |
| 490 | QAction* open_transferable_shader_cache = | 517 | QAction* open_transferable_shader_cache = |
| @@ -503,6 +530,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 503 | context_menu.addSeparator(); | 530 | context_menu.addSeparator(); |
| 504 | QAction* properties = context_menu.addAction(tr("Properties")); | 531 | QAction* properties = context_menu.addAction(tr("Properties")); |
| 505 | 532 | ||
| 533 | favorite->setVisible(program_id != 0); | ||
| 534 | favorite->setCheckable(true); | ||
| 535 | favorite->setChecked(UISettings::values.favorited_ids.contains(program_id)); | ||
| 506 | open_save_location->setVisible(program_id != 0); | 536 | open_save_location->setVisible(program_id != 0); |
| 507 | open_mod_location->setVisible(program_id != 0); | 537 | open_mod_location->setVisible(program_id != 0); |
| 508 | open_transferable_shader_cache->setVisible(program_id != 0); | 538 | open_transferable_shader_cache->setVisible(program_id != 0); |
| @@ -513,6 +543,7 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 513 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | 543 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); |
| 514 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); | 544 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); |
| 515 | 545 | ||
| 546 | connect(favorite, &QAction::triggered, [this, program_id]() { ToggleFavorite(program_id); }); | ||
| 516 | connect(open_save_location, &QAction::triggered, [this, program_id, path]() { | 547 | connect(open_save_location, &QAction::triggered, [this, program_id, path]() { |
| 517 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); | 548 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); |
| 518 | }); | 549 | }); |
| @@ -576,7 +607,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
| 576 | 607 | ||
| 577 | const int row = selected.row(); | 608 | const int row = selected.row(); |
| 578 | 609 | ||
| 579 | move_up->setEnabled(row > 0); | 610 | move_up->setEnabled(row > 1); |
| 580 | move_down->setEnabled(row < item_model->rowCount() - 2); | 611 | move_down->setEnabled(row < item_model->rowCount() - 2); |
| 581 | 612 | ||
| 582 | connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] { | 613 | connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] { |
| @@ -614,6 +645,18 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
| 614 | }); | 645 | }); |
| 615 | } | 646 | } |
| 616 | 647 | ||
| 648 | void GameList::AddFavoritesPopup(QMenu& context_menu) { | ||
| 649 | QAction* clear_all = context_menu.addAction(tr("Clear")); | ||
| 650 | |||
| 651 | connect(clear_all, &QAction::triggered, [this] { | ||
| 652 | for (const auto id : UISettings::values.favorited_ids) { | ||
| 653 | RemoveFavorite(id); | ||
| 654 | } | ||
| 655 | UISettings::values.favorited_ids.clear(); | ||
| 656 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true); | ||
| 657 | }); | ||
| 658 | } | ||
| 659 | |||
| 617 | void GameList::LoadCompatibilityList() { | 660 | void GameList::LoadCompatibilityList() { |
| 618 | QFile compat_list{QStringLiteral(":compatibility_list/compatibility_list.json")}; | 661 | QFile compat_list{QStringLiteral(":compatibility_list/compatibility_list.json")}; |
| 619 | 662 | ||
| @@ -728,6 +771,58 @@ void GameList::RefreshGameDirectory() { | |||
| 728 | } | 771 | } |
| 729 | } | 772 | } |
| 730 | 773 | ||
| 774 | void GameList::ToggleFavorite(u64 program_id) { | ||
| 775 | if (!UISettings::values.favorited_ids.contains(program_id)) { | ||
| 776 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), | ||
| 777 | !search_field->isEmpty()); | ||
| 778 | UISettings::values.favorited_ids.append(program_id); | ||
| 779 | AddFavorite(program_id); | ||
| 780 | item_model->sort(tree_view->header()->sortIndicatorSection(), | ||
| 781 | tree_view->header()->sortIndicatorOrder()); | ||
| 782 | } else { | ||
| 783 | UISettings::values.favorited_ids.removeOne(program_id); | ||
| 784 | RemoveFavorite(program_id); | ||
| 785 | if (UISettings::values.favorited_ids.size() == 0) { | ||
| 786 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true); | ||
| 787 | } | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | void GameList::AddFavorite(u64 program_id) { | ||
| 792 | auto* favorites_row = item_model->item(0); | ||
| 793 | |||
| 794 | for (int i = 1; i < item_model->rowCount() - 1; i++) { | ||
| 795 | const auto* folder = item_model->item(i); | ||
| 796 | for (int j = 0; j < folder->rowCount(); j++) { | ||
| 797 | if (folder->child(j)->data(GameListItemPath::ProgramIdRole).toULongLong() == | ||
| 798 | program_id) { | ||
| 799 | QList<QStandardItem*> list; | ||
| 800 | for (int k = 0; k < item_model->columnCount(); k++) { | ||
| 801 | list.append(folder->child(j, k)->clone()); | ||
| 802 | } | ||
| 803 | list[0]->setData(folder->child(j)->data(GameListItem::SortRole), | ||
| 804 | GameListItem::SortRole); | ||
| 805 | list[0]->setText(folder->child(j)->data(Qt::DisplayRole).toString()); | ||
| 806 | |||
| 807 | favorites_row->appendRow(list); | ||
| 808 | return; | ||
| 809 | } | ||
| 810 | } | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | void GameList::RemoveFavorite(u64 program_id) { | ||
| 815 | auto* favorites_row = item_model->item(0); | ||
| 816 | |||
| 817 | for (int i = 0; i < favorites_row->rowCount(); i++) { | ||
| 818 | const auto* game = favorites_row->child(i); | ||
| 819 | if (game->data(GameListItemPath::ProgramIdRole).toULongLong() == program_id) { | ||
| 820 | favorites_row->removeRow(i); | ||
| 821 | return; | ||
| 822 | } | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 731 | GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} { | 826 | GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} { |
| 732 | connect(parent, &GMainWindow::UpdateThemedIcons, this, | 827 | connect(parent, &GMainWindow::UpdateThemedIcons, this, |
| 733 | &GameListPlaceholder::onUpdateThemedIcons); | 828 | &GameListPlaceholder::onUpdateThemedIcons); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 58059a3c4..9c0a1a482 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -112,10 +112,15 @@ private: | |||
| 112 | 112 | ||
| 113 | void RefreshGameDirectory(); | 113 | void RefreshGameDirectory(); |
| 114 | 114 | ||
| 115 | void ToggleFavorite(u64 program_id); | ||
| 116 | void AddFavorite(u64 program_id); | ||
| 117 | void RemoveFavorite(u64 program_id); | ||
| 118 | |||
| 115 | void PopupContextMenu(const QPoint& menu_location); | 119 | void PopupContextMenu(const QPoint& menu_location); |
| 116 | void AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path); | 120 | void AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path); |
| 117 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); | 121 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); |
| 118 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); | 122 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); |
| 123 | void AddFavoritesPopup(QMenu& context_menu); | ||
| 119 | 124 | ||
| 120 | std::shared_ptr<FileSys::VfsFilesystem> vfs; | 125 | std::shared_ptr<FileSys::VfsFilesystem> vfs; |
| 121 | FileSys::ManualContentProvider* provider; | 126 | FileSys::ManualContentProvider* provider; |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index f25445f18..7ca8ece23 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -29,7 +29,8 @@ enum class GameListItemType { | |||
| 29 | SdmcDir = QStandardItem::UserType + 3, | 29 | SdmcDir = QStandardItem::UserType + 3, |
| 30 | UserNandDir = QStandardItem::UserType + 4, | 30 | UserNandDir = QStandardItem::UserType + 4, |
| 31 | SysNandDir = QStandardItem::UserType + 5, | 31 | SysNandDir = QStandardItem::UserType + 5, |
| 32 | AddDir = QStandardItem::UserType + 6 | 32 | AddDir = QStandardItem::UserType + 6, |
| 33 | Favorites = QStandardItem::UserType + 7, | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | Q_DECLARE_METATYPE(GameListItemType); | 36 | Q_DECLARE_METATYPE(GameListItemType); |
| @@ -310,6 +311,28 @@ public: | |||
| 310 | } | 311 | } |
| 311 | }; | 312 | }; |
| 312 | 313 | ||
| 314 | class GameListFavorites : public GameListItem { | ||
| 315 | public: | ||
| 316 | explicit GameListFavorites() { | ||
| 317 | setData(type(), TypeRole); | ||
| 318 | |||
| 319 | const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); | ||
| 320 | setData(QIcon::fromTheme(QStringLiteral("star")) | ||
| 321 | .pixmap(icon_size) | ||
| 322 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||
| 323 | Qt::DecorationRole); | ||
| 324 | setData(QObject::tr("Favorites"), Qt::DisplayRole); | ||
| 325 | } | ||
| 326 | |||
| 327 | int type() const override { | ||
| 328 | return static_cast<int>(GameListItemType::Favorites); | ||
| 329 | } | ||
| 330 | |||
| 331 | bool operator<(const QStandardItem& other) const override { | ||
| 332 | return false; | ||
| 333 | } | ||
| 334 | }; | ||
| 335 | |||
| 313 | class GameList; | 336 | class GameList; |
| 314 | class QHBoxLayout; | 337 | class QHBoxLayout; |
| 315 | class QTreeView; | 338 | class QTreeView; |
| @@ -324,6 +347,7 @@ public: | |||
| 324 | explicit GameListSearchField(GameList* parent = nullptr); | 347 | explicit GameListSearchField(GameList* parent = nullptr); |
| 325 | 348 | ||
| 326 | void setFilterResult(int visible, int total); | 349 | void setFilterResult(int visible, int total); |
| 350 | bool isEmpty() const; | ||
| 327 | 351 | ||
| 328 | void clear(); | 352 | void clear(); |
| 329 | void setFocus(); | 353 | void setFocus(); |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index ce3945485..5ba00b8c8 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -74,6 +74,7 @@ struct Values { | |||
| 74 | QString game_dir_deprecated; | 74 | QString game_dir_deprecated; |
| 75 | bool game_dir_deprecated_deepscan; | 75 | bool game_dir_deprecated_deepscan; |
| 76 | QVector<UISettings::GameDir> game_dirs; | 76 | QVector<UISettings::GameDir> game_dirs; |
| 77 | QVector<u64> favorited_ids; | ||
| 77 | QStringList recent_files; | 78 | QStringList recent_files; |
| 78 | QString language; | 79 | QString language; |
| 79 | 80 | ||