Add <functional> to files that use std::function
[lsnes.git] / src / platform / wxwidgets / editor-memorywatch.cpp
blob0ed6902a8c06e08a5f006bfc3d1c99bfb91b7137
1 #include <functional>
2 #include <wx/wx.h>
3 #include <wx/statline.h>
4 #include <wx/event.h>
5 #include <wx/control.h>
6 #include <wx/combobox.h>
7 #include <wx/radiobut.h>
8 #include <wx/spinctrl.h>
10 #include "core/instance.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/memorywatch.hpp"
13 #include "core/memorymanip.hpp"
14 #include "core/ui-services.hpp"
15 #include "library/memoryspace.hpp"
16 #include "core/project.hpp"
18 #include "platform/wxwidgets/platform.hpp"
19 #include "platform/wxwidgets/loadsave.hpp"
21 #include "library/string.hpp"
22 #include "library/hex.hpp"
23 #include "interface/romtype.hpp"
27 std::string main_expr;
28 std::string format;
29 unsigned memread_bytes; //0 if not memory read.
30 bool memread_signed_flag;
31 bool memread_float_flag;
32 int memread_endianess;
33 uint64_t memread_scale_div;
34 uint64_t memread_addr_base;
35 uint64_t memread_addr_size;
36 enum position_category {
37 PC_DISABLED,
38 PC_MEMORYWATCH,
39 PC_ONSCREEN
40 } position;
41 std::string enabled; //Ignored for disabled.
42 std::string onscreen_xpos;
43 std::string onscreen_ypos;
44 bool onscreen_alt_origin_x;
45 bool onscreen_alt_origin_y;
46 bool onscreen_cliprange_x;
47 bool onscreen_cliprange_y;
48 std::string onscreen_font; //"" is system default.
49 int64_t onscreen_fg_color;
50 int64_t onscreen_bg_color;
51 int64_t onscreen_halo_color;
55 namespace
57 int log2i(uint64_t v)
59 unsigned l = 0;
60 while(v > 1) {
61 v >>= 1;
62 l++;
64 return l;
67 template<class T>
68 class label_control
70 public:
71 label_control()
73 lbl = NULL;
74 ctrl = NULL;
76 template<typename... U> label_control(wxWindow* parent, const std::string& label, U... args)
78 CHECK_UI_THREAD;
79 lbl = new wxStaticText(parent, wxID_ANY, towxstring(label));
80 ctrl = new T(parent, args...);
82 void show(bool state)
84 CHECK_UI_THREAD;
85 lbl->Show(state);
86 ctrl->Show(state);
88 void enable(bool state)
90 CHECK_UI_THREAD;
91 lbl->Enable(state);
92 ctrl->Enable(state);
94 void add(wxSizer* s, bool prop = false)
96 CHECK_UI_THREAD;
97 s->Add(lbl, 0, wxALIGN_CENTER_VERTICAL);
98 s->Add(ctrl, prop ? 1 : 0, wxGROW);
100 void add_cb(std::function<void(wxStaticText* l, T* c)> cb)
102 cb(lbl, ctrl);
104 wxStaticText* label() { return lbl; }
105 T* operator->() { return ctrl; }
106 private:
107 wxStaticText* lbl;
108 T* ctrl;
111 std::string format_color(int64_t x)
113 return framebuffer::color::stringify(x);
116 int64_t get_color(std::string x)
118 return framebuffer::color(x).asnumber();
122 class wxeditor_memorywatch : public wxDialog
124 public:
125 wxeditor_memorywatch(wxWindow* parent, emulator_instance& _inst, const std::string& name);
126 bool ShouldPreventAppExit() const;
127 void on_position_change(wxCommandEvent& e);
128 void on_fontsel(wxCommandEvent& e);
129 void on_ok(wxCommandEvent& e);
130 void on_cancel(wxCommandEvent& e);
131 void enable_condenable2(wxCommandEvent& e);
132 private:
133 void enable_for_pos(memwatch_printer::position_category p);
134 void enable_for_addr(bool is_addr);
135 void enable_for_vma(bool free, uint64_t _base, uint64_t _size);
136 void enable_condenable();
137 memwatch_printer::position_category get_poscategory();
138 emulator_instance& inst;
139 label_control<wxComboBox> type;
140 label_control<wxTextCtrl> expr;
141 label_control<wxTextCtrl> format;
142 label_control<wxComboBox> endianess;
143 label_control<wxSpinCtrl> scale;
144 label_control<wxComboBox> vma;
145 label_control<wxTextCtrl> addrbase;
146 label_control<wxTextCtrl> addrsize;
147 label_control<wxComboBox> position;
148 wxCheckBox* cond_enable;
149 wxTextCtrl* enabled;
150 label_control<wxTextCtrl> xpos;
151 label_control<wxTextCtrl> ypos;
152 wxCheckBox* alt_origin_x;
153 wxCheckBox* alt_origin_y;
154 wxCheckBox* cliprange_x;
155 wxCheckBox* cliprange_y;
156 label_control<wxTextCtrl> font;
157 wxButton* font_sel;
158 label_control<wxTextCtrl> fg_color;
159 label_control<wxTextCtrl> bg_color;
160 label_control<wxTextCtrl> halo_color;
161 wxButton* ok;
162 wxButton* cancel;
163 std::string name;
164 std::string old_addrbase;
165 std::string old_addrsize;
166 bool was_free;
167 std::map<int, std::pair<uint64_t, uint64_t>> vmas_available;
170 wxeditor_memorywatch::wxeditor_memorywatch(wxWindow* parent, emulator_instance& _inst, const std::string& _name)
171 : wxDialog(parent, wxID_ANY, towxstring("Edit memory watch '" + _name + "'")), inst(_inst), name(_name)
173 CHECK_UI_THREAD;
174 Center();
175 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
176 SetSizer(top_s);
178 //Type.
179 wxSizer* s1 = new wxBoxSizer(wxHORIZONTAL);
180 type = label_control<wxComboBox>(this, "Data type", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
181 nullptr, wxCB_READONLY);
182 type.add(s1);
183 type->Append(wxT("(Expression)"));
184 type->Append(wxT("Signed byte"));
185 type->Append(wxT("Unsigned byte"));
186 type->Append(wxT("Signed word"));
187 type->Append(wxT("Unsigned word"));
188 type->Append(wxT("Signed 3-byte"));
189 type->Append(wxT("Unsigned 3-byte"));
190 type->Append(wxT("Signed dword"));
191 type->Append(wxT("Unsigned dword"));
192 type->Append(wxT("Float"));
193 type->Append(wxT("Signed qword"));
194 type->Append(wxT("Unsigned qword"));
195 type->Append(wxT("Double"));
196 type->SetSelection(3);
197 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
198 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
199 endianess = label_control<wxComboBox>(this, "Endian:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
200 0, nullptr, wxCB_READONLY);
201 endianess.add(s1, true);
202 endianess->Append(wxT("Little"));
203 endianess->Append(wxT("Host"));
204 endianess->Append(wxT("Big"));
205 endianess->SetSelection(0);
206 scale = label_control<wxSpinCtrl>(this, "Scale bits:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
207 wxSP_ARROW_KEYS, 0, 63, 0);
208 scale.add(s1);
209 top_s->Add(s1, 1, wxGROW);
211 //Memory range.
212 wxSizer* s5 = new wxBoxSizer(wxHORIZONTAL);
213 vma = label_control<wxComboBox>(this, "Memory:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
214 nullptr, wxCB_READONLY);
215 vma.add(s5, true);
216 vma->Append(wxT("(All)"));
217 auto i = inst.memory->get_regions();
218 for(auto j : i) {
219 int id = vma->GetCount();
220 vma->Append(towxstring(j->name));
221 vmas_available[id] = std::make_pair(j->base, j->size);
223 //Special registers "VMA".
225 int id = vma->GetCount();
226 vma->Append(towxstring("(registers)"));
227 vmas_available[id] = std::make_pair(0xFFFFFFFFFFFFFFFFULL, 0);
229 vma->SetSelection(0);
230 vma->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
231 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
232 addrbase = label_control<wxTextCtrl>(this, "Base:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
233 addrbase.add(s5, true);
234 addrsize = label_control<wxTextCtrl>(this, "Size:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
235 addrsize.add(s5, true);
236 top_s->Add(s5, 1, wxGROW);
238 //Expression.
239 wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
240 expr = label_control<wxTextCtrl>(this, "Address:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
241 expr.add(s2, true);
242 top_s->Add(s2, 1, wxGROW);
244 //Format:
245 wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
246 format = label_control<wxTextCtrl>(this, "Format:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
247 format.add(s3, true);
248 top_s->Add(s3, 1, wxGROW);
250 wxSizer* sx = new wxBoxSizer(wxVERTICAL);
251 sx->Add(1, 11);
252 top_s->Add(sx, 0, wxGROW);
254 wxSizer* s6 = new wxBoxSizer(wxHORIZONTAL);
255 position = label_control<wxComboBox>(this, "Position: ", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
256 0, nullptr, wxCB_READONLY);
257 position.add(s6, true);
258 position->Append(wxT("Disabled"));
259 position->Append(wxT("Memory watch"));
260 position->Append(wxT("On screen"));
261 position->SetSelection(1);
262 position->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
263 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
264 top_s->Add(s6, 0, wxGROW);
266 wxSizer* s7 = new wxBoxSizer(wxHORIZONTAL);
267 s7->Add(cond_enable = new wxCheckBox(this, wxID_ANY, wxT("Conditional on: ")), 0, wxGROW);
268 s7->Add(enabled = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1, wxGROW);
269 cond_enable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
270 wxCommandEventHandler(wxeditor_memorywatch::enable_condenable2), NULL, this);
271 top_s->Add(s7, 0, wxGROW);
273 wxSizer* s8 = new wxBoxSizer(wxHORIZONTAL);
275 xpos = label_control<wxTextCtrl>(this, "X:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
276 xpos.add(s8, true);
277 s8->Add(alt_origin_x = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
278 s8->Add(cliprange_x = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
279 top_s->Add(s8, 0, wxGROW);
281 wxSizer* s9 = new wxBoxSizer(wxHORIZONTAL);
282 ypos = label_control<wxTextCtrl>(this, "Y:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
283 ypos.add(s9, true);
284 s9->Add(alt_origin_y = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
285 s9->Add(cliprange_y = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
286 top_s->Add(s9, 0, wxGROW);
288 wxSizer* s10 = new wxBoxSizer(wxHORIZONTAL);
289 font = label_control<wxTextCtrl>(this, "Font:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
290 font.add(s10, true);
291 s10->Add(font_sel = new wxButton(this, wxID_ANY, wxT("...")), 0, wxGROW);
292 font_sel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
293 wxCommandEventHandler(wxeditor_memorywatch::on_fontsel), NULL, this);
294 top_s->Add(s10, 0, wxGROW);
296 wxSizer* s11 = new wxBoxSizer(wxHORIZONTAL);
297 fg_color = label_control<wxTextCtrl>(this, "Foreground:", wxID_ANY, wxT("#FFFFFF"),
298 wxDefaultPosition, wxSize(100, -1));
299 fg_color.add(s11, true);
300 bg_color = label_control<wxTextCtrl>(this, "Background:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
301 wxSize(100, -1));
302 bg_color.add(s11, true);
303 halo_color = label_control<wxTextCtrl>(this, "Halo:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
304 wxSize(100, -1));
305 halo_color.add(s11, true);
306 top_s->Add(s11, 0, wxGROW);
308 wxSizer* s12 = new wxBoxSizer(wxHORIZONTAL);
309 s12->AddStretchSpacer();
310 s12->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
311 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_ok), NULL, this);
312 s12->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
313 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_cancel), NULL,
314 this);
315 top_s->Add(s12, 0, wxGROW);
317 memwatch_item it;
318 bool had_it = false;
319 try {
320 it = inst.mwatch->get(name);
321 had_it = true;
322 } catch(...) {
324 if(had_it) {
325 expr->SetValue(towxstring(it.expr));
326 format->SetValue(towxstring(it.format));
327 cond_enable->SetValue(it.printer.cond_enable);
328 enabled->SetValue(towxstring(it.printer.enabled));
329 xpos->SetValue(towxstring(it.printer.onscreen_xpos));
330 ypos->SetValue(towxstring(it.printer.onscreen_ypos));
331 alt_origin_x->SetValue(it.printer.onscreen_alt_origin_x);
332 alt_origin_y->SetValue(it.printer.onscreen_alt_origin_y);
333 cliprange_x->SetValue(it.printer.onscreen_cliprange_x);
334 cliprange_y->SetValue(it.printer.onscreen_cliprange_y);
335 endianess->SetSelection(it.endianess + 1);
336 addrbase->SetValue(towxstring(hex::to<uint64_t>(it.addr_base)));
337 addrsize->SetValue(towxstring(hex::to<uint64_t>(it.addr_size)));
338 if(it.printer.position == memwatch_printer::PC_DISABLED) position->SetSelection(0);
339 if(it.printer.position == memwatch_printer::PC_MEMORYWATCH) position->SetSelection(1);
340 if(it.printer.position == memwatch_printer::PC_ONSCREEN) position->SetSelection(2);
341 switch(it.bytes) {
342 case 0: type->SetSelection(0); break;
343 case 1: type->SetSelection(it.signed_flag ? 1 : 2); break;
344 case 2: type->SetSelection(it.signed_flag ? 3 : 4); break;
345 case 3: type->SetSelection(it.signed_flag ? 5 : 6); break;
346 case 4: type->SetSelection(it.float_flag ? 9 : (it.signed_flag ? 7 : 8)); break;
347 case 8: type->SetSelection(it.float_flag ? 12 : (it.signed_flag ? 11 : 10)); break;
349 scale->SetValue(log2i(it.scale_div));
350 for(auto j : vmas_available) {
351 if(j.second.first == it.addr_base && j.second.second == it.addr_size)
352 vma->SetSelection(j.first);
354 font->SetValue(towxstring(it.printer.onscreen_font));
355 fg_color->SetValue(towxstring(format_color(it.printer.onscreen_fg_color)));
356 bg_color->SetValue(towxstring(format_color(it.printer.onscreen_bg_color)));
357 halo_color->SetValue(towxstring(format_color(it.printer.onscreen_halo_color)));
360 wxCommandEvent e;
361 on_position_change(e);
362 top_s->SetSizeHints(this);
363 Fit();
366 bool wxeditor_memorywatch::ShouldPreventAppExit() const
368 return false;
371 memwatch_printer::position_category wxeditor_memorywatch::get_poscategory()
373 if(position->GetSelection() == 0) return memwatch_printer::PC_DISABLED;
374 if(position->GetSelection() == 1) return memwatch_printer::PC_MEMORYWATCH;
375 if(position->GetSelection() == 2) return memwatch_printer::PC_ONSCREEN;
376 return memwatch_printer::PC_DISABLED; //NOTREACHED.
379 void wxeditor_memorywatch::enable_for_pos(memwatch_printer::position_category p)
381 CHECK_UI_THREAD;
382 bool full_disable = (p == memwatch_printer::PC_DISABLED);
383 cond_enable->Enable(!full_disable);
384 enabled->Enable(cond_enable->GetValue() && !full_disable);
385 xpos.enable(p == memwatch_printer::PC_ONSCREEN);
386 ypos.enable(p == memwatch_printer::PC_ONSCREEN);
387 alt_origin_x->Enable(p == memwatch_printer::PC_ONSCREEN);
388 alt_origin_y->Enable(p == memwatch_printer::PC_ONSCREEN);
389 cliprange_x->Enable(p == memwatch_printer::PC_ONSCREEN);
390 cliprange_y->Enable(p == memwatch_printer::PC_ONSCREEN);
391 font.enable(p == memwatch_printer::PC_ONSCREEN);
392 font_sel->Enable(p == memwatch_printer::PC_ONSCREEN);
393 fg_color.enable(p == memwatch_printer::PC_ONSCREEN);
394 bg_color.enable(p == memwatch_printer::PC_ONSCREEN);
395 halo_color.enable(p == memwatch_printer::PC_ONSCREEN);
398 void wxeditor_memorywatch::enable_condenable()
400 CHECK_UI_THREAD;
401 memwatch_printer::position_category p = get_poscategory();
402 bool full_disable = (p == memwatch_printer::PC_DISABLED);
403 enabled->Enable(cond_enable->GetValue() && !full_disable);
406 void wxeditor_memorywatch::enable_condenable2(wxCommandEvent& e)
408 enable_condenable();
411 void wxeditor_memorywatch::enable_for_addr(bool is_addr)
413 CHECK_UI_THREAD;
414 expr.label()->SetLabel(towxstring(is_addr ? "Address:" : "Expr:"));
415 endianess.enable(is_addr);
416 scale.enable(is_addr);
417 vma.enable(is_addr);
418 addrbase.enable(is_addr && was_free);
419 addrsize.enable(is_addr && was_free);
420 Fit();
423 void wxeditor_memorywatch::enable_for_vma(bool free, uint64_t _base, uint64_t _size)
425 CHECK_UI_THREAD;
426 //TODO: Set default endian.
427 if(!free && !was_free) {
428 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
429 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
430 } else if(free && !was_free) {
431 addrbase->SetValue(towxstring(old_addrbase));
432 addrsize->SetValue(towxstring(old_addrsize));
433 addrbase.enable(true);
434 addrsize.enable(true);
435 } else if(!free && was_free) {
436 old_addrbase = tostdstring(addrbase->GetValue());
437 old_addrsize = tostdstring(addrsize->GetValue());
438 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
439 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
440 addrbase.enable(false);
441 addrsize.enable(false);
443 was_free = free;
446 void wxeditor_memorywatch::on_position_change(wxCommandEvent& e)
448 CHECK_UI_THREAD;
449 enable_for_pos(get_poscategory());
450 int vmasel = vma->GetSelection();
451 if(vmasel == 0)
452 enable_for_vma(true, 0, 0);
453 else if(vmas_available.count(vmasel)) {
454 enable_for_vma(false, vmas_available[vmasel].first, vmas_available[vmasel].second);
455 } else {
456 vma->SetSelection(0);
457 enable_for_vma(true, 0, 0);
459 enable_for_addr(type->GetSelection() != 0);
462 void wxeditor_memorywatch::on_fontsel(wxCommandEvent& e)
464 CHECK_UI_THREAD;
465 try {
466 std::string filename = choose_file_load(this, "Choose font file", UI_get_project_otherpath(inst),
467 filetype_font);
468 font->SetValue(towxstring(filename));
469 } catch(canceled_exception& e) {
473 void wxeditor_memorywatch::on_ok(wxCommandEvent& e)
475 CHECK_UI_THREAD;
476 memwatch_item it;
477 it.expr = tostdstring(expr->GetValue());
478 it.format = tostdstring(format->GetValue());
479 it.printer.cond_enable = cond_enable->GetValue();
480 it.printer.enabled = tostdstring(enabled->GetValue());
481 it.printer.onscreen_xpos = tostdstring(xpos->GetValue());
482 it.printer.onscreen_ypos = tostdstring(ypos->GetValue());
483 it.printer.onscreen_alt_origin_x = alt_origin_x->GetValue();
484 it.printer.onscreen_alt_origin_y = alt_origin_y->GetValue();
485 it.printer.onscreen_cliprange_x = cliprange_x->GetValue();
486 it.printer.onscreen_cliprange_y = cliprange_y->GetValue();
487 it.printer.onscreen_font = tostdstring(font->GetValue());
488 it.endianess = endianess->GetSelection() - 1;
489 try {
490 it.addr_base = hex::from<uint64_t>(tostdstring(addrbase->GetValue()));
491 it.addr_size = hex::from<uint64_t>(tostdstring(addrsize->GetValue()));
492 } catch(std::exception& e) {
493 show_message_ok(NULL, "Bad memory range", std::string("Error parsing memory range: ") + e.what(),
494 wxICON_EXCLAMATION);
495 return;
497 if(position->GetSelection() == 0) it.printer.position = memwatch_printer::PC_DISABLED;
498 else if(position->GetSelection() == 1) it.printer.position = memwatch_printer::PC_MEMORYWATCH;
499 else if(position->GetSelection() == 2) it.printer.position = memwatch_printer::PC_ONSCREEN;
500 else it.printer.position = memwatch_printer::PC_MEMORYWATCH;
501 it.signed_flag = false;
502 it.float_flag = false;
503 switch(type->GetSelection()) {
504 case 0: it.bytes = 0; break;
505 case 1: it.bytes = 1; it.signed_flag = !false; break;
506 case 2: it.bytes = 1; it.signed_flag = !true; break;
507 case 3: it.bytes = 2; it.signed_flag = !false; break;
508 case 4: it.bytes = 2; it.signed_flag = !true; break;
509 case 5: it.bytes = 3; it.signed_flag = !false; break;
510 case 6: it.bytes = 3; it.signed_flag = !true; break;
511 case 7: it.bytes = 4; it.signed_flag = !false; break;
512 case 8: it.bytes = 4; it.signed_flag = !true; break;
513 case 9: it.bytes = 4; it.float_flag = true; break;
514 case 10: it.bytes = 8; it.signed_flag = !false; break;
515 case 11: it.bytes = 8; it.signed_flag = !true; break;
516 case 12: it.bytes = 8; it.float_flag = true; break;
518 it.scale_div = 1ULL << scale->GetValue();
519 try {
520 it.printer.onscreen_fg_color = get_color(tostdstring(fg_color->GetValue()));
521 it.printer.onscreen_bg_color = get_color(tostdstring(bg_color->GetValue()));
522 it.printer.onscreen_halo_color = get_color(tostdstring(halo_color->GetValue()));
523 } catch(std::exception& e) {
524 show_message_ok(NULL, "Bad colors", std::string("Error parsing colors: ") + e.what(),
525 wxICON_EXCLAMATION);
526 return;
528 try {
529 inst.iqueue->run([this, &it]() {
530 CORE().mwatch->set(name, it);
532 } catch(std::exception& e) {
533 show_exception(NULL, "Bad values", "Error setting memory watch", e);
534 return;
536 EndModal(wxID_OK);
539 void wxeditor_memorywatch::on_cancel(wxCommandEvent& e)
541 CHECK_UI_THREAD;
542 EndModal(wxID_CANCEL);
545 class wxeditor_memorywatches : public wxDialog
547 public:
548 wxeditor_memorywatches(wxWindow* parent, emulator_instance& _inst);
549 bool ShouldPreventAppExit() const;
550 void on_memorywatch_change(wxCommandEvent& e);
551 void on_new(wxCommandEvent& e);
552 void on_rename(wxCommandEvent& e);
553 void on_delete(wxCommandEvent& e);
554 void on_edit(wxCommandEvent& e);
555 void on_close(wxCommandEvent& e);
556 private:
557 void refresh();
558 emulator_instance& inst;
559 //TODO: Make this a wxGrid.
560 wxListBox* watches;
561 wxButton* newbutton;
562 wxButton* renamebutton;
563 wxButton* deletebutton;
564 wxButton* editbutton;
565 wxButton* closebutton;
569 wxeditor_memorywatches::wxeditor_memorywatches(wxWindow* parent, emulator_instance& _inst)
570 : wxDialog(parent, wxID_ANY, wxT("lsnes: Edit memory watches"), wxDefaultPosition, wxSize(-1, -1)),
571 inst(_inst)
573 CHECK_UI_THREAD;
574 Centre();
575 wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
576 SetSizer(top_s);
578 top_s->Add(watches = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 300)), 1, wxGROW);
579 watches->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
580 wxCommandEventHandler(wxeditor_memorywatches::on_memorywatch_change), NULL, this);
582 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
583 pbutton_s->AddStretchSpacer();
584 pbutton_s->Add(newbutton = new wxButton(this, wxID_ANY, wxT("New")), 0, wxGROW);
585 pbutton_s->Add(editbutton = new wxButton(this, wxID_ANY, wxT("Edit")), 0, wxGROW);
586 pbutton_s->Add(renamebutton = new wxButton(this, wxID_ANY, wxT("Rename")), 0, wxGROW);
587 pbutton_s->Add(deletebutton = new wxButton(this, wxID_ANY, wxT("Delete")), 0, wxGROW);
588 pbutton_s->Add(closebutton = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
589 newbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
590 wxCommandEventHandler(wxeditor_memorywatches::on_new), NULL, this);
591 editbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
592 wxCommandEventHandler(wxeditor_memorywatches::on_edit), NULL, this);
593 renamebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
594 wxCommandEventHandler(wxeditor_memorywatches::on_rename), NULL, this);
595 deletebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
596 wxCommandEventHandler(wxeditor_memorywatches::on_delete), NULL, this);
597 closebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
598 wxCommandEventHandler(wxeditor_memorywatches::on_close), NULL, this);
599 top_s->Add(pbutton_s, 0, wxGROW);
601 pbutton_s->SetSizeHints(this);
602 top_s->SetSizeHints(this);
603 Fit();
605 refresh();
608 bool wxeditor_memorywatches::ShouldPreventAppExit() const
610 return false;
613 void wxeditor_memorywatches::on_memorywatch_change(wxCommandEvent& e)
615 CHECK_UI_THREAD;
616 std::string watch = tostdstring(watches->GetStringSelection());
617 editbutton->Enable(watch != "");
618 deletebutton->Enable(watch != "");
619 renamebutton->Enable(watch != "");
622 void wxeditor_memorywatches::on_new(wxCommandEvent& e)
624 CHECK_UI_THREAD;
625 try {
626 std::string newname = pick_text(this, "New watch", "Enter name for watch:");
627 if(newname == "")
628 return;
629 wxeditor_memorywatch* nwch = new wxeditor_memorywatch(this, inst, newname);
630 nwch->ShowModal();
631 nwch->Destroy();
632 refresh();
633 } catch(canceled_exception& e) {
634 //Ignore.
636 on_memorywatch_change(e);
639 void wxeditor_memorywatches::on_rename(wxCommandEvent& e)
641 CHECK_UI_THREAD;
642 std::string watch = tostdstring(watches->GetStringSelection());
643 if(watch == "")
644 return;
645 try {
646 bool exists = false;
647 std::string newname = pick_text(this, "Rename watch", "Enter New name for watch:");
648 inst.iqueue->run([watch, newname, &exists]() {
649 exists = !CORE().mwatch->rename(watch, newname);
651 if(exists)
652 show_message_ok(this, "Error", "The target watch already exists", wxICON_EXCLAMATION);
653 refresh();
654 } catch(canceled_exception& e) {
655 //Ignore.
657 on_memorywatch_change(e);
660 void wxeditor_memorywatches::on_delete(wxCommandEvent& e)
662 CHECK_UI_THREAD;
663 std::string watch = tostdstring(watches->GetStringSelection());
664 if(watch != "")
665 inst.iqueue->run([watch]() { CORE().mwatch->clear(watch); });
666 refresh();
667 on_memorywatch_change(e);
670 void wxeditor_memorywatches::on_edit(wxCommandEvent& e)
672 CHECK_UI_THREAD;
673 try {
674 std::string watch = tostdstring(watches->GetStringSelection());
675 if(watch == "")
676 return;
677 std::string wtxt;
678 wxeditor_memorywatch* ewch = new wxeditor_memorywatch(this, inst, watch);
679 ewch->ShowModal();
680 ewch->Destroy();
681 refresh();
682 } catch(canceled_exception& e) {
683 //Ignore.
685 on_memorywatch_change(e);
688 void wxeditor_memorywatches::on_close(wxCommandEvent& e)
690 CHECK_UI_THREAD;
691 EndModal(wxID_OK);
694 void wxeditor_memorywatches::refresh()
696 CHECK_UI_THREAD;
697 std::set<std::string> bind;
698 inst.iqueue->run([&bind]() {
699 bind = CORE().mwatch->enumerate();
701 watches->Clear();
702 for(auto i : bind)
703 watches->Append(towxstring(i));
704 if(watches->GetCount())
705 watches->SetSelection(0);
706 wxCommandEvent e;
707 on_memorywatch_change(e);
710 void wxeditor_memorywatches_display(wxWindow* parent, emulator_instance& inst)
712 CHECK_UI_THREAD;
713 modal_pause_holder hld;
714 wxDialog* editor;
715 try {
716 editor = new wxeditor_memorywatches(parent, inst);
717 editor->ShowModal();
718 } catch(...) {
719 return;
721 editor->Destroy();