Refactor emulator status reporting (and fix the statusbar doesn't update bug)
[lsnes.git] / src / platform / wxwidgets / memorysearch.cpp
blob6df8a5129de0afffe0b9dfac3359704683dee8df
1 #include "core/dispatch.hpp"
2 #include "core/memorymanip.hpp"
3 #include "core/memorywatch.hpp"
4 #include "core/project.hpp"
5 #include "library/hex.hpp"
6 #include "library/string.hpp"
7 #include "library/memorysearch.hpp"
8 #include "library/int24.hpp"
9 #include "library/zip.hpp"
11 #include "platform/wxwidgets/loadsave.hpp"
12 #include "platform/wxwidgets/platform.hpp"
13 #include "platform/wxwidgets/scrollbar.hpp"
14 #include "platform/wxwidgets/textrender.hpp"
16 #include <sstream>
17 #include <fstream>
18 #include <iomanip>
20 #include <wx/wx.h>
21 #include <wx/event.h>
22 #include <wx/control.h>
23 #include <wx/combobox.h>
25 #define wxID_RESET (wxID_HIGHEST + 1)
26 #define wxID_UPDATE (wxID_HIGHEST + 2)
27 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
28 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
29 #define wxID_ADD (wxID_HIGHEST + 5)
30 #define wxID_SET_REGIONS (wxID_HIGHEST + 6)
31 #define wxID_AUTOUPDATE (wxID_HIGHEST + 7)
32 #define wxID_DISQUALIFY (wxID_HIGHEST + 8)
33 #define wxID_POKE (wxID_HIGHEST + 9)
34 #define wxID_SHOW_HEXEDITOR (wxID_HIGHEST + 10)
35 #define wxID_MENU_SAVE_PREVMEM (wxID_HIGHEST + 11)
36 #define wxID_MENU_SAVE_SET (wxID_HIGHEST + 12)
37 #define wxID_MENU_SAVE_ALL (wxID_HIGHEST + 13)
38 #define wxID_MENU_LOAD (wxID_HIGHEST + 14)
39 #define wxID_MENU_UNDO (wxID_HIGHEST + 15)
40 #define wxID_MENU_REDO (wxID_HIGHEST + 16)
41 #define wxID_MENU_DUMP_CANDIDATES (wxID_HIGHEST + 17)
42 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
44 #define DATATYPES 12
45 #define CANDIDATE_LIMIT 512
47 class wxwindow_memorysearch;
48 memory_search* wxwindow_memorysearch_active();
50 namespace
52 unsigned UNDOHISTORY_MAXSIZE = 48;
53 struct _watch_properties {
54 unsigned len;
55 int type; //0 => Unsigned, 1 => Signed, 2 => Float.
56 const char* hformat;
57 } watch_properties[] = {
58 {1, 1, "%02x"},
59 {1, 0, "%02x"},
60 {2, 1, "%04x"},
61 {2, 0, "%04x"},
62 {3, 1, "%06x"},
63 {3, 0, "%06x"},
64 {4, 1, "%08x"},
65 {4, 0, "%08x"},
66 {8, 1, "%016x"},
67 {8, 0, "%016x"},
68 {4, 2, ""},
69 {8, 2, ""},
72 wxwindow_memorysearch* mwatch;
74 const char* datatypes[] = {
75 "signed byte",
76 "unsigned byte",
77 "signed word",
78 "unsigned word",
79 "signed hword",
80 "unsigned hword",
81 "signed dword",
82 "unsigned dword",
83 "signed qword",
84 "unsigned qword",
85 "float",
86 "double"
89 typedef void (wxwindow_memorysearch::*search_fn_t)();
91 struct searchtype
93 const char* name;
94 search_fn_t searches[DATATYPES];
97 template<typename T> std::string format_number_signed(T val, bool hex);
98 template<typename T> std::string format_number_unsigned(T val, bool hex);
100 template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
102 std::ostringstream x;
103 if(hex) {
104 if(val >= 0)
105 x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
106 static_cast<uint64_t>(val);
107 else {
108 int64_t y2 = val;
109 uint64_t y = static_cast<uint64_t>(y2);
110 x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
112 } else
113 x << static_cast<int64_t>(val);
114 return x.str();
117 template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
119 std::ostringstream x;
120 if(hex)
121 x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
122 else
123 x << static_cast<uint64_t>(val);
124 return x.str();
127 template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
129 return format_number_signedh(static_cast<int8_t>(val), 2, hex);
132 template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
134 return format_number_signedh(static_cast<int16_t>(val), 4, hex);
137 template<> std::string format_number_signed<ss_uint24_t>(ss_uint24_t val, bool hex)
139 return format_number_signedh((int32_t)(uint32_t)(val), 6, hex);
142 template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
144 return format_number_signedh(static_cast<int32_t>(val), 8, hex);
147 template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
149 return format_number_signedh(static_cast<int64_t>(val), 16, hex);
152 template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
154 return format_number_unsignedh(val, 2, hex);
157 template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
159 return format_number_unsignedh(val, 4, hex);
162 template<> std::string format_number_unsigned<ss_uint24_t>(ss_uint24_t val, bool hex)
164 return format_number_unsignedh(val, 6, hex);
167 template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
169 return format_number_unsignedh(val, 8, hex);
172 template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
174 return format_number_unsignedh(val, 16, hex);
177 std::string format_number_float(double val)
179 return (stringfmt() << val).str();
183 class wxwindow_memorysearch_vmasel : public wxDialog
185 public:
186 wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled);
187 bool ShouldPreventAppExit() const;
188 std::set<std::string> get_vmas();
189 void on_ok(wxCommandEvent& e);
190 void on_cancel(wxCommandEvent& e);
191 private:
192 std::set<std::string> vmas;
193 std::vector<wxCheckBox*> checkboxes;
194 wxButton* ok;
195 wxButton* cancel;
198 wxwindow_memorysearch_vmasel::wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled)
199 : wxDialog(p, wxID_ANY, towxstring("lsnes: Select enabled regions"), wxDefaultPosition, wxSize(300, -1))
201 auto i = lsnes_memory.get_regions();
202 Centre();
203 wxFlexGridSizer* top_s = new wxFlexGridSizer(i.size() + 1, 1, 0, 0);
204 SetSizer(top_s);
205 for(auto j : i) {
206 if(j->readonly || j->special)
207 continue;
208 wxCheckBox* t;
209 top_s->Add(t = new wxCheckBox(this, wxID_ANY, towxstring(j->name)), 0, wxGROW);
210 if(enabled.count(j->name))
211 t->SetValue(true);
212 checkboxes.push_back(t);
214 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
215 pbutton_s->AddStretchSpacer();
216 pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
217 pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
218 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
219 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_ok), NULL, this);
220 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
221 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_cancel), NULL, this);
222 top_s->Add(pbutton_s);
224 pbutton_s->SetSizeHints(this);
225 top_s->SetSizeHints(this);
226 Fit();
229 bool wxwindow_memorysearch_vmasel::ShouldPreventAppExit() const
231 return false;
234 std::set<std::string> wxwindow_memorysearch_vmasel::get_vmas()
236 return vmas;
239 void wxwindow_memorysearch_vmasel::on_ok(wxCommandEvent& e)
241 for(auto i : checkboxes)
242 if(i->GetValue())
243 vmas.insert(tostdstring(i->GetLabel()));
244 EndModal(wxID_OK);
247 void wxwindow_memorysearch_vmasel::on_cancel(wxCommandEvent& e)
249 EndModal(wxID_CANCEL);
253 class wxwindow_memorysearch : public wxFrame
255 public:
256 class panel : public text_framebuffer_panel
258 public:
259 panel(wxwindow_memorysearch* parent);
260 void set_selection(uint64_t first, uint64_t last);
261 void get_selection(uint64_t& first, uint64_t& last);
262 protected:
263 void prepare_paint();
264 private:
265 wxwindow_memorysearch* parent;
266 uint64_t first_sel;
267 uint64_t last_sel;
269 wxwindow_memorysearch();
270 ~wxwindow_memorysearch();
271 bool ShouldPreventAppExit() const;
272 void on_close(wxCloseEvent& e);
273 void on_button_click(wxCommandEvent& e);
274 void auto_update();
275 void on_mousedrag(wxMouseEvent& e);
276 void on_mouse(wxMouseEvent& e);
277 bool update_queued;
278 template<void(memory_search::*sfn)()> void search_0();
279 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void search_1();
280 template<typename T> void _do_poke_addr(uint64_t addr);
281 template<typename T> std::string _do_format_signed(uint64_t addr, bool hex, bool old)
283 if(old)
284 return format_number_signed<T>(msearch->v_readold<T>(addr), hex);
285 else
286 return format_number_signed<T>(lsnes_memory.read<T>(addr), hex);
288 template<typename T> std::string _do_format_unsigned(uint64_t addr, bool hex, bool old)
290 if(old)
291 return format_number_unsigned<T>(msearch->v_readold<T>(addr), hex);
292 else
293 return format_number_unsigned<T>(lsnes_memory.read<T>(addr), hex);
295 template<typename T> std::string _do_format_float(uint64_t addr, bool hex, bool old)
297 if(old)
298 return format_number_float(msearch->v_readold<T>(addr));
299 else
300 return format_number_float(lsnes_memory.read<T>(addr));
302 void dump_candidates_text();
303 private:
304 friend memory_search* wxwindow_memorysearch_active();
305 friend class panel;
306 template<typename T> T promptvalue(bool& bad);
307 void update();
308 memory_search* msearch;
309 void on_mouse0(wxMouseEvent& e, bool polarity);
310 void on_mousedrag();
311 void on_mouse2(wxMouseEvent& e);
312 void handle_undo_redo(bool redo);
313 void push_undo();
314 void handle_save(memory_search::savestate_type type);
315 void handle_load();
316 wxStaticText* count;
317 scroll_bar* scroll;
318 panel* matches;
319 wxComboBox* type;
320 wxCheckBox* hexmode2;
321 wxCheckBox* autoupdate;
322 std::map<uint64_t, uint64_t> addresses;
323 uint64_t act_line;
324 uint64_t drag_startline;
325 bool dragging;
326 int mpx, mpy;
327 unsigned typecode;
328 bool hexmode;
329 bool toomany;
330 int scroll_delta;
331 std::set<std::string> vmas_enabled;
332 wxMenuItem* undoitem;
333 wxMenuItem* redoitem;
334 std::list<std::vector<char>> undohistory;
335 std::list<std::vector<char>> redohistory;
338 namespace
340 typedef void (wxwindow_memorysearch::*pokefn_t)(uint64_t);
341 pokefn_t pokes[] = {
342 &wxwindow_memorysearch::_do_poke_addr<int8_t>,
343 &wxwindow_memorysearch::_do_poke_addr<uint8_t>,
344 &wxwindow_memorysearch::_do_poke_addr<int16_t>,
345 &wxwindow_memorysearch::_do_poke_addr<uint16_t>,
346 &wxwindow_memorysearch::_do_poke_addr<ss_int24_t>,
347 &wxwindow_memorysearch::_do_poke_addr<ss_uint24_t>,
348 &wxwindow_memorysearch::_do_poke_addr<int32_t>,
349 &wxwindow_memorysearch::_do_poke_addr<uint32_t>,
350 &wxwindow_memorysearch::_do_poke_addr<int64_t>,
351 &wxwindow_memorysearch::_do_poke_addr<uint64_t>,
352 &wxwindow_memorysearch::_do_poke_addr<float>,
353 &wxwindow_memorysearch::_do_poke_addr<double>,
356 typedef std::string (wxwindow_memorysearch::*displayfn_t)(uint64_t, bool hexmode, bool old);
357 displayfn_t displays[] = {
358 &wxwindow_memorysearch::_do_format_signed<uint8_t>,
359 &wxwindow_memorysearch::_do_format_unsigned<uint8_t>,
360 &wxwindow_memorysearch::_do_format_signed<uint16_t>,
361 &wxwindow_memorysearch::_do_format_unsigned<uint16_t>,
362 &wxwindow_memorysearch::_do_format_signed<ss_uint24_t>,
363 &wxwindow_memorysearch::_do_format_unsigned<ss_uint24_t>,
364 &wxwindow_memorysearch::_do_format_signed<uint32_t>,
365 &wxwindow_memorysearch::_do_format_unsigned<uint32_t>,
366 &wxwindow_memorysearch::_do_format_signed<uint64_t>,
367 &wxwindow_memorysearch::_do_format_unsigned<uint64_t>,
368 &wxwindow_memorysearch::_do_format_float<float>,
369 &wxwindow_memorysearch::_do_format_float<double>,
372 struct searchtype searchtbl[] = {
374 "value", {
375 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
376 &memory_search::s_value<uint8_t>>,
377 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
378 &memory_search::s_value<uint8_t>>,
379 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
380 &memory_search::s_value<uint16_t>>,
381 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
382 &memory_search::s_value<uint16_t>>,
383 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
384 &memory_search::s_value<ss_uint24_t>>,
385 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
386 &memory_search::s_value<ss_uint24_t>>,
387 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
388 &memory_search::s_value<uint32_t>>,
389 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
390 &memory_search::s_value<uint32_t>>,
391 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
392 &memory_search::s_value<uint64_t>>,
393 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
394 &memory_search::s_value<uint64_t>>,
395 &wxwindow_memorysearch::search_1<float, float,
396 &memory_search::s_value<float>>,
397 &wxwindow_memorysearch::search_1<double, double,
398 &memory_search::s_value<double>>
401 "diff.", {
402 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
403 &memory_search::s_difference<uint8_t>>,
404 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
405 &memory_search::s_difference<uint8_t>>,
406 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
407 &memory_search::s_difference<uint16_t>>,
408 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
409 &memory_search::s_difference<uint16_t>>,
410 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
411 &memory_search::s_difference<ss_uint24_t>>,
412 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
413 &memory_search::s_difference<ss_uint24_t>>,
414 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
415 &memory_search::s_difference<uint32_t>>,
416 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
417 &memory_search::s_difference<uint32_t>>,
418 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
419 &memory_search::s_difference<uint64_t>>,
420 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
421 &memory_search::s_difference<uint64_t>>,
422 &wxwindow_memorysearch::search_1<float, float,
423 &memory_search::s_difference<float>>,
424 &wxwindow_memorysearch::search_1<double, double,
425 &memory_search::s_difference<double>>
428 "<", {
429 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int8_t>>,
430 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint8_t>>,
431 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int16_t>>,
432 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint16_t>>,
433 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_int24_t>>,
434 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_uint24_t>>,
435 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int32_t>>,
436 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint32_t>>,
437 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int64_t>>,
438 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint64_t>>,
439 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
440 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
443 "<=", {
444 &wxwindow_memorysearch::search_0<&memory_search::s_le<int8_t>>,
445 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint8_t>>,
446 &wxwindow_memorysearch::search_0<&memory_search::s_le<int16_t>>,
447 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint16_t>>,
448 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_int24_t>>,
449 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_uint24_t>>,
450 &wxwindow_memorysearch::search_0<&memory_search::s_le<int32_t>>,
451 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint32_t>>,
452 &wxwindow_memorysearch::search_0<&memory_search::s_le<int64_t>>,
453 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint64_t>>,
454 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
455 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
458 "==", {
459 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int8_t>>,
460 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint8_t>>,
461 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int16_t>>,
462 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint16_t>>,
463 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_int24_t>>,
464 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_uint24_t>>,
465 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int32_t>>,
466 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint32_t>>,
467 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int64_t>>,
468 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint64_t>>,
469 &wxwindow_memorysearch::search_0<&memory_search::s_eq<float>>,
470 &wxwindow_memorysearch::search_0<&memory_search::s_eq<double>>
473 "!=", {
474 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int8_t>>,
475 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint8_t>>,
476 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int16_t>>,
477 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint16_t>>,
478 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_int24_t>>,
479 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_uint24_t>>,
480 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int32_t>>,
481 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint32_t>>,
482 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int64_t>>,
483 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint64_t>>,
484 &wxwindow_memorysearch::search_0<&memory_search::s_ne<float>>,
485 &wxwindow_memorysearch::search_0<&memory_search::s_ne<double>>
488 ">=", {
489 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int8_t>>,
490 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint8_t>>,
491 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int16_t>>,
492 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint16_t>>,
493 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_int24_t>>,
494 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_uint24_t>>,
495 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int32_t>>,
496 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint32_t>>,
497 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int64_t>>,
498 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint64_t>>,
499 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
500 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
503 ">", {
504 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int8_t>>,
505 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint8_t>>,
506 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int16_t>>,
507 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint16_t>>,
508 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_int24_t>>,
509 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_uint24_t>>,
510 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int32_t>>,
511 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint32_t>>,
512 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int64_t>>,
513 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint64_t>>,
514 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
515 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
518 "seq<", {
519 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
520 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
521 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
522 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
523 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_int24_t>>,
524 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_uint24_t>>,
525 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
526 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
527 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
528 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
529 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
530 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
533 "seq<=", {
534 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
535 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
536 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
537 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
538 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_int24_t>>,
539 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_uint24_t>>,
540 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
541 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
542 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
543 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
544 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
545 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
548 "seq>=", {
549 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
550 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
551 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
552 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
553 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_int24_t>>,
554 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_uint24_t>>,
555 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
556 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
557 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
558 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
559 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
560 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
563 "seq>", {
564 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
565 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
566 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
567 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
568 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_int24_t>>,
569 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_uint24_t>>,
570 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
571 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
572 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
573 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
574 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
575 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
578 "true", {
579 &wxwindow_memorysearch::search_0<&memory_search::update>,
580 &wxwindow_memorysearch::search_0<&memory_search::update>,
581 &wxwindow_memorysearch::search_0<&memory_search::update>,
582 &wxwindow_memorysearch::search_0<&memory_search::update>,
583 &wxwindow_memorysearch::search_0<&memory_search::update>,
584 &wxwindow_memorysearch::search_0<&memory_search::update>,
585 &wxwindow_memorysearch::search_0<&memory_search::update>,
586 &wxwindow_memorysearch::search_0<&memory_search::update>,
587 &wxwindow_memorysearch::search_0<&memory_search::update>,
588 &wxwindow_memorysearch::search_0<&memory_search::update>,
589 &wxwindow_memorysearch::search_0<&memory_search::update>,
590 &wxwindow_memorysearch::search_0<&memory_search::update>
596 wxwindow_memorysearch::wxwindow_memorysearch()
597 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
598 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
600 typecode = 0;
601 wxButton* tmp;
602 Centre();
603 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
604 msearch = new memory_search(lsnes_memory);
606 wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
607 SetSizer(toplevel);
609 wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
610 buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
611 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
612 NULL, this);
613 buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
614 wxString _datatypes[DATATYPES];
615 for(size_t i = 0; i < DATATYPES; i++)
616 _datatypes[i] = towxstring(datatypes[i]);
617 buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
618 wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
619 wxGROW);
620 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
621 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
622 buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
623 buttons->Add(autoupdate = new wxCheckBox(this, wxID_AUTOUPDATE, wxT("Update automatically")), 0, wxGROW);
624 autoupdate->SetValue(true);
625 hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
626 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
627 toplevel->Add(buttons);
629 wxFlexGridSizer* searches = new wxFlexGridSizer(0, 6, 0, 0);
630 for(unsigned j = 0; j < sizeof(searchtbl)/sizeof(searchtbl[0]); j++) {
631 std::string name = searchtbl[j].name;
632 searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(name)), 1, wxGROW);
633 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
634 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
636 toplevel->Add(searches);
638 toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXXXXX candidates")), 0, wxGROW);
639 wxBoxSizer* matchesb = new wxBoxSizer(wxHORIZONTAL);
640 matchesb->Add(matches = new panel(this), 1, wxGROW);
641 matchesb->Add(scroll = new scroll_bar(this, wxID_ANY, true), 0, wxGROW);
642 toplevel->Add(matchesb, 1, wxGROW);
644 scroll->set_page_size(matches->get_characters().second);
646 for(auto i : lsnes_memory.get_regions())
647 if(memory_search::searchable_region(i))
648 vmas_enabled.insert(i->name);
650 wxMenuBar* menubar = new wxMenuBar();
651 SetMenuBar(menubar);
652 wxMenu* filemenu = new wxMenu();
653 filemenu->Append(wxID_MENU_DUMP_CANDIDATES, wxT("Dump candidates..."));
654 filemenu->AppendSeparator();
655 filemenu->Append(wxID_MENU_SAVE_PREVMEM, wxT("Save previous memory..."));
656 filemenu->Append(wxID_MENU_SAVE_SET, wxT("Save set of addresses..."));
657 filemenu->Append(wxID_MENU_SAVE_ALL, wxT("Save previous memory and set of addresses..."));
658 filemenu->AppendSeparator();
659 filemenu->Append(wxID_MENU_LOAD, wxT("Load save..."));
660 menubar->Append(filemenu, wxT("File"));
661 wxMenu* editmenu = new wxMenu();
662 undoitem = editmenu->Append(wxID_UNDO, wxT("Undo"));
663 redoitem = editmenu->Append(wxID_REDO, wxT("Redo"));
664 undoitem->Enable(false);
665 redoitem->Enable(false);
666 menubar->Append(editmenu, wxT("Edit"));
667 Connect(wxID_MENU_DUMP_CANDIDATES, wxEVT_COMMAND_MENU_SELECTED,
668 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
669 Connect(wxID_MENU_SAVE_PREVMEM, wxEVT_COMMAND_MENU_SELECTED,
670 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
671 Connect(wxID_MENU_SAVE_SET, wxEVT_COMMAND_MENU_SELECTED,
672 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
673 Connect(wxID_MENU_SAVE_ALL, wxEVT_COMMAND_MENU_SELECTED,
674 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
675 Connect(wxID_MENU_LOAD, wxEVT_COMMAND_MENU_SELECTED,
676 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
677 Connect(wxID_UNDO, wxEVT_COMMAND_MENU_SELECTED,
678 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
679 Connect(wxID_REDO, wxEVT_COMMAND_MENU_SELECTED,
680 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
682 dragging = false;
683 toomany = true;
684 matches->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
685 matches->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
686 matches->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
687 matches->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
688 matches->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
689 matches->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
690 matches->Connect(wxEVT_MOTION, wxMouseEventHandler(wxwindow_memorysearch::on_mousedrag), NULL, this);
691 matches->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
692 scroll->set_handler([this](scroll_bar& s) { this->matches->request_paint(); });
694 toplevel->SetSizeHints(this);
695 Fit();
696 update();
697 Fit();
698 hexmode = false;
701 wxwindow_memorysearch::panel::panel(wxwindow_memorysearch* _parent)
702 : text_framebuffer_panel(_parent, 40, 25, wxID_ANY, NULL)
704 parent = _parent;
705 first_sel = 0;
706 last_sel = 0;
709 void wxwindow_memorysearch::panel::prepare_paint()
711 uint64_t first = parent->scroll->get_position();
712 auto ssize = get_characters();
713 uint64_t last = first + ssize.second;
714 std::vector<std::string> lines;
715 lines.reserve(ssize.second);
716 std::map<uint64_t, uint64_t> addrs;
717 auto* ms = parent->msearch;
718 uint64_t addr_count;
719 bool toomany = false;
720 auto _parent = parent;
721 runemufn([&toomany, &first, &last, ms, &lines, &addrs, &addr_count, _parent]() {
722 addr_count = ms->get_candidate_count();
723 if(last > addr_count) {
724 uint64_t delta = last - addr_count;
725 if(first > delta) {
726 first -= delta;
727 last -= delta;
728 } else {
729 last -= first;
730 first = 0;
733 if(addr_count <= CANDIDATE_LIMIT) {
734 std::list<uint64_t> addrs2 = ms->get_candidates();
735 unsigned long j = 0;
736 for(auto i : addrs2) {
737 std::string row = hex::to(i) + " ";
738 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, false);
739 row += " (Was: ";
740 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, true);
741 row += ')';
742 if(j >= first && j < last)
743 lines.push_back(row);
744 addrs[j++] = i;
746 } else {
747 lines.push_back("Too many candidates to display");
748 toomany = true;
751 std::swap(parent->addresses, addrs);
753 std::ostringstream x;
754 x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
755 parent->count->SetLabel(towxstring(x.str()));
757 clear();
758 for(unsigned i = 0; i < lines.size(); i++) {
759 bool sel = (first + i) >= first_sel && (first + i) < last_sel;
760 write(lines[i], 0, 0, i, sel ? 0xFFFFFF : 0, sel ? 0 : 0xFFFFFF);
763 if(last_sel > last)
764 last_sel = last;
765 if(first_sel > last)
766 first_sel = last;
768 parent->toomany = toomany;
769 parent->scroll->set_range(toomany ? 0 : addr_count);
772 void wxwindow_memorysearch::panel::set_selection(uint64_t first, uint64_t last)
774 first_sel = first;
775 last_sel = last;
776 request_paint();
779 void wxwindow_memorysearch::panel::get_selection(uint64_t& first, uint64_t& last)
781 first = first_sel;
782 last = last_sel;
785 wxwindow_memorysearch::~wxwindow_memorysearch()
787 delete msearch;
788 mwatch = NULL;
791 bool wxwindow_memorysearch::ShouldPreventAppExit() const
793 return false;
796 void wxwindow_memorysearch::dump_candidates_text()
798 try {
799 std::string filename = choose_file_save(this, "Dump memory search", project_otherpath(),
800 filetype_textfile);
801 std::ofstream out(filename);
802 auto ms = msearch;
803 runemufn([ms, this, &out]() {
804 std::list<uint64_t> addrs2 = ms->get_candidates();
805 for(auto i : addrs2) {
806 std::string row = hex::to(i) + " ";
807 row += (this->*displays[this->typecode])(i, this->hexmode, false);
808 row += " (Was: ";
809 row += (this->*displays[this->typecode])(i, this->hexmode, true);
810 row += ')';
811 out << row << std::endl;
814 if(!out)
815 throw std::runtime_error("Can't write save file");
816 } catch(canceled_exception& e) {
817 } catch(std::exception& e) {
818 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
819 return;
823 void wxwindow_memorysearch::handle_save(memory_search::savestate_type type)
825 try {
826 std::vector<char> state;
827 msearch->savestate(state, type);
828 std::string filename = choose_file_save(this, "Save memory search", project_otherpath(),
829 filetype_memorysearch);
830 std::ofstream out(filename, std::ios::binary);
831 out.write(&state[0], state.size());
832 if(!out)
833 throw std::runtime_error("Can't write save file");
834 } catch(canceled_exception& e) {
835 } catch(std::exception& e) {
836 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
837 return;
841 void wxwindow_memorysearch::handle_load()
843 try {
844 std::string filename = choose_file_load(this, "Load memory search", project_otherpath(),
845 filetype_memorysearch);
846 std::vector<char> state = zip::readrel(filename, "");
847 push_undo();
848 msearch->loadstate(state);
849 update();
850 } catch(canceled_exception& e) {
851 } catch(std::exception& e) {
852 show_message_ok(this, "Load error", std::string(e.what()), wxICON_WARNING);
853 return;
857 void wxwindow_memorysearch::handle_undo_redo(bool redo)
859 std::list<std::vector<char>>& a = *(redo ? &redohistory : &undohistory);
860 std::list<std::vector<char>>& b = *(redo ? &undohistory : &redohistory);
861 if(!a.size()) {
862 show_message_ok(this, "Undo/Redo error", "Can't find state to undo/redo to", wxICON_WARNING);
863 return;
865 bool pushed = false;
866 try {
867 std::vector<char> state;
868 msearch->savestate(state, memory_search::ST_SET);
869 b.push_back(state);
870 pushed = true;
871 msearch->loadstate(a.back());
872 a.pop_back();
873 } catch(std::exception& e) {
874 if(pushed)
875 b.pop_back();
876 show_message_ok(this, "Undo/Redo error", std::string(e.what()), wxICON_WARNING);
877 return;
879 undoitem->Enable(undohistory.size());
880 redoitem->Enable(redohistory.size());
881 update();
884 void wxwindow_memorysearch::push_undo()
886 try {
887 std::vector<char> state;
888 msearch->savestate(state, memory_search::ST_SET);
889 undohistory.push_back(state);
890 if(undohistory.size() > UNDOHISTORY_MAXSIZE)
891 undohistory.pop_front();
892 redohistory.clear();
893 undoitem->Enable(undohistory.size());
894 redoitem->Enable(redohistory.size());
895 } catch(...) {
899 void wxwindow_memorysearch::on_mouse(wxMouseEvent& e)
901 if(e.RightUp() || (e.LeftUp() && e.ControlDown()))
902 on_mouse2(e);
903 else if(e.LeftDown())
904 on_mouse0(e, true);
905 else if(e.LeftUp())
906 on_mouse0(e, false);
907 unsigned speed = 1;
908 if(e.ShiftDown())
909 speed = 10;
910 if(e.ShiftDown() && e.ControlDown())
911 speed = 50;
912 scroll->apply_wheel(e.GetWheelRotation(), e.GetWheelDelta(), speed);
915 void wxwindow_memorysearch::on_mouse0(wxMouseEvent& e, bool polarity)
917 dragging = polarity && !toomany;
918 if(dragging) {
919 mpx = e.GetX();
920 mpy = e.GetY();
921 uint64_t first = scroll->get_position();
922 drag_startline = first + e.GetY() / matches->get_cell().second;
923 } else if(mpx == e.GetX() && mpy == e.GetY()) {
924 matches->set_selection(0, 0);
928 void wxwindow_memorysearch::on_mousedrag(wxMouseEvent& e)
930 if(!dragging)
931 return;
932 uint64_t first = scroll->get_position();
933 uint64_t linenow = first + e.GetY() / matches->get_cell().second;
934 if(drag_startline < linenow)
935 matches->set_selection(drag_startline, linenow + 1);
936 else
937 matches->set_selection(linenow, drag_startline + 1);
940 void wxwindow_memorysearch::on_mouse2(wxMouseEvent& e)
942 wxMenu menu;
943 bool some_selected;
944 uint64_t selcount = 0;
945 uint64_t start, end;
946 matches->get_selection(start, end);
947 some_selected = (start < end);
948 if(!some_selected) {
949 uint64_t first = scroll->get_position();
950 act_line = first + e.GetY() / matches->get_cell().second;
951 if(addresses.count(act_line)) {
952 some_selected = true;
953 selcount++;
956 menu.Append(wxID_ADD, wxT("Add watch..."))->Enable(some_selected);
957 menu.Append(wxID_SHOW_HEXEDITOR, wxT("Select in hex editor"))->Enable(selcount == 1 &&
958 wxeditor_hexeditor_available());
959 menu.Append(wxID_POKE, wxT("Poke..."))->Enable(selcount == 1);
960 menu.AppendSeparator();
961 menu.Append(wxID_DISQUALIFY, wxT("Disqualify"))->Enable(some_selected);
962 menu.AppendSeparator();
963 menu.Append(wxID_UPDATE, wxT("Update"));
964 menu.Append(wxID_SET_REGIONS, wxT("Enabled VMAs"));
965 menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
966 NULL, this);
967 PopupMenu(&menu);
970 void wxwindow_memorysearch::on_close(wxCloseEvent& e)
972 Destroy();
973 mwatch = NULL;
976 void wxwindow_memorysearch::auto_update()
978 if(autoupdate->GetValue())
979 update();
982 void wxwindow_memorysearch::update()
984 matches->request_paint();
987 void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
989 int id = e.GetId();
990 if(id == wxID_RESET) {
991 push_undo();
992 msearch->reset();
993 for(auto i : lsnes_memory.get_regions())
994 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
995 msearch->dq_range(i->base, i->last_address());
996 wxeditor_hexeditor_update();
997 } else if(id == wxID_UPDATE) {
998 update();
999 } else if(id == wxID_TYPESELECT) {
1000 wxString c = type->GetValue();
1001 for(unsigned i = 0; i < DATATYPES; i++)
1002 if(c == towxstring(datatypes[i]))
1003 typecode = i;
1004 } else if(id == wxID_HEX_SELECT) {
1005 hexmode = hexmode2->GetValue();
1006 } else if(id == wxID_ADD) {
1007 uint64_t start, end;
1008 matches->get_selection(start, end);
1009 if(start == end) {
1010 start = act_line;
1011 end = act_line + 1;
1013 for(uint64_t r = start; r < end; r++) {
1014 if(!addresses.count(r))
1015 continue;
1016 uint64_t addr = addresses[r];
1017 try {
1018 std::string n = pick_text(this, "Name for watch", (stringfmt()
1019 << "Enter name for watch at 0x" << std::hex << addr << ":").str());
1020 if(n == "")
1021 continue;
1022 lsnes_memorywatch_item e;
1023 e.expr = (stringfmt() << addr).str();
1024 bool is_hex = hexmode2->GetValue();
1025 e.bytes = watch_properties[typecode].len;
1026 e.signed_flag = !is_hex && (watch_properties[typecode].type == 1);
1027 e.float_flag = (watch_properties[typecode].type == 2);
1028 if(e.float_flag) is_hex = false;
1029 e.format = is_hex ? watch_properties[typecode].hformat : "";
1030 auto i = lsnes_memory.get_regions();
1031 int endianess = 0;
1032 for(auto& j : i) {
1033 if(addr >= j->base && addr < j->base + j->size)
1034 endianess = j->endian;
1036 e.endianess = endianess;
1037 runemufn([n, &e]() { lsnes_memorywatch.set(n, e); });
1038 } catch(canceled_exception& e) {
1041 matches->set_selection(0, 0);
1042 } else if(id == wxID_DISQUALIFY) {
1043 uint64_t start, end;
1044 matches->get_selection(start, end);
1045 if(start == end) {
1046 start = act_line;
1047 end = act_line + 1;
1049 push_undo();
1050 for(uint64_t r = start; r < end; r++) {
1051 if(!addresses.count(r))
1052 return;
1053 uint64_t addr = addresses[r];
1054 auto ms = msearch;
1055 runemufn([addr, ms]() { ms->dq_range(addr, addr); });
1057 matches->set_selection(0, 0);
1058 wxeditor_hexeditor_update();
1059 } else if(id == wxID_SET_REGIONS) {
1060 wxwindow_memorysearch_vmasel* d = new wxwindow_memorysearch_vmasel(this, vmas_enabled);
1061 if(d->ShowModal() == wxID_OK)
1062 vmas_enabled = d->get_vmas();
1063 else {
1064 d->Destroy();
1065 return;
1067 d->Destroy();
1068 push_undo();
1069 for(auto i : lsnes_memory.get_regions())
1070 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1071 msearch->dq_range(i->base, i->last_address());
1072 wxeditor_hexeditor_update();
1073 } else if(id == wxID_POKE) {
1074 uint64_t start, end;
1075 matches->get_selection(start, end);
1076 if(start == end) {
1077 start = act_line;
1078 end = act_line + 1;
1080 for(uint64_t r = start; r < end; r++) {
1081 if(!addresses.count(r))
1082 continue;
1083 uint64_t addr = addresses[r];
1084 try {
1085 (this->*(pokes[typecode]))(addr);
1086 } catch(canceled_exception& e) {
1088 return;
1090 } else if(id == wxID_SHOW_HEXEDITOR) {
1091 uint64_t start, end;
1092 matches->get_selection(start, end);
1093 if(start == end) {
1094 start = act_line;
1095 end = act_line + 1;
1097 for(uint64_t r = start; r < end; r++) {
1098 if(!addresses.count(r))
1099 continue;
1100 wxeditor_hexeditor_jumpto(addresses[r]);
1101 return;
1103 } else if(id >= wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE +
1104 (ssize_t)(sizeof(searchtbl)/sizeof(searchtbl[0]))) {
1105 int button = id - wxID_BUTTONS_BASE;
1106 push_undo();
1107 uint64_t old_count = msearch->get_candidate_count();
1108 (this->*(searchtbl[button].searches[typecode]))();
1109 uint64_t new_count = msearch->get_candidate_count();
1110 if(old_count == new_count) {
1111 undohistory.pop_back(); //Shouldn't be undoable.
1112 undoitem->Enable(undohistory.size());
1114 wxeditor_hexeditor_update();
1115 } else if(id == wxID_MENU_DUMP_CANDIDATES) {
1116 dump_candidates_text();
1117 } else if(id == wxID_MENU_SAVE_PREVMEM) {
1118 handle_save(memory_search::ST_PREVMEM);
1119 } else if(id == wxID_MENU_SAVE_SET) {
1120 handle_save(memory_search::ST_SET);
1121 } else if(id == wxID_MENU_SAVE_ALL) {
1122 handle_save(memory_search::ST_ALL);
1123 } else if(id == wxID_MENU_LOAD) {
1124 handle_load();
1125 } else if(id == wxID_UNDO) {
1126 handle_undo_redo(false);
1127 } else if(id == wxID_REDO) {
1128 handle_undo_redo(true);
1130 update();
1133 template<typename T> void wxwindow_memorysearch::_do_poke_addr(uint64_t addr)
1135 T val = msearch->v_read<T>(addr);
1136 std::string v;
1137 try {
1138 v = pick_text(this, "Poke value", (stringfmt() << "Enter value to poke to " << std::hex << "0x"
1139 << addr).str(), (stringfmt() << val).str(), false);
1140 val = parse_value<T>(v);
1141 } catch(canceled_exception& e) {
1142 return;
1143 } catch(...) {
1144 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1145 return;
1147 msearch->v_write<T>(addr, val);
1150 template<void(memory_search::*sfn)()> void wxwindow_memorysearch::search_0()
1152 (msearch->*sfn)();
1155 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void wxwindow_memorysearch::search_1()
1157 bool bad = false;
1158 T val = promptvalue<T>(bad);
1159 if(bad)
1160 return;
1161 (msearch->*sfn)(static_cast<T2>(val));
1164 template<typename T> T wxwindow_memorysearch::promptvalue(bool& bad)
1166 std::string v;
1167 wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
1168 wxT(""));
1169 if(d->ShowModal() == wxID_CANCEL) {
1170 bad = true;
1171 return 0;
1173 v = tostdstring(d->GetValue());
1174 d->Destroy();
1175 T val2;
1176 try {
1177 val2 = parse_value<T>(v);
1178 } catch(...) {
1179 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1180 bad = true;
1181 return 0;
1183 return val2;
1186 void wxwindow_memorysearch_display()
1188 if(mwatch) {
1189 mwatch->Raise();
1190 return;
1192 mwatch = new wxwindow_memorysearch();
1193 mwatch->Show();
1196 void wxwindow_memorysearch_update()
1198 if(mwatch)
1199 mwatch->auto_update();
1202 memory_search* wxwindow_memorysearch_active()
1204 if(mwatch)
1205 return mwatch->msearch;
1206 else
1207 return NULL;