Merge pull request #1334 from lioncash/cheats
Break Cheat Manager components out into their own source files.
This commit is contained in:
commit
833ff4a065
|
@ -24,8 +24,11 @@ endif()
|
|||
set(GUI_SRCS
|
||||
ARCodeAddEdit.cpp
|
||||
AboutDolphin.cpp
|
||||
CheatsWindow.cpp
|
||||
ConfigMain.cpp
|
||||
Cheats/CheatSearchTab.cpp
|
||||
Cheats/CheatsWindow.cpp
|
||||
Cheats/CreateCodeDialog.cpp
|
||||
Cheats/GeckoCodeDiag.cpp
|
||||
Debugger/BreakpointDlg.cpp
|
||||
Debugger/BreakpointView.cpp
|
||||
Debugger/BreakpointWindow.cpp
|
||||
|
@ -47,7 +50,6 @@ set(GUI_SRCS
|
|||
FrameAui.cpp
|
||||
FrameTools.cpp
|
||||
GameListCtrl.cpp
|
||||
GeckoCodeDiag.cpp
|
||||
HotkeyDlg.cpp
|
||||
ISOFile.cpp
|
||||
ISOProperties.cpp
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/CheatSearchTab.h"
|
||||
#include "DolphinWX/Cheats/CreateCodeDialog.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
|
||||
}
|
||||
|
||||
CheatSearchTab::CheatSearchTab(wxWindow* const parent)
|
||||
: wxPanel(parent, -1)
|
||||
{
|
||||
// first scan button
|
||||
m_btn_init_scan = new wxButton(this, -1, _("New Scan"));
|
||||
m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::StartNewSearch, this);
|
||||
|
||||
// next scan button
|
||||
m_btn_next_scan = new wxButton(this, -1, _("Next Scan"));
|
||||
m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::FilterCheatSearchResults, this);
|
||||
m_btn_next_scan->Disable();
|
||||
|
||||
// data size radio buttons
|
||||
m_size_radiobtn.rad_8 = new wxRadioButton(this, -1, _("8 bit"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
m_size_radiobtn.rad_16 = new wxRadioButton(this, -1, _("16 bit"));
|
||||
m_size_radiobtn.rad_32 = new wxRadioButton(this, -1, _("32 bit"));
|
||||
m_size_radiobtn.rad_8->SetValue(true);
|
||||
|
||||
// data sizes groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_new_search = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Data Size"));
|
||||
sizer_cheat_new_search->Add(m_size_radiobtn.rad_8, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_new_search->Add(m_size_radiobtn.rad_16, 0, wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_new_search->Add(m_size_radiobtn.rad_32, 0, wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
// result controls
|
||||
m_lbox_search_results = new wxListBox(this, -1);
|
||||
m_label_results_count = new wxStaticText(this, -1, _("Count:"));
|
||||
|
||||
// create AR code button
|
||||
wxButton* const button_cheat_search_copy_address = new wxButton(this, -1, _("Create AR Code"));
|
||||
button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::CreateARCode, this);
|
||||
|
||||
// results groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_search_results = new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
|
||||
sizer_cheat_search_results->Add(m_label_results_count, 0, wxALIGN_LEFT | wxALL, 5);
|
||||
sizer_cheat_search_results->Add(m_lbox_search_results, 1, wxEXPAND | wxALL, 5);
|
||||
sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
// Search value radio buttons
|
||||
m_value_x_radiobtn.rad_oldvalue = new wxRadioButton(this, -1, _("Previous Value"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
m_value_x_radiobtn.rad_uservalue = new wxRadioButton(this, -1, "");
|
||||
m_value_x_radiobtn.rad_oldvalue->SetValue(true);
|
||||
|
||||
// search value textbox
|
||||
m_textctrl_value_x = new wxTextCtrl(this, -1, "0x0", wxDefaultPosition, wxSize(96,-1));
|
||||
m_textctrl_value_x->Bind(wxEVT_SET_FOCUS, &CheatSearchTab::ApplyFocus, this);
|
||||
|
||||
wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_cheat_filter_text->Add(m_value_x_radiobtn.rad_uservalue, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_filter_text->Add(m_textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
// value groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_search_filter_x = new wxStaticBoxSizer(wxVERTICAL, this, _("Value"));
|
||||
sizer_cheat_search_filter_x->Add(m_value_x_radiobtn.rad_oldvalue, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||
sizer_cheat_search_filter_x->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5);
|
||||
|
||||
// filter types in the compare dropdown
|
||||
static const wxString searches[] = {
|
||||
_("Unknown"),
|
||||
_("Not Equal"),
|
||||
_("Equal"),
|
||||
_("Greater Than"),
|
||||
_("Less Than"),
|
||||
// TODO: Implement between search.
|
||||
//_("Between"),
|
||||
};
|
||||
|
||||
m_search_type = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, sizeof(searches)/sizeof(*searches), searches);
|
||||
m_search_type->Select(0);
|
||||
|
||||
wxStaticBoxSizer* const sizer_cheat_search_filter = new wxStaticBoxSizer(wxVERTICAL, this, _("Search Filter"));
|
||||
sizer_cheat_search_filter->Add(sizer_cheat_search_filter_x, 0, wxALL | wxEXPAND, 5);
|
||||
sizer_cheat_search_filter->Add(m_search_type, 0, wxALL, 5);
|
||||
|
||||
// left sizer
|
||||
wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5);
|
||||
|
||||
// button sizer
|
||||
wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
boxButtons->Add(m_btn_init_scan, 1, wxRIGHT, 5);
|
||||
boxButtons->Add(m_btn_next_scan, 1);
|
||||
|
||||
// right sizer
|
||||
wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_right->Add(sizer_cheat_new_search, 0, wxBOTTOM, 5);
|
||||
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5);
|
||||
sizer_right->AddStretchSpacer(1);
|
||||
sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5);
|
||||
sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
}
|
||||
|
||||
void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
const u8* const memptr = Memory::GetPointer(0);
|
||||
if (memptr == nullptr)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the user-selected data size for this search.
|
||||
m_search_type_size =
|
||||
m_size_radiobtn.rad_8->GetValue() +
|
||||
(m_size_radiobtn.rad_16->GetValue() << 1) +
|
||||
(m_size_radiobtn.rad_32->GetValue() << 2);
|
||||
|
||||
// Set up the search results efficiently to prevent automatic re-allocations.
|
||||
m_search_results.clear();
|
||||
m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size);
|
||||
|
||||
// Enable the "Next Scan" button.
|
||||
m_btn_next_scan->Enable();
|
||||
|
||||
CheatSearchResult r;
|
||||
// can I assume cheatable values will be aligned like this?
|
||||
for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += m_search_type_size)
|
||||
{
|
||||
r.address = addr;
|
||||
memcpy(&r.old_value, memptr + addr, m_search_type_size);
|
||||
m_search_results.push_back(r);
|
||||
}
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
|
||||
void CheatSearchTab::FilterCheatSearchResults(wxCommandEvent&)
|
||||
{
|
||||
const u8* const memptr = Memory::GetPointer(0);
|
||||
if (memptr == nullptr)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the sub-search results efficiently to prevent automatic re-allocations.
|
||||
std::vector<CheatSearchResult> filtered_results;
|
||||
filtered_results.reserve(m_search_results.size());
|
||||
|
||||
// Determine the selected filter
|
||||
// 1 : equal
|
||||
// 2 : greater-than
|
||||
// 4 : less-than
|
||||
|
||||
const int filters[] = {7, 6, 1, 2, 4};
|
||||
int filter_mask = filters[m_search_type->GetSelection()];
|
||||
|
||||
if (m_value_x_radiobtn.rad_oldvalue->GetValue()) // using old value comparison
|
||||
{
|
||||
for (CheatSearchResult& result : m_search_results)
|
||||
{
|
||||
// with big endian, can just use memcmp for ><= comparison
|
||||
int cmp_result = memcmp(memptr + result.address, &result.old_value,m_search_type_size);
|
||||
if (cmp_result < 0)
|
||||
cmp_result = 4;
|
||||
else
|
||||
cmp_result = cmp_result ? 2 : 1;
|
||||
|
||||
if (cmp_result & filter_mask)
|
||||
{
|
||||
memcpy(&result.old_value, memptr + result.address, m_search_type_size);
|
||||
filtered_results.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // using user entered x value comparison
|
||||
{
|
||||
u32 user_x_val;
|
||||
|
||||
// parse the user entered x value
|
||||
if (filter_mask != 7) // don't need the value for the "None" filter
|
||||
{
|
||||
unsigned long parsed_x_val = 0;
|
||||
wxString x_val = m_textctrl_value_x->GetValue();
|
||||
|
||||
if (!x_val.ToULong(&parsed_x_val, 0))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value."));
|
||||
return;
|
||||
}
|
||||
|
||||
user_x_val = (u32)parsed_x_val;
|
||||
|
||||
// #ifdef LIL_ENDIAN :p
|
||||
switch (m_search_type_size)
|
||||
{
|
||||
case 1 :
|
||||
break;
|
||||
case 2 :
|
||||
*(u16*)&user_x_val = Common::swap16((u8*)&user_x_val);
|
||||
break;
|
||||
case 4 :
|
||||
user_x_val = Common::swap32(user_x_val);
|
||||
break;
|
||||
}
|
||||
// #elseif BIG_ENDIAN
|
||||
// would have to move <u32 vals (8/16bit) to start of the user_x_val for the comparisons i use below
|
||||
// #endif
|
||||
}
|
||||
|
||||
for (CheatSearchResult& result : m_search_results)
|
||||
{
|
||||
// with big endian, can just use memcmp for ><= comparison
|
||||
int cmp_result = memcmp(memptr + result.address, &user_x_val, m_search_type_size);
|
||||
if (cmp_result < 0)
|
||||
cmp_result = 4;
|
||||
else if (cmp_result)
|
||||
cmp_result = 2;
|
||||
else
|
||||
cmp_result = 1;
|
||||
|
||||
if (cmp_result & filter_mask)
|
||||
{
|
||||
memcpy(&result.old_value, memptr + result.address, m_search_type_size);
|
||||
filtered_results.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_search_results.swap(filtered_results);
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::ApplyFocus(wxEvent& ev)
|
||||
{
|
||||
ev.Skip();
|
||||
m_value_x_radiobtn.rad_uservalue->SetValue(true);
|
||||
}
|
||||
|
||||
void CheatSearchTab::UpdateCheatSearchResultsList()
|
||||
{
|
||||
m_lbox_search_results->Clear();
|
||||
|
||||
wxString count_label = _("Count:") + wxString::Format(" %lu",
|
||||
(unsigned long)m_search_results.size());
|
||||
if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY)
|
||||
{
|
||||
count_label += _(" (too many to display)");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const CheatSearchResult& result : m_search_results)
|
||||
{
|
||||
u32 display_value = result.old_value;
|
||||
|
||||
// #ifdef LIL_ENDIAN :p
|
||||
switch (m_search_type_size)
|
||||
{
|
||||
case 1 :
|
||||
break;
|
||||
case 2 :
|
||||
*(u16*)&display_value = Common::swap16((u8*)&display_value);
|
||||
break;
|
||||
case 4 :
|
||||
display_value = Common::swap32(display_value);
|
||||
break;
|
||||
}
|
||||
// #elseif BIG_ENDIAN
|
||||
// need to do some stuff in here (for 8 and 16bit) for bigendian
|
||||
// #endif
|
||||
std::string rowfmt = StringFromFormat("0x%%08x 0x%%0%ux %%u/%%i", m_search_type_size*2);
|
||||
|
||||
m_lbox_search_results->Append(
|
||||
wxString::Format(rowfmt.c_str(), result.address, display_value, display_value, display_value));
|
||||
}
|
||||
}
|
||||
|
||||
m_label_results_count->SetLabel(count_label);
|
||||
}
|
||||
|
||||
void CheatSearchTab::CreateARCode(wxCommandEvent&)
|
||||
{
|
||||
const int sel = m_lbox_search_results->GetSelection();
|
||||
if (sel >= 0)
|
||||
{
|
||||
const u32 address = m_search_results[sel].address | ((m_search_type_size & ~1) << 24);
|
||||
|
||||
CreateCodeDialog arcode_dlg(this, address);
|
||||
arcode_dlg.SetExtraStyle(arcode_dlg.GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS);
|
||||
arcode_dlg.ShowModal();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxChoice;
|
||||
class wxCommandEvent;
|
||||
class wxEvent;
|
||||
class wxListBox;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
class wxWindow;
|
||||
|
||||
class CheatSearchTab final : public wxPanel
|
||||
{
|
||||
public:
|
||||
CheatSearchTab(wxWindow* const parent);
|
||||
|
||||
private:
|
||||
class CheatSearchResult final
|
||||
{
|
||||
public:
|
||||
CheatSearchResult() : address(0), old_value(0) {}
|
||||
|
||||
u32 address;
|
||||
u32 old_value;
|
||||
};
|
||||
|
||||
std::vector<CheatSearchResult> m_search_results;
|
||||
unsigned int m_search_type_size;
|
||||
|
||||
wxChoice* m_search_type;
|
||||
wxListBox* m_lbox_search_results;
|
||||
wxStaticText* m_label_results_count;
|
||||
wxTextCtrl* m_textctrl_value_x;
|
||||
|
||||
wxButton* m_btn_init_scan;
|
||||
wxButton* m_btn_next_scan;
|
||||
|
||||
struct
|
||||
{
|
||||
wxRadioButton* rad_8;
|
||||
wxRadioButton* rad_16;
|
||||
wxRadioButton* rad_32;
|
||||
|
||||
} m_size_radiobtn;
|
||||
|
||||
struct
|
||||
{
|
||||
wxRadioButton* rad_oldvalue;
|
||||
wxRadioButton* rad_uservalue;
|
||||
|
||||
} m_value_x_radiobtn;
|
||||
|
||||
void UpdateCheatSearchResultsList();
|
||||
void StartNewSearch(wxCommandEvent& event);
|
||||
void FilterCheatSearchResults(wxCommandEvent& event);
|
||||
void CreateARCode(wxCommandEvent&);
|
||||
void ApplyFocus(wxEvent&);
|
||||
};
|
|
@ -0,0 +1,285 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/translation.h>
|
||||
#include <wx/validate.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreParameter.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/CheatSearchTab.h"
|
||||
#include "DolphinWX/Cheats/CheatsWindow.h"
|
||||
#include "DolphinWX/Cheats/CreateCodeDialog.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
|
||||
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxDIALOG_NO_PARENT)
|
||||
{
|
||||
// Create the GUI controls
|
||||
Init_ChildControls();
|
||||
|
||||
// load codes
|
||||
UpdateGUI();
|
||||
|
||||
SetSize(wxSize(-1, 600));
|
||||
Center();
|
||||
Show();
|
||||
}
|
||||
|
||||
wxCheatsWindow::~wxCheatsWindow()
|
||||
{
|
||||
main_frame->g_CheatsWindow = nullptr;
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Init_ChildControls()
|
||||
{
|
||||
// Main Notebook
|
||||
m_notebook_main = new wxNotebook(this, wxID_ANY);
|
||||
|
||||
// --- Tabs ---
|
||||
// Cheats List Tab
|
||||
m_tab_cheats = new wxPanel(m_notebook_main, wxID_ANY);
|
||||
|
||||
m_checklistbox_cheats_list = new wxCheckListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, wxSize(300, 0), m_cheat_string_list, wxLB_HSCROLL, wxDefaultValidator);
|
||||
m_checklistbox_cheats_list->Bind(wxEVT_LISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemSelected, this);
|
||||
m_checklistbox_cheats_list->Bind(wxEVT_CHECKLISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemToggled, this);
|
||||
|
||||
m_label_code_name = new wxStaticText(m_tab_cheats, wxID_ANY, _("Name: "));
|
||||
m_groupbox_info = new wxStaticBox(m_tab_cheats, wxID_ANY, _("Code Info"));
|
||||
|
||||
m_label_num_codes = new wxStaticText(m_tab_cheats, wxID_ANY, _("Number Of Codes: "));
|
||||
m_listbox_codes_list = new wxListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), 0, nullptr, wxLB_HSCROLL);
|
||||
|
||||
wxStaticBoxSizer* sGroupBoxInfo = new wxStaticBoxSizer(m_groupbox_info, wxVERTICAL);
|
||||
sGroupBoxInfo->Add(m_label_code_name, 0, wxALL, 5);
|
||||
sGroupBoxInfo->Add(m_label_num_codes, 0, wxALL, 5);
|
||||
sGroupBoxInfo->Add(m_listbox_codes_list, 1, wxALL, 5);
|
||||
|
||||
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_tab_cheats->Add(m_checklistbox_cheats_list, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10);
|
||||
sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5);
|
||||
|
||||
m_tab_cheats->SetSizerAndFit(sizer_tab_cheats);
|
||||
|
||||
// Cheat Search Tab
|
||||
wxPanel* const tab_cheat_search = new CheatSearchTab(m_notebook_main);
|
||||
|
||||
// Log Tab
|
||||
m_tab_log = new wxPanel(m_notebook_main, wxID_ANY);
|
||||
|
||||
wxButton* const button_updatelog = new wxButton(m_tab_log, wxID_ANY, _("Update"));
|
||||
button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this);
|
||||
|
||||
m_checkbox_log_ar = new wxCheckBox(m_tab_log, wxID_ANY, _("Enable AR Logging"));
|
||||
m_checkbox_log_ar->Bind(wxEVT_CHECKBOX, &wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
|
||||
|
||||
m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging());
|
||||
m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1), wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
|
||||
|
||||
wxBoxSizer *HStrip1 = new wxBoxSizer(wxHORIZONTAL);
|
||||
HStrip1->Add(m_checkbox_log_ar, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
|
||||
HStrip1->Add(button_updatelog, 0, wxALL, 5);
|
||||
|
||||
wxBoxSizer *sTabLog = new wxBoxSizer(wxVERTICAL);
|
||||
sTabLog->Add(HStrip1, 0, wxALL, 5);
|
||||
sTabLog->Add(m_textctrl_log, 1, wxALL|wxEXPAND, 5);
|
||||
|
||||
m_tab_log->SetSizerAndFit(sTabLog);
|
||||
|
||||
// Add Tabs to Notebook
|
||||
m_notebook_main->AddPage(m_tab_cheats, _("AR Codes"));
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
|
||||
m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes"));
|
||||
m_notebook_main->AddPage(tab_cheat_search, _("Cheat Search"));
|
||||
m_notebook_main->AddPage(m_tab_log, _("Logging"));
|
||||
|
||||
// Button Strip
|
||||
m_button_apply = new wxButton(this, wxID_APPLY, _("Apply"));
|
||||
m_button_apply->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this);
|
||||
wxButton* const button_cancel = new wxButton(this, wxID_CANCEL, _("Cancel"));
|
||||
button_cancel->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonClose_Press, this);
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnEvent_Close, this);
|
||||
Bind(UPDATE_CHEAT_LIST_EVENT, &wxCheatsWindow::OnEvent_CheatsList_Update, this);
|
||||
|
||||
wxStdDialogButtonSizer* const sButtons = new wxStdDialogButtonSizer();
|
||||
sButtons->AddButton(m_button_apply);
|
||||
sButtons->AddButton(button_cancel);
|
||||
sButtons->Realize();
|
||||
|
||||
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
|
||||
sMain->Add(m_notebook_main, 1, wxEXPAND|wxALL, 5);
|
||||
sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5);
|
||||
SetSizerAndFit(sMain);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// load codes for a new ISO ID
|
||||
void wxCheatsWindow::UpdateGUI()
|
||||
{
|
||||
// load code
|
||||
m_gameini_default = SConfig::GetInstance().m_LocalCoreStartupParameter.LoadDefaultGameIni();
|
||||
m_gameini_local = SConfig::GetInstance().m_LocalCoreStartupParameter.LoadLocalGameIni();
|
||||
m_gameini_local_path = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniLocal;
|
||||
Load_ARCodes();
|
||||
Load_GeckoCodes();
|
||||
|
||||
// enable controls
|
||||
m_button_apply->Enable(Core::IsRunning());
|
||||
|
||||
wxString title = _("Cheats Manager");
|
||||
|
||||
// write the ISO name in the title
|
||||
if (Core::IsRunning())
|
||||
SetTitle(title + ": " + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + " - " + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strName);
|
||||
else
|
||||
SetTitle(title);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_ARCodes()
|
||||
{
|
||||
using namespace ActionReplay;
|
||||
|
||||
m_checklistbox_cheats_list->Clear();
|
||||
|
||||
if (!Core::IsRunning())
|
||||
return;
|
||||
|
||||
m_index_list.clear();
|
||||
size_t size = GetCodeListSize();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
ARCode code = GetARCode(i);
|
||||
ARCodeIndex ind;
|
||||
u32 index = m_checklistbox_cheats_list->Append(StrToWxStr(code.name));
|
||||
m_checklistbox_cheats_list->Check(index, code.active);
|
||||
ind.index = i;
|
||||
ind.uiIndex = index;
|
||||
m_index_list.push_back(ind);
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_GeckoCodes()
|
||||
{
|
||||
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID(), true);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
using namespace ActionReplay;
|
||||
|
||||
int index = m_checklistbox_cheats_list->GetSelection();
|
||||
for (size_t i = 0; i < m_index_list.size(); i++)
|
||||
{
|
||||
if ((int)m_index_list[i].uiIndex == index)
|
||||
{
|
||||
ARCode code = GetARCode(i);
|
||||
m_label_code_name->SetLabel(_("Name: ") + StrToWxStr(code.name));
|
||||
|
||||
std::string numcodes = StringFromFormat("Number of Codes: %lu", (unsigned long)code.ops.size());
|
||||
m_label_num_codes->SetLabel(StrToWxStr(numcodes));
|
||||
m_listbox_codes_list->Clear();
|
||||
|
||||
for (const AREntry& entry : code.ops)
|
||||
{
|
||||
std::string ops = StringFromFormat("%08x %08x", entry.cmd_addr, entry.value);
|
||||
m_listbox_codes_list->Append(StrToWxStr(ops));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheatsList_ItemToggled(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
int index = m_checklistbox_cheats_list->GetSelection();
|
||||
for (const ARCodeIndex& code_index : m_index_list)
|
||||
{
|
||||
if ((int)code_index.uiIndex == index)
|
||||
{
|
||||
ActionReplay::SetARCode_IsActive(m_checklistbox_cheats_list->IsChecked(index), code_index.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheatsList_Update(wxCommandEvent& event)
|
||||
{
|
||||
Load_ARCodes();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
|
||||
{
|
||||
// Apply AR Code changes
|
||||
for (const ARCodeIndex& code_index : m_index_list)
|
||||
{
|
||||
ActionReplay::SetARCode_IsActive(m_checklistbox_cheats_list->IsChecked(code_index.uiIndex), code_index.index);
|
||||
}
|
||||
|
||||
// Apply Gecko Code changes
|
||||
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
|
||||
|
||||
// Save gameini, with changed gecko codes
|
||||
if (m_gameini_local_path.size())
|
||||
{
|
||||
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
|
||||
m_gameini_local.Save(m_gameini_local_path);
|
||||
}
|
||||
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
m_textctrl_log->Clear();
|
||||
for (const std::string& text : ActionReplay::GetSelfLog())
|
||||
{
|
||||
m_textctrl_log->AppendText(StrToWxStr(text));
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked());
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxCheckListBox;
|
||||
class wxChoice;
|
||||
class wxCloseEvent;
|
||||
class wxCommandEvent;
|
||||
class wxEvent;
|
||||
class wxListBox;
|
||||
class wxNotebook;
|
||||
class wxRadioButton;
|
||||
class wxStaticBox;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
class wxWindow;
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
class CodeConfigPanel;
|
||||
}
|
||||
|
||||
class wxCheatsWindow final : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxCheatsWindow(wxWindow* const parent);
|
||||
~wxCheatsWindow();
|
||||
void UpdateGUI();
|
||||
|
||||
private:
|
||||
struct ARCodeIndex
|
||||
{
|
||||
u32 uiIndex;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
// --- GUI Controls ---
|
||||
wxButton* m_button_apply;
|
||||
wxNotebook* m_notebook_main;
|
||||
|
||||
wxPanel* m_tab_cheats;
|
||||
wxPanel* m_tab_log;
|
||||
|
||||
wxCheckBox* m_checkbox_log_ar;
|
||||
|
||||
wxStaticText* m_label_code_name;
|
||||
wxStaticText* m_label_num_codes;
|
||||
|
||||
wxCheckListBox* m_checklistbox_cheats_list;
|
||||
|
||||
wxTextCtrl* m_textctrl_log;
|
||||
|
||||
wxListBox* m_listbox_codes_list;
|
||||
|
||||
wxStaticBox* m_groupbox_info;
|
||||
|
||||
wxArrayString m_cheat_string_list;
|
||||
|
||||
std::vector<ARCodeIndex> m_index_list;
|
||||
|
||||
Gecko::CodeConfigPanel* m_geckocode_panel;
|
||||
IniFile m_gameini_default;
|
||||
IniFile m_gameini_local;
|
||||
std::string m_gameini_local_path;
|
||||
|
||||
void Init_ChildControls();
|
||||
|
||||
void Load_ARCodes();
|
||||
void Load_GeckoCodes();
|
||||
|
||||
// --- Wx Events Handlers ---
|
||||
|
||||
// Close Button
|
||||
void OnEvent_ButtonClose_Press(wxCommandEvent& event);
|
||||
void OnEvent_Close(wxCloseEvent& ev);
|
||||
|
||||
// Cheats List
|
||||
void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event);
|
||||
void OnEvent_CheatsList_ItemToggled(wxCommandEvent& event);
|
||||
void OnEvent_CheatsList_Update(wxCommandEvent& event);
|
||||
|
||||
// Apply Changes Button
|
||||
void OnEvent_ApplyChanges_Press(wxCommandEvent& event);
|
||||
|
||||
// Update Log Button
|
||||
void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event);
|
||||
|
||||
// Enable Logging Checkbox
|
||||
void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event);
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinWX/ISOProperties.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/CreateCodeDialog.h"
|
||||
|
||||
// Fired when an ActionReplay code is created.
|
||||
wxDEFINE_EVENT(UPDATE_CHEAT_LIST_EVENT, wxCommandEvent);
|
||||
|
||||
CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
|
||||
: wxDialog(parent, -1, _("Create AR Code"))
|
||||
, m_code_address(address)
|
||||
{
|
||||
wxStaticText* const label_name = new wxStaticText(this, -1, _("Name: "));
|
||||
m_textctrl_name = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(256,-1));
|
||||
|
||||
wxStaticText* const label_code = new wxStaticText(this, -1, _("Code: "));
|
||||
m_textctrl_code = new wxTextCtrl(this, -1, wxString::Format("0x%08x", address));
|
||||
m_textctrl_code->Disable();
|
||||
|
||||
wxStaticText* const label_value = new wxStaticText(this, -1, _("Value: "));
|
||||
m_textctrl_value = new wxTextCtrl(this, -1, "0");
|
||||
|
||||
m_checkbox_use_hex = new wxCheckBox(this, -1, _("Use Hex"));
|
||||
m_checkbox_use_hex->SetValue(true);
|
||||
|
||||
wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_value_label->Add(label_value, 0, wxRIGHT, 5);
|
||||
sizer_value_label->Add(m_checkbox_use_hex);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_main->Add(label_name, 0, wxALL, 5);
|
||||
sizer_main->Add(m_textctrl_name, 0, wxALL, 5);
|
||||
sizer_main->Add(label_code, 0, wxALL, 5);
|
||||
sizer_main->Add(m_textctrl_code, 0, wxALL, 5);
|
||||
sizer_main->Add(sizer_value_label, 0, wxALL, 5);
|
||||
sizer_main->Add(m_textctrl_value, 0, wxALL, 5);
|
||||
sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5);
|
||||
|
||||
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK);
|
||||
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::PressOK(wxCommandEvent& ev)
|
||||
{
|
||||
const wxString code_name = m_textctrl_name->GetValue();
|
||||
if (code_name.empty())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a name."));
|
||||
return;
|
||||
}
|
||||
|
||||
long code_value;
|
||||
int base = m_checkbox_use_hex->IsChecked() ? 16 : 10;
|
||||
if (!m_textctrl_value->GetValue().ToLong(&code_value, base))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Invalid value."));
|
||||
return;
|
||||
}
|
||||
|
||||
//wxString full_code = textctrl_code->GetValue();
|
||||
//full_code += ' ';
|
||||
//full_code += wxString::Format("0x%08x", code_value);
|
||||
|
||||
// create the new code
|
||||
ActionReplay::ARCode new_cheat;
|
||||
new_cheat.active = false;
|
||||
new_cheat.name = WxStrToStr(code_name);
|
||||
const ActionReplay::AREntry new_entry(m_code_address, code_value);
|
||||
new_cheat.ops.push_back(new_entry);
|
||||
|
||||
// pretty hacky - add the code to the gameini
|
||||
{
|
||||
CISOProperties isoprops(SConfig::GetInstance().m_LastFilename, this);
|
||||
// add the code to the isoproperties arcode list
|
||||
arCodes.push_back(new_cheat);
|
||||
// save the gameini
|
||||
isoprops.SaveGameConfig();
|
||||
isoprops.ActionReplayList_Load(); // loads the new arcodes
|
||||
//ActionReplay::UpdateActiveList();
|
||||
}
|
||||
|
||||
// Propagate back to the parent frame to update the cheat list.
|
||||
GetEventHandler()->AddPendingEvent(wxCommandEvent(UPDATE_CHEAT_LIST_EVENT));
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::PressCancel(wxCommandEvent& ev)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev)
|
||||
{
|
||||
Destroy();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class wxCheckBox;
|
||||
class wxTextCtrl;
|
||||
class wxWindow;
|
||||
|
||||
wxDECLARE_EVENT(UPDATE_CHEAT_LIST_EVENT, wxCommandEvent);
|
||||
|
||||
class CreateCodeDialog final : public wxDialog
|
||||
{
|
||||
public:
|
||||
CreateCodeDialog(wxWindow* const parent, const u32 address);
|
||||
|
||||
private:
|
||||
const u32 m_code_address;
|
||||
|
||||
wxTextCtrl* m_textctrl_name;
|
||||
wxTextCtrl* m_textctrl_code;
|
||||
wxTextCtrl* m_textctrl_value;
|
||||
wxCheckBox* m_checkbox_use_hex;
|
||||
|
||||
void PressOK(wxCommandEvent&);
|
||||
void PressCancel(wxCommandEvent&);
|
||||
void OnEvent_Close(wxCloseEvent& ev);
|
||||
};
|
|
@ -27,8 +27,8 @@
|
|||
#include "Core/Core.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "DolphinWX/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
|
||||
class IniFile;
|
||||
|
|
@ -1,681 +0,0 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/toplevel.h>
|
||||
#include <wx/translation.h>
|
||||
#include <wx/validate.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreParameter.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "DolphinWX/CheatsWindow.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/ISOProperties.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
class wxWindow;
|
||||
|
||||
#define MAX_CHEAT_SEARCH_RESULTS_DISPLAY 256
|
||||
|
||||
// meh
|
||||
static wxCheatsWindow *g_cheat_window;
|
||||
|
||||
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxDIALOG_NO_PARENT)
|
||||
{
|
||||
::g_cheat_window = this;
|
||||
|
||||
// Create the GUI controls
|
||||
Init_ChildControls();
|
||||
|
||||
// load codes
|
||||
UpdateGUI();
|
||||
|
||||
SetSize(wxSize(-1, 600));
|
||||
Center();
|
||||
Show();
|
||||
}
|
||||
|
||||
wxCheatsWindow::~wxCheatsWindow()
|
||||
{
|
||||
main_frame->g_CheatsWindow = nullptr;
|
||||
::g_cheat_window = nullptr;
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Init_ChildControls()
|
||||
{
|
||||
wxPanel* const panel = new wxPanel(this);
|
||||
|
||||
// Main Notebook
|
||||
m_Notebook_Main = new wxNotebook(panel, wxID_ANY);
|
||||
|
||||
// --- Tabs ---
|
||||
// $ Cheats List Tab
|
||||
m_Tab_Cheats = new wxPanel(m_Notebook_Main, wxID_ANY);
|
||||
|
||||
m_CheckListBox_CheatsList = new wxCheckListBox(m_Tab_Cheats, wxID_ANY, wxDefaultPosition, wxSize(300, 0), m_CheatStringList, wxLB_HSCROLL, wxDefaultValidator);
|
||||
m_CheckListBox_CheatsList->Bind(wxEVT_LISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemSelected, this);
|
||||
m_CheckListBox_CheatsList->Bind(wxEVT_CHECKLISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemToggled, this);
|
||||
|
||||
m_Label_Codename = new wxStaticText(m_Tab_Cheats, wxID_ANY, _("Name: "));
|
||||
m_GroupBox_Info = new wxStaticBox(m_Tab_Cheats, wxID_ANY, _("Code Info"));
|
||||
|
||||
m_Label_NumCodes = new wxStaticText(m_Tab_Cheats, wxID_ANY, _("Number Of Codes: "));
|
||||
m_ListBox_CodesList = new wxListBox(m_Tab_Cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), 0, nullptr, wxLB_HSCROLL);
|
||||
|
||||
wxStaticBoxSizer* sGroupBoxInfo = new wxStaticBoxSizer(m_GroupBox_Info, wxVERTICAL);
|
||||
sGroupBoxInfo->Add(m_Label_Codename, 0, wxALL, 5);
|
||||
sGroupBoxInfo->Add(m_Label_NumCodes, 0, wxALL, 5);
|
||||
sGroupBoxInfo->Add(m_ListBox_CodesList, 1, wxALL, 5);
|
||||
|
||||
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_tab_cheats->Add(m_CheckListBox_CheatsList, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10);
|
||||
sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5);
|
||||
|
||||
m_Tab_Cheats->SetSizerAndFit(sizer_tab_cheats);
|
||||
|
||||
// $ Cheat Search Tab
|
||||
wxPanel* const tab_cheat_search = new CheatSearchTab(m_Notebook_Main);
|
||||
|
||||
// $ Log Tab
|
||||
m_Tab_Log = new wxPanel(m_Notebook_Main, wxID_ANY);
|
||||
|
||||
wxButton* const button_updatelog = new wxButton(m_Tab_Log, wxID_ANY, _("Update"));
|
||||
button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this);
|
||||
|
||||
m_CheckBox_LogAR = new wxCheckBox(m_Tab_Log, wxID_ANY, _("Enable AR Logging"));
|
||||
m_CheckBox_LogAR->Bind(wxEVT_CHECKBOX, &wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
|
||||
|
||||
m_CheckBox_LogAR->SetValue(ActionReplay::IsSelfLogging());
|
||||
m_TextCtrl_Log = new wxTextCtrl(m_Tab_Log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1), wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
|
||||
|
||||
wxBoxSizer *HStrip1 = new wxBoxSizer(wxHORIZONTAL);
|
||||
HStrip1->Add(m_CheckBox_LogAR, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
|
||||
HStrip1->Add(button_updatelog, 0, wxALL, 5);
|
||||
|
||||
wxBoxSizer *sTabLog = new wxBoxSizer(wxVERTICAL);
|
||||
sTabLog->Add(HStrip1, 0, wxALL, 5);
|
||||
sTabLog->Add(m_TextCtrl_Log, 1, wxALL|wxEXPAND, 5);
|
||||
|
||||
m_Tab_Log->SetSizerAndFit(sTabLog);
|
||||
|
||||
// Add Tabs to Notebook
|
||||
m_Notebook_Main->AddPage(m_Tab_Cheats, _("AR Codes"));
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook_Main);
|
||||
m_Notebook_Main->AddPage(m_geckocode_panel, _("Gecko Codes"));
|
||||
m_Notebook_Main->AddPage(tab_cheat_search, _("Cheat Search"));
|
||||
m_Notebook_Main->AddPage(m_Tab_Log, _("Logging"));
|
||||
|
||||
// Button Strip
|
||||
button_apply = new wxButton(panel, wxID_APPLY, _("Apply"));
|
||||
button_apply->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this);
|
||||
wxButton* const button_cancel = new wxButton(panel, wxID_CANCEL, _("Cancel"));
|
||||
button_cancel->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonClose_Press, this);
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnEvent_Close, this);
|
||||
|
||||
wxStdDialogButtonSizer* const sButtons = new wxStdDialogButtonSizer();
|
||||
sButtons->AddButton(button_apply);
|
||||
sButtons->AddButton(button_cancel);
|
||||
sButtons->Realize();
|
||||
|
||||
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
|
||||
sMain->Add(m_Notebook_Main, 1, wxEXPAND|wxALL, 5);
|
||||
sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5);
|
||||
panel->SetSizerAndFit(sMain);
|
||||
|
||||
wxBoxSizer* const frame_szr = new wxBoxSizer(wxVERTICAL);
|
||||
frame_szr->Add(panel, 1, wxEXPAND);
|
||||
SetSizerAndFit(frame_szr);
|
||||
}
|
||||
|
||||
CheatSearchTab::CheatSearchTab(wxWindow* const parent)
|
||||
: wxPanel(parent, -1)
|
||||
{
|
||||
// first scan button
|
||||
btnInitScan = new wxButton(this, -1, _("New Scan"));
|
||||
btnInitScan->Bind(wxEVT_BUTTON, &CheatSearchTab::StartNewSearch, this);
|
||||
|
||||
// next scan button
|
||||
btnNextScan = new wxButton(this, -1, _("Next Scan"));
|
||||
btnNextScan->Bind(wxEVT_BUTTON, &CheatSearchTab::FilterCheatSearchResults, this);
|
||||
btnNextScan->Disable();
|
||||
|
||||
// data size radio buttons
|
||||
size_radiobtn.rad_8 = new wxRadioButton(this, -1, _("8 bit"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
size_radiobtn.rad_16 = new wxRadioButton(this, -1, _("16 bit"));
|
||||
size_radiobtn.rad_32 = new wxRadioButton(this, -1, _("32 bit"));
|
||||
size_radiobtn.rad_8->SetValue(true);
|
||||
|
||||
// data sizes groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_new_search = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Data Size"));
|
||||
sizer_cheat_new_search->Add(size_radiobtn.rad_8, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_new_search->Add(size_radiobtn.rad_16, 0, wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_new_search->Add(size_radiobtn.rad_32, 0, wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
// result controls
|
||||
lbox_search_results = new wxListBox(this, -1);
|
||||
label_results_count = new wxStaticText(this, -1, _("Count:"));
|
||||
|
||||
// create AR code button
|
||||
wxButton* const button_cheat_search_copy_address = new wxButton(this, -1, _("Create AR Code"));
|
||||
button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::CreateARCode, this);
|
||||
|
||||
// results groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_search_results = new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
|
||||
sizer_cheat_search_results->Add(label_results_count, 0, wxALIGN_LEFT | wxALL, 5);
|
||||
sizer_cheat_search_results->Add(lbox_search_results, 1, wxEXPAND | wxALL, 5);
|
||||
sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
// Search value radio buttons
|
||||
value_x_radiobtn.rad_oldvalue = new wxRadioButton(this, -1, _("Previous Value"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
value_x_radiobtn.rad_uservalue = new wxRadioButton(this, -1, "");
|
||||
value_x_radiobtn.rad_oldvalue->SetValue(true);
|
||||
|
||||
// search value textbox
|
||||
textctrl_value_x = new wxTextCtrl(this, -1, "0x0", wxDefaultPosition, wxSize(96,-1));
|
||||
textctrl_value_x->Bind(wxEVT_SET_FOCUS, &CheatSearchTab::ApplyFocus, this);
|
||||
|
||||
wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_cheat_filter_text->Add(value_x_radiobtn.rad_uservalue, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
sizer_cheat_filter_text->Add(textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
// value groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_search_filter_x = new wxStaticBoxSizer(wxVERTICAL, this, _("Value"));
|
||||
sizer_cheat_search_filter_x->Add(value_x_radiobtn.rad_oldvalue, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||
sizer_cheat_search_filter_x->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5);
|
||||
|
||||
// filter types in the compare dropdown
|
||||
static const wxString searches[] = {
|
||||
_("Unknown"),
|
||||
_("Not Equal"),
|
||||
_("Equal"),
|
||||
_("Greater Than"),
|
||||
_("Less Than"),
|
||||
// TODO: Implement between search.
|
||||
//_("Between"),
|
||||
};
|
||||
|
||||
search_type = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, sizeof(searches)/sizeof(*searches), searches);
|
||||
search_type->Select(0);
|
||||
|
||||
wxStaticBoxSizer* const sizer_cheat_search_filter = new wxStaticBoxSizer(wxVERTICAL, this, _("Search Filter"));
|
||||
sizer_cheat_search_filter->Add(sizer_cheat_search_filter_x, 0, wxALL | wxEXPAND, 5);
|
||||
sizer_cheat_search_filter->Add(search_type, 0, wxALL, 5);
|
||||
|
||||
// left sizer
|
||||
wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5);
|
||||
|
||||
// button sizer
|
||||
wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
boxButtons->Add(btnInitScan, 1, wxRIGHT, 5);
|
||||
boxButtons->Add(btnNextScan, 1);
|
||||
|
||||
// right sizer
|
||||
wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_right->Add(sizer_cheat_new_search, 0, wxBOTTOM, 5);
|
||||
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5);
|
||||
sizer_right->AddStretchSpacer(1);
|
||||
sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5);
|
||||
sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// load codes for a new ISO ID
|
||||
void wxCheatsWindow::UpdateGUI()
|
||||
{
|
||||
// load code
|
||||
m_gameini_default = SConfig::GetInstance().m_LocalCoreStartupParameter.LoadDefaultGameIni();
|
||||
m_gameini_local = SConfig::GetInstance().m_LocalCoreStartupParameter.LoadLocalGameIni();
|
||||
m_gameini_local_path = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIniLocal;
|
||||
Load_ARCodes();
|
||||
Load_GeckoCodes();
|
||||
|
||||
// enable controls
|
||||
button_apply->Enable(Core::IsRunning());
|
||||
|
||||
wxString title = _("Cheats Manager");
|
||||
|
||||
// write the ISO name in the title
|
||||
if (Core::IsRunning())
|
||||
SetTitle(title + ": " + SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID() + " - " + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strName);
|
||||
else
|
||||
SetTitle(title);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_ARCodes()
|
||||
{
|
||||
using namespace ActionReplay;
|
||||
|
||||
m_CheckListBox_CheatsList->Clear();
|
||||
|
||||
if (!Core::IsRunning())
|
||||
return;
|
||||
|
||||
indexList.clear();
|
||||
size_t size = GetCodeListSize();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
ARCode code = GetARCode(i);
|
||||
ARCodeIndex ind;
|
||||
u32 index = m_CheckListBox_CheatsList->Append(StrToWxStr(code.name));
|
||||
m_CheckListBox_CheatsList->Check(index, code.active);
|
||||
ind.index = i;
|
||||
ind.uiIndex = index;
|
||||
indexList.push_back(ind);
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_GeckoCodes()
|
||||
{
|
||||
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID(), true);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
using namespace ActionReplay;
|
||||
|
||||
int index = m_CheckListBox_CheatsList->GetSelection();
|
||||
for (size_t i = 0; i < indexList.size(); i++)
|
||||
{
|
||||
if ((int)indexList[i].uiIndex == index)
|
||||
{
|
||||
ARCode code = GetARCode(i);
|
||||
m_Label_Codename->SetLabel(_("Name: ") + StrToWxStr(code.name));
|
||||
|
||||
std::string numcodes = StringFromFormat("Number of Codes: %lu", (unsigned long)code.ops.size());
|
||||
m_Label_NumCodes->SetLabel(StrToWxStr(numcodes));
|
||||
m_ListBox_CodesList->Clear();
|
||||
|
||||
for (const AREntry& entry : code.ops)
|
||||
{
|
||||
std::string ops = StringFromFormat("%08x %08x", entry.cmd_addr, entry.value);
|
||||
m_ListBox_CodesList->Append(StrToWxStr(ops));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheatsList_ItemToggled(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
int index = m_CheckListBox_CheatsList->GetSelection();
|
||||
for (const ARCodeIndex& code_index : indexList)
|
||||
{
|
||||
if ((int)code_index.uiIndex == index)
|
||||
{
|
||||
ActionReplay::SetARCode_IsActive(m_CheckListBox_CheatsList->IsChecked(index), code_index.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
|
||||
{
|
||||
// Apply AR Code changes
|
||||
for (const ARCodeIndex& code_index : indexList)
|
||||
{
|
||||
ActionReplay::SetARCode_IsActive(m_CheckListBox_CheatsList->IsChecked(code_index.uiIndex), code_index.index);
|
||||
}
|
||||
|
||||
// Apply Gecko Code changes
|
||||
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
|
||||
|
||||
// Save gameini, with changed gecko codes
|
||||
if (m_gameini_local_path.size())
|
||||
{
|
||||
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
|
||||
m_gameini_local.Save(m_gameini_local_path);
|
||||
}
|
||||
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
m_TextCtrl_Log->Clear();
|
||||
for (const std::string& text : ActionReplay::GetSelfLog())
|
||||
{
|
||||
m_TextCtrl_Log->AppendText(StrToWxStr(text));
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
ActionReplay::EnableSelfLogging(m_CheckBox_LogAR->IsChecked());
|
||||
}
|
||||
|
||||
void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
const u8* const memptr = Memory::GetPointer(0);
|
||||
if (nullptr == memptr)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the user-selected data size for this search.
|
||||
search_type_size =
|
||||
size_radiobtn.rad_8->GetValue() +
|
||||
(size_radiobtn.rad_16->GetValue() << 1) +
|
||||
(size_radiobtn.rad_32->GetValue() << 2);
|
||||
|
||||
// Set up the search results efficiently to prevent automatic re-allocations.
|
||||
search_results.clear();
|
||||
search_results.reserve(Memory::RAM_SIZE / search_type_size);
|
||||
|
||||
// Enable the "Next Scan" button.
|
||||
btnNextScan->Enable();
|
||||
|
||||
CheatSearchResult r;
|
||||
// can I assume cheatable values will be aligned like this?
|
||||
for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += search_type_size)
|
||||
{
|
||||
r.address = addr;
|
||||
memcpy(&r.old_value, memptr + addr, search_type_size);
|
||||
search_results.push_back(r);
|
||||
}
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::FilterCheatSearchResults(wxCommandEvent&)
|
||||
{
|
||||
const u8* const memptr = Memory::GetPointer(0);
|
||||
if (nullptr == memptr)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the sub-search results efficiently to prevent automatic re-allocations.
|
||||
std::vector<CheatSearchResult> filtered_results;
|
||||
filtered_results.reserve(search_results.size());
|
||||
|
||||
|
||||
// Determine the selected filter
|
||||
// 1 : equal
|
||||
// 2 : greater-than
|
||||
// 4 : less-than
|
||||
|
||||
const int filters[] = {7, 6, 1, 2, 4};
|
||||
int filter_mask = filters[search_type->GetSelection()];
|
||||
|
||||
if (value_x_radiobtn.rad_oldvalue->GetValue()) // using old value comparison
|
||||
{
|
||||
for (CheatSearchResult& result : search_results)
|
||||
{
|
||||
// with big endian, can just use memcmp for ><= comparison
|
||||
int cmp_result = memcmp(memptr + result.address, &result.old_value, search_type_size);
|
||||
if (cmp_result < 0)
|
||||
cmp_result = 4;
|
||||
else
|
||||
cmp_result = cmp_result ? 2 : 1;
|
||||
|
||||
if (cmp_result & filter_mask)
|
||||
{
|
||||
memcpy(&result.old_value, memptr + result.address, search_type_size);
|
||||
filtered_results.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // using user entered x value comparison
|
||||
{
|
||||
u32 user_x_val;
|
||||
|
||||
// parse the user entered x value
|
||||
if (filter_mask != 7) // don't need the value for the "None" filter
|
||||
{
|
||||
unsigned long parsed_x_val = 0;
|
||||
wxString x_val = textctrl_value_x->GetValue();
|
||||
|
||||
if (!x_val.ToULong(&parsed_x_val, 0))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value."));
|
||||
return;
|
||||
}
|
||||
|
||||
user_x_val = (u32)parsed_x_val;
|
||||
|
||||
// #ifdef LIL_ENDIAN :p
|
||||
switch (search_type_size)
|
||||
{
|
||||
case 1 :
|
||||
break;
|
||||
case 2 :
|
||||
*(u16*)&user_x_val = Common::swap16((u8*)&user_x_val);
|
||||
break;
|
||||
case 4 :
|
||||
user_x_val = Common::swap32(user_x_val);
|
||||
break;
|
||||
}
|
||||
// #elseif BIG_ENDIAN
|
||||
// would have to move <u32 vals (8/16bit) to start of the user_x_val for the comparisons i use below
|
||||
// #endif
|
||||
}
|
||||
|
||||
for (CheatSearchResult& result : search_results)
|
||||
{
|
||||
// with big endian, can just use memcmp for ><= comparison
|
||||
int cmp_result = memcmp(memptr + result.address, &user_x_val, search_type_size);
|
||||
if (cmp_result < 0)
|
||||
cmp_result = 4;
|
||||
else if (cmp_result)
|
||||
cmp_result = 2;
|
||||
else
|
||||
cmp_result = 1;
|
||||
|
||||
if (cmp_result & filter_mask)
|
||||
{
|
||||
memcpy(&result.old_value, memptr + result.address, search_type_size);
|
||||
filtered_results.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
search_results.swap(filtered_results);
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::ApplyFocus(wxEvent& ev)
|
||||
{
|
||||
ev.Skip();
|
||||
value_x_radiobtn.rad_uservalue->SetValue(true);
|
||||
}
|
||||
|
||||
void CheatSearchTab::UpdateCheatSearchResultsList()
|
||||
{
|
||||
lbox_search_results->Clear();
|
||||
|
||||
wxString count_label = _("Count:") + wxString::Format(" %lu",
|
||||
(unsigned long)search_results.size());
|
||||
if (search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY)
|
||||
{
|
||||
count_label += _(" (too many to display)");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const CheatSearchResult& result : search_results)
|
||||
{
|
||||
u32 display_value = result.old_value;
|
||||
|
||||
// #ifdef LIL_ENDIAN :p
|
||||
switch (search_type_size)
|
||||
{
|
||||
case 1 :
|
||||
break;
|
||||
case 2 :
|
||||
*(u16*)&display_value = Common::swap16((u8*)&display_value);
|
||||
break;
|
||||
case 4 :
|
||||
display_value = Common::swap32(display_value);
|
||||
break;
|
||||
}
|
||||
// #elseif BIG_ENDIAN
|
||||
// need to do some stuff in here (for 8 and 16bit) for bigendian
|
||||
// #endif
|
||||
std::string rowfmt = StringFromFormat("0x%%08x 0x%%0%ux %%u/%%i", search_type_size*2);
|
||||
|
||||
lbox_search_results->Append(
|
||||
wxString::Format(rowfmt.c_str(), result.address, display_value, display_value, display_value));
|
||||
}
|
||||
}
|
||||
|
||||
label_results_count->SetLabel(count_label);
|
||||
}
|
||||
|
||||
void CheatSearchTab::CreateARCode(wxCommandEvent&)
|
||||
{
|
||||
const int sel = lbox_search_results->GetSelection();
|
||||
if (sel >= 0)
|
||||
{
|
||||
const u32 address = search_results[sel].address | ((search_type_size & ~1) << 24);
|
||||
|
||||
CreateCodeDialog arcode_dlg(this, address);
|
||||
arcode_dlg.ShowModal();
|
||||
}
|
||||
}
|
||||
|
||||
CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
|
||||
: wxDialog(parent, -1, _("Create AR Code"))
|
||||
, code_address(address)
|
||||
{
|
||||
wxStaticText* const label_name = new wxStaticText(this, -1, _("Name: "));
|
||||
textctrl_name = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(256,-1));
|
||||
|
||||
wxStaticText* const label_code = new wxStaticText(this, -1, _("Code: "));
|
||||
textctrl_code = new wxTextCtrl(this, -1, wxString::Format("0x%08x", address));
|
||||
textctrl_code->Disable();
|
||||
|
||||
wxStaticText* const label_value = new wxStaticText(this, -1, _("Value: "));
|
||||
textctrl_value = new wxTextCtrl(this, -1, "0");
|
||||
|
||||
checkbox_use_hex = new wxCheckBox(this, -1, _("Use Hex"));
|
||||
checkbox_use_hex->SetValue(true);
|
||||
|
||||
wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_value_label->Add(label_value, 0, wxRIGHT, 5);
|
||||
sizer_value_label->Add(checkbox_use_hex);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_main->Add(label_name, 0, wxALL, 5);
|
||||
sizer_main->Add(textctrl_name, 0, wxALL, 5);
|
||||
sizer_main->Add(label_code, 0, wxALL, 5);
|
||||
sizer_main->Add(textctrl_code, 0, wxALL, 5);
|
||||
sizer_main->Add(sizer_value_label, 0, wxALL, 5);
|
||||
sizer_main->Add(textctrl_value, 0, wxALL, 5);
|
||||
sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5);
|
||||
|
||||
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK);
|
||||
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::PressOK(wxCommandEvent& ev)
|
||||
{
|
||||
const wxString code_name = textctrl_name->GetValue();
|
||||
if (code_name.empty())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a name."));
|
||||
return;
|
||||
}
|
||||
|
||||
long code_value;
|
||||
int base = checkbox_use_hex->IsChecked() ? 16 : 10;
|
||||
if (!textctrl_value->GetValue().ToLong(&code_value, base))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Invalid value."));
|
||||
return;
|
||||
}
|
||||
|
||||
//wxString full_code = textctrl_code->GetValue();
|
||||
//full_code += ' ';
|
||||
//full_code += wxString::Format("0x%08x", code_value);
|
||||
|
||||
// create the new code
|
||||
ActionReplay::ARCode new_cheat;
|
||||
new_cheat.active = false;
|
||||
new_cheat.name = WxStrToStr(code_name);
|
||||
const ActionReplay::AREntry new_entry(code_address, code_value);
|
||||
new_cheat.ops.push_back(new_entry);
|
||||
|
||||
// pretty hacky - add the code to the gameini
|
||||
{
|
||||
CISOProperties isoprops(SConfig::GetInstance().m_LastFilename, this);
|
||||
// add the code to the isoproperties arcode list
|
||||
arCodes.push_back(new_cheat);
|
||||
// save the gameini
|
||||
isoprops.SaveGameConfig();
|
||||
isoprops.ActionReplayList_Load(); // loads the new arcodes
|
||||
//ActionReplay::UpdateActiveList();
|
||||
}
|
||||
|
||||
// refresh arcode list in other tab
|
||||
::g_cheat_window->Load_ARCodes();
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::PressCancel(wxCommandEvent& ev)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev)
|
||||
{
|
||||
Destroy();
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxCheckListBox;
|
||||
class wxChoice;
|
||||
class wxCloseEvent;
|
||||
class wxCommandEvent;
|
||||
class wxEvent;
|
||||
class wxListBox;
|
||||
class wxNotebook;
|
||||
class wxRadioButton;
|
||||
class wxStaticBox;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
class wxWindow;
|
||||
|
||||
namespace Gecko { class CodeConfigPanel; }
|
||||
|
||||
class CreateCodeDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
CreateCodeDialog(wxWindow* const parent, const u32 address);
|
||||
|
||||
protected:
|
||||
|
||||
const u32 code_address;
|
||||
|
||||
wxTextCtrl *textctrl_name, *textctrl_code, *textctrl_value;
|
||||
wxCheckBox *checkbox_use_hex;
|
||||
|
||||
void PressOK(wxCommandEvent&);
|
||||
void PressCancel(wxCommandEvent&);
|
||||
void OnEvent_Close(wxCloseEvent& ev);
|
||||
};
|
||||
|
||||
class CheatSearchTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
CheatSearchTab(wxWindow* const parent);
|
||||
|
||||
protected:
|
||||
|
||||
class CheatSearchResult
|
||||
{
|
||||
public:
|
||||
CheatSearchResult() : address(0), old_value(0) {}
|
||||
|
||||
u32 address;
|
||||
u32 old_value;
|
||||
};
|
||||
|
||||
std::vector<CheatSearchResult> search_results;
|
||||
unsigned int search_type_size;
|
||||
|
||||
wxChoice* search_type;
|
||||
wxListBox* lbox_search_results;
|
||||
wxStaticText* label_results_count;
|
||||
wxTextCtrl* textctrl_value_x;
|
||||
wxButton *btnInitScan, *btnNextScan;
|
||||
|
||||
struct
|
||||
{
|
||||
wxRadioButton *rad_8, *rad_16, *rad_32;
|
||||
|
||||
} size_radiobtn;
|
||||
|
||||
struct
|
||||
{
|
||||
wxRadioButton *rad_oldvalue, *rad_uservalue;
|
||||
|
||||
} value_x_radiobtn;
|
||||
|
||||
void UpdateCheatSearchResultsList();
|
||||
void StartNewSearch(wxCommandEvent& event);
|
||||
void FilterCheatSearchResults(wxCommandEvent& event);
|
||||
void CreateARCode(wxCommandEvent&);
|
||||
void ApplyFocus(wxEvent&);
|
||||
};
|
||||
|
||||
class wxCheatsWindow : public wxDialog
|
||||
{
|
||||
friend class CreateCodeDialog;
|
||||
|
||||
public:
|
||||
wxCheatsWindow(wxWindow* const parent);
|
||||
~wxCheatsWindow();
|
||||
void UpdateGUI();
|
||||
|
||||
protected:
|
||||
|
||||
struct ARCodeIndex {
|
||||
u32 uiIndex;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
// --- GUI Controls ---
|
||||
wxButton* button_apply;
|
||||
wxNotebook *m_Notebook_Main;
|
||||
|
||||
wxPanel *m_Tab_Cheats;
|
||||
wxPanel *m_Tab_Log;
|
||||
|
||||
wxCheckBox *m_CheckBox_LogAR;
|
||||
|
||||
wxStaticText *m_Label_Codename;
|
||||
wxStaticText *m_Label_NumCodes;
|
||||
|
||||
wxCheckListBox *m_CheckListBox_CheatsList;
|
||||
|
||||
wxTextCtrl *m_TextCtrl_Log;
|
||||
|
||||
wxListBox *m_ListBox_CodesList;
|
||||
|
||||
wxStaticBox *m_GroupBox_Info;
|
||||
|
||||
wxArrayString m_CheatStringList;
|
||||
|
||||
std::vector<ARCodeIndex> indexList;
|
||||
|
||||
Gecko::CodeConfigPanel *m_geckocode_panel;
|
||||
IniFile m_gameini_default;
|
||||
IniFile m_gameini_local;
|
||||
std::string m_gameini_local_path;
|
||||
|
||||
void Init_ChildControls();
|
||||
|
||||
void Load_ARCodes();
|
||||
void Load_GeckoCodes();
|
||||
|
||||
// --- Wx Events Handlers ---
|
||||
|
||||
// $ Close Button
|
||||
void OnEvent_ButtonClose_Press(wxCommandEvent& event);
|
||||
void OnEvent_Close(wxCloseEvent& ev);
|
||||
|
||||
// $ Cheats List
|
||||
void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event);
|
||||
void OnEvent_CheatsList_ItemToggled(wxCommandEvent& event);
|
||||
|
||||
// $ Apply Changes Button
|
||||
void OnEvent_ApplyChanges_Press(wxCommandEvent& event);
|
||||
|
||||
// $ Update Log Button
|
||||
void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event);
|
||||
|
||||
// $ Enable Logging Checkbox
|
||||
void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event);
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
|
@ -50,7 +50,10 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="AboutDolphin.cpp" />
|
||||
<ClCompile Include="ARCodeAddEdit.cpp" />
|
||||
<ClCompile Include="CheatsWindow.cpp" />
|
||||
<ClCompile Include="Cheats\CheatSearchTab.cpp" />
|
||||
<ClCompile Include="Cheats\CheatsWindow.cpp" />
|
||||
<ClCompile Include="Cheats\CreateCodeDialog.cpp" />
|
||||
<ClCompile Include="Cheats\GeckoCodeDiag.cpp" />
|
||||
<ClCompile Include="ConfigMain.cpp" />
|
||||
<ClCompile Include="Debugger\BreakpointDlg.cpp" />
|
||||
<ClCompile Include="Debugger\BreakpointView.cpp" />
|
||||
|
@ -73,7 +76,6 @@
|
|||
<ClCompile Include="FrameAui.cpp" />
|
||||
<ClCompile Include="FrameTools.cpp" />
|
||||
<ClCompile Include="GameListCtrl.cpp" />
|
||||
<ClCompile Include="GeckoCodeDiag.cpp" />
|
||||
<ClCompile Include="GLInterface\GLInterface.cpp" />
|
||||
<ClCompile Include="GLInterface\WGL.cpp" />
|
||||
<ClCompile Include="HotkeyDlg.cpp" />
|
||||
|
@ -102,8 +104,11 @@
|
|||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="AboutDolphin.h" />
|
||||
<ClInclude Include="ARCodeAddEdit.h" />
|
||||
<ClInclude Include="CheatsWindow.h" />
|
||||
<ClInclude Include="ConfigMain.h" />
|
||||
<ClInclude Include="Cheats\CheatSearchTab.h" />
|
||||
<ClInclude Include="Cheats\CheatsWindow.h" />
|
||||
<ClInclude Include="Cheats\CreateCodeDialog.h" />
|
||||
<ClInclude Include="Cheats\GeckoCodeDiag.h" />
|
||||
<ClInclude Include="Debugger\BreakpointDlg.h" />
|
||||
<ClInclude Include="Debugger\BreakpointView.h" />
|
||||
<ClInclude Include="Debugger\BreakpointWindow.h" />
|
||||
|
@ -122,7 +127,6 @@
|
|||
<ClInclude Include="FifoPlayerDlg.h" />
|
||||
<ClInclude Include="Frame.h" />
|
||||
<ClInclude Include="GameListCtrl.h" />
|
||||
<ClInclude Include="GeckoCodeDiag.h" />
|
||||
<ClInclude Include="GLInterface\WGL.h" />
|
||||
<ClInclude Include="Globals.h" />
|
||||
<ClInclude Include="HotkeyDlg.h" />
|
||||
|
@ -189,7 +193,7 @@
|
|||
<ProjectReference Include="$(CoreDir)InputCommon\InputCommon.vcxproj">
|
||||
<Project>{6bbd47cf-91fd-4077-b676-8b76980178a9}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(CoreDir)UICommon\UICommon.vcxproj">
|
||||
<ProjectReference Include="$(CoreDir)UICommon\UICommon.vcxproj">
|
||||
<Project>{604C8368-F34A-4D55-82C8-CC92A0C13254}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(CoreDir)VideoBackends\D3D\D3D.vcxproj">
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
<Filter Include="GUI">
|
||||
<UniqueIdentifier>{0c0288ac-1168-4534-b3d3-051b9981f842}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Cheats">
|
||||
<UniqueIdentifier>{20acf084-7e31-4b1e-beec-b99bac38a681}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Debugger">
|
||||
<UniqueIdentifier>{ef70fd67-8f30-467a-8af0-ea0d48837f04}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -30,6 +33,18 @@
|
|||
<ClCompile Include="MainNoGUI.cpp" />
|
||||
<ClCompile Include="WXInputBase.cpp" />
|
||||
<ClCompile Include="WxUtils.cpp" />
|
||||
<ClCompile Include="Cheats\CheatsWindow.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\CreateCodeDialog.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\CheatSearchTab.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\GeckoCodeDiag.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\BreakpointDlg.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
|
@ -102,9 +117,6 @@
|
|||
<ClCompile Include="ARCodeAddEdit.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CheatsWindow.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ConfigMain.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
|
@ -123,9 +135,6 @@
|
|||
<ClCompile Include="GameListCtrl.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeckoCodeDiag.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HotkeyDlg.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
|
@ -159,6 +168,18 @@
|
|||
<ClInclude Include="Main.h" />
|
||||
<ClInclude Include="WXInputBase.h" />
|
||||
<ClInclude Include="WxUtils.h" />
|
||||
<ClInclude Include="Cheats\CheatSearchTab.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\CheatsWindow.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\CreateCodeDialog.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\GeckoCodeDiag.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\BreakpointDlg.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
|
@ -228,9 +249,6 @@
|
|||
<ClInclude Include="ARCodeAddEdit.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CheatsWindow.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ConfigMain.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
|
@ -243,9 +261,6 @@
|
|||
<ClInclude Include="GameListCtrl.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GeckoCodeDiag.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Globals.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
#include "DiscIO/NANDContentLoader.h"
|
||||
|
||||
#include "DolphinWX/AboutDolphin.h"
|
||||
#include "DolphinWX/CheatsWindow.h"
|
||||
#include "DolphinWX/ConfigMain.h"
|
||||
#include "DolphinWX/FifoPlayerDlg.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
|
@ -78,6 +77,7 @@
|
|||
#include "DolphinWX/WiimoteConfigDiag.h"
|
||||
#include "DolphinWX/WXInputBase.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/CheatsWindow.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
|
|
@ -69,11 +69,11 @@
|
|||
#include "DiscIO/Volume.h"
|
||||
#include "DiscIO/VolumeCreator.h"
|
||||
#include "DolphinWX/ARCodeAddEdit.h"
|
||||
#include "DolphinWX/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/ISOFile.h"
|
||||
#include "DolphinWX/ISOProperties.h"
|
||||
#include "DolphinWX/PatchAddEdit.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/resources/isoprop_disc.xpm"
|
||||
#include "DolphinWX/resources/isoprop_file.xpm"
|
||||
#include "DolphinWX/resources/isoprop_folder.xpm"
|
||||
|
|
Loading…
Reference in New Issue