From ff2c05da50b162f507ea3e5c8591093b8925c736 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 2 May 2018 21:58:03 +0200 Subject: [PATCH] Qt: Use pointer to game info instead of index in game list this should fix differences between model and view --- rpcs3/rpcs3qt/game_list_frame.cpp | 178 ++++++++++++++++++------------ rpcs3/rpcs3qt/game_list_frame.h | 13 ++- rpcs3/rpcs3qt/game_list_grid.cpp | 3 +- rpcs3/rpcs3qt/game_list_grid.h | 2 +- rpcs3/rpcs3qt/gui_settings.h | 5 + 5 files changed, 121 insertions(+), 80 deletions(-) diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index b8d99d5f0b..5c25bcc8e2 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -115,7 +115,7 @@ game_list_frame::game_list_frame(std::shared_ptr guiSettings, std: // Events connect(m_gameList, &QTableWidget::customContextMenuRequested, this, &game_list_frame::ShowContextMenu); - connect(m_gameList, &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot); + connect(m_gameList, &QTableWidget::itemDoubleClicked, this, &game_list_frame::doubleClickedSlot); connect(m_gameList->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnColClicked); connect(m_gameList->horizontalHeader(), &QHeaderView::customContextMenuRequested, [=](const QPoint& pos) @@ -125,30 +125,30 @@ game_list_frame::game_list_frame(std::shared_ptr guiSettings, std: configure->exec(mapToGlobal(pos)); }); - connect(m_xgrid, &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot); + connect(m_xgrid, &QTableWidget::itemDoubleClicked, this, &game_list_frame::doubleClickedSlot); connect(m_xgrid, &QTableWidget::customContextMenuRequested, this, &game_list_frame::ShowContextMenu); connect(m_game_compat.get(), &game_compatibility::DownloadStarted, [=]() { - for (auto& game : m_game_data) + for (const auto& game : m_game_data) { - game.compat = m_game_compat->GetStatusData("Download"); + game->compat = m_game_compat->GetStatusData("Download"); } Refresh(); }); connect(m_game_compat.get(), &game_compatibility::DownloadFinished, [=]() { - for (auto& game : m_game_data) + for (const auto& game : m_game_data) { - game.compat = m_game_compat->GetCompatibility(game.info.serial); + game->compat = m_game_compat->GetCompatibility(game->info.serial); } Refresh(); }); connect(m_game_compat.get(), &game_compatibility::DownloadError, [=](const QString& error) { - for (auto& game : m_game_data) + for (const auto& game : m_game_data) { - game.compat = m_game_compat->GetCompatibility(game.info.serial); + game->compat = m_game_compat->GetCompatibility(game->info.serial); } Refresh(); QMessageBox::warning(this, tr("Warning!"), tr("Failed to retrieve the online compatibility database!\nFalling back to local database.\n\n") + tr(qPrintable(error))); @@ -249,16 +249,19 @@ void game_list_frame::OnColClicked(int col) } // Get visibility of entries -bool game_list_frame::IsEntryVisible(const GUI_GameInfo& game) +bool game_list_frame::IsEntryVisible(const game_info& game) { auto matches_category = [&]() { if (m_isListLayout) - return m_categoryFilters.contains(qstr(game.info.category)); - return category::CategoryInMap(game.info.category, category::cat_boot); + { + return m_categoryFilters.contains(qstr(game->info.category)); + } + return category::CategoryInMap(game->info.category, category::cat_boot); }; - bool is_visible = m_show_hidden || !m_hidden_list.contains(qstr(game.info.serial)); - return is_visible && matches_category() && SearchMatchesApp(game.info.name, game.info.serial); + + bool is_visible = m_show_hidden || !m_hidden_list.contains(qstr(game->info.serial)); + return is_visible && matches_category() && SearchMatchesApp(game->info.name, game->info.serial); } void game_list_frame::SortGameList() @@ -382,7 +385,7 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter) QPixmap pxmap = PaintedPixmap(img, hasCustomConfig); - m_game_data.push_back({ game, m_game_compat->GetCompatibility(game.serial), img, pxmap, hasCustomConfig }); + m_game_data.push_back(game_info(new gui_game_info{ game, m_game_compat->GetCompatibility(game.serial), img, pxmap, hasCustomConfig })); } catch (const std::exception& e) { @@ -391,9 +394,9 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter) // Blame MSVC for double }} }} - auto op = [](const GUI_GameInfo& game1, const GUI_GameInfo& game2) + auto op = [](const game_info& game1, const game_info& game2) { - return qstr(game1.info.name).toLower() < qstr(game2.info.name).toLower(); + return qstr(game1->info.name).toLower() < qstr(game2->info.name).toLower(); }; // Sort by name at the very least. @@ -433,7 +436,7 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter) int scroll_position = m_xgrid->verticalScrollBar()->value(); PopulateGameGrid(games_per_row, m_Icon_Size, m_Icon_Color); - connect(m_xgrid, &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot); + connect(m_xgrid, &QTableWidget::itemDoubleClicked, this, &game_list_frame::doubleClickedSlot); connect(m_xgrid, &QTableWidget::customContextMenuRequested, this, &game_list_frame::ShowContextMenu); m_Central_Widget->addWidget(m_xgrid); m_Central_Widget->setCurrentWidget(m_xgrid); @@ -477,21 +480,31 @@ static void open_dir(const std::string& spath) QDesktopServices::openUrl(QUrl("file:///" + path)); } -void game_list_frame::doubleClickedSlot(const QModelIndex& index) +void game_list_frame::doubleClickedSlot(QTableWidgetItem *item) { - int i; + if (item == nullptr) + { + return; + } + + game_info game; if (m_isListLayout) { - i = m_gameList->item(index.row(), gui::column_icon)->data(Qt::UserRole).toInt(); + game = GetGameInfoFromItem(m_gameList->item(item->row(), gui::column_icon)); } else { - i = m_xgrid->item(index.row(), index.column())->data(Qt::ItemDataRole::UserRole).toInt(); + game = GetGameInfoFromItem(item); + } + + if (game.get() == nullptr) + { + return; } LOG_NOTICE(LOADER, "Booting from gamelist per doubleclick..."); - Q_EMIT RequestBoot(m_game_data[i].info.path); + Q_EMIT RequestBoot(game->info.path); } void game_list_frame::ShowContextMenu(const QPoint &pos) @@ -511,18 +524,13 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) globalPos = m_xgrid->mapToGlobal(pos); } - if (item == nullptr) + game_info gameinfo = GetGameInfoFromItem(item); + if (gameinfo.get() == nullptr) { - return; // null happens if you are double clicking in dockwidget area on nothing. + return; } - int index = item->data(Qt::UserRole).toInt(); - if (index == -1) - { - return; // invalid - } - - GameInfo currGame = m_game_data[index].info; + GameInfo currGame = gameinfo->info; const QString serial = qstr(currGame.serial); // Make Actions @@ -549,7 +557,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) QAction* checkCompat = myMenu.addAction(tr("&Check Game Compatibility")); QAction* downloadCompat = myMenu.addAction(tr("&Download Compatibility Database")); - const std::string config_base_dir = fs::get_config_dir() + "data/" + m_game_data[index].info.serial; + const std::string config_base_dir = fs::get_config_dir() + "data/" + currGame.serial; connect(boot, &QAction::triggered, [=] { @@ -559,7 +567,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) connect(configure, &QAction::triggered, [=] { settings_dialog dlg(xgui_settings, xemu_settings, 0, this, &currGame); - if (dlg.exec() == QDialog::Accepted && !m_game_data[index].hasCustomConfig) + if (dlg.exec() == QDialog::Accepted && !gameinfo->hasCustomConfig) { ShowCustomConfigIcon(item, true); } @@ -595,7 +603,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) RemoveCustomConfiguration(config_base_dir); } fs::remove_all(currGame.path); - m_game_data.erase(m_game_data.begin() + index); + m_game_data.erase(std::remove(m_game_data.begin(), m_game_data.end(), gameinfo), m_game_data.end()); if (m_isListLayout) { m_gameList->removeRow(m_gameList->currentItem()->row()); @@ -661,7 +669,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) } // Disable removeconfig if no config exists. - removeConfig->setEnabled(m_game_data[index].hasCustomConfig); + removeConfig->setEnabled(gameinfo->hasCustomConfig); // remove delete options if necessary if (!fs::is_dir(config_base_dir)) @@ -773,19 +781,20 @@ QPixmap game_list_frame::PaintedPixmap(const QImage& img, bool paintConfigIcon) void game_list_frame::ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled) { - if (item == nullptr) + auto game = GetGameInfoFromItem(item); + if (game == nullptr) { return; } - int index = item->data(Qt::UserRole).toInt(); - auto& game = m_game_data[index]; - game.hasCustomConfig = enabled; - game.pxmap = PaintedPixmap(game.icon, enabled); + game->hasCustomConfig = enabled; + game->pxmap = PaintedPixmap(game->icon, enabled); if (!m_isListLayout) { - m_xgrid->addItem(game.pxmap, qstr(game.info.name).simplified(), index, m_xgrid->currentItem()->row(), m_xgrid->currentItem()->column()); + int r = m_xgrid->currentItem()->row(), c = m_xgrid->currentItem()->column(); + m_xgrid->addItem(game->pxmap, qstr(game->info.name).simplified(), r, c); + m_xgrid->item(r, c)->setData(gui::game_role, QVariant::fromValue(game)); } else if (enabled) { @@ -793,7 +802,7 @@ void game_list_frame::ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled) } else { - m_gameList->setItem(item->row(), gui::column_name, new custom_table_widget_item(game.info.name)); + m_gameList->setItem(item->row(), gui::column_name, new custom_table_widget_item(game->info.name)); } } @@ -821,7 +830,7 @@ void game_list_frame::RepaintIcons(const bool& fromSettings) for (auto& game : m_game_data) { - game.pxmap = PaintedPixmap(game.icon, game.hasCustomConfig); + game->pxmap = PaintedPixmap(game->icon, game->hasCustomConfig); } Refresh(); @@ -923,43 +932,44 @@ int 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::DecorationRole, game->pxmap); icon_item->setData(Qt::UserRole, index, true); + icon_item->setData(gui::game_role, QVariant::fromValue(game)); // Title - custom_table_widget_item* title_item = new custom_table_widget_item(game.info.name); - if (game.hasCustomConfig) + custom_table_widget_item* title_item = new custom_table_widget_item(game->info.name); + if (game->hasCustomConfig) { title_item->setIcon(QIcon(":/Icons/cog_black.png")); } // Move Support (http://www.psdevwiki.com/ps3/PARAM.SFO#ATTRIBUTE) - bool supports_move = game.info.attr & 0x800000; + bool supports_move = game->info.attr & 0x800000; // Compatibility custom_table_widget_item* compat_item = new custom_table_widget_item; - compat_item->setText(game.compat.text + (game.compat.date.isEmpty() ? "" : " (" + game.compat.date + ")")); - compat_item->setData(Qt::UserRole, game.compat.index, true); - compat_item->setToolTip(game.compat.tooltip); - if (!game.compat.color.isEmpty()) + compat_item->setText(game->compat.text + (game->compat.date.isEmpty() ? "" : " (" + game->compat.date + ")")); + compat_item->setData(Qt::UserRole, game->compat.index, true); + compat_item->setToolTip(game->compat.tooltip); + if (!game->compat.color.isEmpty()) { - compat_item->setData(Qt::DecorationRole, compat_pixmap(game.compat.color)); + compat_item->setData(Qt::DecorationRole, compat_pixmap(game->compat.color)); } m_gameList->setItem(row, gui::column_icon, icon_item); m_gameList->setItem(row, gui::column_name, title_item); - m_gameList->setItem(row, gui::column_serial, new custom_table_widget_item(game.info.serial)); - m_gameList->setItem(row, gui::column_firmware, new custom_table_widget_item(game.info.fw)); - m_gameList->setItem(row, gui::column_version, new custom_table_widget_item(game.info.app_ver)); - m_gameList->setItem(row, gui::column_category, new custom_table_widget_item(game.info.category)); - m_gameList->setItem(row, gui::column_path, new custom_table_widget_item(game.info.path)); + m_gameList->setItem(row, gui::column_serial, new custom_table_widget_item(game->info.serial)); + m_gameList->setItem(row, gui::column_firmware, new custom_table_widget_item(game->info.fw)); + m_gameList->setItem(row, gui::column_version, new custom_table_widget_item(game->info.app_ver)); + m_gameList->setItem(row, gui::column_category, new custom_table_widget_item(game->info.category)); + m_gameList->setItem(row, gui::column_path, new custom_table_widget_item(game->info.path)); m_gameList->setItem(row, gui::column_move, new custom_table_widget_item(sstr(supports_move ? tr("Supported") : tr("Not Supported")), Qt::UserRole, !supports_move)); - m_gameList->setItem(row, gui::column_resolution, new custom_table_widget_item(GetStringFromU32(game.info.resolution, resolution::mode, true))); - m_gameList->setItem(row, gui::column_sound, new custom_table_widget_item(GetStringFromU32(game.info.sound_format, sound::format, true))); - m_gameList->setItem(row, gui::column_parental, new custom_table_widget_item(GetStringFromU32(game.info.parental_lvl, parental::level), Qt::UserRole, game.info.parental_lvl)); + m_gameList->setItem(row, gui::column_resolution, new custom_table_widget_item(GetStringFromU32(game->info.resolution, resolution::mode, true))); + m_gameList->setItem(row, gui::column_sound, new custom_table_widget_item(GetStringFromU32(game->info.sound_format, sound::format, true))); + m_gameList->setItem(row, gui::column_parental, new custom_table_widget_item(GetStringFromU32(game->info.parental_lvl, parental::level), Qt::UserRole, game->info.parental_lvl)); m_gameList->setItem(row, gui::column_compat, compat_item); - if (selected_item == game.info.icon_path) + if (selected_item == game->info.icon_path) { result = row; } @@ -992,14 +1002,14 @@ void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, con m_xgrid = new game_list_grid(image_size, image_color, m_Margin_Factor, m_Text_Factor, showText); } - // Get list of matching apps and their index - QList> matching_apps; + // Get list of matching apps + QList matching_apps; - for (uint i = 0; i < m_game_data.size(); i++) + for (const auto& app : m_game_data) { - if (IsEntryVisible(m_game_data[i])) + if (IsEntryVisible(app)) { - matching_apps.append(QPair(&m_game_data[i], i)); + matching_apps.push_back(app); } } @@ -1026,11 +1036,12 @@ void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, con for (const auto& app : matching_apps) { - const QString title = qstr(app.first->info.name).simplified(); // simplified() forces single line text + const QString title = qstr(app->info.name).simplified(); // simplified() forces single line text - m_xgrid->addItem(app.first->pxmap, title, app.second, r, c); + m_xgrid->addItem(app->pxmap, title, r, c); + m_xgrid->item(r, c)->setData(gui::game_role, QVariant::fromValue(app)); - if (selected_item == app.first->info.icon_path) + if (selected_item == app->info.icon_path) { m_xgrid->setCurrentItem(m_xgrid->item(r, c)); } @@ -1048,7 +1059,6 @@ void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, con { QTableWidgetItem* emptyItem = new QTableWidgetItem(); emptyItem->setFlags(Qt::NoItemFlags); - emptyItem->setData(Qt::UserRole, -1); m_xgrid->setItem(r, col, emptyItem); } } @@ -1079,10 +1089,16 @@ std::string game_list_frame::CurrentSelectionIconPath() if (m_gameList->selectedItems().count()) { QTableWidgetItem* item = m_oldLayoutIsList ? m_gameList->item(m_gameList->currentRow(), 0) : m_xgrid->currentItem(); - int ind = item->data(Qt::UserRole).toInt(); + QVariant var = item->data(gui::game_role); - if (ind < m_game_data.size()) - selection = m_game_data.at(ind).info.icon_path; + if (var.canConvert()) + { + auto game = var.value(); + if (game) + { + selection = game->info.icon_path; + } + } } m_oldLayoutIsList = m_isListLayout; @@ -1119,3 +1135,19 @@ std::string game_list_frame::GetStringFromU32(const u32& key, const std::mapdata(gui::game_role); + if (!var.canConvert()) + { + return nullptr; + } + + return var.value(); +} diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h index 98155baebb..1b027c2189 100644 --- a/rpcs3/rpcs3qt/game_list_frame.h +++ b/rpcs3/rpcs3qt/game_list_frame.h @@ -160,7 +160,7 @@ namespace sound } /* Having the icons associated with the game info simplifies logic internally */ -struct GUI_GameInfo +struct gui_game_info { GameInfo info; compat_status compat; @@ -169,6 +169,9 @@ struct GUI_GameInfo bool hasCustomConfig; }; +typedef std::shared_ptr game_info; +Q_DECLARE_METATYPE(game_info) + class game_list_frame : public custom_dock_widget { Q_OBJECT @@ -207,7 +210,7 @@ private Q_SLOTS: bool DeleteLLVMCache(const std::string& base_dir, bool is_interactive = false); void OnColClicked(int col); void ShowContextMenu(const QPoint &pos); - void doubleClickedSlot(const QModelIndex& index); + void doubleClickedSlot(QTableWidgetItem *item); Q_SIGNALS: void GameListFrameClosed(); void RequestBoot(const std::string& path); @@ -221,7 +224,7 @@ private: QPixmap PaintedPixmap(const QImage& img, bool paintConfigIcon = false); void ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled); void PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color); - bool IsEntryVisible(const GUI_GameInfo& game); + bool IsEntryVisible(const game_info& game); void SortGameList(); int PopulateGameList(); @@ -230,6 +233,8 @@ private: std::string CurrentSelectionIconPath(); std::string GetStringFromU32(const u32& key, const std::map& map, bool combined = false); + game_info GetGameInfoFromItem(QTableWidgetItem* item); + // Which widget we are displaying depends on if we are in grid or list mode. QMainWindow* m_Game_Dock; QStackedWidget* m_Central_Widget; @@ -254,7 +259,7 @@ private: // Data std::shared_ptr xgui_settings; std::shared_ptr xemu_settings; - std::vector m_game_data; + QList m_game_data; QSet m_hidden_list; bool m_show_hidden{false}; diff --git a/rpcs3/rpcs3qt/game_list_grid.cpp b/rpcs3/rpcs3qt/game_list_grid.cpp index 9cef947f6b..6ba48d2c3f 100644 --- a/rpcs3/rpcs3qt/game_list_grid.cpp +++ b/rpcs3/rpcs3qt/game_list_grid.cpp @@ -58,7 +58,7 @@ void game_list_grid::setIconSize(const QSize& size) } } -void game_list_grid::addItem(const QPixmap& img, const QString& name, const int& idx, const int& row, const int& col) +void game_list_grid::addItem(const QPixmap& img, const QString& name, const int& row, const int& col) { // define size of expanded image, which is raw image size + margins QSize exp_size; @@ -91,7 +91,6 @@ void game_list_grid::addItem(const QPixmap& img, const QString& name, const int& // create item with expanded image, title and position QTableWidgetItem* item = new QTableWidgetItem(); item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img)); - item->setData(Qt::ItemDataRole::UserRole, idx); item->setData(Qt::ItemDataRole::ToolTipRole, name); if (m_text_enabled) diff --git a/rpcs3/rpcs3qt/game_list_grid.h b/rpcs3/rpcs3qt/game_list_grid.h index e648f7669b..4d1aeb6f9b 100644 --- a/rpcs3/rpcs3qt/game_list_grid.h +++ b/rpcs3/rpcs3qt/game_list_grid.h @@ -22,7 +22,7 @@ public: void enableText(const bool& enabled); void setIconSize(const QSize& size); - void addItem(const QPixmap& img, const QString& name, const int& idx, const int& row, const int& col); + void addItem(const QPixmap& img, const QString& name, const int& row, const int& col); qreal getMarginFactor(); diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index 5d961ddc0e..aa30a45309 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -39,6 +39,11 @@ namespace gui { static QString stylesheet; + enum custom_roles + { + game_role = Qt::UserRole + 1337, + }; + enum game_list_columns { column_icon,