wxwidgets: GUI for memory search

This commit is contained in:
Ilari Liusvaara 2012-01-15 16:50:08 +02:00
parent 72348aee8b
commit 9908dc094f
3 changed files with 389 additions and 1 deletions

View file

@ -31,6 +31,8 @@ void wxeditor_axes_display(wxWindow* parent);
void wxeditor_authors_display(wxWindow* parent);
void wxeditor_settings_display(wxWindow* parent);
//Auxillary windows.
void wxwindow_memorysearch_display();
template<typename T>
void functor_call_helper2(void* args)

View file

@ -68,7 +68,8 @@ enum
wxID_DUMP_FIRST,
wxID_DUMP_LAST = wxID_DUMP_FIRST + 1023,
wxID_REWIND_MOVIE,
wxID_EDIT_JUKEBOX
wxID_EDIT_JUKEBOX,
wxID_MEMORY_SEARCH
};
@ -824,6 +825,8 @@ wxwin_mainwindow::wxwin_mainwindow()
menu_separator();
menu_entry(wxID_LOAD_MEMORYWATCH, wxT("Load memory watch"));
menu_entry(wxID_SAVE_MEMORYWATCH, wxT("Save memory watch"));
menu_separator();
menu_entry(wxID_MEMORY_SEARCH, wxT("Memory Search"));
//Settings menu: (ACFOS)
menu_start(wxT("Settings"));
menu_entry(wxID_EDIT_AXES, wxT("Configure axes"));
@ -1034,6 +1037,9 @@ void wxwin_mainwindow::handle_menu_click(wxCommandEvent& e)
case wxID_LOAD_MEMORYWATCH:
menu_load_memorywatch(e);
break;
case wxID_MEMORY_SEARCH:
wxwindow_memorysearch_display();
break;
case wxID_ABOUT: {
std::ostringstream str;
str << "Version: lsnes rr" << lsnes_version << std::endl;

View file

@ -0,0 +1,380 @@
#include "core/dispatch.hpp"
#include "core/memorymanip.hpp"
#include "plat-wxwidgets/platform.hpp"
#include <sstream>
#include <iomanip>
#include <wx/wx.h>
#include <wx/event.h>
#include <wx/control.h>
#include <wx/combobox.h>
#define wxID_RESET (wxID_HIGHEST + 1)
#define wxID_UPDATE (wxID_HIGHEST + 2)
#define wxID_TYPESELECT (wxID_HIGHEST + 3)
#define wxID_HEX_SELECT (wxID_HIGHEST + 4)
#define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
#define DATATYPES 8
#define BROW_SIZE 8
#define PRIMITIVES 7
#define CANDIDATE_LIMIT 200
class wxwindow_memorysearch;
namespace
{
wxwindow_memorysearch* mwatch;
const char* datatypes[] = {
"signed byte",
"unsigned byte",
"signed word",
"unsigned word",
"signed dword",
"unsigned dword",
"signed qword",
"unsigned qword"
};
const char* searchtypes[] = {
"value",
"<",
"<=",
"==",
"!=",
">=",
">",
"true"
};
typedef void (memorysearch::*primitive_search_t)();
primitive_search_t primitive_searches[DATATYPES][PRIMITIVES] = {
{ &memorysearch::byte_slt, &memorysearch::byte_sle, &memorysearch::byte_seq, &memorysearch::byte_sne,
&memorysearch::byte_sge, &memorysearch::byte_sgt, &memorysearch::update },
{ &memorysearch::byte_ult, &memorysearch::byte_ule, &memorysearch::byte_ueq, &memorysearch::byte_une,
&memorysearch::byte_uge, &memorysearch::byte_ugt, &memorysearch::update },
{ &memorysearch::word_slt, &memorysearch::word_sle, &memorysearch::word_seq, &memorysearch::word_sne,
&memorysearch::word_sge, &memorysearch::word_sgt, &memorysearch::update },
{ &memorysearch::word_ult, &memorysearch::word_ule, &memorysearch::word_ueq, &memorysearch::word_une,
&memorysearch::word_uge, &memorysearch::word_ugt, &memorysearch::update },
{ &memorysearch::dword_slt, &memorysearch::dword_sle, &memorysearch::dword_seq,
&memorysearch::dword_sne, &memorysearch::dword_sge, &memorysearch::dword_sgt, &memorysearch::update },
{ &memorysearch::dword_ult, &memorysearch::dword_ule, &memorysearch::dword_ueq,
&memorysearch::dword_une, &memorysearch::dword_uge, &memorysearch::dword_ugt, &memorysearch::update },
{ &memorysearch::qword_slt, &memorysearch::qword_sle, &memorysearch::qword_seq,
&memorysearch::qword_sne, &memorysearch::qword_sge, &memorysearch::qword_sgt, &memorysearch::update },
{ &memorysearch::qword_ult, &memorysearch::qword_ule, &memorysearch::qword_ueq,
&memorysearch::qword_une, &memorysearch::qword_uge, &memorysearch::qword_ugt, &memorysearch::update }
};
std::string hexformat_address(uint32_t addr)
{
std::ostringstream x;
x << std::setfill('0') << std::setw(8) << std::hex << addr;
return x.str();
}
template<typename T> std::string format_number_signed(T val, bool hex);
template<typename T> std::string format_number_unsigned(T val, bool hex);
template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
{
std::ostringstream x;
if(hex) {
if(val >= 0)
x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
static_cast<uint64_t>(val);
else {
int64_t y2 = val;
uint64_t y = static_cast<uint64_t>(y2);
x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
}
} else
x << static_cast<int64_t>(val);
return x.str();
}
template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
{
std::ostringstream x;
if(hex)
x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
else
x << static_cast<uint64_t>(val);
return x.str();
}
template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
{
return format_number_signedh(static_cast<int8_t>(val), 2, hex);
}
template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
{
return format_number_signedh(static_cast<int16_t>(val), 4, hex);
}
template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
{
return format_number_signedh(static_cast<int32_t>(val), 8, hex);
}
template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
{
return format_number_signedh(static_cast<int64_t>(val), 16, hex);
}
template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
{
return format_number_unsignedh(val, 2, hex);
}
template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
{
return format_number_unsignedh(val, 4, hex);
}
template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
{
return format_number_unsignedh(val, 8, hex);
}
template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
{
return format_number_unsignedh(val, 16, hex);
}
}
class wxwindow_memorysearch : public wxFrame
{
public:
wxwindow_memorysearch();
~wxwindow_memorysearch();
bool ShouldPreventAppExit() const;
void on_close(wxCloseEvent& e);
void on_button_click(wxCommandEvent& e);
bool update_queued;
private:
template<typename T> void valuesearch();
template<typename T> void valuesearch2(T value);
void update();
memorysearch* msearch;
wxStaticText* count;
wxTextCtrl* matches;
wxComboBox* type;
wxCheckBox* hexmode2;
unsigned typecode;
bool hexmode;
};
wxwindow_memorysearch::wxwindow_memorysearch()
: wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
{
typecode = 0;
wxButton* tmp;
Centre();
Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
msearch = new memorysearch();
wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
SetSizer(toplevel);
wxFlexGridSizer* buttons = new wxFlexGridSizer(1, 5, 0, 0);
buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
NULL, this);
buttons->Add(tmp = new wxButton(this, wxID_UPDATE, wxT("Update")), 0, wxGROW);
tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
NULL, this);
buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
wxString _datatypes[DATATYPES];
for(size_t i = 0; i < DATATYPES; i++)
_datatypes[i] = towxstring(datatypes[i]);
buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
wxGROW);
type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
toplevel->Add(buttons);
wxFlexGridSizer* searches = new wxFlexGridSizer(1, BROW_SIZE, 0, 0);
for(unsigned j = 0; j < BROW_SIZE; j++) {
searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(searchtypes[j])), 1, wxGROW);
tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
}
toplevel->Add(searches);
toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXX candidates")), 0, wxGROW);
toplevel->Add(matches = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, 300),
wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP), 1, wxGROW);
toplevel->SetSizeHints(this);
Fit();
update();
Fit();
}
wxwindow_memorysearch::~wxwindow_memorysearch()
{
delete msearch;
mwatch = NULL;
}
bool wxwindow_memorysearch::ShouldPreventAppExit() const
{
return false;
}
void wxwindow_memorysearch::on_close(wxCloseEvent& e)
{
Destroy();
mwatch = NULL;
}
void wxwindow_memorysearch::update()
{
std::string ret;
uint32_t addr_count;
runemufn([msearch, &ret, &addr_count, typecode, hexmode]() {
addr_count = msearch->get_candidate_count();
if(addr_count <= CANDIDATE_LIMIT) {
std::list<uint32_t> addrs = msearch->get_candidates();
for(auto i : addrs) {
std::ostringstream row;
row << hexformat_address(i) << " ";
switch(typecode) {
case 0: row << format_number_signed(memory_read_byte(i), hexmode); break;
case 1: row << format_number_unsigned(memory_read_byte(i), hexmode); break;
case 2: row << format_number_signed(memory_read_word(i), hexmode); break;
case 3: row << format_number_unsigned(memory_read_word(i), hexmode); break;
case 4: row << format_number_signed(memory_read_dword(i), hexmode); break;
case 5: row << format_number_unsigned(memory_read_dword(i), hexmode); break;
case 6: row << format_number_signed(memory_read_qword(i), hexmode); break;
case 7: row << format_number_unsigned(memory_read_qword(i), hexmode); break;
};
row << std::endl;
ret = ret + row.str();
}
} else {
ret = "Too many candidates to display";
}
});
std::ostringstream x;
x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
count->SetLabel(towxstring(x.str()));
matches->SetValue(towxstring(ret));
Fit();
update_queued = false;
}
void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
{
wxwindow_memorysearch* tmp = this;
int id = e.GetId();
if(id == wxID_RESET) {
msearch->reset();
} else if(id == wxID_UPDATE) {
update();
} else if(id == wxID_TYPESELECT) {
wxString c = type->GetValue();
for(unsigned i = 0; i < DATATYPES; i++)
if(c == towxstring(datatypes[i]))
typecode = i;
} else if(id == wxID_HEX_SELECT) {
hexmode = hexmode2->GetValue();
} else if(id == wxID_BUTTONS_BASE) {
//Value search.
switch(typecode)
{
case 0: valuesearch<int8_t>(); break;
case 1: valuesearch<uint8_t>(); break;
case 2: valuesearch<int16_t>(); break;
case 3: valuesearch<uint16_t>(); break;
case 4: valuesearch<int32_t>(); break;
case 5: valuesearch<uint32_t>(); break;
case 6: valuesearch<int64_t>(); break;
case 7: valuesearch<uint64_t>(); break;
};
} else if(id > wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE + 1 + PRIMITIVES ) {
int button = id - wxID_BUTTONS_BASE - 1;
(msearch->*(primitive_searches[typecode][button]))();
}
update();
}
template<typename T> void wxwindow_memorysearch::valuesearch()
{
std::string v;
wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
wxT(""));
if(d->ShowModal() == wxID_CANCEL)
return;
v = tostdstring(d->GetValue());
d->Destroy();
T val2;
try {
val2 = parse_value<T>(v);
} catch(...) {
wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
}
valuesearch2(val2);
update();
}
template<> void wxwindow_memorysearch::valuesearch2<int8_t>(int8_t val)
{
msearch->byte_value(static_cast<uint8_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<uint8_t>(uint8_t val)
{
msearch->byte_value(static_cast<uint8_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<int16_t>(int16_t val)
{
msearch->word_value(static_cast<uint16_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<uint16_t>(uint16_t val)
{
msearch->word_value(static_cast<uint16_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<int32_t>(int32_t val)
{
msearch->dword_value(static_cast<uint32_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<uint32_t>(uint32_t val)
{
msearch->dword_value(static_cast<uint32_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<int64_t>(int64_t val)
{
msearch->qword_value(static_cast<uint64_t>(val));
}
template<> void wxwindow_memorysearch::valuesearch2<uint64_t>(uint64_t val)
{
msearch->qword_value(static_cast<uint64_t>(val));
}
void wxwindow_memorysearch_display()
{
if(mwatch) {
mwatch->Raise();
return;
}
mwatch = new wxwindow_memorysearch();
mwatch->Show();
}