Fix Win32 build
[lsnes.git] / src / platform / wxwidgets / memorysearch.cpp
blobb50b77a9d2d9c064c5566f4d173085b157257c81
1 #include <wx/wx.h>
2 #include <wx/event.h>
3 #include <wx/control.h>
4 #include <wx/combobox.h>
6 #include "core/dispatch.hpp"
7 #include "core/instance.hpp"
8 #include "core/instance-map.hpp"
9 #include "core/memorymanip.hpp"
10 #include "core/memorywatch.hpp"
11 #include "core/project.hpp"
12 #include "core/ui-services.hpp"
13 #include "library/hex.hpp"
14 #include "library/string.hpp"
15 #include "library/memorysearch.hpp"
16 #include "library/int24.hpp"
17 #include "library/zip.hpp"
19 #include "platform/wxwidgets/loadsave.hpp"
20 #include "platform/wxwidgets/platform.hpp"
21 #include "platform/wxwidgets/scrollbar.hpp"
22 #include "platform/wxwidgets/textrender.hpp"
24 #include <sstream>
25 #include <fstream>
26 #include <iomanip>
28 #define wxID_RESET (wxID_HIGHEST + 1)
29 #define wxID_UPDATE (wxID_HIGHEST + 2)
30 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
31 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
32 #define wxID_ADD (wxID_HIGHEST + 5)
33 #define wxID_SET_REGIONS (wxID_HIGHEST + 6)
34 #define wxID_AUTOUPDATE (wxID_HIGHEST + 7)
35 #define wxID_DISQUALIFY (wxID_HIGHEST + 8)
36 #define wxID_POKE (wxID_HIGHEST + 9)
37 #define wxID_SHOW_HEXEDITOR (wxID_HIGHEST + 10)
38 #define wxID_MENU_SAVE_PREVMEM (wxID_HIGHEST + 11)
39 #define wxID_MENU_SAVE_SET (wxID_HIGHEST + 12)
40 #define wxID_MENU_SAVE_ALL (wxID_HIGHEST + 13)
41 #define wxID_MENU_LOAD (wxID_HIGHEST + 14)
42 #define wxID_MENU_UNDO (wxID_HIGHEST + 15)
43 #define wxID_MENU_REDO (wxID_HIGHEST + 16)
44 #define wxID_MENU_DUMP_CANDIDATES (wxID_HIGHEST + 17)
45 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
47 #define DATATYPES 12
48 #define CANDIDATE_LIMIT 512
50 class wxwindow_memorysearch;
51 memory_search* wxwindow_memorysearch_active();
53 namespace
55 unsigned UNDOHISTORY_MAXSIZE = 48;
56 struct _watch_properties {
57 unsigned len;
58 int type; //0 => Unsigned, 1 => Signed, 2 => Float.
59 const char* hformat;
60 } watch_properties[] = {
61 {1, 1, "%02x"},
62 {1, 0, "%02x"},
63 {2, 1, "%04x"},
64 {2, 0, "%04x"},
65 {3, 1, "%06x"},
66 {3, 0, "%06x"},
67 {4, 1, "%08x"},
68 {4, 0, "%08x"},
69 {8, 1, "%016x"},
70 {8, 0, "%016x"},
71 {4, 2, ""},
72 {8, 2, ""},
75 instance_map<wxwindow_memorysearch> mwatch;
77 const char* datatypes[] = {
78 "signed byte",
79 "unsigned byte",
80 "signed word",
81 "unsigned word",
82 "signed hword",
83 "unsigned hword",
84 "signed dword",
85 "unsigned dword",
86 "signed qword",
87 "unsigned qword",
88 "float",
89 "double"
92 typedef void (wxwindow_memorysearch::*search_fn_t)();
94 struct searchtype
96 const char* name;
97 search_fn_t searches[DATATYPES];
100 template<typename T> std::string format_number_signed(T val, bool hex);
101 template<typename T> std::string format_number_unsigned(T val, bool hex);
103 template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
105 std::ostringstream x;
106 if(hex) {
107 if(val >= 0)
108 x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
109 static_cast<uint64_t>(val);
110 else {
111 int64_t y2 = val;
112 uint64_t y = static_cast<uint64_t>(y2);
113 x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
115 } else
116 x << static_cast<int64_t>(val);
117 return x.str();
120 template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
122 std::ostringstream x;
123 if(hex)
124 x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
125 else
126 x << static_cast<uint64_t>(val);
127 return x.str();
130 template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
132 return format_number_signedh(static_cast<int8_t>(val), 2, hex);
135 template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
137 return format_number_signedh(static_cast<int16_t>(val), 4, hex);
140 template<> std::string format_number_signed<ss_uint24_t>(ss_uint24_t val, bool hex)
142 return format_number_signedh((int32_t)(uint32_t)(val), 6, hex);
145 template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
147 return format_number_signedh(static_cast<int32_t>(val), 8, hex);
150 template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
152 return format_number_signedh(static_cast<int64_t>(val), 16, hex);
155 template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
157 return format_number_unsignedh(val, 2, hex);
160 template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
162 return format_number_unsignedh(val, 4, hex);
165 template<> std::string format_number_unsigned<ss_uint24_t>(ss_uint24_t val, bool hex)
167 return format_number_unsignedh(val, 6, hex);
170 template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
172 return format_number_unsignedh(val, 8, hex);
175 template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
177 return format_number_unsignedh(val, 16, hex);
180 std::string format_number_float(double val)
182 return (stringfmt() << val).str();
186 class wxwindow_memorysearch_vmasel : public wxDialog
188 public:
189 wxwindow_memorysearch_vmasel(wxWindow* p, emulator_instance& _inst, const std::set<std::string>& enabled);
190 bool ShouldPreventAppExit() const;
191 std::set<std::string> get_vmas();
192 void on_ok(wxCommandEvent& e);
193 void on_cancel(wxCommandEvent& e);
194 private:
195 emulator_instance& inst;
196 std::set<std::string> vmas;
197 std::vector<wxCheckBox*> checkboxes;
198 wxButton* ok;
199 wxButton* cancel;
202 wxwindow_memorysearch_vmasel::wxwindow_memorysearch_vmasel(wxWindow* p, emulator_instance& _inst,
203 const std::set<std::string>& enabled)
204 : wxDialog(p, wxID_ANY, towxstring("lsnes: Select enabled regions"), wxDefaultPosition, wxSize(300, -1)),
205 inst(_inst)
207 CHECK_UI_THREAD;
208 auto i = inst.memory->get_regions();
209 Centre();
210 wxFlexGridSizer* top_s = new wxFlexGridSizer(i.size() + 1, 1, 0, 0);
211 SetSizer(top_s);
212 for(auto j : i) {
213 if(j->readonly || j->special)
214 continue;
215 wxCheckBox* t;
216 top_s->Add(t = new wxCheckBox(this, wxID_ANY, towxstring(j->name)), 0, wxGROW);
217 if(enabled.count(j->name))
218 t->SetValue(true);
219 checkboxes.push_back(t);
221 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
222 pbutton_s->AddStretchSpacer();
223 pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
224 pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
225 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
226 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_ok), NULL, this);
227 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
228 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_cancel), NULL, this);
229 top_s->Add(pbutton_s);
231 pbutton_s->SetSizeHints(this);
232 top_s->SetSizeHints(this);
233 Fit();
236 bool wxwindow_memorysearch_vmasel::ShouldPreventAppExit() const
238 return false;
241 std::set<std::string> wxwindow_memorysearch_vmasel::get_vmas()
243 return vmas;
246 void wxwindow_memorysearch_vmasel::on_ok(wxCommandEvent& e)
248 CHECK_UI_THREAD;
249 for(auto i : checkboxes)
250 if(i->GetValue())
251 vmas.insert(tostdstring(i->GetLabel()));
252 EndModal(wxID_OK);
255 void wxwindow_memorysearch_vmasel::on_cancel(wxCommandEvent& e)
257 CHECK_UI_THREAD;
258 EndModal(wxID_CANCEL);
262 class wxwindow_memorysearch : public wxFrame
264 public:
265 class panel : public text_framebuffer_panel
267 public:
268 panel(wxwindow_memorysearch* parent, emulator_instance& _inst);
269 void set_selection(uint64_t first, uint64_t last);
270 void get_selection(uint64_t& first, uint64_t& last);
271 protected:
272 void prepare_paint();
273 private:
274 emulator_instance& inst;
275 wxwindow_memorysearch* parent;
276 uint64_t first_sel;
277 uint64_t last_sel;
279 wxwindow_memorysearch(emulator_instance& _inst);
280 ~wxwindow_memorysearch();
281 bool ShouldPreventAppExit() const;
282 void on_close(wxCloseEvent& e);
283 void on_button_click(wxCommandEvent& e);
284 void auto_update();
285 void on_mousedrag(wxMouseEvent& e);
286 void on_mouse(wxMouseEvent& e);
287 emulator_instance& inst;
288 bool update_queued;
289 template<void(memory_search::*sfn)()> void search_0();
290 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void search_1();
291 template<typename T> void _do_poke_addr(uint64_t addr);
292 template<typename T> std::string _do_format_signed(uint64_t addr, bool hex, bool old)
294 if(old)
295 return format_number_signed<T>(msearch->v_readold<T>(addr), hex);
296 else
297 return format_number_signed<T>(inst.memory->read<T>(addr), hex);
299 template<typename T> std::string _do_format_unsigned(uint64_t addr, bool hex, bool old)
301 if(old)
302 return format_number_unsigned<T>(msearch->v_readold<T>(addr), hex);
303 else
304 return format_number_unsigned<T>(inst.memory->read<T>(addr), hex);
306 template<typename T> std::string _do_format_float(uint64_t addr, bool hex, bool old)
308 if(old)
309 return format_number_float(msearch->v_readold<T>(addr));
310 else
311 return format_number_float(inst.memory->read<T>(addr));
313 void dump_candidates_text();
314 private:
315 friend memory_search* wxwindow_memorysearch_active(emulator_instance& inst);
316 friend class panel;
317 template<typename T> T promptvalue(bool& bad);
318 void update();
319 memory_search* msearch;
320 void on_mouse0(wxMouseEvent& e, bool polarity);
321 void on_mousedrag();
322 void on_mouse2(wxMouseEvent& e);
323 void handle_undo_redo(bool redo);
324 void push_undo();
325 void handle_save(memory_search::savestate_type type);
326 void handle_load();
327 std::string format_address(uint64_t addr);
328 wxStaticText* count;
329 scroll_bar* scroll;
330 panel* matches;
331 wxComboBox* type;
332 wxCheckBox* hexmode2;
333 wxCheckBox* autoupdate;
334 std::map<uint64_t, uint64_t> addresses;
335 uint64_t act_line;
336 uint64_t drag_startline;
337 bool dragging;
338 int mpx, mpy;
339 unsigned typecode;
340 bool hexmode;
341 bool toomany;
342 int scroll_delta;
343 std::set<std::string> vmas_enabled;
344 std::map<std::string, std::pair<uint64_t, uint64_t>> vma_info;
345 wxMenuItem* undoitem;
346 wxMenuItem* redoitem;
347 std::list<std::vector<char>> undohistory;
348 std::list<std::vector<char>> redohistory;
351 std::string wxwindow_memorysearch::format_address(uint64_t addr)
353 for(auto i : vma_info) {
354 if(i.second.first <= addr && i.second.first + i.second.second > addr) {
355 //Hit.
356 unsigned hcount = 1;
357 uint64_t t = i.second.second;
358 while(t > 0x10) { hcount++; t >>= 4; }
359 return (stringfmt() << i.first << "+" << std::hex << std::setw(hcount) << std::setfill('0')
360 << (addr - i.second.first)).str();
363 //Fallback.
364 return hex::to(addr);
367 namespace
369 typedef void (wxwindow_memorysearch::*pokefn_t)(uint64_t);
370 pokefn_t pokes[] = {
371 &wxwindow_memorysearch::_do_poke_addr<int8_t>,
372 &wxwindow_memorysearch::_do_poke_addr<uint8_t>,
373 &wxwindow_memorysearch::_do_poke_addr<int16_t>,
374 &wxwindow_memorysearch::_do_poke_addr<uint16_t>,
375 &wxwindow_memorysearch::_do_poke_addr<ss_int24_t>,
376 &wxwindow_memorysearch::_do_poke_addr<ss_uint24_t>,
377 &wxwindow_memorysearch::_do_poke_addr<int32_t>,
378 &wxwindow_memorysearch::_do_poke_addr<uint32_t>,
379 &wxwindow_memorysearch::_do_poke_addr<int64_t>,
380 &wxwindow_memorysearch::_do_poke_addr<uint64_t>,
381 &wxwindow_memorysearch::_do_poke_addr<float>,
382 &wxwindow_memorysearch::_do_poke_addr<double>,
385 typedef std::string (wxwindow_memorysearch::*displayfn_t)(uint64_t, bool hexmode, bool old);
386 displayfn_t displays[] = {
387 &wxwindow_memorysearch::_do_format_signed<uint8_t>,
388 &wxwindow_memorysearch::_do_format_unsigned<uint8_t>,
389 &wxwindow_memorysearch::_do_format_signed<uint16_t>,
390 &wxwindow_memorysearch::_do_format_unsigned<uint16_t>,
391 &wxwindow_memorysearch::_do_format_signed<ss_uint24_t>,
392 &wxwindow_memorysearch::_do_format_unsigned<ss_uint24_t>,
393 &wxwindow_memorysearch::_do_format_signed<uint32_t>,
394 &wxwindow_memorysearch::_do_format_unsigned<uint32_t>,
395 &wxwindow_memorysearch::_do_format_signed<uint64_t>,
396 &wxwindow_memorysearch::_do_format_unsigned<uint64_t>,
397 &wxwindow_memorysearch::_do_format_float<float>,
398 &wxwindow_memorysearch::_do_format_float<double>,
401 struct searchtype searchtbl[] = {
403 "value", {
404 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
405 &memory_search::s_value<uint8_t>>,
406 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
407 &memory_search::s_value<uint8_t>>,
408 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
409 &memory_search::s_value<uint16_t>>,
410 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
411 &memory_search::s_value<uint16_t>>,
412 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
413 &memory_search::s_value<ss_uint24_t>>,
414 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
415 &memory_search::s_value<ss_uint24_t>>,
416 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
417 &memory_search::s_value<uint32_t>>,
418 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
419 &memory_search::s_value<uint32_t>>,
420 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
421 &memory_search::s_value<uint64_t>>,
422 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
423 &memory_search::s_value<uint64_t>>,
424 &wxwindow_memorysearch::search_1<float, float,
425 &memory_search::s_value<float>>,
426 &wxwindow_memorysearch::search_1<double, double,
427 &memory_search::s_value<double>>
430 "diff.", {
431 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
432 &memory_search::s_difference<uint8_t>>,
433 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
434 &memory_search::s_difference<uint8_t>>,
435 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
436 &memory_search::s_difference<uint16_t>>,
437 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
438 &memory_search::s_difference<uint16_t>>,
439 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
440 &memory_search::s_difference<ss_uint24_t>>,
441 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
442 &memory_search::s_difference<ss_uint24_t>>,
443 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
444 &memory_search::s_difference<uint32_t>>,
445 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
446 &memory_search::s_difference<uint32_t>>,
447 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
448 &memory_search::s_difference<uint64_t>>,
449 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
450 &memory_search::s_difference<uint64_t>>,
451 &wxwindow_memorysearch::search_1<float, float,
452 &memory_search::s_difference<float>>,
453 &wxwindow_memorysearch::search_1<double, double,
454 &memory_search::s_difference<double>>
457 "<", {
458 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int8_t>>,
459 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint8_t>>,
460 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int16_t>>,
461 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint16_t>>,
462 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_int24_t>>,
463 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_uint24_t>>,
464 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int32_t>>,
465 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint32_t>>,
466 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int64_t>>,
467 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint64_t>>,
468 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
469 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
472 "<=", {
473 &wxwindow_memorysearch::search_0<&memory_search::s_le<int8_t>>,
474 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint8_t>>,
475 &wxwindow_memorysearch::search_0<&memory_search::s_le<int16_t>>,
476 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint16_t>>,
477 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_int24_t>>,
478 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_uint24_t>>,
479 &wxwindow_memorysearch::search_0<&memory_search::s_le<int32_t>>,
480 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint32_t>>,
481 &wxwindow_memorysearch::search_0<&memory_search::s_le<int64_t>>,
482 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint64_t>>,
483 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
484 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
487 "==", {
488 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int8_t>>,
489 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint8_t>>,
490 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int16_t>>,
491 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint16_t>>,
492 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_int24_t>>,
493 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_uint24_t>>,
494 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int32_t>>,
495 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint32_t>>,
496 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int64_t>>,
497 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint64_t>>,
498 &wxwindow_memorysearch::search_0<&memory_search::s_eq<float>>,
499 &wxwindow_memorysearch::search_0<&memory_search::s_eq<double>>
502 "!=", {
503 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int8_t>>,
504 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint8_t>>,
505 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int16_t>>,
506 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint16_t>>,
507 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_int24_t>>,
508 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_uint24_t>>,
509 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int32_t>>,
510 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint32_t>>,
511 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int64_t>>,
512 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint64_t>>,
513 &wxwindow_memorysearch::search_0<&memory_search::s_ne<float>>,
514 &wxwindow_memorysearch::search_0<&memory_search::s_ne<double>>
517 ">=", {
518 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int8_t>>,
519 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint8_t>>,
520 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int16_t>>,
521 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint16_t>>,
522 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_int24_t>>,
523 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_uint24_t>>,
524 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int32_t>>,
525 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint32_t>>,
526 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int64_t>>,
527 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint64_t>>,
528 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
529 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
532 ">", {
533 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int8_t>>,
534 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint8_t>>,
535 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int16_t>>,
536 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint16_t>>,
537 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_int24_t>>,
538 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_uint24_t>>,
539 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int32_t>>,
540 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint32_t>>,
541 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int64_t>>,
542 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint64_t>>,
543 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
544 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
547 "seq<", {
548 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
549 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
550 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
551 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
552 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_int24_t>>,
553 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_uint24_t>>,
554 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
555 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
556 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
557 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
558 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
559 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
562 "seq<=", {
563 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
564 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
565 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
566 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
567 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_int24_t>>,
568 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_uint24_t>>,
569 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
570 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
571 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
572 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
573 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
574 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
577 "seq>=", {
578 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
579 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
580 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
581 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
582 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_int24_t>>,
583 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_uint24_t>>,
584 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
585 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
586 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
587 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
588 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
589 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
592 "seq>", {
593 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
594 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
595 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
596 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
597 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_int24_t>>,
598 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_uint24_t>>,
599 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
600 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
601 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
602 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
603 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
604 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
607 "true", {
608 &wxwindow_memorysearch::search_0<&memory_search::update>,
609 &wxwindow_memorysearch::search_0<&memory_search::update>,
610 &wxwindow_memorysearch::search_0<&memory_search::update>,
611 &wxwindow_memorysearch::search_0<&memory_search::update>,
612 &wxwindow_memorysearch::search_0<&memory_search::update>,
613 &wxwindow_memorysearch::search_0<&memory_search::update>,
614 &wxwindow_memorysearch::search_0<&memory_search::update>,
615 &wxwindow_memorysearch::search_0<&memory_search::update>,
616 &wxwindow_memorysearch::search_0<&memory_search::update>,
617 &wxwindow_memorysearch::search_0<&memory_search::update>,
618 &wxwindow_memorysearch::search_0<&memory_search::update>,
619 &wxwindow_memorysearch::search_0<&memory_search::update>
625 wxwindow_memorysearch::wxwindow_memorysearch(emulator_instance& _inst)
626 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
627 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX), inst(_inst)
629 CHECK_UI_THREAD;
630 typecode = 0;
631 wxButton* tmp;
632 Centre();
633 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
634 msearch = new memory_search(*inst.memory);
636 wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
637 SetSizer(toplevel);
639 wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
640 buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
641 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
642 NULL, this);
643 buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
644 wxString _datatypes[DATATYPES];
645 for(size_t i = 0; i < DATATYPES; i++)
646 _datatypes[i] = towxstring(datatypes[i]);
647 buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
648 wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
649 wxGROW);
650 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
651 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
652 buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
653 buttons->Add(autoupdate = new wxCheckBox(this, wxID_AUTOUPDATE, wxT("Update automatically")), 0, wxGROW);
654 autoupdate->SetValue(true);
655 hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
656 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
657 toplevel->Add(buttons);
659 wxFlexGridSizer* searches = new wxFlexGridSizer(0, 6, 0, 0);
660 for(unsigned j = 0; j < sizeof(searchtbl)/sizeof(searchtbl[0]); j++) {
661 std::string name = searchtbl[j].name;
662 searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(name)), 1, wxGROW);
663 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
664 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
666 toplevel->Add(searches);
668 toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXXXXX candidates")), 0, wxGROW);
669 wxBoxSizer* matchesb = new wxBoxSizer(wxHORIZONTAL);
670 matchesb->Add(matches = new panel(this, inst), 1, wxGROW);
671 matchesb->Add(scroll = new scroll_bar(this, wxID_ANY, true), 0, wxGROW);
672 toplevel->Add(matchesb, 1, wxGROW);
674 scroll->set_page_size(matches->get_characters().second);
676 for(auto i : inst.memory->get_regions()) {
677 if(memory_search::searchable_region(i))
678 vmas_enabled.insert(i->name);
679 vma_info[i->name] = std::make_pair(i->base, i->size);
682 wxMenuBar* menubar = new wxMenuBar();
683 SetMenuBar(menubar);
684 wxMenu* filemenu = new wxMenu();
685 filemenu->Append(wxID_MENU_DUMP_CANDIDATES, wxT("Dump candidates..."));
686 filemenu->AppendSeparator();
687 filemenu->Append(wxID_MENU_SAVE_PREVMEM, wxT("Save previous memory..."));
688 filemenu->Append(wxID_MENU_SAVE_SET, wxT("Save set of addresses..."));
689 filemenu->Append(wxID_MENU_SAVE_ALL, wxT("Save previous memory and set of addresses..."));
690 filemenu->AppendSeparator();
691 filemenu->Append(wxID_MENU_LOAD, wxT("Load save..."));
692 menubar->Append(filemenu, wxT("File"));
693 wxMenu* editmenu = new wxMenu();
694 undoitem = editmenu->Append(wxID_UNDO, wxT("Undo"));
695 redoitem = editmenu->Append(wxID_REDO, wxT("Redo"));
696 undoitem->Enable(false);
697 redoitem->Enable(false);
698 menubar->Append(editmenu, wxT("Edit"));
699 Connect(wxID_MENU_DUMP_CANDIDATES, wxEVT_COMMAND_MENU_SELECTED,
700 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
701 Connect(wxID_MENU_SAVE_PREVMEM, wxEVT_COMMAND_MENU_SELECTED,
702 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
703 Connect(wxID_MENU_SAVE_SET, wxEVT_COMMAND_MENU_SELECTED,
704 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
705 Connect(wxID_MENU_SAVE_ALL, wxEVT_COMMAND_MENU_SELECTED,
706 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
707 Connect(wxID_MENU_LOAD, wxEVT_COMMAND_MENU_SELECTED,
708 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
709 Connect(wxID_UNDO, wxEVT_COMMAND_MENU_SELECTED,
710 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
711 Connect(wxID_REDO, wxEVT_COMMAND_MENU_SELECTED,
712 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
714 dragging = false;
715 toomany = true;
716 matches->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
717 matches->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
718 matches->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
719 matches->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
720 matches->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
721 matches->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
722 matches->Connect(wxEVT_MOTION, wxMouseEventHandler(wxwindow_memorysearch::on_mousedrag), NULL, this);
723 matches->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
724 scroll->set_handler([this](scroll_bar& s) { this->matches->request_paint(); });
726 toplevel->SetSizeHints(this);
727 Fit();
728 update();
729 Fit();
730 hexmode = false;
733 wxwindow_memorysearch::panel::panel(wxwindow_memorysearch* _parent, emulator_instance& _inst)
734 : text_framebuffer_panel(_parent, 40, 25, wxID_ANY, NULL), inst(_inst)
736 parent = _parent;
737 first_sel = 0;
738 last_sel = 0;
741 void wxwindow_memorysearch::panel::prepare_paint()
743 CHECK_UI_THREAD;
744 uint64_t first = parent->scroll->get_position();
745 auto ssize = get_characters();
746 uint64_t last = first + ssize.second;
747 std::vector<std::string> lines;
748 lines.reserve(ssize.second);
749 std::map<uint64_t, uint64_t> addrs;
750 auto* ms = parent->msearch;
751 uint64_t addr_count;
752 bool toomany = false;
753 auto _parent = parent;
754 inst.iqueue->run([&toomany, &first, &last, ms, &lines, &addrs, &addr_count, _parent]() {
755 addr_count = ms->get_candidate_count();
756 if(last > addr_count) {
757 uint64_t delta = last - addr_count;
758 if(first > delta) {
759 first -= delta;
760 last -= delta;
761 } else {
762 last -= first;
763 first = 0;
766 if(addr_count <= CANDIDATE_LIMIT) {
767 std::list<uint64_t> addrs2 = ms->get_candidates();
768 unsigned long j = 0;
769 for(auto i : addrs2) {
770 std::string row = _parent->format_address(i) + " ";
771 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, false);
772 row += " (Was: ";
773 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, true);
774 row += ')';
775 if(j >= first && j < last)
776 lines.push_back(row);
777 addrs[j++] = i;
779 } else {
780 lines.push_back("Too many candidates to display");
781 toomany = true;
784 std::swap(parent->addresses, addrs);
786 std::ostringstream x;
787 x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
788 parent->count->SetLabel(towxstring(x.str()));
790 clear();
791 for(unsigned i = 0; i < lines.size(); i++) {
792 bool sel = (first + i) >= first_sel && (first + i) < last_sel;
793 write(lines[i], 0, 0, i, sel ? 0xFFFFFF : 0, sel ? 0 : 0xFFFFFF);
796 if(last_sel > last)
797 last_sel = last;
798 if(first_sel > last)
799 first_sel = last;
801 parent->toomany = toomany;
802 parent->scroll->set_range(toomany ? 0 : addr_count);
805 void wxwindow_memorysearch::panel::set_selection(uint64_t first, uint64_t last)
807 first_sel = first;
808 last_sel = last;
809 request_paint();
812 void wxwindow_memorysearch::panel::get_selection(uint64_t& first, uint64_t& last)
814 first = first_sel;
815 last = last_sel;
818 wxwindow_memorysearch::~wxwindow_memorysearch()
820 delete msearch;
821 mwatch.remove(inst);
824 bool wxwindow_memorysearch::ShouldPreventAppExit() const
826 return false;
829 void wxwindow_memorysearch::dump_candidates_text()
831 try {
832 std::string filename = choose_file_save(this, "Dump memory search",
833 UI_get_project_otherpath(inst), filetype_textfile);
834 std::ofstream out(filename);
835 auto ms = msearch;
836 inst.iqueue->run([ms, this, &out]() {
837 std::list<uint64_t> addrs2 = ms->get_candidates();
838 for(auto i : addrs2) {
839 std::string row = format_address(i) + " ";
840 row += (this->*displays[this->typecode])(i, this->hexmode, false);
841 row += " (Was: ";
842 row += (this->*displays[this->typecode])(i, this->hexmode, true);
843 row += ')';
844 out << row << std::endl;
847 if(!out)
848 throw std::runtime_error("Can't write save file");
849 } catch(canceled_exception& e) {
850 } catch(std::exception& e) {
851 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
852 return;
856 void wxwindow_memorysearch::handle_save(memory_search::savestate_type type)
858 try {
859 std::vector<char> state;
860 msearch->savestate(state, type);
861 std::string filename = choose_file_save(this, "Save memory search",
862 UI_get_project_otherpath(inst), filetype_memorysearch);
863 std::ofstream out(filename, std::ios::binary);
864 out.write(&state[0], state.size());
865 if(!out)
866 throw std::runtime_error("Can't write save file");
867 } catch(canceled_exception& e) {
868 } catch(std::exception& e) {
869 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
870 return;
874 void wxwindow_memorysearch::handle_load()
876 try {
877 std::string filename = choose_file_load(this, "Load memory search",
878 UI_get_project_otherpath(inst), filetype_memorysearch);
879 std::vector<char> state = zip::readrel(filename, "");
880 push_undo();
881 msearch->loadstate(state);
882 update();
883 } catch(canceled_exception& e) {
884 } catch(std::exception& e) {
885 show_message_ok(this, "Load error", std::string(e.what()), wxICON_WARNING);
886 return;
890 void wxwindow_memorysearch::handle_undo_redo(bool redo)
892 std::list<std::vector<char>>& a = *(redo ? &redohistory : &undohistory);
893 std::list<std::vector<char>>& b = *(redo ? &undohistory : &redohistory);
894 if(!a.size()) {
895 show_message_ok(this, "Undo/Redo error", "Can't find state to undo/redo to", wxICON_WARNING);
896 return;
898 bool pushed = false;
899 try {
900 std::vector<char> state;
901 msearch->savestate(state, memory_search::ST_SET);
902 b.push_back(state);
903 pushed = true;
904 msearch->loadstate(a.back());
905 a.pop_back();
906 } catch(std::exception& e) {
907 if(pushed)
908 b.pop_back();
909 show_message_ok(this, "Undo/Redo error", std::string(e.what()), wxICON_WARNING);
910 return;
912 undoitem->Enable(undohistory.size());
913 redoitem->Enable(redohistory.size());
914 update();
917 void wxwindow_memorysearch::push_undo()
919 try {
920 std::vector<char> state;
921 msearch->savestate(state, memory_search::ST_SET);
922 undohistory.push_back(state);
923 if(undohistory.size() > UNDOHISTORY_MAXSIZE)
924 undohistory.pop_front();
925 redohistory.clear();
926 undoitem->Enable(undohistory.size());
927 redoitem->Enable(redohistory.size());
928 } catch(...) {
932 void wxwindow_memorysearch::on_mouse(wxMouseEvent& e)
934 CHECK_UI_THREAD;
935 if(e.RightUp() || (e.LeftUp() && e.ControlDown()))
936 on_mouse2(e);
937 else if(e.LeftDown())
938 on_mouse0(e, true);
939 else if(e.LeftUp())
940 on_mouse0(e, false);
941 unsigned speed = 1;
942 if(e.ShiftDown())
943 speed = 10;
944 if(e.ShiftDown() && e.ControlDown())
945 speed = 50;
946 scroll->apply_wheel(e.GetWheelRotation(), e.GetWheelDelta(), speed);
949 void wxwindow_memorysearch::on_mouse0(wxMouseEvent& e, bool polarity)
951 CHECK_UI_THREAD;
952 dragging = polarity && !toomany;
953 if(dragging) {
954 mpx = e.GetX();
955 mpy = e.GetY();
956 uint64_t first = scroll->get_position();
957 drag_startline = first + e.GetY() / matches->get_cell().second;
958 } else if(mpx == e.GetX() && mpy == e.GetY()) {
959 matches->set_selection(0, 0);
963 void wxwindow_memorysearch::on_mousedrag(wxMouseEvent& e)
965 CHECK_UI_THREAD;
966 if(!dragging)
967 return;
968 uint64_t first = scroll->get_position();
969 uint64_t linenow = first + e.GetY() / matches->get_cell().second;
970 if(drag_startline < linenow)
971 matches->set_selection(drag_startline, linenow + 1);
972 else
973 matches->set_selection(linenow, drag_startline + 1);
976 void wxwindow_memorysearch::on_mouse2(wxMouseEvent& e)
978 CHECK_UI_THREAD;
979 wxMenu menu;
980 bool some_selected;
981 uint64_t selcount = 0;
982 uint64_t start, end;
983 matches->get_selection(start, end);
984 some_selected = (start < end);
985 if(!some_selected) {
986 uint64_t first = scroll->get_position();
987 act_line = first + e.GetY() / matches->get_cell().second;
988 if(addresses.count(act_line)) {
989 some_selected = true;
990 selcount++;
993 menu.Append(wxID_ADD, wxT("Add watch..."))->Enable(some_selected);
994 menu.Append(wxID_SHOW_HEXEDITOR, wxT("Select in hex editor"))->Enable(selcount == 1 &&
995 wxeditor_hexeditor_available(inst));
996 menu.Append(wxID_POKE, wxT("Poke..."))->Enable(selcount == 1);
997 menu.AppendSeparator();
998 menu.Append(wxID_DISQUALIFY, wxT("Disqualify"))->Enable(some_selected);
999 menu.AppendSeparator();
1000 menu.Append(wxID_UPDATE, wxT("Update"));
1001 menu.Append(wxID_SET_REGIONS, wxT("Enabled VMAs"));
1002 menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
1003 NULL, this);
1004 PopupMenu(&menu);
1007 void wxwindow_memorysearch::on_close(wxCloseEvent& e)
1009 CHECK_UI_THREAD;
1010 Destroy();
1013 void wxwindow_memorysearch::auto_update()
1015 CHECK_UI_THREAD;
1016 if(autoupdate->GetValue())
1017 update();
1020 void wxwindow_memorysearch::update()
1022 matches->request_paint();
1025 void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
1027 CHECK_UI_THREAD;
1028 int id = e.GetId();
1029 if(id == wxID_RESET) {
1030 push_undo();
1031 msearch->reset();
1032 //Update all VMA info too.
1033 for(auto i : inst.memory->get_regions()) {
1034 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1035 msearch->dq_range(i->base, i->last_address());
1036 vma_info[i->name] = std::make_pair(i->base, i->size);
1038 wxeditor_hexeditor_update(inst);
1039 } else if(id == wxID_UPDATE) {
1040 update();
1041 } else if(id == wxID_TYPESELECT) {
1042 wxString c = type->GetValue();
1043 for(unsigned i = 0; i < DATATYPES; i++)
1044 if(c == towxstring(datatypes[i]))
1045 typecode = i;
1046 } else if(id == wxID_HEX_SELECT) {
1047 hexmode = hexmode2->GetValue();
1048 } else if(id == wxID_ADD) {
1049 uint64_t start, end;
1050 matches->get_selection(start, end);
1051 if(start == end) {
1052 start = act_line;
1053 end = act_line + 1;
1055 for(uint64_t r = start; r < end; r++) {
1056 if(!addresses.count(r))
1057 continue;
1058 uint64_t addr = addresses[r];
1059 try {
1060 std::string n = pick_text(this, "Name for watch", (stringfmt()
1061 << "Enter name for watch at 0x" << std::hex << addr << ":").str());
1062 if(n == "")
1063 continue;
1064 memwatch_item e;
1065 e.expr = (stringfmt() << addr).str();
1066 bool is_hex = hexmode2->GetValue();
1067 e.bytes = watch_properties[typecode].len;
1068 e.signed_flag = !is_hex && (watch_properties[typecode].type == 1);
1069 e.float_flag = (watch_properties[typecode].type == 2);
1070 if(e.float_flag) is_hex = false;
1071 e.format = is_hex ? watch_properties[typecode].hformat : "";
1072 auto i = inst.memory->get_regions();
1073 int endianess = 0;
1074 for(auto& j : i) {
1075 if(addr >= j->base && addr < j->base + j->size)
1076 endianess = j->endian;
1078 e.endianess = endianess;
1079 inst.iqueue->run([n, &e]() { CORE().mwatch->set(n, e); });
1080 } catch(canceled_exception& e) {
1083 matches->set_selection(0, 0);
1084 } else if(id == wxID_DISQUALIFY) {
1085 uint64_t start, end;
1086 matches->get_selection(start, end);
1087 if(start == end) {
1088 start = act_line;
1089 end = act_line + 1;
1091 push_undo();
1092 for(uint64_t r = start; r < end; r++) {
1093 if(!addresses.count(r))
1094 return;
1095 uint64_t addr = addresses[r];
1096 auto ms = msearch;
1097 inst.iqueue->run([addr, ms]() { ms->dq_range(addr, addr); });
1099 matches->set_selection(0, 0);
1100 wxeditor_hexeditor_update(inst);
1101 } else if(id == wxID_SET_REGIONS) {
1102 wxwindow_memorysearch_vmasel* d = new wxwindow_memorysearch_vmasel(this, inst, vmas_enabled);
1103 if(d->ShowModal() == wxID_OK)
1104 vmas_enabled = d->get_vmas();
1105 else {
1106 d->Destroy();
1107 return;
1109 d->Destroy();
1110 push_undo();
1111 for(auto i : inst.memory->get_regions())
1112 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1113 msearch->dq_range(i->base, i->last_address());
1114 wxeditor_hexeditor_update(inst);
1115 } else if(id == wxID_POKE) {
1116 uint64_t start, end;
1117 matches->get_selection(start, end);
1118 if(start == end) {
1119 start = act_line;
1120 end = act_line + 1;
1122 for(uint64_t r = start; r < end; r++) {
1123 if(!addresses.count(r))
1124 continue;
1125 uint64_t addr = addresses[r];
1126 try {
1127 (this->*(pokes[typecode]))(addr);
1128 } catch(canceled_exception& e) {
1130 return;
1132 } else if(id == wxID_SHOW_HEXEDITOR) {
1133 uint64_t start, end;
1134 matches->get_selection(start, end);
1135 if(start == end) {
1136 start = act_line;
1137 end = act_line + 1;
1139 for(uint64_t r = start; r < end; r++) {
1140 if(!addresses.count(r))
1141 continue;
1142 wxeditor_hexeditor_jumpto(inst, addresses[r]);
1143 return;
1145 } else if(id >= wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE +
1146 (ssize_t)(sizeof(searchtbl)/sizeof(searchtbl[0]))) {
1147 int button = id - wxID_BUTTONS_BASE;
1148 push_undo();
1149 uint64_t old_count = msearch->get_candidate_count();
1150 (this->*(searchtbl[button].searches[typecode]))();
1151 uint64_t new_count = msearch->get_candidate_count();
1152 if(old_count == new_count) {
1153 undohistory.pop_back(); //Shouldn't be undoable.
1154 undoitem->Enable(undohistory.size());
1156 wxeditor_hexeditor_update(inst);
1157 } else if(id == wxID_MENU_DUMP_CANDIDATES) {
1158 dump_candidates_text();
1159 } else if(id == wxID_MENU_SAVE_PREVMEM) {
1160 handle_save(memory_search::ST_PREVMEM);
1161 } else if(id == wxID_MENU_SAVE_SET) {
1162 handle_save(memory_search::ST_SET);
1163 } else if(id == wxID_MENU_SAVE_ALL) {
1164 handle_save(memory_search::ST_ALL);
1165 } else if(id == wxID_MENU_LOAD) {
1166 handle_load();
1167 } else if(id == wxID_UNDO) {
1168 handle_undo_redo(false);
1169 } else if(id == wxID_REDO) {
1170 handle_undo_redo(true);
1172 update();
1175 template<typename T> void wxwindow_memorysearch::_do_poke_addr(uint64_t addr)
1177 CHECK_UI_THREAD;
1178 T val = msearch->v_read<T>(addr);
1179 std::string v;
1180 try {
1181 v = pick_text(this, "Poke value", (stringfmt() << "Enter value to poke to " << std::hex << "0x"
1182 << addr).str(), (stringfmt() << val).str(), false);
1183 val = parse_value<T>(v);
1184 } catch(canceled_exception& e) {
1185 return;
1186 } catch(...) {
1187 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1188 return;
1190 msearch->v_write<T>(addr, val);
1193 template<void(memory_search::*sfn)()> void wxwindow_memorysearch::search_0()
1195 (msearch->*sfn)();
1198 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void wxwindow_memorysearch::search_1()
1200 CHECK_UI_THREAD;
1201 bool bad = false;
1202 T val = promptvalue<T>(bad);
1203 if(bad)
1204 return;
1205 (msearch->*sfn)(static_cast<T2>(val));
1208 template<typename T> T wxwindow_memorysearch::promptvalue(bool& bad)
1210 CHECK_UI_THREAD;
1211 std::string v;
1212 wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
1213 wxT(""));
1214 if(d->ShowModal() == wxID_CANCEL) {
1215 bad = true;
1216 return 0;
1218 v = tostdstring(d->GetValue());
1219 d->Destroy();
1220 T val2;
1221 try {
1222 val2 = parse_value<T>(v);
1223 } catch(...) {
1224 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1225 bad = true;
1226 return 0;
1228 return val2;
1231 void wxwindow_memorysearch_display(emulator_instance& inst)
1233 CHECK_UI_THREAD;
1234 auto e = mwatch.lookup(inst);
1235 if(e) {
1236 e->Raise();
1237 return;
1239 mwatch.create(inst)->Show();
1242 void wxwindow_memorysearch_update(emulator_instance& inst)
1244 auto e = mwatch.lookup(inst);
1245 if(e) e->auto_update();
1248 memory_search* wxwindow_memorysearch_active(emulator_instance& inst)
1250 auto e = mwatch.lookup(inst);
1251 return e ? e->msearch : NULL;