mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-03-19 03:42:36 +00:00
Merge pull request #14344 from TryTwo/cheatsearch_work2
Cheat Search: Add ability to delete items and fix duplicate commands
This commit is contained in:
commit
02db73c8dc
@ -283,6 +283,15 @@ void Cheats::CheatSearchSession<T>::ResetResults()
|
||||
m_search_results.clear();
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user