From fa7c969e154cf8c6d89c831bbe4ad88cb54c9ffb Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Thu, 26 Oct 2023 13:06:16 -0700 Subject: [PATCH 1/4] CheatSearch: Use index range for ClonePartial Specify the begin and end indices instead of filling a vector with all the indices which are continuous anyway. --- Source/Core/Core/CheatSearch.cpp | 12 +++++------- Source/Core/Core/CheatSearch.h | 12 ++++++------ Source/Core/DolphinQt/CheatSearchWidget.cpp | 21 ++++----------------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index bf60485416..78f206ecfb 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -614,17 +614,15 @@ std::unique_ptr Cheats::CheatSearchSession::C template std::unique_ptr -Cheats::CheatSearchSession::ClonePartial(const std::vector& result_indices) const +Cheats::CheatSearchSession::ClonePartial(const size_t begin_index, const size_t end_index) const { - const auto& results = m_search_results; - std::vector> partial_results; - partial_results.reserve(result_indices.size()); - for (size_t idx : result_indices) - partial_results.push_back(results[idx]); + if (begin_index == 0 && end_index >= m_search_results.size()) + return Clone(); auto c = std::make_unique>(m_memory_ranges, m_address_space, m_aligned); - c->m_search_results = std::move(partial_results); + c->m_search_results.assign(m_search_results.begin() + begin_index, + m_search_results.begin() + end_index); c->m_compare_type = this->m_compare_type; c->m_filter_type = this->m_filter_type; c->m_value = this->m_value; diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index 696347fcf3..5f72a0a9a0 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -165,11 +165,11 @@ public: // Create a complete copy of this search session. virtual std::unique_ptr Clone() const = 0; - // Create a partial copy of this search session. Only the results with the passed indices are - // copied. This is useful if you want to run a next search on only partial result data of a + // Create a partial copy of this search session. Only the results with indices in the given range + // are copied. This is useful if you want to run a next search on only partial result data of a // previous search. - virtual std::unique_ptr - ClonePartial(const std::vector& result_indices) const = 0; + virtual std::unique_ptr ClonePartial(size_t begin_index, + size_t end_index) const = 0; }; template @@ -210,8 +210,8 @@ public: bool WasFirstSearchDone() const override; std::unique_ptr Clone() const override; - std::unique_ptr - ClonePartial(const std::vector& result_indices) const override; + std::unique_ptr ClonePartial(size_t begin_index, + size_t end_index) const override; private: std::vector> m_search_results; diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index 1f9d226601..4e91f5ddcd 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -373,28 +373,15 @@ void CheatSearchWidget::OnNextScanClicked() bool CheatSearchWidget::RefreshValues() { - const size_t result_count = m_session->GetResultCount(); - if (result_count == 0) + const size_t displayed_result_count = std::min(TABLE_MAX_ROWS, m_session->GetResultCount()); + if (displayed_result_count == 0) { m_info_label_1->setText(tr("Cannot refresh without results.")); return false; } - const bool too_many_results = result_count > TABLE_MAX_ROWS; - std::unique_ptr tmp; - if (too_many_results) - { - std::vector value_indices; - value_indices.reserve(TABLE_MAX_ROWS); - for (size_t i = 0; i < TABLE_MAX_ROWS; ++i) - value_indices.push_back(i); - tmp = m_session->ClonePartial(value_indices); - } - else - { - tmp = m_session->Clone(); - } - + std::unique_ptr tmp = + m_session->ClonePartial(0, displayed_result_count); tmp->SetFilterType(Cheats::FilterType::DoNotFilter); const Cheats::SearchErrorCode error_code = [&tmp] { From 7dfb23d38cf18c18eafc5dfbb84a196fa3b34005 Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Sat, 28 Oct 2023 12:25:41 -0700 Subject: [PATCH 2/4] CheatSearchWidget: Don't recreate table when refreshing values The table only needs to be recreated when the displayed addresses might change. If we're just refreshing the current values then update those table cells and leave the rest of the table alone. --- Source/Core/DolphinQt/CheatSearchWidget.cpp | 39 +++++++++++++++------ Source/Core/DolphinQt/CheatSearchWidget.h | 4 ++- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index 4e91f5ddcd..d595bb78b4 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -61,7 +61,7 @@ CheatSearchWidget::CheatSearchWidget(std::unique_ptrGetResultValueAsString(i, show_in_hex); } - UpdateGuiTable(); + RecreateGUITable(); } else { @@ -404,7 +404,7 @@ bool CheatSearchWidget::RefreshValues() tmp->GetResultValueAsString(i, show_in_hex); } - UpdateGuiTable(); + RefreshGUICurrentValues(); m_info_label_1->setText(tr("Refreshed current values.")); return true; } @@ -419,7 +419,7 @@ void CheatSearchWidget::OnResetClicked() m_session->ResetResults(); m_address_table_current_values.clear(); - UpdateGuiTable(); + RecreateGUITable(); m_info_label_1->setText(tr("Waiting for first scan...")); m_info_label_2->clear(); } @@ -475,7 +475,7 @@ void CheatSearchWidget::OnDisplayHexCheckboxStateChanged() return; if (!RefreshValues()) - UpdateGuiTable(); + RefreshGUICurrentValues(); } void CheatSearchWidget::GenerateARCode() @@ -511,7 +511,28 @@ void CheatSearchWidget::GenerateARCode() } } -void CheatSearchWidget::UpdateGuiTable() +void CheatSearchWidget::RefreshCurrentValueTableItem( + QTableWidgetItem* const current_value_table_item) +{ + const auto address = current_value_table_item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); + const auto curr_val_iter = m_address_table_current_values.find(address); + if (curr_val_iter != m_address_table_current_values.end()) + current_value_table_item->setText(QString::fromStdString(curr_val_iter->second)); + else + current_value_table_item->setText(QStringLiteral("---")); +} + +void CheatSearchWidget::RefreshGUICurrentValues() +{ + for (size_t i = 0; i < m_session->GetResultCount(); ++i) + { + QTableWidgetItem* const current_value_table_item = + m_address_table->item(static_cast(i), ADDRESS_TABLE_COLUMN_INDEX_CURRENT_VALUE); + RefreshCurrentValueTableItem(current_value_table_item); + } +} + +void CheatSearchWidget::RecreateGUITable() { const QSignalBlocker blocker(m_address_table); @@ -557,13 +578,9 @@ void CheatSearchWidget::UpdateGuiTable() auto* current_value_item = new QTableWidgetItem(); current_value_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); - const auto curr_val_it = m_address_table_current_values.find(address); - if (curr_val_it != m_address_table_current_values.end()) - current_value_item->setText(QString::fromStdString(curr_val_it->second)); - else - current_value_item->setText(QStringLiteral("---")); current_value_item->setData(ADDRESS_TABLE_ADDRESS_ROLE, address); current_value_item->setData(ADDRESS_TABLE_RESULT_INDEX_ROLE, static_cast(i)); m_address_table->setItem(i, ADDRESS_TABLE_COLUMN_INDEX_CURRENT_VALUE, current_value_item); + RefreshCurrentValueTableItem(current_value_item); } } diff --git a/Source/Core/DolphinQt/CheatSearchWidget.h b/Source/Core/DolphinQt/CheatSearchWidget.h index e885f7a181..30b8cc5f44 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.h +++ b/Source/Core/DolphinQt/CheatSearchWidget.h @@ -57,7 +57,9 @@ private: void OnDisplayHexCheckboxStateChanged(); bool RefreshValues(); - void UpdateGuiTable(); + void RefreshCurrentValueTableItem(QTableWidgetItem* current_value_table_item); + void RefreshGUICurrentValues(); + void RecreateGUITable(); void GenerateARCode(); std::unique_ptr m_session; From fdb7328c737f2bba148b903491b66fa62cc03703 Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Sat, 28 Oct 2023 16:30:22 -0700 Subject: [PATCH 3/4] CheatSearch: Update Current Values at end of frame At the end of each frame automatically update the Current Value for visible table rows in the selected and visible CheatSearchWidget (if any). Also update all Current Values in all CheatSearchWidgets when the State changes to Paused. Only updating visible table rows serves to minimize the performance cost of this feature. If the user scrolls to an un-updated cell it will promptly be updated by either the next VIEndFieldEvent or the State transitioning to Paused. --- Source/Core/Core/HW/VideoInterface.cpp | 2 + Source/Core/DolphinQt/CheatSearchWidget.cpp | 66 +++++++++++++++------ Source/Core/DolphinQt/CheatSearchWidget.h | 9 ++- Source/Core/DolphinQt/CheatsManager.cpp | 47 ++++++++++++++- Source/Core/DolphinQt/CheatsManager.h | 16 ++++- Source/Core/VideoCommon/VideoEvents.h | 3 + 6 files changed, 120 insertions(+), 23 deletions(-) diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index 68b6564f86..c89ac88f84 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -33,6 +33,7 @@ #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" +#include "VideoCommon/VideoEvents.h" namespace VideoInterface { @@ -839,6 +840,7 @@ void VideoInterfaceManager::EndField(FieldType field, u64 ticks) OutputField(field, ticks); g_perf_metrics.CountVBlank(); + VIEndFieldEvent::Trigger(); Core::OnFrameEnd(); } diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index d595bb78b4..302bd645d0 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -263,6 +263,7 @@ void CheatSearchWidget::ConnectWidgets() void CheatSearchWidget::OnNextScanClicked() { + Core::CPUThreadGuard guard(Core::System::GetInstance()); const bool had_old_results = m_session->WasFirstSearchDone(); const size_t old_count = m_session->GetResultCount(); @@ -288,8 +289,7 @@ void CheatSearchWidget::OnNextScanClicked() } } - const Cheats::SearchErrorCode error_code = [this] { - Core::CPUThreadGuard guard(Core::System::GetInstance()); + const Cheats::SearchErrorCode error_code = [this, &guard] { return m_session->RunSearch(guard); }(); @@ -371,17 +371,11 @@ void CheatSearchWidget::OnNextScanClicked() } } -bool CheatSearchWidget::RefreshValues() +bool CheatSearchWidget::UpdateTableRows(const Core::CPUThreadGuard& guard, const size_t begin_index, + const size_t end_index) { - const size_t displayed_result_count = std::min(TABLE_MAX_ROWS, m_session->GetResultCount()); - if (displayed_result_count == 0) - { - m_info_label_1->setText(tr("Cannot refresh without results.")); - return false; - } - std::unique_ptr tmp = - m_session->ClonePartial(0, displayed_result_count); + m_session->ClonePartial(begin_index, end_index); tmp->SetFilterType(Cheats::FilterType::DoNotFilter); const Cheats::SearchErrorCode error_code = [&tmp] { @@ -395,7 +389,6 @@ bool CheatSearchWidget::RefreshValues() return false; } - m_address_table_current_values.clear(); const bool show_in_hex = m_display_values_in_hex_checkbox->isChecked(); const size_t result_count_to_display = tmp->GetResultCount(); for (size_t i = 0; i < result_count_to_display; ++i) @@ -404,18 +397,41 @@ bool CheatSearchWidget::RefreshValues() tmp->GetResultValueAsString(i, show_in_hex); } - RefreshGUICurrentValues(); + RefreshGUICurrentValues(begin_index, end_index); m_info_label_1->setText(tr("Refreshed current values.")); return true; } +void CheatSearchWidget::UpdateTableVisibleCurrentValues() +{ + Core::CPUThreadGuard guard(Core::System::GetInstance()); + if (m_address_table->rowCount() == 0) + return; + + UpdateTableRows(guard, GetVisibleRowsBeginIndex(), GetVisibleRowsEndIndex()); +} + +bool CheatSearchWidget::UpdateTableAllCurrentValues() +{ + Core::CPUThreadGuard guard(Core::System::GetInstance()); + const size_t result_count = m_address_table->rowCount(); + if (result_count == 0) + { + m_info_label_1->setText(tr("Cannot refresh without results.")); + return false; + } + + return UpdateTableRows(guard, 0, result_count); +} + void CheatSearchWidget::OnRefreshClicked() { - RefreshValues(); + UpdateTableAllCurrentValues(); } void CheatSearchWidget::OnResetClicked() { + Core::CPUThreadGuard guard(Core::System::GetInstance()); m_session->ResetResults(); m_address_table_current_values.clear(); @@ -441,6 +457,18 @@ void CheatSearchWidget::OnAddressTableItemChanged(QTableWidgetItem* item) } } +int CheatSearchWidget::GetVisibleRowsBeginIndex() const +{ + return m_address_table->rowAt(0); +} + +int CheatSearchWidget::GetVisibleRowsEndIndex() const +{ + const int row_at_bottom_of_viewport = m_address_table->rowAt(m_address_table->height()); + const int end_index = m_address_table->rowCount(); + return row_at_bottom_of_viewport == -1 ? end_index : row_at_bottom_of_viewport + 1; +} + void CheatSearchWidget::OnAddressTableContextMenu() { if (m_address_table->selectedItems().isEmpty()) @@ -474,12 +502,14 @@ void CheatSearchWidget::OnDisplayHexCheckboxStateChanged() if (!m_session->WasFirstSearchDone()) return; - if (!RefreshValues()) - RefreshGUICurrentValues(); + // If the game is running CheatsManager::OnFrameEnd will update values automatically. + if (Core::GetState() != Core::State::Running) + UpdateTableAllCurrentValues(); } void CheatSearchWidget::GenerateARCode() { + Core::CPUThreadGuard guard(Core::System::GetInstance()); if (m_address_table->selectedItems().isEmpty()) return; @@ -522,9 +552,9 @@ void CheatSearchWidget::RefreshCurrentValueTableItem( current_value_table_item->setText(QStringLiteral("---")); } -void CheatSearchWidget::RefreshGUICurrentValues() +void CheatSearchWidget::RefreshGUICurrentValues(const size_t begin_index, const size_t end_index) { - for (size_t i = 0; i < m_session->GetResultCount(); ++i) + for (size_t i = begin_index; i < end_index; ++i) { QTableWidgetItem* const current_value_table_item = m_address_table->item(static_cast(i), ADDRESS_TABLE_COLUMN_INDEX_CURRENT_VALUE); diff --git a/Source/Core/DolphinQt/CheatSearchWidget.h b/Source/Core/DolphinQt/CheatSearchWidget.h index 30b8cc5f44..a9955632ee 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.h +++ b/Source/Core/DolphinQt/CheatSearchWidget.h @@ -39,6 +39,9 @@ public: explicit CheatSearchWidget(std::unique_ptr session); ~CheatSearchWidget() override; + bool UpdateTableAllCurrentValues(); + void UpdateTableVisibleCurrentValues(); + signals: void ActionReplayCodeGenerated(const ActionReplay::ARCode& ar_code); void RequestWatch(QString name, u32 address); @@ -56,11 +59,13 @@ private: void OnValueSourceChanged(); void OnDisplayHexCheckboxStateChanged(); - bool RefreshValues(); void RefreshCurrentValueTableItem(QTableWidgetItem* current_value_table_item); - void RefreshGUICurrentValues(); + void RefreshGUICurrentValues(size_t begin_index, size_t end_index); + bool UpdateTableRows(const Core::CPUThreadGuard& guard, size_t begin_index, size_t end_index); void RecreateGUITable(); void GenerateARCode(); + int GetVisibleRowsBeginIndex() const; + int GetVisibleRowsEndIndex() const; std::unique_ptr m_session; diff --git a/Source/Core/DolphinQt/CheatsManager.cpp b/Source/Core/DolphinQt/CheatsManager.cpp index 743126f574..c083081549 100644 --- a/Source/Core/DolphinQt/CheatsManager.cpp +++ b/Source/Core/DolphinQt/CheatsManager.cpp @@ -19,8 +19,10 @@ #include "DolphinQt/CheatSearchWidget.h" #include "DolphinQt/Config/ARCodeWidget.h" #include "DolphinQt/Config/GeckoCodeWidget.h" +#include "DolphinQt/QtUtils/PartiallyClosableTabWidget.h" #include "DolphinQt/Settings.h" -#include "QtUtils/PartiallyClosableTabWidget.h" + +#include "VideoCommon/VideoEvents.h" CheatsManager::CheatsManager(QWidget* parent) : QDialog(parent) { @@ -48,6 +50,49 @@ CheatsManager::~CheatsManager() void CheatsManager::OnStateChanged(Core::State state) { RefreshCodeTabs(state, false); + if (state == Core::State::Paused) + UpdateAllCheatSearchWidgetCurrentValues(); +} + +void CheatsManager::OnFrameEnd() +{ + if (!isVisible()) + return; + + auto* const selected_cheat_search_widget = + qobject_cast(m_tab_widget->currentWidget()); + if (selected_cheat_search_widget != nullptr) + selected_cheat_search_widget->UpdateTableVisibleCurrentValues(); +} + +void CheatsManager::UpdateAllCheatSearchWidgetCurrentValues() +{ + for (int i = 0; i < m_tab_widget->count(); ++i) + { + auto* const cheat_search_widget = qobject_cast(m_tab_widget->widget(i)); + if (cheat_search_widget != nullptr) + cheat_search_widget->UpdateTableAllCurrentValues(); + } +} + +void CheatsManager::RegisterAfterFrameEventCallback() +{ + m_VI_end_field_event = VIEndFieldEvent::Register([this] { OnFrameEnd(); }, "CheatsManager"); +} + +void CheatsManager::RemoveAfterFrameEventCallback() +{ + m_VI_end_field_event.reset(); +} + +void CheatsManager::hideEvent(QHideEvent* event) +{ + RemoveAfterFrameEventCallback(); +} + +void CheatsManager::showEvent(QShowEvent* event) +{ + RegisterAfterFrameEventCallback(); } void CheatsManager::RefreshCodeTabs(Core::State state, bool force) diff --git a/Source/Core/DolphinQt/CheatsManager.h b/Source/Core/DolphinQt/CheatsManager.h index 5e7ddb8bb2..2692999bb7 100644 --- a/Source/Core/DolphinQt/CheatsManager.h +++ b/Source/Core/DolphinQt/CheatsManager.h @@ -11,14 +11,16 @@ #include #include "Common/CommonTypes.h" -#include "DolphinQt/GameList/GameListModel.h" - #include "Core/CheatSearch.h" +#include "DolphinQt/GameList/GameListModel.h" +#include "VideoCommon/VideoEvents.h" class ARCodeWidget; class GeckoCodeWidget; class CheatSearchFactoryWidget; class QDialogButtonBox; +class QHideEvent; +class QShowEvent; class PartiallyClosableTabWidget; namespace Core @@ -38,14 +40,22 @@ signals: void ShowMemory(u32 address); void RequestWatch(QString name, u32 address); +protected: + void hideEvent(QHideEvent* event) override; + void showEvent(QShowEvent* event) override; + private: void CreateWidgets(); void ConnectWidgets(); void OnStateChanged(Core::State state); + void OnFrameEnd(); + void RegisterAfterFrameEventCallback(); + void RemoveAfterFrameEventCallback(); void OnNewSessionCreated(const Cheats::CheatSearchSessionBase& session); void OnTabCloseRequested(int index); void RefreshCodeTabs(Core::State state, bool force); + void UpdateAllCheatSearchWidgetCurrentValues(); std::string m_game_id; std::string m_game_tdb_id; @@ -57,4 +67,6 @@ private: ARCodeWidget* m_ar_code = nullptr; GeckoCodeWidget* m_gecko_code = nullptr; CheatSearchFactoryWidget* m_cheat_search_new = nullptr; + + Common::EventHook m_VI_end_field_event; }; diff --git a/Source/Core/VideoCommon/VideoEvents.h b/Source/Core/VideoCommon/VideoEvents.h index c611925b2c..191db9802c 100644 --- a/Source/Core/VideoCommon/VideoEvents.h +++ b/Source/Core/VideoCommon/VideoEvents.h @@ -81,3 +81,6 @@ using BeforePresentEvent = Common::HookableEvent<"BeforePresent", PresentInfo&>; // An event that is triggered after a frame is presented. // The exact timing of this event depends on backend/driver support. using AfterPresentEvent = Common::HookableEvent<"AfterPresent", PresentInfo&>; + +// An end of frame event that runs on the CPU thread +using VIEndFieldEvent = Common::HookableEvent<"VIEndField">; From 9230266529ff70981a89a9cf95e9665a479f1168 Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Sun, 29 Oct 2023 15:20:23 -0700 Subject: [PATCH 4/4] CheatSearchWidget: Add checkbox to toggle Current Value autoupdate --- Source/Core/DolphinQt/CheatSearchWidget.cpp | 45 ++++++++++++++++----- Source/Core/DolphinQt/CheatSearchWidget.h | 14 +++++-- Source/Core/DolphinQt/CheatsManager.cpp | 7 +++- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index 302bd645d0..d588c078b8 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -69,6 +69,9 @@ CheatSearchWidget::~CheatSearchWidget() auto& settings = Settings::GetQSettings(); settings.setValue(QStringLiteral("cheatsearchwidget/displayhex"), m_display_values_in_hex_checkbox->isChecked()); + settings.setValue(QStringLiteral("cheatsearchwidget/autoupdatecurrentvalues"), + m_autoupdate_current_values->isChecked()); + if (m_session->IsIntegerType()) { settings.setValue(QStringLiteral("cheatsearchwidget/parsehex"), @@ -229,16 +232,25 @@ void CheatSearchWidget::CreateWidgets() m_info_label_1 = new QLabel(tr("Waiting for first scan...")); m_info_label_2 = new QLabel(); + auto* const checkboxes_layout = new QHBoxLayout(); m_display_values_in_hex_checkbox = new QCheckBox(tr("Display values in Hex")); m_display_values_in_hex_checkbox->setChecked( settings.value(QStringLiteral("cheatsearchwidget/displayhex")).toBool()); + checkboxes_layout->addWidget(m_display_values_in_hex_checkbox); + checkboxes_layout->setStretchFactor(m_display_values_in_hex_checkbox, 1); + + m_autoupdate_current_values = new QCheckBox(tr("Automatically update Current Values")); + m_autoupdate_current_values->setChecked( + settings.value(QStringLiteral("cheatsearchwidget/autoupdatecurrentvalues"), true).toBool()); + checkboxes_layout->addWidget(m_autoupdate_current_values); + checkboxes_layout->setStretchFactor(m_autoupdate_current_values, 2); QVBoxLayout* layout = new QVBoxLayout(); layout->addWidget(session_info_label); layout->addWidget(instructions_label); layout->addLayout(value_layout); layout->addLayout(button_layout); - layout->addWidget(m_display_values_in_hex_checkbox); + layout->addLayout(checkboxes_layout); layout->addWidget(m_info_label_1); layout->addWidget(m_info_label_2); layout->addWidget(m_address_table); @@ -372,8 +384,10 @@ void CheatSearchWidget::OnNextScanClicked() } bool CheatSearchWidget::UpdateTableRows(const Core::CPUThreadGuard& guard, const size_t begin_index, - const size_t end_index) + const size_t end_index, const UpdateSource source) { + const bool update_status_text = source == UpdateSource::User; + std::unique_ptr tmp = m_session->ClonePartial(begin_index, end_index); tmp->SetFilterType(Cheats::FilterType::DoNotFilter); @@ -385,7 +399,8 @@ bool CheatSearchWidget::UpdateTableRows(const Core::CPUThreadGuard& guard, const if (error_code != Cheats::SearchErrorCode::Success) { - m_info_label_1->setText(tr("Refresh failed. Please run the game for a bit and try again.")); + if (update_status_text) + m_info_label_1->setText(tr("Refresh failed. Please run the game for a bit and try again.")); return false; } @@ -398,35 +413,43 @@ bool CheatSearchWidget::UpdateTableRows(const Core::CPUThreadGuard& guard, const } RefreshGUICurrentValues(begin_index, end_index); - m_info_label_1->setText(tr("Refreshed current values.")); + if (update_status_text) + m_info_label_1->setText(tr("Refreshed current values.")); return true; } -void CheatSearchWidget::UpdateTableVisibleCurrentValues() +void CheatSearchWidget::UpdateTableVisibleCurrentValues(const UpdateSource source) { + if (source == UpdateSource::Auto && !m_autoupdate_current_values->isChecked()) + return; + Core::CPUThreadGuard guard(Core::System::GetInstance()); if (m_address_table->rowCount() == 0) return; - UpdateTableRows(guard, GetVisibleRowsBeginIndex(), GetVisibleRowsEndIndex()); + UpdateTableRows(guard, GetVisibleRowsBeginIndex(), GetVisibleRowsEndIndex(), source); } -bool CheatSearchWidget::UpdateTableAllCurrentValues() +bool CheatSearchWidget::UpdateTableAllCurrentValues(const UpdateSource source) { + if (source == UpdateSource::Auto && !m_autoupdate_current_values->isChecked()) + return false; + Core::CPUThreadGuard guard(Core::System::GetInstance()); const size_t result_count = m_address_table->rowCount(); if (result_count == 0) { - m_info_label_1->setText(tr("Cannot refresh without results.")); + if (source == UpdateSource::User) + m_info_label_1->setText(tr("Cannot refresh without results.")); return false; } - return UpdateTableRows(guard, 0, result_count); + return UpdateTableRows(guard, 0, result_count, source); } void CheatSearchWidget::OnRefreshClicked() { - UpdateTableAllCurrentValues(); + UpdateTableAllCurrentValues(UpdateSource::User); } void CheatSearchWidget::OnResetClicked() @@ -504,7 +527,7 @@ void CheatSearchWidget::OnDisplayHexCheckboxStateChanged() // If the game is running CheatsManager::OnFrameEnd will update values automatically. if (Core::GetState() != Core::State::Running) - UpdateTableAllCurrentValues(); + UpdateTableAllCurrentValues(UpdateSource::User); } void CheatSearchWidget::GenerateARCode() diff --git a/Source/Core/DolphinQt/CheatSearchWidget.h b/Source/Core/DolphinQt/CheatSearchWidget.h index a9955632ee..5c3ad52423 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.h +++ b/Source/Core/DolphinQt/CheatSearchWidget.h @@ -39,8 +39,14 @@ public: explicit CheatSearchWidget(std::unique_ptr session); ~CheatSearchWidget() override; - bool UpdateTableAllCurrentValues(); - void UpdateTableVisibleCurrentValues(); + enum class UpdateSource + { + User, + Auto, + }; + + bool UpdateTableAllCurrentValues(UpdateSource source); + void UpdateTableVisibleCurrentValues(UpdateSource source); signals: void ActionReplayCodeGenerated(const ActionReplay::ARCode& ar_code); @@ -61,7 +67,8 @@ private: void RefreshCurrentValueTableItem(QTableWidgetItem* current_value_table_item); void RefreshGUICurrentValues(size_t begin_index, size_t end_index); - bool UpdateTableRows(const Core::CPUThreadGuard& guard, size_t begin_index, size_t end_index); + bool UpdateTableRows(const Core::CPUThreadGuard& guard, size_t begin_index, size_t end_index, + UpdateSource source); void RecreateGUITable(); void GenerateARCode(); int GetVisibleRowsBeginIndex() const; @@ -86,5 +93,6 @@ private: QPushButton* m_reset_button; QCheckBox* m_parse_values_as_hex_checkbox; QCheckBox* m_display_values_in_hex_checkbox; + QCheckBox* m_autoupdate_current_values; QTableWidget* m_address_table; }; diff --git a/Source/Core/DolphinQt/CheatsManager.cpp b/Source/Core/DolphinQt/CheatsManager.cpp index c083081549..0b80de7304 100644 --- a/Source/Core/DolphinQt/CheatsManager.cpp +++ b/Source/Core/DolphinQt/CheatsManager.cpp @@ -62,7 +62,10 @@ void CheatsManager::OnFrameEnd() auto* const selected_cheat_search_widget = qobject_cast(m_tab_widget->currentWidget()); if (selected_cheat_search_widget != nullptr) - selected_cheat_search_widget->UpdateTableVisibleCurrentValues(); + { + selected_cheat_search_widget->UpdateTableVisibleCurrentValues( + CheatSearchWidget::UpdateSource::Auto); + } } void CheatsManager::UpdateAllCheatSearchWidgetCurrentValues() @@ -71,7 +74,7 @@ void CheatsManager::UpdateAllCheatSearchWidgetCurrentValues() { auto* const cheat_search_widget = qobject_cast(m_tab_widget->widget(i)); if (cheat_search_widget != nullptr) - cheat_search_widget->UpdateTableAllCurrentValues(); + cheat_search_widget->UpdateTableAllCurrentValues(CheatSearchWidget::UpdateSource::Auto); } }