Make various instance stuff to take references to other instance objs
[lsnes.git] / src / platform / wxwidgets / memorysearch.cpp
blobb989c62710d9888b2afae4109b675f3004aa2823
1 #include "core/dispatch.hpp"
2 #include "core/instance.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/memorywatch.hpp"
5 #include "core/project.hpp"
6 #include "library/hex.hpp"
7 #include "library/string.hpp"
8 #include "library/memorysearch.hpp"
9 #include "library/int24.hpp"
10 #include "library/zip.hpp"
12 #include "platform/wxwidgets/loadsave.hpp"
13 #include "platform/wxwidgets/platform.hpp"
14 #include "platform/wxwidgets/scrollbar.hpp"
15 #include "platform/wxwidgets/textrender.hpp"
17 #include <sstream>
18 #include <fstream>
19 #include <iomanip>
21 #include <wx/wx.h>
22 #include <wx/event.h>
23 #include <wx/control.h>
24 #include <wx/combobox.h>
26 #define wxID_RESET (wxID_HIGHEST + 1)
27 #define wxID_UPDATE (wxID_HIGHEST + 2)
28 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
29 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
30 #define wxID_ADD (wxID_HIGHEST + 5)
31 #define wxID_SET_REGIONS (wxID_HIGHEST + 6)
32 #define wxID_AUTOUPDATE (wxID_HIGHEST + 7)
33 #define wxID_DISQUALIFY (wxID_HIGHEST + 8)
34 #define wxID_POKE (wxID_HIGHEST + 9)
35 #define wxID_SHOW_HEXEDITOR (wxID_HIGHEST + 10)
36 #define wxID_MENU_SAVE_PREVMEM (wxID_HIGHEST + 11)
37 #define wxID_MENU_SAVE_SET (wxID_HIGHEST + 12)
38 #define wxID_MENU_SAVE_ALL (wxID_HIGHEST + 13)
39 #define wxID_MENU_LOAD (wxID_HIGHEST + 14)
40 #define wxID_MENU_UNDO (wxID_HIGHEST + 15)
41 #define wxID_MENU_REDO (wxID_HIGHEST + 16)
42 #define wxID_MENU_DUMP_CANDIDATES (wxID_HIGHEST + 17)
43 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
45 #define DATATYPES 12
46 #define CANDIDATE_LIMIT 512
48 class wxwindow_memorysearch;
49 memory_search* wxwindow_memorysearch_active();
51 namespace
53 unsigned UNDOHISTORY_MAXSIZE = 48;
54 struct _watch_properties {
55 unsigned len;
56 int type; //0 => Unsigned, 1 => Signed, 2 => Float.
57 const char* hformat;
58 } watch_properties[] = {
59 {1, 1, "%02x"},
60 {1, 0, "%02x"},
61 {2, 1, "%04x"},
62 {2, 0, "%04x"},
63 {3, 1, "%06x"},
64 {3, 0, "%06x"},
65 {4, 1, "%08x"},
66 {4, 0, "%08x"},
67 {8, 1, "%016x"},
68 {8, 0, "%016x"},
69 {4, 2, ""},
70 {8, 2, ""},
73 wxwindow_memorysearch* mwatch;
75 const char* datatypes[] = {
76 "signed byte",
77 "unsigned byte",
78 "signed word",
79 "unsigned word",
80 "signed hword",
81 "unsigned hword",
82 "signed dword",
83 "unsigned dword",
84 "signed qword",
85 "unsigned qword",
86 "float",
87 "double"
90 typedef void (wxwindow_memorysearch::*search_fn_t)();
92 struct searchtype
94 const char* name;
95 search_fn_t searches[DATATYPES];
98 template<typename T> std::string format_number_signed(T val, bool hex);
99 template<typename T> std::string format_number_unsigned(T val, bool hex);
101 template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
103 std::ostringstream x;
104 if(hex) {
105 if(val >= 0)
106 x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
107 static_cast<uint64_t>(val);
108 else {
109 int64_t y2 = val;
110 uint64_t y = static_cast<uint64_t>(y2);
111 x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
113 } else
114 x << static_cast<int64_t>(val);
115 return x.str();
118 template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
120 std::ostringstream x;
121 if(hex)
122 x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
123 else
124 x << static_cast<uint64_t>(val);
125 return x.str();
128 template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
130 return format_number_signedh(static_cast<int8_t>(val), 2, hex);
133 template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
135 return format_number_signedh(static_cast<int16_t>(val), 4, hex);
138 template<> std::string format_number_signed<ss_uint24_t>(ss_uint24_t val, bool hex)
140 return format_number_signedh((int32_t)(uint32_t)(val), 6, hex);
143 template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
145 return format_number_signedh(static_cast<int32_t>(val), 8, hex);
148 template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
150 return format_number_signedh(static_cast<int64_t>(val), 16, hex);
153 template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
155 return format_number_unsignedh(val, 2, hex);
158 template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
160 return format_number_unsignedh(val, 4, hex);
163 template<> std::string format_number_unsigned<ss_uint24_t>(ss_uint24_t val, bool hex)
165 return format_number_unsignedh(val, 6, hex);
168 template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
170 return format_number_unsignedh(val, 8, hex);
173 template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
175 return format_number_unsignedh(val, 16, hex);
178 std::string format_number_float(double val)
180 return (stringfmt() << val).str();
184 class wxwindow_memorysearch_vmasel : public wxDialog
186 public:
187 wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled);
188 bool ShouldPreventAppExit() const;
189 std::set<std::string> get_vmas();
190 void on_ok(wxCommandEvent& e);
191 void on_cancel(wxCommandEvent& e);
192 private:
193 std::set<std::string> vmas;
194 std::vector<wxCheckBox*> checkboxes;
195 wxButton* ok;
196 wxButton* cancel;
199 wxwindow_memorysearch_vmasel::wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled)
200 : wxDialog(p, wxID_ANY, towxstring("lsnes: Select enabled regions"), wxDefaultPosition, wxSize(300, -1))
202 auto i = lsnes_instance.memory.get_regions();
203 Centre();
204 wxFlexGridSizer* top_s = new wxFlexGridSizer(i.size() + 1, 1, 0, 0);
205 SetSizer(top_s);
206 for(auto j : i) {
207 if(j->readonly || j->special)
208 continue;
209 wxCheckBox* t;
210 top_s->Add(t = new wxCheckBox(this, wxID_ANY, towxstring(j->name)), 0, wxGROW);
211 if(enabled.count(j->name))
212 t->SetValue(true);
213 checkboxes.push_back(t);
215 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
216 pbutton_s->AddStretchSpacer();
217 pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
218 pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
219 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
220 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_ok), NULL, this);
221 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
222 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_cancel), NULL, this);
223 top_s->Add(pbutton_s);
225 pbutton_s->SetSizeHints(this);
226 top_s->SetSizeHints(this);
227 Fit();
230 bool wxwindow_memorysearch_vmasel::ShouldPreventAppExit() const
232 return false;
235 std::set<std::string> wxwindow_memorysearch_vmasel::get_vmas()
237 return vmas;
240 void wxwindow_memorysearch_vmasel::on_ok(wxCommandEvent& e)
242 for(auto i : checkboxes)
243 if(i->GetValue())
244 vmas.insert(tostdstring(i->GetLabel()));
245 EndModal(wxID_OK);
248 void wxwindow_memorysearch_vmasel::on_cancel(wxCommandEvent& e)
250 EndModal(wxID_CANCEL);
254 class wxwindow_memorysearch : public wxFrame
256 public:
257 class panel : public text_framebuffer_panel
259 public:
260 panel(wxwindow_memorysearch* parent);
261 void set_selection(uint64_t first, uint64_t last);
262 void get_selection(uint64_t& first, uint64_t& last);
263 protected:
264 void prepare_paint();
265 private:
266 wxwindow_memorysearch* parent;
267 uint64_t first_sel;
268 uint64_t last_sel;
270 wxwindow_memorysearch();
271 ~wxwindow_memorysearch();
272 bool ShouldPreventAppExit() const;
273 void on_close(wxCloseEvent& e);
274 void on_button_click(wxCommandEvent& e);
275 void auto_update();
276 void on_mousedrag(wxMouseEvent& e);
277 void on_mouse(wxMouseEvent& e);
278 bool update_queued;
279 template<void(memory_search::*sfn)()> void search_0();
280 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void search_1();
281 template<typename T> void _do_poke_addr(uint64_t addr);
282 template<typename T> std::string _do_format_signed(uint64_t addr, bool hex, bool old)
284 if(old)
285 return format_number_signed<T>(msearch->v_readold<T>(addr), hex);
286 else
287 return format_number_signed<T>(lsnes_instance.memory.read<T>(addr), hex);
289 template<typename T> std::string _do_format_unsigned(uint64_t addr, bool hex, bool old)
291 if(old)
292 return format_number_unsigned<T>(msearch->v_readold<T>(addr), hex);
293 else
294 return format_number_unsigned<T>(lsnes_instance.memory.read<T>(addr), hex);
296 template<typename T> std::string _do_format_float(uint64_t addr, bool hex, bool old)
298 if(old)
299 return format_number_float(msearch->v_readold<T>(addr));
300 else
301 return format_number_float(lsnes_instance.memory.read<T>(addr));
303 void dump_candidates_text();
304 private:
305 friend memory_search* wxwindow_memorysearch_active();
306 friend class panel;
307 template<typename T> T promptvalue(bool& bad);
308 void update();
309 memory_search* msearch;
310 void on_mouse0(wxMouseEvent& e, bool polarity);
311 void on_mousedrag();
312 void on_mouse2(wxMouseEvent& e);
313 void handle_undo_redo(bool redo);
314 void push_undo();
315 void handle_save(memory_search::savestate_type type);
316 void handle_load();
317 std::string format_address(uint64_t addr);
318 wxStaticText* count;
319 scroll_bar* scroll;
320 panel* matches;
321 wxComboBox* type;
322 wxCheckBox* hexmode2;
323 wxCheckBox* autoupdate;
324 std::map<uint64_t, uint64_t> addresses;
325 uint64_t act_line;
326 uint64_t drag_startline;
327 bool dragging;
328 int mpx, mpy;
329 unsigned typecode;
330 bool hexmode;
331 bool toomany;
332 int scroll_delta;
333 std::set<std::string> vmas_enabled;
334 std::map<std::string, std::pair<uint64_t, uint64_t>> vma_info;
335 wxMenuItem* undoitem;
336 wxMenuItem* redoitem;
337 std::list<std::vector<char>> undohistory;
338 std::list<std::vector<char>> redohistory;
341 std::string wxwindow_memorysearch::format_address(uint64_t addr)
343 for(auto i : vma_info) {
344 if(i.second.first <= addr && i.second.first + i.second.second > addr) {
345 //Hit.
346 unsigned hcount = 1;
347 uint64_t t = i.second.second;
348 while(t > 0x10) { hcount++; t >>= 4; }
349 return (stringfmt() << i.first << "+" << std::hex << std::setw(hcount) << std::setfill('0')
350 << (addr - i.second.first)).str();
353 //Fallback.
354 return hex::to(addr);
357 namespace
359 typedef void (wxwindow_memorysearch::*pokefn_t)(uint64_t);
360 pokefn_t pokes[] = {
361 &wxwindow_memorysearch::_do_poke_addr<int8_t>,
362 &wxwindow_memorysearch::_do_poke_addr<uint8_t>,
363 &wxwindow_memorysearch::_do_poke_addr<int16_t>,
364 &wxwindow_memorysearch::_do_poke_addr<uint16_t>,
365 &wxwindow_memorysearch::_do_poke_addr<ss_int24_t>,
366 &wxwindow_memorysearch::_do_poke_addr<ss_uint24_t>,
367 &wxwindow_memorysearch::_do_poke_addr<int32_t>,
368 &wxwindow_memorysearch::_do_poke_addr<uint32_t>,
369 &wxwindow_memorysearch::_do_poke_addr<int64_t>,
370 &wxwindow_memorysearch::_do_poke_addr<uint64_t>,
371 &wxwindow_memorysearch::_do_poke_addr<float>,
372 &wxwindow_memorysearch::_do_poke_addr<double>,
375 typedef std::string (wxwindow_memorysearch::*displayfn_t)(uint64_t, bool hexmode, bool old);
376 displayfn_t displays[] = {
377 &wxwindow_memorysearch::_do_format_signed<uint8_t>,
378 &wxwindow_memorysearch::_do_format_unsigned<uint8_t>,
379 &wxwindow_memorysearch::_do_format_signed<uint16_t>,
380 &wxwindow_memorysearch::_do_format_unsigned<uint16_t>,
381 &wxwindow_memorysearch::_do_format_signed<ss_uint24_t>,
382 &wxwindow_memorysearch::_do_format_unsigned<ss_uint24_t>,
383 &wxwindow_memorysearch::_do_format_signed<uint32_t>,
384 &wxwindow_memorysearch::_do_format_unsigned<uint32_t>,
385 &wxwindow_memorysearch::_do_format_signed<uint64_t>,
386 &wxwindow_memorysearch::_do_format_unsigned<uint64_t>,
387 &wxwindow_memorysearch::_do_format_float<float>,
388 &wxwindow_memorysearch::_do_format_float<double>,
391 struct searchtype searchtbl[] = {
393 "value", {
394 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
395 &memory_search::s_value<uint8_t>>,
396 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
397 &memory_search::s_value<uint8_t>>,
398 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
399 &memory_search::s_value<uint16_t>>,
400 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
401 &memory_search::s_value<uint16_t>>,
402 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
403 &memory_search::s_value<ss_uint24_t>>,
404 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
405 &memory_search::s_value<ss_uint24_t>>,
406 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
407 &memory_search::s_value<uint32_t>>,
408 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
409 &memory_search::s_value<uint32_t>>,
410 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
411 &memory_search::s_value<uint64_t>>,
412 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
413 &memory_search::s_value<uint64_t>>,
414 &wxwindow_memorysearch::search_1<float, float,
415 &memory_search::s_value<float>>,
416 &wxwindow_memorysearch::search_1<double, double,
417 &memory_search::s_value<double>>
420 "diff.", {
421 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
422 &memory_search::s_difference<uint8_t>>,
423 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
424 &memory_search::s_difference<uint8_t>>,
425 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
426 &memory_search::s_difference<uint16_t>>,
427 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
428 &memory_search::s_difference<uint16_t>>,
429 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
430 &memory_search::s_difference<ss_uint24_t>>,
431 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
432 &memory_search::s_difference<ss_uint24_t>>,
433 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
434 &memory_search::s_difference<uint32_t>>,
435 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
436 &memory_search::s_difference<uint32_t>>,
437 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
438 &memory_search::s_difference<uint64_t>>,
439 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
440 &memory_search::s_difference<uint64_t>>,
441 &wxwindow_memorysearch::search_1<float, float,
442 &memory_search::s_difference<float>>,
443 &wxwindow_memorysearch::search_1<double, double,
444 &memory_search::s_difference<double>>
447 "<", {
448 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int8_t>>,
449 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint8_t>>,
450 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int16_t>>,
451 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint16_t>>,
452 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_int24_t>>,
453 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_uint24_t>>,
454 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int32_t>>,
455 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint32_t>>,
456 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int64_t>>,
457 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint64_t>>,
458 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
459 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
462 "<=", {
463 &wxwindow_memorysearch::search_0<&memory_search::s_le<int8_t>>,
464 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint8_t>>,
465 &wxwindow_memorysearch::search_0<&memory_search::s_le<int16_t>>,
466 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint16_t>>,
467 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_int24_t>>,
468 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_uint24_t>>,
469 &wxwindow_memorysearch::search_0<&memory_search::s_le<int32_t>>,
470 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint32_t>>,
471 &wxwindow_memorysearch::search_0<&memory_search::s_le<int64_t>>,
472 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint64_t>>,
473 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
474 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
477 "==", {
478 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int8_t>>,
479 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint8_t>>,
480 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int16_t>>,
481 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint16_t>>,
482 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_int24_t>>,
483 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_uint24_t>>,
484 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int32_t>>,
485 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint32_t>>,
486 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int64_t>>,
487 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint64_t>>,
488 &wxwindow_memorysearch::search_0<&memory_search::s_eq<float>>,
489 &wxwindow_memorysearch::search_0<&memory_search::s_eq<double>>
492 "!=", {
493 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int8_t>>,
494 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint8_t>>,
495 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int16_t>>,
496 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint16_t>>,
497 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_int24_t>>,
498 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_uint24_t>>,
499 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int32_t>>,
500 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint32_t>>,
501 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int64_t>>,
502 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint64_t>>,
503 &wxwindow_memorysearch::search_0<&memory_search::s_ne<float>>,
504 &wxwindow_memorysearch::search_0<&memory_search::s_ne<double>>
507 ">=", {
508 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int8_t>>,
509 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint8_t>>,
510 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int16_t>>,
511 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint16_t>>,
512 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_int24_t>>,
513 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_uint24_t>>,
514 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int32_t>>,
515 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint32_t>>,
516 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int64_t>>,
517 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint64_t>>,
518 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
519 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
522 ">", {
523 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int8_t>>,
524 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint8_t>>,
525 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int16_t>>,
526 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint16_t>>,
527 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_int24_t>>,
528 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_uint24_t>>,
529 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int32_t>>,
530 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint32_t>>,
531 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int64_t>>,
532 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint64_t>>,
533 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
534 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
537 "seq<", {
538 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
539 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
540 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
541 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
542 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_int24_t>>,
543 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_uint24_t>>,
544 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
545 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
546 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
547 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
548 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
549 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
552 "seq<=", {
553 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
554 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
555 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
556 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
557 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_int24_t>>,
558 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_uint24_t>>,
559 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
560 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
561 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
562 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
563 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
564 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
567 "seq>=", {
568 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
569 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
570 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
571 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
572 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_int24_t>>,
573 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_uint24_t>>,
574 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
575 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
576 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
577 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
578 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
579 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
582 "seq>", {
583 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
584 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
585 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
586 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
587 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_int24_t>>,
588 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_uint24_t>>,
589 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
590 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
591 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
592 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
593 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
594 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
597 "true", {
598 &wxwindow_memorysearch::search_0<&memory_search::update>,
599 &wxwindow_memorysearch::search_0<&memory_search::update>,
600 &wxwindow_memorysearch::search_0<&memory_search::update>,
601 &wxwindow_memorysearch::search_0<&memory_search::update>,
602 &wxwindow_memorysearch::search_0<&memory_search::update>,
603 &wxwindow_memorysearch::search_0<&memory_search::update>,
604 &wxwindow_memorysearch::search_0<&memory_search::update>,
605 &wxwindow_memorysearch::search_0<&memory_search::update>,
606 &wxwindow_memorysearch::search_0<&memory_search::update>,
607 &wxwindow_memorysearch::search_0<&memory_search::update>,
608 &wxwindow_memorysearch::search_0<&memory_search::update>,
609 &wxwindow_memorysearch::search_0<&memory_search::update>
615 wxwindow_memorysearch::wxwindow_memorysearch()
616 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
617 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
619 typecode = 0;
620 wxButton* tmp;
621 Centre();
622 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
623 msearch = new memory_search(lsnes_instance.memory);
625 wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
626 SetSizer(toplevel);
628 wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
629 buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
630 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
631 NULL, this);
632 buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
633 wxString _datatypes[DATATYPES];
634 for(size_t i = 0; i < DATATYPES; i++)
635 _datatypes[i] = towxstring(datatypes[i]);
636 buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
637 wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
638 wxGROW);
639 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
640 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
641 buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
642 buttons->Add(autoupdate = new wxCheckBox(this, wxID_AUTOUPDATE, wxT("Update automatically")), 0, wxGROW);
643 autoupdate->SetValue(true);
644 hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
645 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
646 toplevel->Add(buttons);
648 wxFlexGridSizer* searches = new wxFlexGridSizer(0, 6, 0, 0);
649 for(unsigned j = 0; j < sizeof(searchtbl)/sizeof(searchtbl[0]); j++) {
650 std::string name = searchtbl[j].name;
651 searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(name)), 1, wxGROW);
652 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
653 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
655 toplevel->Add(searches);
657 toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXXXXX candidates")), 0, wxGROW);
658 wxBoxSizer* matchesb = new wxBoxSizer(wxHORIZONTAL);
659 matchesb->Add(matches = new panel(this), 1, wxGROW);
660 matchesb->Add(scroll = new scroll_bar(this, wxID_ANY, true), 0, wxGROW);
661 toplevel->Add(matchesb, 1, wxGROW);
663 scroll->set_page_size(matches->get_characters().second);
665 for(auto i : lsnes_instance.memory.get_regions()) {
666 if(memory_search::searchable_region(i))
667 vmas_enabled.insert(i->name);
668 vma_info[i->name] = std::make_pair(i->base, i->size);
671 wxMenuBar* menubar = new wxMenuBar();
672 SetMenuBar(menubar);
673 wxMenu* filemenu = new wxMenu();
674 filemenu->Append(wxID_MENU_DUMP_CANDIDATES, wxT("Dump candidates..."));
675 filemenu->AppendSeparator();
676 filemenu->Append(wxID_MENU_SAVE_PREVMEM, wxT("Save previous memory..."));
677 filemenu->Append(wxID_MENU_SAVE_SET, wxT("Save set of addresses..."));
678 filemenu->Append(wxID_MENU_SAVE_ALL, wxT("Save previous memory and set of addresses..."));
679 filemenu->AppendSeparator();
680 filemenu->Append(wxID_MENU_LOAD, wxT("Load save..."));
681 menubar->Append(filemenu, wxT("File"));
682 wxMenu* editmenu = new wxMenu();
683 undoitem = editmenu->Append(wxID_UNDO, wxT("Undo"));
684 redoitem = editmenu->Append(wxID_REDO, wxT("Redo"));
685 undoitem->Enable(false);
686 redoitem->Enable(false);
687 menubar->Append(editmenu, wxT("Edit"));
688 Connect(wxID_MENU_DUMP_CANDIDATES, wxEVT_COMMAND_MENU_SELECTED,
689 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
690 Connect(wxID_MENU_SAVE_PREVMEM, wxEVT_COMMAND_MENU_SELECTED,
691 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
692 Connect(wxID_MENU_SAVE_SET, wxEVT_COMMAND_MENU_SELECTED,
693 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
694 Connect(wxID_MENU_SAVE_ALL, wxEVT_COMMAND_MENU_SELECTED,
695 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
696 Connect(wxID_MENU_LOAD, wxEVT_COMMAND_MENU_SELECTED,
697 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
698 Connect(wxID_UNDO, wxEVT_COMMAND_MENU_SELECTED,
699 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
700 Connect(wxID_REDO, wxEVT_COMMAND_MENU_SELECTED,
701 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
703 dragging = false;
704 toomany = true;
705 matches->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
706 matches->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
707 matches->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
708 matches->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
709 matches->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
710 matches->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
711 matches->Connect(wxEVT_MOTION, wxMouseEventHandler(wxwindow_memorysearch::on_mousedrag), NULL, this);
712 matches->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
713 scroll->set_handler([this](scroll_bar& s) { this->matches->request_paint(); });
715 toplevel->SetSizeHints(this);
716 Fit();
717 update();
718 Fit();
719 hexmode = false;
722 wxwindow_memorysearch::panel::panel(wxwindow_memorysearch* _parent)
723 : text_framebuffer_panel(_parent, 40, 25, wxID_ANY, NULL)
725 parent = _parent;
726 first_sel = 0;
727 last_sel = 0;
730 void wxwindow_memorysearch::panel::prepare_paint()
732 uint64_t first = parent->scroll->get_position();
733 auto ssize = get_characters();
734 uint64_t last = first + ssize.second;
735 std::vector<std::string> lines;
736 lines.reserve(ssize.second);
737 std::map<uint64_t, uint64_t> addrs;
738 auto* ms = parent->msearch;
739 uint64_t addr_count;
740 bool toomany = false;
741 auto _parent = parent;
742 lsnes_instance.iqueue.run([&toomany, &first, &last, ms, &lines, &addrs, &addr_count, _parent]() {
743 addr_count = ms->get_candidate_count();
744 if(last > addr_count) {
745 uint64_t delta = last - addr_count;
746 if(first > delta) {
747 first -= delta;
748 last -= delta;
749 } else {
750 last -= first;
751 first = 0;
754 if(addr_count <= CANDIDATE_LIMIT) {
755 std::list<uint64_t> addrs2 = ms->get_candidates();
756 unsigned long j = 0;
757 for(auto i : addrs2) {
758 std::string row = _parent->format_address(i) + " ";
759 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, false);
760 row += " (Was: ";
761 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, true);
762 row += ')';
763 if(j >= first && j < last)
764 lines.push_back(row);
765 addrs[j++] = i;
767 } else {
768 lines.push_back("Too many candidates to display");
769 toomany = true;
772 std::swap(parent->addresses, addrs);
774 std::ostringstream x;
775 x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
776 parent->count->SetLabel(towxstring(x.str()));
778 clear();
779 for(unsigned i = 0; i < lines.size(); i++) {
780 bool sel = (first + i) >= first_sel && (first + i) < last_sel;
781 write(lines[i], 0, 0, i, sel ? 0xFFFFFF : 0, sel ? 0 : 0xFFFFFF);
784 if(last_sel > last)
785 last_sel = last;
786 if(first_sel > last)
787 first_sel = last;
789 parent->toomany = toomany;
790 parent->scroll->set_range(toomany ? 0 : addr_count);
793 void wxwindow_memorysearch::panel::set_selection(uint64_t first, uint64_t last)
795 first_sel = first;
796 last_sel = last;
797 request_paint();
800 void wxwindow_memorysearch::panel::get_selection(uint64_t& first, uint64_t& last)
802 first = first_sel;
803 last = last_sel;
806 wxwindow_memorysearch::~wxwindow_memorysearch()
808 delete msearch;
809 mwatch = NULL;
812 bool wxwindow_memorysearch::ShouldPreventAppExit() const
814 return false;
817 void wxwindow_memorysearch::dump_candidates_text()
819 try {
820 std::string filename = choose_file_save(this, "Dump memory search",
821 lsnes_instance.project.otherpath(), filetype_textfile);
822 std::ofstream out(filename);
823 auto ms = msearch;
824 lsnes_instance.iqueue.run([ms, this, &out]() {
825 std::list<uint64_t> addrs2 = ms->get_candidates();
826 for(auto i : addrs2) {
827 std::string row = format_address(i) + " ";
828 row += (this->*displays[this->typecode])(i, this->hexmode, false);
829 row += " (Was: ";
830 row += (this->*displays[this->typecode])(i, this->hexmode, true);
831 row += ')';
832 out << row << std::endl;
835 if(!out)
836 throw std::runtime_error("Can't write save file");
837 } catch(canceled_exception& e) {
838 } catch(std::exception& e) {
839 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
840 return;
844 void wxwindow_memorysearch::handle_save(memory_search::savestate_type type)
846 try {
847 std::vector<char> state;
848 msearch->savestate(state, type);
849 std::string filename = choose_file_save(this, "Save memory search",
850 lsnes_instance.project.otherpath(), filetype_memorysearch);
851 std::ofstream out(filename, std::ios::binary);
852 out.write(&state[0], state.size());
853 if(!out)
854 throw std::runtime_error("Can't write save file");
855 } catch(canceled_exception& e) {
856 } catch(std::exception& e) {
857 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
858 return;
862 void wxwindow_memorysearch::handle_load()
864 try {
865 std::string filename = choose_file_load(this, "Load memory search",
866 lsnes_instance.project.otherpath(), filetype_memorysearch);
867 std::vector<char> state = zip::readrel(filename, "");
868 push_undo();
869 msearch->loadstate(state);
870 update();
871 } catch(canceled_exception& e) {
872 } catch(std::exception& e) {
873 show_message_ok(this, "Load error", std::string(e.what()), wxICON_WARNING);
874 return;
878 void wxwindow_memorysearch::handle_undo_redo(bool redo)
880 std::list<std::vector<char>>& a = *(redo ? &redohistory : &undohistory);
881 std::list<std::vector<char>>& b = *(redo ? &undohistory : &redohistory);
882 if(!a.size()) {
883 show_message_ok(this, "Undo/Redo error", "Can't find state to undo/redo to", wxICON_WARNING);
884 return;
886 bool pushed = false;
887 try {
888 std::vector<char> state;
889 msearch->savestate(state, memory_search::ST_SET);
890 b.push_back(state);
891 pushed = true;
892 msearch->loadstate(a.back());
893 a.pop_back();
894 } catch(std::exception& e) {
895 if(pushed)
896 b.pop_back();
897 show_message_ok(this, "Undo/Redo error", std::string(e.what()), wxICON_WARNING);
898 return;
900 undoitem->Enable(undohistory.size());
901 redoitem->Enable(redohistory.size());
902 update();
905 void wxwindow_memorysearch::push_undo()
907 try {
908 std::vector<char> state;
909 msearch->savestate(state, memory_search::ST_SET);
910 undohistory.push_back(state);
911 if(undohistory.size() > UNDOHISTORY_MAXSIZE)
912 undohistory.pop_front();
913 redohistory.clear();
914 undoitem->Enable(undohistory.size());
915 redoitem->Enable(redohistory.size());
916 } catch(...) {
920 void wxwindow_memorysearch::on_mouse(wxMouseEvent& e)
922 if(e.RightUp() || (e.LeftUp() && e.ControlDown()))
923 on_mouse2(e);
924 else if(e.LeftDown())
925 on_mouse0(e, true);
926 else if(e.LeftUp())
927 on_mouse0(e, false);
928 unsigned speed = 1;
929 if(e.ShiftDown())
930 speed = 10;
931 if(e.ShiftDown() && e.ControlDown())
932 speed = 50;
933 scroll->apply_wheel(e.GetWheelRotation(), e.GetWheelDelta(), speed);
936 void wxwindow_memorysearch::on_mouse0(wxMouseEvent& e, bool polarity)
938 dragging = polarity && !toomany;
939 if(dragging) {
940 mpx = e.GetX();
941 mpy = e.GetY();
942 uint64_t first = scroll->get_position();
943 drag_startline = first + e.GetY() / matches->get_cell().second;
944 } else if(mpx == e.GetX() && mpy == e.GetY()) {
945 matches->set_selection(0, 0);
949 void wxwindow_memorysearch::on_mousedrag(wxMouseEvent& e)
951 if(!dragging)
952 return;
953 uint64_t first = scroll->get_position();
954 uint64_t linenow = first + e.GetY() / matches->get_cell().second;
955 if(drag_startline < linenow)
956 matches->set_selection(drag_startline, linenow + 1);
957 else
958 matches->set_selection(linenow, drag_startline + 1);
961 void wxwindow_memorysearch::on_mouse2(wxMouseEvent& e)
963 wxMenu menu;
964 bool some_selected;
965 uint64_t selcount = 0;
966 uint64_t start, end;
967 matches->get_selection(start, end);
968 some_selected = (start < end);
969 if(!some_selected) {
970 uint64_t first = scroll->get_position();
971 act_line = first + e.GetY() / matches->get_cell().second;
972 if(addresses.count(act_line)) {
973 some_selected = true;
974 selcount++;
977 menu.Append(wxID_ADD, wxT("Add watch..."))->Enable(some_selected);
978 menu.Append(wxID_SHOW_HEXEDITOR, wxT("Select in hex editor"))->Enable(selcount == 1 &&
979 wxeditor_hexeditor_available());
980 menu.Append(wxID_POKE, wxT("Poke..."))->Enable(selcount == 1);
981 menu.AppendSeparator();
982 menu.Append(wxID_DISQUALIFY, wxT("Disqualify"))->Enable(some_selected);
983 menu.AppendSeparator();
984 menu.Append(wxID_UPDATE, wxT("Update"));
985 menu.Append(wxID_SET_REGIONS, wxT("Enabled VMAs"));
986 menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
987 NULL, this);
988 PopupMenu(&menu);
991 void wxwindow_memorysearch::on_close(wxCloseEvent& e)
993 Destroy();
994 mwatch = NULL;
997 void wxwindow_memorysearch::auto_update()
999 if(autoupdate->GetValue())
1000 update();
1003 void wxwindow_memorysearch::update()
1005 matches->request_paint();
1008 void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
1010 int id = e.GetId();
1011 if(id == wxID_RESET) {
1012 push_undo();
1013 msearch->reset();
1014 //Update all VMA info too.
1015 for(auto i : lsnes_instance.memory.get_regions()) {
1016 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1017 msearch->dq_range(i->base, i->last_address());
1018 vma_info[i->name] = std::make_pair(i->base, i->size);
1020 wxeditor_hexeditor_update();
1021 } else if(id == wxID_UPDATE) {
1022 update();
1023 } else if(id == wxID_TYPESELECT) {
1024 wxString c = type->GetValue();
1025 for(unsigned i = 0; i < DATATYPES; i++)
1026 if(c == towxstring(datatypes[i]))
1027 typecode = i;
1028 } else if(id == wxID_HEX_SELECT) {
1029 hexmode = hexmode2->GetValue();
1030 } else if(id == wxID_ADD) {
1031 uint64_t start, end;
1032 matches->get_selection(start, end);
1033 if(start == end) {
1034 start = act_line;
1035 end = act_line + 1;
1037 for(uint64_t r = start; r < end; r++) {
1038 if(!addresses.count(r))
1039 continue;
1040 uint64_t addr = addresses[r];
1041 try {
1042 std::string n = pick_text(this, "Name for watch", (stringfmt()
1043 << "Enter name for watch at 0x" << std::hex << addr << ":").str());
1044 if(n == "")
1045 continue;
1046 memwatch_item e(lsnes_instance.memory);
1047 e.expr = (stringfmt() << addr).str();
1048 bool is_hex = hexmode2->GetValue();
1049 e.bytes = watch_properties[typecode].len;
1050 e.signed_flag = !is_hex && (watch_properties[typecode].type == 1);
1051 e.float_flag = (watch_properties[typecode].type == 2);
1052 if(e.float_flag) is_hex = false;
1053 e.format = is_hex ? watch_properties[typecode].hformat : "";
1054 auto i = lsnes_instance.memory.get_regions();
1055 int endianess = 0;
1056 for(auto& j : i) {
1057 if(addr >= j->base && addr < j->base + j->size)
1058 endianess = j->endian;
1060 e.endianess = endianess;
1061 lsnes_instance.iqueue.run([n, &e]() { lsnes_instance.mwatch.set(n, e); });
1062 } catch(canceled_exception& e) {
1065 matches->set_selection(0, 0);
1066 } else if(id == wxID_DISQUALIFY) {
1067 uint64_t start, end;
1068 matches->get_selection(start, end);
1069 if(start == end) {
1070 start = act_line;
1071 end = act_line + 1;
1073 push_undo();
1074 for(uint64_t r = start; r < end; r++) {
1075 if(!addresses.count(r))
1076 return;
1077 uint64_t addr = addresses[r];
1078 auto ms = msearch;
1079 lsnes_instance.iqueue.run([addr, ms]() { ms->dq_range(addr, addr); });
1081 matches->set_selection(0, 0);
1082 wxeditor_hexeditor_update();
1083 } else if(id == wxID_SET_REGIONS) {
1084 wxwindow_memorysearch_vmasel* d = new wxwindow_memorysearch_vmasel(this, vmas_enabled);
1085 if(d->ShowModal() == wxID_OK)
1086 vmas_enabled = d->get_vmas();
1087 else {
1088 d->Destroy();
1089 return;
1091 d->Destroy();
1092 push_undo();
1093 for(auto i : lsnes_instance.memory.get_regions())
1094 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1095 msearch->dq_range(i->base, i->last_address());
1096 wxeditor_hexeditor_update();
1097 } else if(id == wxID_POKE) {
1098 uint64_t start, end;
1099 matches->get_selection(start, end);
1100 if(start == end) {
1101 start = act_line;
1102 end = act_line + 1;
1104 for(uint64_t r = start; r < end; r++) {
1105 if(!addresses.count(r))
1106 continue;
1107 uint64_t addr = addresses[r];
1108 try {
1109 (this->*(pokes[typecode]))(addr);
1110 } catch(canceled_exception& e) {
1112 return;
1114 } else if(id == wxID_SHOW_HEXEDITOR) {
1115 uint64_t start, end;
1116 matches->get_selection(start, end);
1117 if(start == end) {
1118 start = act_line;
1119 end = act_line + 1;
1121 for(uint64_t r = start; r < end; r++) {
1122 if(!addresses.count(r))
1123 continue;
1124 wxeditor_hexeditor_jumpto(addresses[r]);
1125 return;
1127 } else if(id >= wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE +
1128 (ssize_t)(sizeof(searchtbl)/sizeof(searchtbl[0]))) {
1129 int button = id - wxID_BUTTONS_BASE;
1130 push_undo();
1131 uint64_t old_count = msearch->get_candidate_count();
1132 (this->*(searchtbl[button].searches[typecode]))();
1133 uint64_t new_count = msearch->get_candidate_count();
1134 if(old_count == new_count) {
1135 undohistory.pop_back(); //Shouldn't be undoable.
1136 undoitem->Enable(undohistory.size());
1138 wxeditor_hexeditor_update();
1139 } else if(id == wxID_MENU_DUMP_CANDIDATES) {
1140 dump_candidates_text();
1141 } else if(id == wxID_MENU_SAVE_PREVMEM) {
1142 handle_save(memory_search::ST_PREVMEM);
1143 } else if(id == wxID_MENU_SAVE_SET) {
1144 handle_save(memory_search::ST_SET);
1145 } else if(id == wxID_MENU_SAVE_ALL) {
1146 handle_save(memory_search::ST_ALL);
1147 } else if(id == wxID_MENU_LOAD) {
1148 handle_load();
1149 } else if(id == wxID_UNDO) {
1150 handle_undo_redo(false);
1151 } else if(id == wxID_REDO) {
1152 handle_undo_redo(true);
1154 update();
1157 template<typename T> void wxwindow_memorysearch::_do_poke_addr(uint64_t addr)
1159 T val = msearch->v_read<T>(addr);
1160 std::string v;
1161 try {
1162 v = pick_text(this, "Poke value", (stringfmt() << "Enter value to poke to " << std::hex << "0x"
1163 << addr).str(), (stringfmt() << val).str(), false);
1164 val = parse_value<T>(v);
1165 } catch(canceled_exception& e) {
1166 return;
1167 } catch(...) {
1168 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1169 return;
1171 msearch->v_write<T>(addr, val);
1174 template<void(memory_search::*sfn)()> void wxwindow_memorysearch::search_0()
1176 (msearch->*sfn)();
1179 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void wxwindow_memorysearch::search_1()
1181 bool bad = false;
1182 T val = promptvalue<T>(bad);
1183 if(bad)
1184 return;
1185 (msearch->*sfn)(static_cast<T2>(val));
1188 template<typename T> T wxwindow_memorysearch::promptvalue(bool& bad)
1190 std::string v;
1191 wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
1192 wxT(""));
1193 if(d->ShowModal() == wxID_CANCEL) {
1194 bad = true;
1195 return 0;
1197 v = tostdstring(d->GetValue());
1198 d->Destroy();
1199 T val2;
1200 try {
1201 val2 = parse_value<T>(v);
1202 } catch(...) {
1203 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1204 bad = true;
1205 return 0;
1207 return val2;
1210 void wxwindow_memorysearch_display()
1212 if(mwatch) {
1213 mwatch->Raise();
1214 return;
1216 mwatch = new wxwindow_memorysearch();
1217 mwatch->Show();
1220 void wxwindow_memorysearch_update()
1222 if(mwatch)
1223 mwatch->auto_update();
1226 memory_search* wxwindow_memorysearch_active()
1228 if(mwatch)
1229 return mwatch->msearch;
1230 else
1231 return NULL;