diff options
Diffstat (limited to 'src')
| -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 |
5 files changed, 144 insertions, 5 deletions
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 | ||