diff options
| author | Dentomologist <dentomologist@gmail.com> | 2026-02-19 14:36:54 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-19 14:36:54 -0800 |
| commit | 02db73c8dcb67f78fb93087a1fc24b65591f25f0 (patch) | |
| tree | 4718cd225976b62a8c404fc227e94fbdd2954bdc /Source | |
| parent | 9323074ada4b1d372809dc71ed092efe8d0e4c8e (diff) | |
| parent | 954219f781a05b9ad9175ebcf578d40625af41bc (diff) | |
Merge pull request #14344 from TryTwo/cheatsearch_work2
Cheat Search: Add ability to delete items and fix duplicate commands
Diffstat (limited to 'Source')
| -rw-r--r-- | Source/Core/Core/CheatSearch.cpp | 9 | ||||
| -rw-r--r-- | Source/Core/Core/CheatSearch.h | 4 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/CheatSearchWidget.cpp | 45 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/CheatSearchWidget.h | 1 |
4 files changed, 54 insertions, 5 deletions
diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index 2cf509e880..063a09a582 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -284,6 +284,15 @@ void Cheats::CheatSearchSession<T>::ResetResults() } template <typename T> +void Cheats::CheatSearchSession<T>::RemoveResult(size_t index) +{ + if (index < m_search_results.size()) + { + m_search_results.erase(m_search_results.begin() + index); + } +} + +template <typename T> static std::function<bool(const T& new_value)> MakeCompareFunctionForSpecificValue(Cheats::CompareType op, const T& old_value) { diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index 7df135d51a..7d1c089835 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -168,6 +168,9 @@ public: virtual bool WriteValue(const Core::CPUThreadGuard& guard, std::span<u32> addresses) const = 0; + // User can delete a search result. + virtual void RemoveResult(size_t index) = 0; + // Create a complete copy of this search session. virtual std::unique_ptr<CheatSearchSessionBase> Clone() const = 0; @@ -195,6 +198,7 @@ public: bool SetValueFromString(const std::string& value_as_string, bool force_parse_as_hex) override; void ResetResults() override; + void RemoveResult(size_t index) override; SearchErrorCode RunSearch(const Core::CPUThreadGuard& guard) override; size_t GetMemoryRangeCount() const override; diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index 629d8dbafb..35468d5fcc 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -3,7 +3,9 @@ #include "DolphinQt/CheatSearchWidget.h" +#include <algorithm> #include <optional> +#include <ranges> #include <string> #include <unordered_map> #include <utility> @@ -224,6 +226,7 @@ void CheatSearchWidget::CreateWidgets() m_address_table = new QTableWidget(); m_address_table->setContextMenuPolicy(Qt::CustomContextMenu); + m_address_table->setSelectionBehavior(QAbstractItemView::SelectRows); m_info_label_1 = new QLabel(tr("Waiting for first scan...")); m_info_label_2 = new QLabel(); @@ -483,6 +486,8 @@ void CheatSearchWidget::OnAddressTableContextMenu() if (m_address_table->selectedItems().isEmpty()) return; + std::vector<const QTableWidgetItem*> selected_items = GetSelectedAddressTableItems(); + QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose, true); @@ -491,8 +496,8 @@ void CheatSearchWidget::OnAddressTableContextMenu() const u32 address = item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); emit ShowMemory(address); }); - menu->addAction(tr("Add to watch"), this, [this] { - for (auto* const item : m_address_table->selectedItems()) + menu->addAction(tr("Add to watch"), this, [this, selected_items] { + for (auto* const item : selected_items) { const u32 address = item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); const QString name = QStringLiteral("mem_%1").arg(address, 8, 16, QLatin1Char('0')); @@ -501,6 +506,15 @@ void CheatSearchWidget::OnAddressTableContextMenu() }); menu->addAction(tr("Generate Action Replay Code(s)"), this, &CheatSearchWidget::GenerateARCodes); menu->addAction(tr("Write value"), this, &CheatSearchWidget::WriteValue); + menu->addAction(tr("Delete Address"), this, [this, selected_items] { + // Process in reverse so removal won't change the index of items about to be processed. + for (auto* const item : selected_items | std::views::reverse) + { + const u32 index = item->data(ADDRESS_TABLE_RESULT_INDEX_ROLE).toUInt(); + m_last_value_session->RemoveResult(index); + } + RecreateGUITable(); + }); menu->exec(QCursor::pos()); } @@ -533,7 +547,7 @@ void CheatSearchWidget::GenerateARCodes() bool had_multiple_errors = false; std::optional<Cheats::GenerateActionReplayCodeErrorCode> error_code; - for (auto* const item : m_address_table->selectedItems()) + for (auto* const item : GetSelectedAddressTableItems()) { const u32 index = item->data(ADDRESS_TABLE_RESULT_INDEX_ROLE).toUInt(); const auto result = Cheats::GenerateActionReplayCode(*m_last_value_session, index); @@ -600,9 +614,9 @@ void CheatSearchWidget::WriteValue() return; } - auto items = m_address_table->selectedItems(); + auto items = GetSelectedAddressTableItems(); std::vector<u32> addresses(items.size()); - std::transform(items.begin(), items.end(), addresses.begin(), [](QTableWidgetItem* item) { + std::transform(items.begin(), items.end(), addresses.begin(), [](const QTableWidgetItem* item) { return item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); }); Core::CPUThreadGuard guard{m_system}; @@ -610,6 +624,7 @@ void CheatSearchWidget::WriteValue() { m_info_label_1->setText(tr("There was an error writing (some) values.")); } + UpdateTableAllCurrentValues(UpdateSource::User); } size_t CheatSearchWidget::GetTableRowCount() const @@ -638,6 +653,26 @@ void CheatSearchWidget::RefreshGUICurrentValues(const size_t begin_index, const } } +const std::vector<const QTableWidgetItem*> CheatSearchWidget::GetSelectedAddressTableItems() const +{ + // Don't process each selectedItems(), as it can produce duplicate commands for one address when + // multiple items in the same row are selected. Instead, uses rows and gets one item from each + // row. All row items have identical data. + auto selected_rows = m_address_table->selectionModel()->selectedRows(); + + // Ascending address order. + std::sort(selected_rows.begin(), selected_rows.end(), + [](const QModelIndex& a, const QModelIndex& b) { return a.row() < b.row(); }); + + std::vector<const QTableWidgetItem*> selected_items; + for (const auto& index : selected_rows) + { + const int row = index.row(); + selected_items.push_back(m_address_table->item(row, 0)); + } + return selected_items; +} + void CheatSearchWidget::RecreateGUITable() { const QSignalBlocker blocker(m_address_table); diff --git a/Source/Core/DolphinQt/CheatSearchWidget.h b/Source/Core/DolphinQt/CheatSearchWidget.h index 18aa5a14b0..5dec20c3ed 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.h +++ b/Source/Core/DolphinQt/CheatSearchWidget.h @@ -75,6 +75,7 @@ private: int GetVisibleRowsBeginIndex() const; int GetVisibleRowsEndIndex() const; size_t GetTableRowCount() const; + const std::vector<const QTableWidgetItem*> GetSelectedAddressTableItems() const; Core::System& m_system; |
