wxwidgets: GUI for memory search
[lsnes.git] / src / plat-wxwidgets / memorysearch.cpp
blob88e169bfa1b1cd75714ec1853da3f0e873f99e8f
1 #include "core/dispatch.hpp"
2 #include "core/memorymanip.hpp"
4 #include "plat-wxwidgets/platform.hpp"
6 #include <sstream>
7 #include <iomanip>
9 #include <wx/wx.h>
10 #include <wx/event.h>
11 #include <wx/control.h>
12 #include <wx/combobox.h>
14 #define wxID_RESET (wxID_HIGHEST + 1)
15 #define wxID_UPDATE (wxID_HIGHEST + 2)
16 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
17 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
18 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
20 #define DATATYPES 8
21 #define BROW_SIZE 8
22 #define PRIMITIVES 7
24 #define CANDIDATE_LIMIT 200
26 class wxwindow_memorysearch;
27 namespace
29 wxwindow_memorysearch* mwatch;
30 const char* datatypes[] = {
31 "signed byte",
32 "unsigned byte",
33 "signed word",
34 "unsigned word",
35 "signed dword",
36 "unsigned dword",
37 "signed qword",
38 "unsigned qword"
41 const char* searchtypes[] = {
42 "value",
43 "<",
44 "<=",
45 "==",
46 "!=",
47 ">=",
48 ">",
49 "true"
52 typedef void (memorysearch::*primitive_search_t)();
54 primitive_search_t primitive_searches[DATATYPES][PRIMITIVES] = {
55 { &memorysearch::byte_slt, &memorysearch::byte_sle, &memorysearch::byte_seq, &memorysearch::byte_sne,
56 &memorysearch::byte_sge, &memorysearch::byte_sgt, &memorysearch::update },
57 { &memorysearch::byte_ult, &memorysearch::byte_ule, &memorysearch::byte_ueq, &memorysearch::byte_une,
58 &memorysearch::byte_uge, &memorysearch::byte_ugt, &memorysearch::update },
59 { &memorysearch::word_slt, &memorysearch::word_sle, &memorysearch::word_seq, &memorysearch::word_sne,
60 &memorysearch::word_sge, &memorysearch::word_sgt, &memorysearch::update },
61 { &memorysearch::word_ult, &memorysearch::word_ule, &memorysearch::word_ueq, &memorysearch::word_une,
62 &memorysearch::word_uge, &memorysearch::word_ugt, &memorysearch::update },
63 { &memorysearch::dword_slt, &memorysearch::dword_sle, &memorysearch::dword_seq,
64 &memorysearch::dword_sne, &memorysearch::dword_sge, &memorysearch::dword_sgt, &memorysearch::update },
65 { &memorysearch::dword_ult, &memorysearch::dword_ule, &memorysearch::dword_ueq,
66 &memorysearch::dword_une, &memorysearch::dword_uge, &memorysearch::dword_ugt, &memorysearch::update },
67 { &memorysearch::qword_slt, &memorysearch::qword_sle, &memorysearch::qword_seq,
68 &memorysearch::qword_sne, &memorysearch::qword_sge, &memorysearch::qword_sgt, &memorysearch::update },
69 { &memorysearch::qword_ult, &memorysearch::qword_ule, &memorysearch::qword_ueq,
70 &memorysearch::qword_une, &memorysearch::qword_uge, &memorysearch::qword_ugt, &memorysearch::update }
73 std::string hexformat_address(uint32_t addr)
75 std::ostringstream x;
76 x << std::setfill('0') << std::setw(8) << std::hex << addr;
77 return x.str();
80 template<typename T> std::string format_number_signed(T val, bool hex);
81 template<typename T> std::string format_number_unsigned(T val, bool hex);
83 template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
85 std::ostringstream x;
86 if(hex) {
87 if(val >= 0)
88 x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
89 static_cast<uint64_t>(val);
90 else {
91 int64_t y2 = val;
92 uint64_t y = static_cast<uint64_t>(y2);
93 x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
95 } else
96 x << static_cast<int64_t>(val);
97 return x.str();
100 template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
102 std::ostringstream x;
103 if(hex)
104 x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
105 else
106 x << static_cast<uint64_t>(val);
107 return x.str();
110 template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
112 return format_number_signedh(static_cast<int8_t>(val), 2, hex);
115 template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
117 return format_number_signedh(static_cast<int16_t>(val), 4, hex);
120 template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
122 return format_number_signedh(static_cast<int32_t>(val), 8, hex);
125 template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
127 return format_number_signedh(static_cast<int64_t>(val), 16, hex);
130 template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
132 return format_number_unsignedh(val, 2, hex);
135 template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
137 return format_number_unsignedh(val, 4, hex);
140 template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
142 return format_number_unsignedh(val, 8, hex);
145 template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
147 return format_number_unsignedh(val, 16, hex);
151 class wxwindow_memorysearch : public wxFrame
153 public:
154 wxwindow_memorysearch();
155 ~wxwindow_memorysearch();
156 bool ShouldPreventAppExit() const;
157 void on_close(wxCloseEvent& e);
158 void on_button_click(wxCommandEvent& e);
159 bool update_queued;
160 private:
161 template<typename T> void valuesearch();
162 template<typename T> void valuesearch2(T value);
163 void update();
164 memorysearch* msearch;
165 wxStaticText* count;
166 wxTextCtrl* matches;
167 wxComboBox* type;
168 wxCheckBox* hexmode2;
169 unsigned typecode;
170 bool hexmode;
173 wxwindow_memorysearch::wxwindow_memorysearch()
174 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
175 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
177 typecode = 0;
178 wxButton* tmp;
179 Centre();
180 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
181 msearch = new memorysearch();
183 wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
184 SetSizer(toplevel);
186 wxFlexGridSizer* buttons = new wxFlexGridSizer(1, 5, 0, 0);
187 buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
188 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
189 NULL, this);
190 buttons->Add(tmp = new wxButton(this, wxID_UPDATE, wxT("Update")), 0, wxGROW);
191 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
192 NULL, this);
193 buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
194 wxString _datatypes[DATATYPES];
195 for(size_t i = 0; i < DATATYPES; i++)
196 _datatypes[i] = towxstring(datatypes[i]);
197 buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
198 wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
199 wxGROW);
200 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
201 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
202 buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
203 hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
204 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
205 toplevel->Add(buttons);
207 wxFlexGridSizer* searches = new wxFlexGridSizer(1, BROW_SIZE, 0, 0);
208 for(unsigned j = 0; j < BROW_SIZE; j++) {
209 searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(searchtypes[j])), 1, wxGROW);
210 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
211 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
213 toplevel->Add(searches);
215 toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXX candidates")), 0, wxGROW);
216 toplevel->Add(matches = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, 300),
217 wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP), 1, wxGROW);
219 toplevel->SetSizeHints(this);
220 Fit();
221 update();
222 Fit();
225 wxwindow_memorysearch::~wxwindow_memorysearch()
227 delete msearch;
228 mwatch = NULL;
231 bool wxwindow_memorysearch::ShouldPreventAppExit() const
233 return false;
236 void wxwindow_memorysearch::on_close(wxCloseEvent& e)
238 Destroy();
239 mwatch = NULL;
242 void wxwindow_memorysearch::update()
244 std::string ret;
245 uint32_t addr_count;
246 runemufn([msearch, &ret, &addr_count, typecode, hexmode]() {
247 addr_count = msearch->get_candidate_count();
248 if(addr_count <= CANDIDATE_LIMIT) {
249 std::list<uint32_t> addrs = msearch->get_candidates();
250 for(auto i : addrs) {
251 std::ostringstream row;
252 row << hexformat_address(i) << " ";
253 switch(typecode) {
254 case 0: row << format_number_signed(memory_read_byte(i), hexmode); break;
255 case 1: row << format_number_unsigned(memory_read_byte(i), hexmode); break;
256 case 2: row << format_number_signed(memory_read_word(i), hexmode); break;
257 case 3: row << format_number_unsigned(memory_read_word(i), hexmode); break;
258 case 4: row << format_number_signed(memory_read_dword(i), hexmode); break;
259 case 5: row << format_number_unsigned(memory_read_dword(i), hexmode); break;
260 case 6: row << format_number_signed(memory_read_qword(i), hexmode); break;
261 case 7: row << format_number_unsigned(memory_read_qword(i), hexmode); break;
263 row << std::endl;
264 ret = ret + row.str();
266 } else {
267 ret = "Too many candidates to display";
270 std::ostringstream x;
271 x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
272 count->SetLabel(towxstring(x.str()));
273 matches->SetValue(towxstring(ret));
274 Fit();
275 update_queued = false;
278 void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
280 wxwindow_memorysearch* tmp = this;
281 int id = e.GetId();
282 if(id == wxID_RESET) {
283 msearch->reset();
284 } else if(id == wxID_UPDATE) {
285 update();
286 } else if(id == wxID_TYPESELECT) {
287 wxString c = type->GetValue();
288 for(unsigned i = 0; i < DATATYPES; i++)
289 if(c == towxstring(datatypes[i]))
290 typecode = i;
291 } else if(id == wxID_HEX_SELECT) {
292 hexmode = hexmode2->GetValue();
293 } else if(id == wxID_BUTTONS_BASE) {
294 //Value search.
295 switch(typecode)
297 case 0: valuesearch<int8_t>(); break;
298 case 1: valuesearch<uint8_t>(); break;
299 case 2: valuesearch<int16_t>(); break;
300 case 3: valuesearch<uint16_t>(); break;
301 case 4: valuesearch<int32_t>(); break;
302 case 5: valuesearch<uint32_t>(); break;
303 case 6: valuesearch<int64_t>(); break;
304 case 7: valuesearch<uint64_t>(); break;
306 } else if(id > wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE + 1 + PRIMITIVES ) {
307 int button = id - wxID_BUTTONS_BASE - 1;
308 (msearch->*(primitive_searches[typecode][button]))();
310 update();
313 template<typename T> void wxwindow_memorysearch::valuesearch()
315 std::string v;
316 wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
317 wxT(""));
318 if(d->ShowModal() == wxID_CANCEL)
319 return;
320 v = tostdstring(d->GetValue());
321 d->Destroy();
322 T val2;
323 try {
324 val2 = parse_value<T>(v);
325 } catch(...) {
326 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
328 valuesearch2(val2);
329 update();
332 template<> void wxwindow_memorysearch::valuesearch2<int8_t>(int8_t val)
334 msearch->byte_value(static_cast<uint8_t>(val));
337 template<> void wxwindow_memorysearch::valuesearch2<uint8_t>(uint8_t val)
339 msearch->byte_value(static_cast<uint8_t>(val));
342 template<> void wxwindow_memorysearch::valuesearch2<int16_t>(int16_t val)
344 msearch->word_value(static_cast<uint16_t>(val));
347 template<> void wxwindow_memorysearch::valuesearch2<uint16_t>(uint16_t val)
349 msearch->word_value(static_cast<uint16_t>(val));
352 template<> void wxwindow_memorysearch::valuesearch2<int32_t>(int32_t val)
354 msearch->dword_value(static_cast<uint32_t>(val));
357 template<> void wxwindow_memorysearch::valuesearch2<uint32_t>(uint32_t val)
359 msearch->dword_value(static_cast<uint32_t>(val));
362 template<> void wxwindow_memorysearch::valuesearch2<int64_t>(int64_t val)
364 msearch->qword_value(static_cast<uint64_t>(val));
367 template<> void wxwindow_memorysearch::valuesearch2<uint64_t>(uint64_t val)
369 msearch->qword_value(static_cast<uint64_t>(val));
372 void wxwindow_memorysearch_display()
374 if(mwatch) {
375 mwatch->Raise();
376 return;
378 mwatch = new wxwindow_memorysearch();
379 mwatch->Show();