Upload UI
[lsnes.git] / src / platform / wxwidgets / memorysearch.cpp
blob29b6aa3d2f42f9660ac8f877b4da4d6a8ce0d3d8
1 #include "core/dispatch.hpp"
2 #include "core/memorymanip.hpp"
3 #include "core/memorywatch.hpp"
4 #include "core/project.hpp"
5 #include "library/string.hpp"
6 #include "library/memorysearch.hpp"
7 #include "library/int24.hpp"
8 #include "library/zip.hpp"
10 #include "platform/wxwidgets/loadsave.hpp"
11 #include "platform/wxwidgets/platform.hpp"
12 #include "platform/wxwidgets/scrollbar.hpp"
13 #include "platform/wxwidgets/textrender.hpp"
15 #include <sstream>
16 #include <fstream>
17 #include <iomanip>
19 #include <wx/wx.h>
20 #include <wx/event.h>
21 #include <wx/control.h>
22 #include <wx/combobox.h>
24 #define wxID_RESET (wxID_HIGHEST + 1)
25 #define wxID_UPDATE (wxID_HIGHEST + 2)
26 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
27 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
28 #define wxID_ADD (wxID_HIGHEST + 5)
29 #define wxID_SET_REGIONS (wxID_HIGHEST + 6)
30 #define wxID_AUTOUPDATE (wxID_HIGHEST + 7)
31 #define wxID_DISQUALIFY (wxID_HIGHEST + 8)
32 #define wxID_POKE (wxID_HIGHEST + 9)
33 #define wxID_SHOW_HEXEDITOR (wxID_HIGHEST + 10)
34 #define wxID_MENU_SAVE_PREVMEM (wxID_HIGHEST + 11)
35 #define wxID_MENU_SAVE_SET (wxID_HIGHEST + 12)
36 #define wxID_MENU_SAVE_ALL (wxID_HIGHEST + 13)
37 #define wxID_MENU_LOAD (wxID_HIGHEST + 14)
38 #define wxID_MENU_UNDO (wxID_HIGHEST + 15)
39 #define wxID_MENU_REDO (wxID_HIGHEST + 16)
40 #define wxID_MENU_DUMP_CANDIDATES (wxID_HIGHEST + 17)
41 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
43 #define DATATYPES 12
44 #define CANDIDATE_LIMIT 512
46 class wxwindow_memorysearch;
47 memory_search* wxwindow_memorysearch_active();
49 namespace
51 unsigned UNDOHISTORY_MAXSIZE = 48;
52 const char* watchchars = "bBwWoOdDqQfF";
54 wxwindow_memorysearch* mwatch;
56 const char* datatypes[] = {
57 "signed byte",
58 "unsigned byte",
59 "signed word",
60 "unsigned word",
61 "signed hword",
62 "unsigned hword",
63 "signed dword",
64 "unsigned dword",
65 "signed qword",
66 "unsigned qword",
67 "float",
68 "double"
71 typedef void (wxwindow_memorysearch::*search_fn_t)();
73 struct searchtype
75 const char* name;
76 search_fn_t searches[DATATYPES];
79 std::string hexformat_address(uint64_t addr)
81 std::ostringstream x;
82 x << std::setfill('0') << std::setw(16) << std::hex << addr;
83 return x.str();
86 template<typename T> std::string format_number_signed(T val, bool hex);
87 template<typename T> std::string format_number_unsigned(T val, bool hex);
89 template<typename T> std::string format_number_signedh(T val, unsigned hwidth, bool hex)
91 std::ostringstream x;
92 if(hex) {
93 if(val >= 0)
94 x << "+" << std::setfill('0') << std::setw(hwidth) << std::hex <<
95 static_cast<uint64_t>(val);
96 else {
97 int64_t y2 = val;
98 uint64_t y = static_cast<uint64_t>(y2);
99 x << "-" << std::setfill('0') << std::setw(hwidth) << std::hex << (~y + 1);
101 } else
102 x << static_cast<int64_t>(val);
103 return x.str();
106 template<typename T> std::string format_number_unsignedh(T val, unsigned hwidth, bool hex)
108 std::ostringstream x;
109 if(hex)
110 x << std::setfill('0') << std::setw(hwidth) << std::hex << static_cast<uint64_t>(val);
111 else
112 x << static_cast<uint64_t>(val);
113 return x.str();
116 template<> std::string format_number_signed<uint8_t>(uint8_t val, bool hex)
118 return format_number_signedh(static_cast<int8_t>(val), 2, hex);
121 template<> std::string format_number_signed<uint16_t>(uint16_t val, bool hex)
123 return format_number_signedh(static_cast<int16_t>(val), 4, hex);
126 template<> std::string format_number_signed<ss_uint24_t>(ss_uint24_t val, bool hex)
128 return format_number_signedh((int32_t)(uint32_t)(val), 6, hex);
131 template<> std::string format_number_signed<uint32_t>(uint32_t val, bool hex)
133 return format_number_signedh(static_cast<int32_t>(val), 8, hex);
136 template<> std::string format_number_signed<uint64_t>(uint64_t val, bool hex)
138 return format_number_signedh(static_cast<int64_t>(val), 16, hex);
141 template<> std::string format_number_unsigned<uint8_t>(uint8_t val, bool hex)
143 return format_number_unsignedh(val, 2, hex);
146 template<> std::string format_number_unsigned<uint16_t>(uint16_t val, bool hex)
148 return format_number_unsignedh(val, 4, hex);
151 template<> std::string format_number_unsigned<ss_uint24_t>(ss_uint24_t val, bool hex)
153 return format_number_unsignedh(val, 6, hex);
156 template<> std::string format_number_unsigned<uint32_t>(uint32_t val, bool hex)
158 return format_number_unsignedh(val, 8, hex);
161 template<> std::string format_number_unsigned<uint64_t>(uint64_t val, bool hex)
163 return format_number_unsignedh(val, 16, hex);
166 std::string format_number_float(double val)
168 return (stringfmt() << val).str();
172 class wxwindow_memorysearch_vmasel : public wxDialog
174 public:
175 wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled);
176 bool ShouldPreventAppExit() const;
177 std::set<std::string> get_vmas();
178 void on_ok(wxCommandEvent& e);
179 void on_cancel(wxCommandEvent& e);
180 private:
181 std::set<std::string> vmas;
182 std::vector<wxCheckBox*> checkboxes;
183 wxButton* ok;
184 wxButton* cancel;
187 wxwindow_memorysearch_vmasel::wxwindow_memorysearch_vmasel(wxWindow* p, const std::set<std::string>& enabled)
188 : wxDialog(p, wxID_ANY, towxstring("lsnes: Select enabled regions"), wxDefaultPosition, wxSize(300, -1))
190 auto i = lsnes_memory.get_regions();
191 Centre();
192 wxFlexGridSizer* top_s = new wxFlexGridSizer(i.size() + 1, 1, 0, 0);
193 SetSizer(top_s);
194 for(auto j : i) {
195 if(j->readonly || j->special)
196 continue;
197 wxCheckBox* t;
198 top_s->Add(t = new wxCheckBox(this, wxID_ANY, towxstring(j->name)), 0, wxGROW);
199 if(enabled.count(j->name))
200 t->SetValue(true);
201 checkboxes.push_back(t);
203 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
204 pbutton_s->AddStretchSpacer();
205 pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
206 pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
207 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
208 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_ok), NULL, this);
209 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
210 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_cancel), NULL, this);
211 top_s->Add(pbutton_s);
213 pbutton_s->SetSizeHints(this);
214 top_s->SetSizeHints(this);
215 Fit();
218 bool wxwindow_memorysearch_vmasel::ShouldPreventAppExit() const
220 return false;
223 std::set<std::string> wxwindow_memorysearch_vmasel::get_vmas()
225 return vmas;
228 void wxwindow_memorysearch_vmasel::on_ok(wxCommandEvent& e)
230 for(auto i : checkboxes)
231 if(i->GetValue())
232 vmas.insert(tostdstring(i->GetLabel()));
233 EndModal(wxID_OK);
236 void wxwindow_memorysearch_vmasel::on_cancel(wxCommandEvent& e)
238 EndModal(wxID_CANCEL);
242 class wxwindow_memorysearch : public wxFrame
244 public:
245 class panel : public text_framebuffer_panel
247 public:
248 panel(wxwindow_memorysearch* parent);
249 void set_selection(uint64_t first, uint64_t last);
250 void get_selection(uint64_t& first, uint64_t& last);
251 protected:
252 void prepare_paint();
253 private:
254 wxwindow_memorysearch* parent;
255 uint64_t first_sel;
256 uint64_t last_sel;
258 wxwindow_memorysearch();
259 ~wxwindow_memorysearch();
260 bool ShouldPreventAppExit() const;
261 void on_close(wxCloseEvent& e);
262 void on_button_click(wxCommandEvent& e);
263 void auto_update();
264 void on_mousedrag(wxMouseEvent& e);
265 void on_mouse(wxMouseEvent& e);
266 bool update_queued;
267 template<void(memory_search::*sfn)()> void search_0();
268 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void search_1();
269 template<typename T> void _do_poke_addr(uint64_t addr);
270 template<typename T> std::string _do_format_signed(uint64_t addr, bool hex, bool old)
272 if(old)
273 return format_number_signed<T>(msearch->v_readold<T>(addr), hex);
274 else
275 return format_number_signed<T>(lsnes_memory.read<T>(addr), hex);
277 template<typename T> std::string _do_format_unsigned(uint64_t addr, bool hex, bool old)
279 if(old)
280 return format_number_unsigned<T>(msearch->v_readold<T>(addr), hex);
281 else
282 return format_number_unsigned<T>(lsnes_memory.read<T>(addr), hex);
284 template<typename T> std::string _do_format_float(uint64_t addr, bool hex, bool old)
286 if(old)
287 return format_number_float(msearch->v_readold<T>(addr));
288 else
289 return format_number_float(lsnes_memory.read<T>(addr));
291 void dump_candidates_text();
292 private:
293 friend memory_search* wxwindow_memorysearch_active();
294 friend class panel;
295 template<typename T> T promptvalue(bool& bad);
296 void update();
297 memory_search* msearch;
298 void on_mouse0(wxMouseEvent& e, bool polarity);
299 void on_mousedrag();
300 void on_mouse2(wxMouseEvent& e);
301 void handle_undo_redo(bool redo);
302 void push_undo();
303 void handle_save(memory_search::savestate_type type);
304 void handle_load();
305 wxStaticText* count;
306 scroll_bar* scroll;
307 panel* matches;
308 wxComboBox* type;
309 wxCheckBox* hexmode2;
310 wxCheckBox* autoupdate;
311 std::map<uint64_t, uint64_t> addresses;
312 uint64_t act_line;
313 uint64_t drag_startline;
314 bool dragging;
315 int mpx, mpy;
316 unsigned typecode;
317 bool hexmode;
318 bool toomany;
319 int scroll_delta;
320 std::set<std::string> vmas_enabled;
321 wxMenuItem* undoitem;
322 wxMenuItem* redoitem;
323 std::list<std::vector<char>> undohistory;
324 std::list<std::vector<char>> redohistory;
327 namespace
329 typedef void (wxwindow_memorysearch::*pokefn_t)(uint64_t);
330 pokefn_t pokes[] = {
331 &wxwindow_memorysearch::_do_poke_addr<int8_t>,
332 &wxwindow_memorysearch::_do_poke_addr<uint8_t>,
333 &wxwindow_memorysearch::_do_poke_addr<int16_t>,
334 &wxwindow_memorysearch::_do_poke_addr<uint16_t>,
335 &wxwindow_memorysearch::_do_poke_addr<ss_int24_t>,
336 &wxwindow_memorysearch::_do_poke_addr<ss_uint24_t>,
337 &wxwindow_memorysearch::_do_poke_addr<int32_t>,
338 &wxwindow_memorysearch::_do_poke_addr<uint32_t>,
339 &wxwindow_memorysearch::_do_poke_addr<int64_t>,
340 &wxwindow_memorysearch::_do_poke_addr<uint64_t>,
341 &wxwindow_memorysearch::_do_poke_addr<float>,
342 &wxwindow_memorysearch::_do_poke_addr<double>,
345 typedef std::string (wxwindow_memorysearch::*displayfn_t)(uint64_t, bool hexmode, bool old);
346 displayfn_t displays[] = {
347 &wxwindow_memorysearch::_do_format_signed<uint8_t>,
348 &wxwindow_memorysearch::_do_format_unsigned<uint8_t>,
349 &wxwindow_memorysearch::_do_format_signed<uint16_t>,
350 &wxwindow_memorysearch::_do_format_unsigned<uint16_t>,
351 &wxwindow_memorysearch::_do_format_signed<ss_uint24_t>,
352 &wxwindow_memorysearch::_do_format_unsigned<ss_uint24_t>,
353 &wxwindow_memorysearch::_do_format_signed<uint32_t>,
354 &wxwindow_memorysearch::_do_format_signed<uint32_t>,
355 &wxwindow_memorysearch::_do_format_unsigned<uint64_t>,
356 &wxwindow_memorysearch::_do_format_unsigned<uint64_t>,
357 &wxwindow_memorysearch::_do_format_float<float>,
358 &wxwindow_memorysearch::_do_format_float<double>,
361 struct searchtype searchtbl[] = {
363 "value", {
364 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
365 &memory_search::s_value<uint8_t>>,
366 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
367 &memory_search::s_value<uint8_t>>,
368 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
369 &memory_search::s_value<uint16_t>>,
370 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
371 &memory_search::s_value<uint16_t>>,
372 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
373 &memory_search::s_value<ss_uint24_t>>,
374 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
375 &memory_search::s_value<ss_uint24_t>>,
376 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
377 &memory_search::s_value<uint32_t>>,
378 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
379 &memory_search::s_value<uint32_t>>,
380 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
381 &memory_search::s_value<uint64_t>>,
382 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
383 &memory_search::s_value<uint64_t>>,
384 &wxwindow_memorysearch::search_1<float, float,
385 &memory_search::s_value<float>>,
386 &wxwindow_memorysearch::search_1<double, double,
387 &memory_search::s_value<double>>
390 "diff.", {
391 &wxwindow_memorysearch::search_1<int8_t, uint8_t,
392 &memory_search::s_difference<uint8_t>>,
393 &wxwindow_memorysearch::search_1<uint8_t, uint8_t,
394 &memory_search::s_difference<uint8_t>>,
395 &wxwindow_memorysearch::search_1<int16_t, uint16_t,
396 &memory_search::s_difference<uint16_t>>,
397 &wxwindow_memorysearch::search_1<uint16_t, uint16_t,
398 &memory_search::s_difference<uint16_t>>,
399 &wxwindow_memorysearch::search_1<ss_int24_t, ss_uint24_t,
400 &memory_search::s_difference<ss_uint24_t>>,
401 &wxwindow_memorysearch::search_1<ss_uint24_t, ss_uint24_t,
402 &memory_search::s_difference<ss_uint24_t>>,
403 &wxwindow_memorysearch::search_1<int32_t, uint32_t,
404 &memory_search::s_difference<uint32_t>>,
405 &wxwindow_memorysearch::search_1<uint32_t, uint32_t,
406 &memory_search::s_difference<uint32_t>>,
407 &wxwindow_memorysearch::search_1<int64_t, uint64_t,
408 &memory_search::s_difference<uint64_t>>,
409 &wxwindow_memorysearch::search_1<uint64_t, uint64_t,
410 &memory_search::s_difference<uint64_t>>,
411 &wxwindow_memorysearch::search_1<float, float,
412 &memory_search::s_difference<float>>,
413 &wxwindow_memorysearch::search_1<double, double,
414 &memory_search::s_difference<double>>
417 "<", {
418 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int8_t>>,
419 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint8_t>>,
420 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int16_t>>,
421 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint16_t>>,
422 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_int24_t>>,
423 &wxwindow_memorysearch::search_0<&memory_search::s_lt<ss_uint24_t>>,
424 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int32_t>>,
425 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint32_t>>,
426 &wxwindow_memorysearch::search_0<&memory_search::s_lt<int64_t>>,
427 &wxwindow_memorysearch::search_0<&memory_search::s_lt<uint64_t>>,
428 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
429 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
432 "<=", {
433 &wxwindow_memorysearch::search_0<&memory_search::s_le<int8_t>>,
434 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint8_t>>,
435 &wxwindow_memorysearch::search_0<&memory_search::s_le<int16_t>>,
436 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint16_t>>,
437 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_int24_t>>,
438 &wxwindow_memorysearch::search_0<&memory_search::s_le<ss_uint24_t>>,
439 &wxwindow_memorysearch::search_0<&memory_search::s_le<int32_t>>,
440 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint32_t>>,
441 &wxwindow_memorysearch::search_0<&memory_search::s_le<int64_t>>,
442 &wxwindow_memorysearch::search_0<&memory_search::s_le<uint64_t>>,
443 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
444 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
447 "==", {
448 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int8_t>>,
449 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint8_t>>,
450 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int16_t>>,
451 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint16_t>>,
452 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_int24_t>>,
453 &wxwindow_memorysearch::search_0<&memory_search::s_eq<ss_uint24_t>>,
454 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int32_t>>,
455 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint32_t>>,
456 &wxwindow_memorysearch::search_0<&memory_search::s_eq<int64_t>>,
457 &wxwindow_memorysearch::search_0<&memory_search::s_eq<uint64_t>>,
458 &wxwindow_memorysearch::search_0<&memory_search::s_eq<float>>,
459 &wxwindow_memorysearch::search_0<&memory_search::s_eq<double>>
462 "!=", {
463 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int8_t>>,
464 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint8_t>>,
465 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int16_t>>,
466 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint16_t>>,
467 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_int24_t>>,
468 &wxwindow_memorysearch::search_0<&memory_search::s_ne<ss_uint24_t>>,
469 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int32_t>>,
470 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint32_t>>,
471 &wxwindow_memorysearch::search_0<&memory_search::s_ne<int64_t>>,
472 &wxwindow_memorysearch::search_0<&memory_search::s_ne<uint64_t>>,
473 &wxwindow_memorysearch::search_0<&memory_search::s_ne<float>>,
474 &wxwindow_memorysearch::search_0<&memory_search::s_ne<double>>
477 ">=", {
478 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int8_t>>,
479 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint8_t>>,
480 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int16_t>>,
481 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint16_t>>,
482 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_int24_t>>,
483 &wxwindow_memorysearch::search_0<&memory_search::s_ge<ss_uint24_t>>,
484 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int32_t>>,
485 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint32_t>>,
486 &wxwindow_memorysearch::search_0<&memory_search::s_ge<int64_t>>,
487 &wxwindow_memorysearch::search_0<&memory_search::s_ge<uint64_t>>,
488 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
489 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
492 ">", {
493 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int8_t>>,
494 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint8_t>>,
495 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int16_t>>,
496 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint16_t>>,
497 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_int24_t>>,
498 &wxwindow_memorysearch::search_0<&memory_search::s_gt<ss_uint24_t>>,
499 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int32_t>>,
500 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint32_t>>,
501 &wxwindow_memorysearch::search_0<&memory_search::s_gt<int64_t>>,
502 &wxwindow_memorysearch::search_0<&memory_search::s_gt<uint64_t>>,
503 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
504 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
507 "seq<", {
508 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
509 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint8_t>>,
510 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
511 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint16_t>>,
512 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_int24_t>>,
513 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<ss_uint24_t>>,
514 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
515 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint32_t>>,
516 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
517 &wxwindow_memorysearch::search_0<&memory_search::s_seqlt<uint64_t>>,
518 &wxwindow_memorysearch::search_0<&memory_search::s_lt<float>>,
519 &wxwindow_memorysearch::search_0<&memory_search::s_lt<double>>
522 "seq<=", {
523 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
524 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint8_t>>,
525 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
526 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint16_t>>,
527 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_int24_t>>,
528 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<ss_uint24_t>>,
529 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
530 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint32_t>>,
531 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
532 &wxwindow_memorysearch::search_0<&memory_search::s_seqle<uint64_t>>,
533 &wxwindow_memorysearch::search_0<&memory_search::s_le<float>>,
534 &wxwindow_memorysearch::search_0<&memory_search::s_le<double>>
537 "seq>=", {
538 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
539 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint8_t>>,
540 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
541 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint16_t>>,
542 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_int24_t>>,
543 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<ss_uint24_t>>,
544 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
545 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint32_t>>,
546 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
547 &wxwindow_memorysearch::search_0<&memory_search::s_seqge<uint64_t>>,
548 &wxwindow_memorysearch::search_0<&memory_search::s_ge<float>>,
549 &wxwindow_memorysearch::search_0<&memory_search::s_ge<double>>
552 "seq>", {
553 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
554 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint8_t>>,
555 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
556 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint16_t>>,
557 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_int24_t>>,
558 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<ss_uint24_t>>,
559 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
560 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint32_t>>,
561 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
562 &wxwindow_memorysearch::search_0<&memory_search::s_seqgt<uint64_t>>,
563 &wxwindow_memorysearch::search_0<&memory_search::s_gt<float>>,
564 &wxwindow_memorysearch::search_0<&memory_search::s_gt<double>>
567 "true", {
568 &wxwindow_memorysearch::search_0<&memory_search::update>,
569 &wxwindow_memorysearch::search_0<&memory_search::update>,
570 &wxwindow_memorysearch::search_0<&memory_search::update>,
571 &wxwindow_memorysearch::search_0<&memory_search::update>,
572 &wxwindow_memorysearch::search_0<&memory_search::update>,
573 &wxwindow_memorysearch::search_0<&memory_search::update>,
574 &wxwindow_memorysearch::search_0<&memory_search::update>,
575 &wxwindow_memorysearch::search_0<&memory_search::update>,
576 &wxwindow_memorysearch::search_0<&memory_search::update>,
577 &wxwindow_memorysearch::search_0<&memory_search::update>,
578 &wxwindow_memorysearch::search_0<&memory_search::update>,
579 &wxwindow_memorysearch::search_0<&memory_search::update>
585 wxwindow_memorysearch::wxwindow_memorysearch()
586 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Memory Search"), wxDefaultPosition, wxSize(-1, -1),
587 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
589 typecode = 0;
590 wxButton* tmp;
591 Centre();
592 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwindow_memorysearch::on_close));
593 msearch = new memory_search(lsnes_memory);
595 wxFlexGridSizer* toplevel = new wxFlexGridSizer(4, 1, 0, 0);
596 SetSizer(toplevel);
598 wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
599 buttons->Add(tmp = new wxButton(this, wxID_RESET, wxT("Reset")), 0, wxGROW);
600 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
601 NULL, this);
602 buttons->Add(new wxStaticText(this, wxID_ANY, wxT("Data type:")), 0, wxGROW);
603 wxString _datatypes[DATATYPES];
604 for(size_t i = 0; i < DATATYPES; i++)
605 _datatypes[i] = towxstring(datatypes[i]);
606 buttons->Add(type = new wxComboBox(this, wxID_TYPESELECT, _datatypes[typecode], wxDefaultPosition,
607 wxDefaultSize, DATATYPES, _datatypes, wxCB_READONLY), 0,
608 wxGROW);
609 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
610 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
611 buttons->Add(hexmode2 = new wxCheckBox(this, wxID_HEX_SELECT, wxT("Hex display")), 0, wxGROW);
612 buttons->Add(autoupdate = new wxCheckBox(this, wxID_AUTOUPDATE, wxT("Update automatically")), 0, wxGROW);
613 autoupdate->SetValue(true);
614 hexmode2->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
615 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
616 toplevel->Add(buttons);
618 wxFlexGridSizer* searches = new wxFlexGridSizer(0, 6, 0, 0);
619 for(unsigned j = 0; j < sizeof(searchtbl)/sizeof(searchtbl[0]); j++) {
620 std::string name = searchtbl[j].name;
621 searches->Add(tmp = new wxButton(this, wxID_BUTTONS_BASE + j, towxstring(name)), 1, wxGROW);
622 tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
623 wxCommandEventHandler(wxwindow_memorysearch::on_button_click), NULL, this);
625 toplevel->Add(searches);
627 toplevel->Add(count = new wxStaticText(this, wxID_ANY, wxT("XXXXXX candidates")), 0, wxGROW);
628 wxBoxSizer* matchesb = new wxBoxSizer(wxHORIZONTAL);
629 matchesb->Add(matches = new panel(this), 1, wxGROW);
630 matchesb->Add(scroll = new scroll_bar(this, wxID_ANY, true), 0, wxGROW);
631 toplevel->Add(matchesb, 1, wxGROW);
633 scroll->set_page_size(matches->get_characters().second);
635 for(auto i : lsnes_memory.get_regions())
636 if(memory_search::searchable_region(i))
637 vmas_enabled.insert(i->name);
639 wxMenuBar* menubar = new wxMenuBar();
640 SetMenuBar(menubar);
641 wxMenu* filemenu = new wxMenu();
642 filemenu->Append(wxID_MENU_DUMP_CANDIDATES, wxT("Dump candidates..."));
643 filemenu->AppendSeparator();
644 filemenu->Append(wxID_MENU_SAVE_PREVMEM, wxT("Save previous memory..."));
645 filemenu->Append(wxID_MENU_SAVE_SET, wxT("Save set of addresses..."));
646 filemenu->Append(wxID_MENU_SAVE_ALL, wxT("Save previous memory and set of addresses..."));
647 filemenu->AppendSeparator();
648 filemenu->Append(wxID_MENU_LOAD, wxT("Load save..."));
649 menubar->Append(filemenu, wxT("File"));
650 wxMenu* editmenu = new wxMenu();
651 undoitem = editmenu->Append(wxID_UNDO, wxT("Undo"));
652 redoitem = editmenu->Append(wxID_REDO, wxT("Redo"));
653 undoitem->Enable(false);
654 redoitem->Enable(false);
655 menubar->Append(editmenu, wxT("Edit"));
656 Connect(wxID_MENU_DUMP_CANDIDATES, wxEVT_COMMAND_MENU_SELECTED,
657 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
658 Connect(wxID_MENU_SAVE_PREVMEM, wxEVT_COMMAND_MENU_SELECTED,
659 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
660 Connect(wxID_MENU_SAVE_SET, wxEVT_COMMAND_MENU_SELECTED,
661 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
662 Connect(wxID_MENU_SAVE_ALL, wxEVT_COMMAND_MENU_SELECTED,
663 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
664 Connect(wxID_MENU_LOAD, wxEVT_COMMAND_MENU_SELECTED,
665 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
666 Connect(wxID_UNDO, wxEVT_COMMAND_MENU_SELECTED,
667 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
668 Connect(wxID_REDO, wxEVT_COMMAND_MENU_SELECTED,
669 wxCommandEventHandler(wxwindow_memorysearch::on_button_click));
671 dragging = false;
672 toomany = true;
673 matches->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
674 matches->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
675 matches->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
676 matches->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
677 matches->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
678 matches->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
679 matches->Connect(wxEVT_MOTION, wxMouseEventHandler(wxwindow_memorysearch::on_mousedrag), NULL, this);
680 matches->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxwindow_memorysearch::on_mouse), NULL, this);
681 scroll->set_handler([this](scroll_bar& s) { this->matches->request_paint(); });
683 toplevel->SetSizeHints(this);
684 Fit();
685 update();
686 Fit();
687 hexmode = false;
690 wxwindow_memorysearch::panel::panel(wxwindow_memorysearch* _parent)
691 : text_framebuffer_panel(_parent, 40, 25, wxID_ANY, NULL)
693 parent = _parent;
694 first_sel = 0;
695 last_sel = 0;
698 void wxwindow_memorysearch::panel::prepare_paint()
700 uint64_t first = parent->scroll->get_position();
701 auto ssize = get_characters();
702 uint64_t last = first + ssize.second;
703 std::vector<std::string> lines;
704 lines.reserve(ssize.second);
705 std::map<uint64_t, uint64_t> addrs;
706 auto* ms = parent->msearch;
707 uint64_t addr_count;
708 bool toomany = false;
709 auto _parent = parent;
710 runemufn([&toomany, &first, &last, ms, &lines, &addrs, &addr_count, _parent]() {
711 addr_count = ms->get_candidate_count();
712 if(last > addr_count) {
713 uint64_t delta = last - addr_count;
714 if(first > delta) {
715 first -= delta;
716 last -= delta;
717 } else {
718 last -= first;
719 first = 0;
722 if(addr_count <= CANDIDATE_LIMIT) {
723 std::list<uint64_t> addrs2 = ms->get_candidates();
724 long j = 0;
725 for(auto i : addrs2) {
726 std::string row = hexformat_address(i) + " ";
727 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, false);
728 row += " (Was: ";
729 row += (_parent->*displays[_parent->typecode])(i, _parent->hexmode, true);
730 row += ')';
731 if(j >= first && j < last)
732 lines.push_back(row);
733 addrs[j++] = i;
735 } else {
736 lines.push_back("Too many candidates to display");
737 toomany = true;
740 std::swap(parent->addresses, addrs);
742 std::ostringstream x;
743 x << addr_count << " " << ((addr_count != 1) ? "candidates" : "candidate");
744 parent->count->SetLabel(towxstring(x.str()));
746 clear();
747 for(unsigned i = 0; i < lines.size(); i++) {
748 bool sel = (first + i) >= first_sel && (first + i) < last_sel;
749 write(lines[i], 0, 0, i, sel ? 0xFFFFFF : 0, sel ? 0 : 0xFFFFFF);
752 if(last_sel > last)
753 last_sel = last;
754 if(first_sel > last)
755 first_sel = last;
757 parent->toomany = toomany;
758 parent->scroll->set_range(toomany ? 0 : addr_count);
761 void wxwindow_memorysearch::panel::set_selection(uint64_t first, uint64_t last)
763 first_sel = first;
764 last_sel = last;
765 request_paint();
768 void wxwindow_memorysearch::panel::get_selection(uint64_t& first, uint64_t& last)
770 first = first_sel;
771 last = last_sel;
774 wxwindow_memorysearch::~wxwindow_memorysearch()
776 delete msearch;
777 mwatch = NULL;
780 bool wxwindow_memorysearch::ShouldPreventAppExit() const
782 return false;
785 void wxwindow_memorysearch::dump_candidates_text()
787 try {
788 std::string filename = choose_file_save(this, "Dump memory search", project_otherpath(),
789 filetype_textfile);
790 std::ofstream out(filename);
791 auto ms = msearch;
792 runemufn([ms, this, &out]() {
793 std::list<uint64_t> addrs2 = ms->get_candidates();
794 long j = 0;
795 for(auto i : addrs2) {
796 std::string row = hexformat_address(i) + " ";
797 row += (this->*displays[this->typecode])(i, this->hexmode, false);
798 row += " (Was: ";
799 row += (this->*displays[this->typecode])(i, this->hexmode, true);
800 row += ')';
801 out << row << std::endl;
804 if(!out)
805 throw std::runtime_error("Can't write save file");
806 } catch(canceled_exception& e) {
807 } catch(std::exception& e) {
808 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
809 return;
813 void wxwindow_memorysearch::handle_save(memory_search::savestate_type type)
815 try {
816 std::vector<char> state;
817 msearch->savestate(state, type);
818 std::string filename = choose_file_save(this, "Save memory search", project_otherpath(),
819 filetype_memorysearch);
820 std::ofstream out(filename, std::ios::binary);
821 out.write(&state[0], state.size());
822 if(!out)
823 throw std::runtime_error("Can't write save file");
824 } catch(canceled_exception& e) {
825 } catch(std::exception& e) {
826 show_message_ok(this, "Save error", std::string(e.what()), wxICON_WARNING);
827 return;
831 void wxwindow_memorysearch::handle_load()
833 try {
834 std::string filename = choose_file_load(this, "Load memory search", project_otherpath(),
835 filetype_memorysearch);
836 std::vector<char> state = read_file_relative(filename, "");
837 push_undo();
838 msearch->loadstate(state);
839 update();
840 } catch(canceled_exception& e) {
841 } catch(std::exception& e) {
842 show_message_ok(this, "Load error", std::string(e.what()), wxICON_WARNING);
843 return;
847 void wxwindow_memorysearch::handle_undo_redo(bool redo)
849 std::list<std::vector<char>>& a = *(redo ? &redohistory : &undohistory);
850 std::list<std::vector<char>>& b = *(redo ? &undohistory : &redohistory);
851 if(!a.size()) {
852 show_message_ok(this, "Undo/Redo error", "Can't find state to undo/redo to", wxICON_WARNING);
853 return;
855 bool pushed = false;
856 try {
857 std::vector<char> state;
858 msearch->savestate(state, memory_search::ST_SET);
859 b.push_back(state);
860 pushed = true;
861 msearch->loadstate(a.back());
862 a.pop_back();
863 } catch(std::exception& e) {
864 if(pushed)
865 b.pop_back();
866 show_message_ok(this, "Undo/Redo error", std::string(e.what()), wxICON_WARNING);
867 return;
869 undoitem->Enable(undohistory.size());
870 redoitem->Enable(redohistory.size());
871 update();
874 void wxwindow_memorysearch::push_undo()
876 try {
877 std::vector<char> state;
878 msearch->savestate(state, memory_search::ST_SET);
879 undohistory.push_back(state);
880 if(undohistory.size() > UNDOHISTORY_MAXSIZE)
881 undohistory.pop_front();
882 redohistory.clear();
883 undoitem->Enable(undohistory.size());
884 redoitem->Enable(redohistory.size());
885 } catch(...) {
889 void wxwindow_memorysearch::on_mouse(wxMouseEvent& e)
891 if(e.RightUp() || (e.LeftUp() && e.ControlDown()))
892 on_mouse2(e);
893 else if(e.LeftDown())
894 on_mouse0(e, true);
895 else if(e.LeftUp())
896 on_mouse0(e, false);
897 unsigned speed = 1;
898 if(e.ShiftDown())
899 speed = 10;
900 if(e.ShiftDown() && e.ControlDown())
901 speed = 50;
902 scroll->apply_wheel(e.GetWheelRotation(), e.GetWheelDelta(), speed);
905 void wxwindow_memorysearch::on_mouse0(wxMouseEvent& e, bool polarity)
907 dragging = polarity && !toomany;
908 if(dragging) {
909 mpx = e.GetX();
910 mpy = e.GetY();
911 uint64_t first = scroll->get_position();
912 drag_startline = first + e.GetY() / matches->get_cell().second;
913 } else if(mpx == e.GetX() && mpy == e.GetY()) {
914 matches->set_selection(0, 0);
918 void wxwindow_memorysearch::on_mousedrag(wxMouseEvent& e)
920 if(!dragging)
921 return;
922 uint64_t first = scroll->get_position();
923 uint64_t linenow = first + e.GetY() / matches->get_cell().second;
924 if(drag_startline < linenow)
925 matches->set_selection(drag_startline, linenow + 1);
926 else
927 matches->set_selection(linenow, drag_startline + 1);
930 void wxwindow_memorysearch::on_mouse2(wxMouseEvent& e)
932 wxMenu menu;
933 bool some_selected;
934 uint64_t selcount = 0;
935 uint64_t start, end;
936 matches->get_selection(start, end);
937 some_selected = (start < end);
938 if(!some_selected) {
939 uint64_t first = scroll->get_position();
940 act_line = first + e.GetY() / matches->get_cell().second;
941 if(addresses.count(act_line)) {
942 some_selected = true;
943 selcount++;
946 menu.Append(wxID_ADD, wxT("Add watch..."))->Enable(some_selected);
947 menu.Append(wxID_SHOW_HEXEDITOR, wxT("Select in hex editor"))->Enable(selcount == 1 &&
948 wxeditor_hexeditor_available());
949 menu.Append(wxID_POKE, wxT("Poke..."))->Enable(selcount == 1);
950 menu.AppendSeparator();
951 menu.Append(wxID_DISQUALIFY, wxT("Disqualify"))->Enable(some_selected);
952 menu.AppendSeparator();
953 menu.Append(wxID_UPDATE, wxT("Update"));
954 menu.Append(wxID_SET_REGIONS, wxT("Enabled VMAs"));
955 menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxwindow_memorysearch::on_button_click),
956 NULL, this);
957 PopupMenu(&menu);
960 void wxwindow_memorysearch::on_close(wxCloseEvent& e)
962 Destroy();
963 mwatch = NULL;
966 void wxwindow_memorysearch::auto_update()
968 if(autoupdate->GetValue())
969 update();
972 void wxwindow_memorysearch::update()
974 matches->request_paint();
977 void wxwindow_memorysearch::on_button_click(wxCommandEvent& e)
979 int id = e.GetId();
980 if(id == wxID_RESET) {
981 push_undo();
982 msearch->reset();
983 for(auto i : lsnes_memory.get_regions())
984 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
985 msearch->dq_range(i->base, i->last_address());
986 wxeditor_hexeditor_update();
987 } else if(id == wxID_UPDATE) {
988 update();
989 } else if(id == wxID_TYPESELECT) {
990 wxString c = type->GetValue();
991 for(unsigned i = 0; i < DATATYPES; i++)
992 if(c == towxstring(datatypes[i]))
993 typecode = i;
994 } else if(id == wxID_HEX_SELECT) {
995 hexmode = hexmode2->GetValue();
996 } else if(id == wxID_ADD) {
997 uint64_t start, end;
998 matches->get_selection(start, end);
999 if(start == end) {
1000 start = act_line;
1001 end = act_line + 1;
1003 char wch = watchchars[typecode];
1004 for(long r = start; r < end; r++) {
1005 if(!addresses.count(r))
1006 continue;
1007 uint64_t addr = addresses[r];
1008 try {
1009 std::string n = pick_text(this, "Name for watch", (stringfmt()
1010 << "Enter name for watch at 0x" << std::hex << addr << ":").str());
1011 if(n == "")
1012 continue;
1013 std::string e = (stringfmt() << "C0x" << std::hex << addr << "z" << wch).str();
1014 runemufn([n, e]() { set_watchexpr_for(n, e); });
1015 } catch(canceled_exception& e) {
1018 matches->set_selection(0, 0);
1019 } else if(id == wxID_DISQUALIFY) {
1020 uint64_t start, end;
1021 matches->get_selection(start, end);
1022 if(start == end) {
1023 start = act_line;
1024 end = act_line + 1;
1026 push_undo();
1027 for(long r = start; r < end; r++) {
1028 if(!addresses.count(r))
1029 return;
1030 uint64_t addr = addresses[r];
1031 auto ms = msearch;
1032 runemufn([addr, ms]() { ms->dq_range(addr, addr); });
1034 matches->set_selection(0, 0);
1035 wxeditor_hexeditor_update();
1036 } else if(id == wxID_SET_REGIONS) {
1037 wxwindow_memorysearch_vmasel* d = new wxwindow_memorysearch_vmasel(this, vmas_enabled);
1038 if(d->ShowModal() == wxID_OK)
1039 vmas_enabled = d->get_vmas();
1040 else {
1041 d->Destroy();
1042 return;
1044 d->Destroy();
1045 push_undo();
1046 for(auto i : lsnes_memory.get_regions())
1047 if(memory_search::searchable_region(i) && !vmas_enabled.count(i->name))
1048 msearch->dq_range(i->base, i->last_address());
1049 wxeditor_hexeditor_update();
1050 } else if(id == wxID_POKE) {
1051 uint64_t start, end;
1052 matches->get_selection(start, end);
1053 if(start == end) {
1054 start = act_line;
1055 end = act_line + 1;
1057 for(long r = start; r < end; r++) {
1058 if(!addresses.count(r))
1059 continue;
1060 uint64_t addr = addresses[r];
1061 try {
1062 (this->*(pokes[typecode]))(addr);
1063 } catch(canceled_exception& e) {
1065 return;
1067 } else if(id == wxID_SHOW_HEXEDITOR) {
1068 uint64_t start, end;
1069 matches->get_selection(start, end);
1070 if(start == end) {
1071 start = act_line;
1072 end = act_line + 1;
1074 for(long r = start; r < end; r++) {
1075 if(!addresses.count(r))
1076 continue;
1077 wxeditor_hexeditor_jumpto(addresses[r]);
1078 return;
1080 } else if(id >= wxID_BUTTONS_BASE && id < wxID_BUTTONS_BASE + (sizeof(searchtbl)/sizeof(searchtbl[0]))) {
1081 int button = id - wxID_BUTTONS_BASE;
1082 push_undo();
1083 uint64_t old_count = msearch->get_candidate_count();
1084 (this->*(searchtbl[button].searches[typecode]))();
1085 uint64_t new_count = msearch->get_candidate_count();
1086 if(old_count == new_count) {
1087 undohistory.pop_back(); //Shouldn't be undoable.
1088 undoitem->Enable(undohistory.size());
1090 wxeditor_hexeditor_update();
1091 } else if(id == wxID_MENU_DUMP_CANDIDATES) {
1092 dump_candidates_text();
1093 } else if(id == wxID_MENU_SAVE_PREVMEM) {
1094 handle_save(memory_search::ST_PREVMEM);
1095 } else if(id == wxID_MENU_SAVE_SET) {
1096 handle_save(memory_search::ST_SET);
1097 } else if(id == wxID_MENU_SAVE_ALL) {
1098 handle_save(memory_search::ST_ALL);
1099 } else if(id == wxID_MENU_LOAD) {
1100 handle_load();
1101 } else if(id == wxID_UNDO) {
1102 handle_undo_redo(false);
1103 } else if(id == wxID_REDO) {
1104 handle_undo_redo(true);
1106 update();
1109 template<typename T> void wxwindow_memorysearch::_do_poke_addr(uint64_t addr)
1111 T val = msearch->v_read<T>(addr);
1112 std::string v;
1113 try {
1114 v = pick_text(this, "Poke value", (stringfmt() << "Enter value to poke to " << std::hex << "0x"
1115 << addr).str(), (stringfmt() << val).str(), false);
1116 val = parse_value<T>(v);
1117 } catch(canceled_exception& e) {
1118 return;
1119 } catch(...) {
1120 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1121 return;
1123 msearch->v_write<T>(addr, val);
1126 template<void(memory_search::*sfn)()> void wxwindow_memorysearch::search_0()
1128 (msearch->*sfn)();
1131 template<typename T, typename T2, void(memory_search::*sfn)(T2 val)> void wxwindow_memorysearch::search_1()
1133 bool bad = false;
1134 T val = promptvalue<T>(bad);
1135 if(bad)
1136 return;
1137 (msearch->*sfn)(static_cast<T2>(val));
1140 template<typename T> T wxwindow_memorysearch::promptvalue(bool& bad)
1142 std::string v;
1143 wxTextEntryDialog* d = new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
1144 wxT(""));
1145 if(d->ShowModal() == wxID_CANCEL) {
1146 bad = true;
1147 return 0;
1149 v = tostdstring(d->GetValue());
1150 d->Destroy();
1151 T val2;
1152 try {
1153 val2 = parse_value<T>(v);
1154 } catch(...) {
1155 wxMessageBox(towxstring("Bad value '" + v + "'"), _T("Error"), wxICON_WARNING | wxOK, this);
1156 bad = true;
1157 return 0;
1159 return val2;
1162 void wxwindow_memorysearch_display()
1164 if(mwatch) {
1165 mwatch->Raise();
1166 return;
1168 mwatch = new wxwindow_memorysearch();
1169 mwatch->Show();
1172 void wxwindow_memorysearch_update()
1174 if(mwatch)
1175 mwatch->auto_update();
1178 memory_search* wxwindow_memorysearch_active()
1180 if(mwatch)
1181 return mwatch->msearch;
1182 else
1183 return NULL;