DolphinWX: Split cheat window components into their own source files

This commit is contained in:
Lioncash
2014-10-18 17:32:50 -04:00
parent 4ddd54847c
commit f0769233e6
15 changed files with 958 additions and 867 deletions

View File

@ -0,0 +1,318 @@
// 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.ShowModal();
}
}

View File

@ -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&);
};

View File

@ -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()
{
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_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(panel, wxID_APPLY, _("Apply"));
m_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(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);
panel->SetSizerAndFit(sMain);
wxBoxSizer* const frame_szr = new wxBoxSizer(wxVERTICAL);
frame_szr->Add(panel, 1, wxEXPAND);
SetSizerAndFit(frame_szr);
}
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_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());
}

View File

@ -0,0 +1,105 @@
// 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
{
friend class CreateCodeDialog;
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);
// 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);
};

View File

@ -0,0 +1,109 @@
// 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"
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();
}
Close();
}
void CreateCodeDialog::PressCancel(wxCommandEvent& ev)
{
Close();
}
void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev)
{
Destroy();
}

View File

@ -0,0 +1,32 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
#include "Common/CommonTypes.h"
class wxCheckBox;
class wxCommandEvent;
class wxTextCtrl;
class wxWindow;
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);
};

View File

@ -0,0 +1,313 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <sstream>
#include <string>
#include <vector>
#include <SFML/Network/Http.hpp>
#include <wx/button.h>
#include <wx/chartype.h>
#include <wx/checklst.h>
#include <wx/defs.h>
#include <wx/event.h>
#include <wx/gdicmn.h>
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/translation.h>
#include <wx/window.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/Core.h"
#include "Core/GeckoCode.h"
#include "Core/GeckoCodeConfig.h"
#include "DolphinWX/WxUtils.h"
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
class IniFile;
namespace Gecko
{
static const wxString wxstr_name(wxTRANSLATE("Name: ")),
wxstr_notes(wxTRANSLATE("Notes: ")),
wxstr_creator(wxTRANSLATE("Creator: "));
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
: wxPanel(parent, -1)
{
m_listbox_gcodes = new wxCheckListBox(this, -1);
m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this);
m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this);
m_infobox.label_name = new wxStaticText(this, -1, wxGetTranslation(wxstr_name));
m_infobox.label_creator = new wxStaticText(this, -1, wxGetTranslation(wxstr_creator));
m_infobox.label_notes = new wxStaticText(this, -1, wxGetTranslation(wxstr_notes));
m_infobox.textctrl_notes = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
// TODO: buttons to add/edit codes
// sizers
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
// button sizer
wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL);
btn_download = new wxButton(this, -1, _("Download Codes (WiiRD Database)"), wxDefaultPosition, wxSize(128, -1));
btn_download->Enable(false);
btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
sizer_buttons->AddStretchSpacer(1);
sizer_buttons->Add(btn_download, 1, wxEXPAND);
// horizontal sizer
wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL);
sizer_vert->Add(sizer_infobox, 1, wxEXPAND);
sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5);
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5);
SetSizerAndFit(sizer_main);
}
void CodeConfigPanel::UpdateCodeList(bool checkRunning)
{
// disable the button if it doesn't have an effect
btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty());
m_listbox_gcodes->Clear();
// add the codes to the listbox
for (const GeckoCode& code : m_gcodes)
{
m_listbox_gcodes->Append(StrToWxStr(code.name));
if (code.enabled)
{
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true);
}
}
wxCommandEvent evt;
UpdateInfoBox(evt);
}
void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid, bool checkRunning)
{
m_gameid = gameid;
m_gcodes.clear();
if (!checkRunning || Core::IsRunning())
Gecko::LoadCodes(globalIni, localIni, m_gcodes);
UpdateCodeList(checkRunning);
}
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
{
const int sel = evt.GetInt(); // this right?
if (sel > -1)
m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel);
}
void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
{
m_infobox.listbox_codes->Clear();
const int sel = m_listbox_gcodes->GetSelection();
if (sel > -1)
{
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name));
// notes textctrl
m_infobox.textctrl_notes->Clear();
for (const std::string& note : m_gcodes[sel].notes)
{
m_infobox.textctrl_notes->AppendText(StrToWxStr(note));
}
m_infobox.textctrl_notes->ScrollLines(-99); // silly
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + StrToWxStr(m_gcodes[sel].creator));
// add codes to info listbox
for (const GeckoCode::Code& code : m_gcodes[sel].codes)
{
m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data));
}
}
else
{
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name));
m_infobox.textctrl_notes->Clear();
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator));
}
}
void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
{
if (m_gameid.empty())
return;
std::string gameid = m_gameid;
switch (m_gameid[0])
{
case 'R':
case 'S':
case 'G':
break;
default:
// All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters
gameid = m_gameid.substr(0, 4);
break;
}
sf::Http::Request req;
req.SetURI("/txt.php?txt=" + gameid);
sf::Http http;
http.SetHost("geckocodes.org");
const sf::Http::Response resp = http.SendRequest(req, 5.0f);
if (sf::Http::Response::Ok == resp.GetStatus())
{
// temp vector containing parsed codes
std::vector<GeckoCode> gcodes;
// parse the codes
std::istringstream ss(resp.GetBody());
std::string line;
// seek past the header, get to the first code
std::getline(ss, line);
std::getline(ss, line);
std::getline(ss, line);
int read_state = 0;
GeckoCode gcode;
while ((std::getline(ss, line).good()))
{
// empty line
if (0 == line.size() || line == "\r" || line == "\n") // \r\n checks might not be needed
{
// add the code
if (gcode.codes.size())
gcodes.push_back(gcode);
gcode = GeckoCode();
read_state = 0;
continue;
}
switch (read_state)
{
// read new code
case 0 :
{
std::istringstream ssline(line);
// stop at [ character (beginning of contributor name)
std::getline(ssline, gcode.name, '[');
gcode.name = StripSpaces(gcode.name);
gcode.user_defined = true;
// read the code creator name
std::getline(ssline, gcode.creator, ']');
read_state = 1;
}
break;
// read code lines
case 1 :
{
std::istringstream ssline(line);
std::string addr, data;
ssline >> addr >> data;
ssline.seekg(0);
// check if this line a code, silly, but the dumb txt file comment lines can start with valid hex chars :/
if (8 == addr.length() && 8 == data.length())
{
GeckoCode::Code new_code;
new_code.original_line = line;
ssline >> std::hex >> new_code.address >> new_code.data;
gcode.codes.push_back(new_code);
}
else
{
gcode.notes.push_back(line);
read_state = 2; // start reading comments
}
}
break;
// read comment lines
case 2 :
// append comment line
gcode.notes.push_back(line);
break;
}
}
// add the last code
if (gcode.codes.size())
gcodes.push_back(gcode);
if (gcodes.size())
{
unsigned long added_count = 0;
// append the codes to the code list
for (const GeckoCode& code : gcodes)
{
// only add codes which do not already exist
std::vector<GeckoCode>::const_iterator
existing_gcodes_iter = m_gcodes.begin(),
existing_gcodes_end = m_gcodes.end();
for (;; ++existing_gcodes_iter)
{
if (existing_gcodes_end == existing_gcodes_iter)
{
m_gcodes.push_back(code);
++added_count;
break;
}
// code exists
if (existing_gcodes_iter->Compare(code))
break;
}
}
wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"),
(unsigned long)gcodes.size(), added_count));
// refresh the list
UpdateCodeList();
}
else
{
wxMessageBox(_("File contained no codes."));
}
}
else
{
WxUtils::ShowErrorDialog(_("Failed to download codes."));
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include <wx/panel.h>
#include "Core/GeckoCode.h"
class IniFile;
class wxButton;
class wxCheckListBox;
class wxCommandEvent;
class wxListBox;
class wxStaticText;
class wxTextCtrl;
class wxWindow;
namespace Gecko
{
class CodeConfigPanel : public wxPanel
{
public:
CodeConfigPanel(wxWindow* const parent);
void LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid = "", bool checkRunning = false);
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
protected:
void UpdateInfoBox(wxCommandEvent&);
void ToggleCode(wxCommandEvent& evt);
void DownloadCodes(wxCommandEvent&);
//void ApplyChanges(wxCommandEvent&);
void UpdateCodeList(bool checkRunning = false);
private:
std::vector<GeckoCode> m_gcodes;
std::string m_gameid;
// wxwidgets stuff
wxCheckListBox* m_listbox_gcodes;
struct
{
wxStaticText* label_name, *label_notes, *label_creator;
wxTextCtrl* textctrl_notes;
wxListBox* listbox_codes;
} m_infobox;
wxButton* btn_download;
};
}