mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
DolphinQt: Rewrite cheat search GUI.
This commit is contained in:
@@ -16,6 +16,10 @@ set(CMAKE_AUTOMOC ON)
|
||||
add_executable(dolphin-emu
|
||||
AboutDialog.cpp
|
||||
AboutDialog.h
|
||||
CheatSearchFactoryWidget.cpp
|
||||
CheatSearchFactoryWidget.h
|
||||
CheatSearchWidget.cpp
|
||||
CheatSearchWidget.h
|
||||
CheatsManager.cpp
|
||||
CheatsManager.h
|
||||
ConvertDialog.cpp
|
||||
@@ -269,6 +273,8 @@ add_executable(dolphin-emu
|
||||
QtUtils/ModalMessageBox.cpp
|
||||
QtUtils/ModalMessageBox.h
|
||||
QtUtils/ParallelProgressDialog.h
|
||||
QtUtils/PartiallyClosableTabWidget.cpp
|
||||
QtUtils/PartiallyClosableTabWidget.h
|
||||
QtUtils/ImageConverter.cpp
|
||||
QtUtils/ImageConverter.h
|
||||
QtUtils/UTF8CodePointCountValidator.cpp
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/CheatSearchFactoryWidget.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/CheatSearch.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
|
||||
CheatSearchFactoryWidget::CheatSearchFactoryWidget()
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
RefreshGui();
|
||||
}
|
||||
|
||||
CheatSearchFactoryWidget::~CheatSearchFactoryWidget() = default;
|
||||
|
||||
Q_DECLARE_METATYPE(Cheats::DataType);
|
||||
|
||||
void CheatSearchFactoryWidget::CreateWidgets()
|
||||
{
|
||||
auto* layout = new QVBoxLayout();
|
||||
|
||||
auto* address_space_group = new QGroupBox(tr("Address Space"));
|
||||
auto* address_space_layout = new QVBoxLayout();
|
||||
address_space_group->setLayout(address_space_layout);
|
||||
|
||||
m_standard_address_space = new QRadioButton(tr("Typical GameCube/Wii Address Space"));
|
||||
m_standard_address_space->setChecked(true);
|
||||
m_custom_address_space = new QRadioButton(tr("Custom Address Space"));
|
||||
|
||||
QLabel* label_standard_address_space =
|
||||
new QLabel(tr("Sets up the search using standard MEM1 and (on Wii) MEM2 mappings in virtual "
|
||||
"address space. This will work for the vast majority of games."));
|
||||
label_standard_address_space->setWordWrap(true);
|
||||
|
||||
auto* custom_address_space_layout = new QVBoxLayout();
|
||||
custom_address_space_layout->setMargin(6);
|
||||
auto* custom_address_space_button_group = new QButtonGroup();
|
||||
m_custom_virtual_address_space = new QRadioButton(tr("Use virtual addresses when possible"));
|
||||
m_custom_virtual_address_space->setChecked(true);
|
||||
m_custom_physical_address_space = new QRadioButton(tr("Use physical addresses"));
|
||||
m_custom_effective_address_space =
|
||||
new QRadioButton(tr("Use memory mapper configuration at time of scan"));
|
||||
custom_address_space_button_group->addButton(m_custom_virtual_address_space);
|
||||
custom_address_space_button_group->addButton(m_custom_physical_address_space);
|
||||
custom_address_space_button_group->addButton(m_custom_effective_address_space);
|
||||
custom_address_space_layout->addWidget(m_custom_virtual_address_space);
|
||||
custom_address_space_layout->addWidget(m_custom_physical_address_space);
|
||||
custom_address_space_layout->addWidget(m_custom_effective_address_space);
|
||||
|
||||
QLabel* label_range_start = new QLabel(tr("Range Start: "));
|
||||
m_custom_address_start = new QLineEdit(QStringLiteral("0x80000000"));
|
||||
QLabel* label_range_end = new QLabel(tr("Range End: "));
|
||||
m_custom_address_end = new QLineEdit(QStringLiteral("0x81800000"));
|
||||
custom_address_space_layout->addWidget(label_range_start);
|
||||
custom_address_space_layout->addWidget(m_custom_address_start);
|
||||
custom_address_space_layout->addWidget(label_range_end);
|
||||
custom_address_space_layout->addWidget(m_custom_address_end);
|
||||
|
||||
address_space_layout->addWidget(m_standard_address_space);
|
||||
address_space_layout->addWidget(label_standard_address_space);
|
||||
address_space_layout->addWidget(m_custom_address_space);
|
||||
address_space_layout->addLayout(custom_address_space_layout);
|
||||
|
||||
layout->addWidget(address_space_group);
|
||||
|
||||
auto* data_type_group = new QGroupBox(tr("Data Type"));
|
||||
auto* data_type_layout = new QVBoxLayout();
|
||||
data_type_group->setLayout(data_type_layout);
|
||||
|
||||
m_data_type_dropdown = new QComboBox();
|
||||
m_data_type_dropdown->addItem(tr("8-bit Unsigned Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::U8));
|
||||
m_data_type_dropdown->addItem(tr("16-bit Unsigned Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::U16));
|
||||
m_data_type_dropdown->addItem(tr("32-bit Unsigned Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::U32));
|
||||
m_data_type_dropdown->addItem(tr("64-bit Unsigned Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::U64));
|
||||
m_data_type_dropdown->addItem(tr("8-bit Signed Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::S8));
|
||||
m_data_type_dropdown->addItem(tr("16-bit Signed Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::S16));
|
||||
m_data_type_dropdown->addItem(tr("32-bit Signed Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::S32));
|
||||
m_data_type_dropdown->addItem(tr("64-bit Signed Integer"),
|
||||
QVariant::fromValue(Cheats::DataType::S64));
|
||||
m_data_type_dropdown->addItem(tr("32-bit Float"), QVariant::fromValue(Cheats::DataType::F32));
|
||||
m_data_type_dropdown->addItem(tr("64-bit Float"), QVariant::fromValue(Cheats::DataType::F64));
|
||||
m_data_type_dropdown->setCurrentIndex(6); // select 32bit signed int by default
|
||||
|
||||
data_type_layout->addWidget(m_data_type_dropdown);
|
||||
|
||||
m_data_type_aligned = new QCheckBox(tr("Aligned to data type length"));
|
||||
m_data_type_aligned->setChecked(true);
|
||||
|
||||
data_type_layout->addWidget(m_data_type_aligned);
|
||||
|
||||
layout->addWidget(data_type_group);
|
||||
|
||||
m_new_search = new QPushButton(tr("New Search"));
|
||||
layout->addWidget(m_new_search);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void CheatSearchFactoryWidget::ConnectWidgets()
|
||||
{
|
||||
connect(m_new_search, &QPushButton::clicked, this, &CheatSearchFactoryWidget::OnNewSearchClicked);
|
||||
connect(m_standard_address_space, &QPushButton::toggled, this,
|
||||
&CheatSearchFactoryWidget::OnAddressSpaceRadioChanged);
|
||||
connect(m_custom_address_space, &QRadioButton::toggled, this,
|
||||
&CheatSearchFactoryWidget::OnAddressSpaceRadioChanged);
|
||||
}
|
||||
|
||||
void CheatSearchFactoryWidget::RefreshGui()
|
||||
{
|
||||
bool enable_custom = m_custom_address_space->isChecked();
|
||||
m_custom_virtual_address_space->setEnabled(enable_custom);
|
||||
m_custom_physical_address_space->setEnabled(enable_custom);
|
||||
m_custom_effective_address_space->setEnabled(enable_custom);
|
||||
m_custom_address_start->setEnabled(enable_custom);
|
||||
m_custom_address_end->setEnabled(enable_custom);
|
||||
}
|
||||
|
||||
void CheatSearchFactoryWidget::OnAddressSpaceRadioChanged()
|
||||
{
|
||||
RefreshGui();
|
||||
}
|
||||
|
||||
void CheatSearchFactoryWidget::OnNewSearchClicked()
|
||||
{
|
||||
std::vector<Cheats::MemoryRange> memory_ranges;
|
||||
PowerPC::RequestedAddressSpace address_space;
|
||||
if (m_standard_address_space->isChecked())
|
||||
{
|
||||
memory_ranges.emplace_back(0x80000000, Memory::GetRamSizeReal());
|
||||
if (SConfig::GetInstance().bWii)
|
||||
memory_ranges.emplace_back(0x90000000, Memory::GetExRamSizeReal());
|
||||
address_space = PowerPC::RequestedAddressSpace::Virtual;
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string address_start_str = m_custom_address_start->text().toStdString();
|
||||
const std::string address_end_str = m_custom_address_end->text().toStdString();
|
||||
|
||||
u64 address_start;
|
||||
u64 address_end;
|
||||
if (!TryParse(address_start_str, &address_start) || !TryParse(address_end_str, &address_end))
|
||||
return;
|
||||
if (address_end <= address_start || address_end > 0x1'0000'0000)
|
||||
return;
|
||||
|
||||
memory_ranges.emplace_back(static_cast<u32>(address_start), address_end - address_start);
|
||||
|
||||
if (m_custom_virtual_address_space->isChecked())
|
||||
address_space = PowerPC::RequestedAddressSpace::Virtual;
|
||||
else if (m_custom_physical_address_space->isChecked())
|
||||
address_space = PowerPC::RequestedAddressSpace::Physical;
|
||||
else
|
||||
address_space = PowerPC::RequestedAddressSpace::Effective;
|
||||
}
|
||||
|
||||
bool aligned = m_data_type_aligned->isChecked();
|
||||
auto data_type = m_data_type_dropdown->currentData().value<Cheats::DataType>();
|
||||
auto session = Cheats::MakeSession(std::move(memory_ranges), address_space, aligned, data_type);
|
||||
if (session)
|
||||
emit NewSessionCreated(*session);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "Core/CheatSearch.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
|
||||
class CheatSearchFactoryWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheatSearchFactoryWidget();
|
||||
~CheatSearchFactoryWidget() override;
|
||||
|
||||
signals:
|
||||
void NewSessionCreated(const Cheats::CheatSearchSessionBase& session);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
void RefreshGui();
|
||||
|
||||
void OnAddressSpaceRadioChanged();
|
||||
void OnNewSearchClicked();
|
||||
|
||||
QRadioButton* m_standard_address_space;
|
||||
QRadioButton* m_custom_address_space;
|
||||
|
||||
QRadioButton* m_custom_virtual_address_space;
|
||||
QRadioButton* m_custom_physical_address_space;
|
||||
QRadioButton* m_custom_effective_address_space;
|
||||
|
||||
QLineEdit* m_custom_address_start;
|
||||
QLineEdit* m_custom_address_end;
|
||||
|
||||
QComboBox* m_data_type_dropdown;
|
||||
QCheckBox* m_data_type_aligned;
|
||||
|
||||
QPushButton* m_new_search;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/CheatSearch.h"
|
||||
|
||||
namespace ActionReplay
|
||||
{
|
||||
struct ARCode;
|
||||
}
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QTableWidget;
|
||||
class QTableWidgetItem;
|
||||
|
||||
struct CheatSearchTableUserData
|
||||
{
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
class CheatSearchWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheatSearchWidget(std::unique_ptr<Cheats::CheatSearchSessionBase> session);
|
||||
~CheatSearchWidget() override;
|
||||
|
||||
signals:
|
||||
void ActionReplayCodeGenerated(const ActionReplay::ARCode& ar_code);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
void OnNextScanClicked();
|
||||
void OnRefreshClicked();
|
||||
void OnResetClicked();
|
||||
void OnAddressTableItemChanged(QTableWidgetItem* item);
|
||||
void OnAddressTableContextMenu();
|
||||
void OnValueSourceChanged();
|
||||
void OnHexCheckboxStateChanged();
|
||||
|
||||
bool RefreshValues();
|
||||
void UpdateGuiTable();
|
||||
void GenerateARCode();
|
||||
|
||||
std::unique_ptr<Cheats::CheatSearchSessionBase> m_session;
|
||||
|
||||
// storage for the 'Current Value' column's data
|
||||
std::unordered_map<u32, std::string> m_address_table_current_values;
|
||||
|
||||
// storage for user-entered metadata such as text descriptions for memory addresses
|
||||
// this is intentionally NOT cleared when updating values or resetting or similar
|
||||
std::unordered_map<u32, CheatSearchTableUserData> m_address_table_user_data;
|
||||
|
||||
QComboBox* m_compare_type_dropdown;
|
||||
QComboBox* m_value_source_dropdown;
|
||||
QLineEdit* m_given_value_text;
|
||||
QLabel* m_info_label_1;
|
||||
QLabel* m_info_label_2;
|
||||
QPushButton* m_next_scan_button;
|
||||
QPushButton* m_refresh_values_button;
|
||||
QPushButton* m_reset_button;
|
||||
QCheckBox* m_display_values_in_hex_checkbox;
|
||||
QTableWidget* m_address_table;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <QDialog>
|
||||
@@ -12,29 +13,19 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "DolphinQt/GameList/GameListModel.h"
|
||||
|
||||
#include "Core/CheatSearch.h"
|
||||
|
||||
class ARCodeWidget;
|
||||
class QComboBox;
|
||||
class GeckoCodeWidget;
|
||||
class CheatSearchFactoryWidget;
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
class QSplitter;
|
||||
class QTabWidget;
|
||||
class QTableWidget;
|
||||
class QTableWidgetItem;
|
||||
struct Result;
|
||||
class PartiallyClosableTabWidget;
|
||||
|
||||
namespace Core
|
||||
{
|
||||
enum class State;
|
||||
}
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class CheatsManager : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -43,51 +34,20 @@ public:
|
||||
~CheatsManager();
|
||||
|
||||
private:
|
||||
QWidget* CreateCheatSearch();
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
void OnStateChanged(Core::State state);
|
||||
|
||||
size_t GetTypeSize() const;
|
||||
std::function<bool(u32)> CreateMatchFunction();
|
||||
|
||||
void Reset();
|
||||
void NewSearch();
|
||||
void NextSearch();
|
||||
void Update();
|
||||
void GenerateARCode();
|
||||
|
||||
void OnWatchContextMenu();
|
||||
void OnMatchContextMenu();
|
||||
void OnWatchItemChanged(QTableWidgetItem* item);
|
||||
void OnNewSessionCreated(const Cheats::CheatSearchSessionBase& session);
|
||||
void OnTabCloseRequested(int index);
|
||||
|
||||
std::string m_game_id;
|
||||
std::string m_game_tdb_id;
|
||||
u16 m_revision = 0;
|
||||
|
||||
std::vector<Result> m_results;
|
||||
std::vector<Result> m_watch;
|
||||
QDialogButtonBox* m_button_box;
|
||||
QTabWidget* m_tab_widget = nullptr;
|
||||
PartiallyClosableTabWidget* m_tab_widget = nullptr;
|
||||
|
||||
QWidget* m_cheat_search;
|
||||
ARCodeWidget* m_ar_code = nullptr;
|
||||
|
||||
QLabel* m_result_label;
|
||||
QTableWidget* m_match_table;
|
||||
QTableWidget* m_watch_table;
|
||||
QSplitter* m_option_splitter;
|
||||
QSplitter* m_table_splitter;
|
||||
QComboBox* m_match_length;
|
||||
QComboBox* m_match_operation;
|
||||
QLineEdit* m_match_value;
|
||||
QPushButton* m_match_new;
|
||||
QPushButton* m_match_next;
|
||||
QPushButton* m_match_refresh;
|
||||
QPushButton* m_match_reset;
|
||||
|
||||
QRadioButton* m_match_decimal;
|
||||
QRadioButton* m_match_hexadecimal;
|
||||
QRadioButton* m_match_octal;
|
||||
bool m_updating = false;
|
||||
GeckoCodeWidget* m_gecko_code = nullptr;
|
||||
CheatSearchFactoryWidget* m_cheat_search_new = nullptr;
|
||||
};
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AboutDialog.cpp" />
|
||||
<ClCompile Include="CheatSearchFactoryWidget.cpp" />
|
||||
<ClCompile Include="CheatSearchWidget.cpp" />
|
||||
<ClCompile Include="CheatsManager.cpp" />
|
||||
<ClCompile Include="Config\ARCodeWidget.cpp" />
|
||||
<ClCompile Include="Config\CheatCodeEditor.cpp" />
|
||||
@@ -168,6 +170,7 @@
|
||||
<ClCompile Include="QtUtils\FlowLayout.cpp" />
|
||||
<ClCompile Include="QtUtils\ImageConverter.cpp" />
|
||||
<ClCompile Include="QtUtils\ModalMessageBox.cpp" />
|
||||
<ClCompile Include="QtUtils\PartiallyClosableTabWidget.cpp" />
|
||||
<ClCompile Include="QtUtils\UTF8CodePointCountValidator.cpp" />
|
||||
<ClCompile Include="QtUtils\WindowActivationEventFilter.cpp" />
|
||||
<ClCompile Include="QtUtils\WinIconHelper.cpp" />
|
||||
@@ -227,6 +230,8 @@
|
||||
<ClInclude Include="Translation.h" />
|
||||
<ClInclude Include="WiiUpdate.h" />
|
||||
<QtMoc Include="AboutDialog.h" />
|
||||
<QtMoc Include="CheatSearchFactoryWidget.h" />
|
||||
<QtMoc Include="CheatSearchWidget.h" />
|
||||
<QtMoc Include="CheatsManager.h" />
|
||||
<QtMoc Include="Config\ARCodeWidget.h" />
|
||||
<QtMoc Include="Config\CheatWarningWidget.h" />
|
||||
@@ -340,6 +345,7 @@
|
||||
<QtMoc Include="QtUtils\ElidedButton.h" />
|
||||
<QtMoc Include="QtUtils\FileOpenEventFilter.h" />
|
||||
<QtMoc Include="QtUtils\ParallelProgressDialog.h" />
|
||||
<QtMoc Include="QtUtils\PartiallyClosableTabWidget.h" />
|
||||
<QtMoc Include="QtUtils\UTF8CodePointCountValidator.h" />
|
||||
<QtMoc Include="QtUtils\WindowActivationEventFilter.h" />
|
||||
<QtMoc Include="RenderWidget.h" />
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/QtUtils/PartiallyClosableTabWidget.h"
|
||||
|
||||
#include <QStyle>
|
||||
#include <QTabBar>
|
||||
|
||||
PartiallyClosableTabWidget::PartiallyClosableTabWidget(QWidget* parent) : QTabWidget(parent)
|
||||
{
|
||||
setTabsClosable(true);
|
||||
}
|
||||
|
||||
void PartiallyClosableTabWidget::setTabUnclosable(int index)
|
||||
{
|
||||
QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)style()->styleHint(
|
||||
QStyle::SH_TabBar_CloseButtonPosition, nullptr, this);
|
||||
tabBar()->setTabButton(index, closeSide, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTabWidget>
|
||||
|
||||
class QEvent;
|
||||
|
||||
class PartiallyClosableTabWidget : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PartiallyClosableTabWidget(QWidget* parent = nullptr);
|
||||
|
||||
void setTabUnclosable(int index);
|
||||
};
|
||||
Reference in New Issue
Block a user