Fix Win32 build
[lsnes.git] / src / platform / wxwidgets / editor-memorywatch.cpp
blob29e20f82c79f1021267afbdad44f1e024081b335
1 #include <wx/wx.h>
2 #include <wx/statline.h>
3 #include <wx/event.h>
4 #include <wx/control.h>
5 #include <wx/combobox.h>
6 #include <wx/radiobut.h>
7 #include <wx/spinctrl.h>
9 #include "core/instance.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/memorywatch.hpp"
12 #include "core/memorymanip.hpp"
13 #include "core/ui-services.hpp"
14 #include "library/memoryspace.hpp"
15 #include "core/project.hpp"
17 #include "platform/wxwidgets/platform.hpp"
18 #include "platform/wxwidgets/loadsave.hpp"
20 #include "library/string.hpp"
21 #include "library/hex.hpp"
22 #include "interface/romtype.hpp"
26 std::string main_expr;
27 std::string format;
28 unsigned memread_bytes; //0 if not memory read.
29 bool memread_signed_flag;
30 bool memread_float_flag;
31 int memread_endianess;
32 uint64_t memread_scale_div;
33 uint64_t memread_addr_base;
34 uint64_t memread_addr_size;
35 enum position_category {
36 PC_DISABLED,
37 PC_MEMORYWATCH,
38 PC_ONSCREEN
39 } position;
40 std::string enabled; //Ignored for disabled.
41 std::string onscreen_xpos;
42 std::string onscreen_ypos;
43 bool onscreen_alt_origin_x;
44 bool onscreen_alt_origin_y;
45 bool onscreen_cliprange_x;
46 bool onscreen_cliprange_y;
47 std::string onscreen_font; //"" is system default.
48 int64_t onscreen_fg_color;
49 int64_t onscreen_bg_color;
50 int64_t onscreen_halo_color;
54 namespace
56 int log2i(uint64_t v)
58 unsigned l = 0;
59 while(v > 1) {
60 v >>= 1;
61 l++;
63 return l;
66 template<class T>
67 class label_control
69 public:
70 label_control()
72 lbl = NULL;
73 ctrl = NULL;
75 template<typename... U> label_control(wxWindow* parent, const std::string& label, U... args)
77 CHECK_UI_THREAD;
78 lbl = new wxStaticText(parent, wxID_ANY, towxstring(label));
79 ctrl = new T(parent, args...);
81 void show(bool state)
83 CHECK_UI_THREAD;
84 lbl->Show(state);
85 ctrl->Show(state);
87 void enable(bool state)
89 CHECK_UI_THREAD;
90 lbl->Enable(state);
91 ctrl->Enable(state);
93 void add(wxSizer* s, bool prop = false)
95 CHECK_UI_THREAD;
96 s->Add(lbl, 0, wxALIGN_CENTER_VERTICAL);
97 s->Add(ctrl, prop ? 1 : 0, wxGROW);
99 void add_cb(std::function<void(wxStaticText* l, T* c)> cb)
101 cb(lbl, ctrl);
103 wxStaticText* label() { return lbl; }
104 T* operator->() { return ctrl; }
105 private:
106 wxStaticText* lbl;
107 T* ctrl;
110 std::string format_color(int64_t x)
112 return framebuffer::color::stringify(x);
115 int64_t get_color(std::string x)
117 return framebuffer::color(x).asnumber();
121 class wxeditor_memorywatch : public wxDialog
123 public:
124 wxeditor_memorywatch(wxWindow* parent, emulator_instance& _inst, const std::string& name);
125 bool ShouldPreventAppExit() const;
126 void on_position_change(wxCommandEvent& e);
127 void on_fontsel(wxCommandEvent& e);
128 void on_ok(wxCommandEvent& e);
129 void on_cancel(wxCommandEvent& e);
130 void enable_condenable2(wxCommandEvent& e);
131 private:
132 void enable_for_pos(memwatch_printer::position_category p);
133 void enable_for_addr(bool is_addr);
134 void enable_for_vma(bool free, uint64_t _base, uint64_t _size);
135 void enable_condenable();
136 memwatch_printer::position_category get_poscategory();
137 emulator_instance& inst;
138 label_control<wxComboBox> type;
139 label_control<wxTextCtrl> expr;
140 label_control<wxTextCtrl> format;
141 label_control<wxComboBox> endianess;
142 label_control<wxSpinCtrl> scale;
143 label_control<wxComboBox> vma;
144 label_control<wxTextCtrl> addrbase;
145 label_control<wxTextCtrl> addrsize;
146 label_control<wxComboBox> position;
147 wxCheckBox* cond_enable;
148 wxTextCtrl* enabled;
149 label_control<wxTextCtrl> xpos;
150 label_control<wxTextCtrl> ypos;
151 wxCheckBox* alt_origin_x;
152 wxCheckBox* alt_origin_y;
153 wxCheckBox* cliprange_x;
154 wxCheckBox* cliprange_y;
155 label_control<wxTextCtrl> font;
156 wxButton* font_sel;
157 label_control<wxTextCtrl> fg_color;
158 label_control<wxTextCtrl> bg_color;
159 label_control<wxTextCtrl> halo_color;
160 wxButton* ok;
161 wxButton* cancel;
162 std::string name;
163 std::string old_addrbase;
164 std::string old_addrsize;
165 bool was_free;
166 std::map<int, std::pair<uint64_t, uint64_t>> vmas_available;
169 wxeditor_memorywatch::wxeditor_memorywatch(wxWindow* parent, emulator_instance& _inst, const std::string& _name)
170 : wxDialog(parent, wxID_ANY, towxstring("Edit memory watch '" + _name + "'")), inst(_inst), name(_name)
172 CHECK_UI_THREAD;
173 Center();
174 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
175 SetSizer(top_s);
177 //Type.
178 wxSizer* s1 = new wxBoxSizer(wxHORIZONTAL);
179 type = label_control<wxComboBox>(this, "Data type", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
180 nullptr, wxCB_READONLY);
181 type.add(s1);
182 type->Append("(Expression)");
183 type->Append("Signed byte");
184 type->Append("Unsigned byte");
185 type->Append("Signed word");
186 type->Append("Unsigned word");
187 type->Append("Signed 3-byte");
188 type->Append("Unsigned 3-byte");
189 type->Append("Signed dword");
190 type->Append("Unsigned dword");
191 type->Append("Float");
192 type->Append("Signed qword");
193 type->Append("Unsigned qword");
194 type->Append("Double");
195 type->SetSelection(3);
196 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
197 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
198 endianess = label_control<wxComboBox>(this, "Endian:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
199 0, nullptr, wxCB_READONLY);
200 endianess.add(s1, true);
201 endianess->Append(wxT("Little"));
202 endianess->Append(wxT("Host"));
203 endianess->Append(wxT("Big"));
204 endianess->SetSelection(0);
205 scale = label_control<wxSpinCtrl>(this, "Scale bits:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
206 wxSP_ARROW_KEYS, 0, 63, 0);
207 scale.add(s1);
208 top_s->Add(s1, 1, wxGROW);
210 //Memory range.
211 wxSizer* s5 = new wxBoxSizer(wxHORIZONTAL);
212 vma = label_control<wxComboBox>(this, "Memory:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
213 nullptr, wxCB_READONLY);
214 vma.add(s5, true);
215 vma->Append(wxT("(All)"));
216 auto i = inst.memory->get_regions();
217 for(auto j : i) {
218 int id = vma->GetCount();
219 vma->Append(towxstring(j->name));
220 vmas_available[id] = std::make_pair(j->base, j->size);
222 //Special registers "VMA".
224 int id = vma->GetCount();
225 vma->Append(towxstring("(registers)"));
226 vmas_available[id] = std::make_pair(0xFFFFFFFFFFFFFFFFULL, 0);
228 vma->SetSelection(0);
229 vma->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
230 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
231 addrbase = label_control<wxTextCtrl>(this, "Base:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
232 addrbase.add(s5, true);
233 addrsize = label_control<wxTextCtrl>(this, "Size:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
234 addrsize.add(s5, true);
235 top_s->Add(s5, 1, wxGROW);
237 //Expression.
238 wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
239 expr = label_control<wxTextCtrl>(this, "Address:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
240 expr.add(s2, true);
241 top_s->Add(s2, 1, wxGROW);
243 //Format:
244 wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
245 format = label_control<wxTextCtrl>(this, "Format:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
246 format.add(s3, true);
247 top_s->Add(s3, 1, wxGROW);
249 wxSizer* sx = new wxBoxSizer(wxVERTICAL);
250 sx->Add(1, 11);
251 top_s->Add(sx, 0, wxGROW);
253 wxSizer* s6 = new wxBoxSizer(wxHORIZONTAL);
254 position = label_control<wxComboBox>(this, "Position: ", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
255 0, nullptr, wxCB_READONLY);
256 position.add(s6, true);
257 position->Append(wxT("Disabled"));
258 position->Append(wxT("Memory watch"));
259 position->Append(wxT("On screen"));
260 position->SetSelection(1);
261 position->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
262 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
263 top_s->Add(s6, 0, wxGROW);
265 wxSizer* s7 = new wxBoxSizer(wxHORIZONTAL);
266 s7->Add(cond_enable = new wxCheckBox(this, wxID_ANY, wxT("Conditional on: ")), 0, wxGROW);
267 s7->Add(enabled = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1, wxGROW);
268 cond_enable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
269 wxCommandEventHandler(wxeditor_memorywatch::enable_condenable2), NULL, this);
270 top_s->Add(s7, 0, wxGROW);
272 wxSizer* s8 = new wxBoxSizer(wxHORIZONTAL);
274 xpos = label_control<wxTextCtrl>(this, "X:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
275 xpos.add(s8, true);
276 s8->Add(alt_origin_x = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
277 s8->Add(cliprange_x = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
278 top_s->Add(s8, 0, wxGROW);
280 wxSizer* s9 = new wxBoxSizer(wxHORIZONTAL);
281 ypos = label_control<wxTextCtrl>(this, "Y:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
282 ypos.add(s9, true);
283 s9->Add(alt_origin_y = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
284 s9->Add(cliprange_y = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
285 top_s->Add(s9, 0, wxGROW);
287 wxSizer* s10 = new wxBoxSizer(wxHORIZONTAL);
288 font = label_control<wxTextCtrl>(this, "Font:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
289 font.add(s10, true);
290 s10->Add(font_sel = new wxButton(this, wxID_ANY, wxT("...")), 0, wxGROW);
291 font_sel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
292 wxCommandEventHandler(wxeditor_memorywatch::on_fontsel), NULL, this);
293 top_s->Add(s10, 0, wxGROW);
295 wxSizer* s11 = new wxBoxSizer(wxHORIZONTAL);
296 fg_color = label_control<wxTextCtrl>(this, "Foreground:", wxID_ANY, wxT("#FFFFFF"),
297 wxDefaultPosition, wxSize(100, -1));
298 fg_color.add(s11, true);
299 bg_color = label_control<wxTextCtrl>(this, "Background:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
300 wxSize(100, -1));
301 bg_color.add(s11, true);
302 halo_color = label_control<wxTextCtrl>(this, "Halo:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
303 wxSize(100, -1));
304 halo_color.add(s11, true);
305 top_s->Add(s11, 0, wxGROW);
307 wxSizer* s12 = new wxBoxSizer(wxHORIZONTAL);
308 s12->AddStretchSpacer();
309 s12->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
310 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_ok), NULL, this);
311 s12->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
312 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_cancel), NULL,
313 this);
314 top_s->Add(s12, 0, wxGROW);
316 memwatch_item it;
317 bool had_it = false;
318 try {
319 it = inst.mwatch->get(name);
320 had_it = true;
321 } catch(...) {
323 if(had_it) {
324 expr->SetValue(towxstring(it.expr));
325 format->SetValue(towxstring(it.format));
326 cond_enable->SetValue(it.printer.cond_enable);
327 enabled->SetValue(it.printer.enabled);
328 xpos->SetValue(it.printer.onscreen_xpos);
329 ypos->SetValue(it.printer.onscreen_ypos);
330 alt_origin_x->SetValue(it.printer.onscreen_alt_origin_x);
331 alt_origin_y->SetValue(it.printer.onscreen_alt_origin_y);
332 cliprange_x->SetValue(it.printer.onscreen_cliprange_x);
333 cliprange_y->SetValue(it.printer.onscreen_cliprange_y);
334 endianess->SetSelection(it.endianess + 1);
335 addrbase->SetValue(towxstring(hex::to<uint64_t>(it.addr_base)));
336 addrsize->SetValue(towxstring(hex::to<uint64_t>(it.addr_size)));
337 if(it.printer.position == memwatch_printer::PC_DISABLED) position->SetSelection(0);
338 if(it.printer.position == memwatch_printer::PC_MEMORYWATCH) position->SetSelection(1);
339 if(it.printer.position == memwatch_printer::PC_ONSCREEN) position->SetSelection(2);
340 switch(it.bytes) {
341 case 0: type->SetSelection(0); break;
342 case 1: type->SetSelection(it.signed_flag ? 1 : 2); break;
343 case 2: type->SetSelection(it.signed_flag ? 3 : 4); break;
344 case 3: type->SetSelection(it.signed_flag ? 5 : 6); break;
345 case 4: type->SetSelection(it.float_flag ? 9 : (it.signed_flag ? 7 : 8)); break;
346 case 8: type->SetSelection(it.float_flag ? 12 : (it.signed_flag ? 11 : 10)); break;
348 scale->SetValue(log2i(it.scale_div));
349 for(auto j : vmas_available) {
350 if(j.second.first == it.addr_base && j.second.second == it.addr_size)
351 vma->SetSelection(j.first);
353 font->SetValue(towxstring(it.printer.onscreen_font));
354 fg_color->SetValue(towxstring(format_color(it.printer.onscreen_fg_color)));
355 bg_color->SetValue(towxstring(format_color(it.printer.onscreen_bg_color)));
356 halo_color->SetValue(towxstring(format_color(it.printer.onscreen_halo_color)));
359 wxCommandEvent e;
360 on_position_change(e);
361 top_s->SetSizeHints(this);
362 Fit();
365 bool wxeditor_memorywatch::ShouldPreventAppExit() const
367 return false;
370 memwatch_printer::position_category wxeditor_memorywatch::get_poscategory()
372 if(position->GetSelection() == 0) return memwatch_printer::PC_DISABLED;
373 if(position->GetSelection() == 1) return memwatch_printer::PC_MEMORYWATCH;
374 if(position->GetSelection() == 2) return memwatch_printer::PC_ONSCREEN;
375 return memwatch_printer::PC_DISABLED; //NOTREACHED.
378 void wxeditor_memorywatch::enable_for_pos(memwatch_printer::position_category p)
380 CHECK_UI_THREAD;
381 bool full_disable = (p == memwatch_printer::PC_DISABLED);
382 cond_enable->Enable(!full_disable);
383 enabled->Enable(cond_enable->GetValue() && !full_disable);
384 xpos.enable(p == memwatch_printer::PC_ONSCREEN);
385 ypos.enable(p == memwatch_printer::PC_ONSCREEN);
386 alt_origin_x->Enable(p == memwatch_printer::PC_ONSCREEN);
387 alt_origin_y->Enable(p == memwatch_printer::PC_ONSCREEN);
388 cliprange_x->Enable(p == memwatch_printer::PC_ONSCREEN);
389 cliprange_y->Enable(p == memwatch_printer::PC_ONSCREEN);
390 font.enable(p == memwatch_printer::PC_ONSCREEN);
391 font_sel->Enable(p == memwatch_printer::PC_ONSCREEN);
392 fg_color.enable(p == memwatch_printer::PC_ONSCREEN);
393 bg_color.enable(p == memwatch_printer::PC_ONSCREEN);
394 halo_color.enable(p == memwatch_printer::PC_ONSCREEN);
397 void wxeditor_memorywatch::enable_condenable()
399 CHECK_UI_THREAD;
400 memwatch_printer::position_category p = get_poscategory();
401 bool full_disable = (p == memwatch_printer::PC_DISABLED);
402 enabled->Enable(cond_enable->GetValue() && !full_disable);
405 void wxeditor_memorywatch::enable_condenable2(wxCommandEvent& e)
407 enable_condenable();
410 void wxeditor_memorywatch::enable_for_addr(bool is_addr)
412 CHECK_UI_THREAD;
413 expr.label()->SetLabel(towxstring(is_addr ? "Address:" : "Expr:"));
414 endianess.enable(is_addr);
415 scale.enable(is_addr);
416 vma.enable(is_addr);
417 addrbase.enable(is_addr && was_free);
418 addrsize.enable(is_addr && was_free);
419 Fit();
422 void wxeditor_memorywatch::enable_for_vma(bool free, uint64_t _base, uint64_t _size)
424 CHECK_UI_THREAD;
425 //TODO: Set default endian.
426 if(!free && !was_free) {
427 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
428 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
429 } else if(free && !was_free) {
430 addrbase->SetValue(towxstring(old_addrbase));
431 addrsize->SetValue(towxstring(old_addrsize));
432 addrbase.enable(true);
433 addrsize.enable(true);
434 } else if(!free && was_free) {
435 old_addrbase = tostdstring(addrbase->GetValue());
436 old_addrsize = tostdstring(addrsize->GetValue());
437 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
438 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
439 addrbase.enable(false);
440 addrsize.enable(false);
442 was_free = free;
445 void wxeditor_memorywatch::on_position_change(wxCommandEvent& e)
447 CHECK_UI_THREAD;
448 enable_for_pos(get_poscategory());
449 int vmasel = vma->GetSelection();
450 if(vmasel == 0)
451 enable_for_vma(true, 0, 0);
452 else if(vmas_available.count(vmasel)) {
453 enable_for_vma(false, vmas_available[vmasel].first, vmas_available[vmasel].second);
454 } else {
455 vma->SetSelection(0);
456 enable_for_vma(true, 0, 0);
458 enable_for_addr(type->GetSelection() != 0);
461 void wxeditor_memorywatch::on_fontsel(wxCommandEvent& e)
463 CHECK_UI_THREAD;
464 try {
465 std::string filename = choose_file_load(this, "Choose font file", UI_get_project_otherpath(inst),
466 filetype_font);
467 font->SetValue(towxstring(filename));
468 } catch(canceled_exception& e) {
472 void wxeditor_memorywatch::on_ok(wxCommandEvent& e)
474 CHECK_UI_THREAD;
475 memwatch_item it;
476 it.expr = tostdstring(expr->GetValue());
477 it.format = tostdstring(format->GetValue());
478 it.printer.cond_enable = cond_enable->GetValue();
479 it.printer.enabled = tostdstring(enabled->GetValue());
480 it.printer.onscreen_xpos = tostdstring(xpos->GetValue());
481 it.printer.onscreen_ypos = tostdstring(ypos->GetValue());
482 it.printer.onscreen_alt_origin_x = alt_origin_x->GetValue();
483 it.printer.onscreen_alt_origin_y = alt_origin_y->GetValue();
484 it.printer.onscreen_cliprange_x = cliprange_x->GetValue();
485 it.printer.onscreen_cliprange_y = cliprange_y->GetValue();
486 it.printer.onscreen_font = tostdstring(font->GetValue());
487 it.endianess = endianess->GetSelection() - 1;
488 try {
489 it.addr_base = hex::from<uint64_t>(tostdstring(addrbase->GetValue()));
490 it.addr_size = hex::from<uint64_t>(tostdstring(addrsize->GetValue()));
491 } catch(std::exception& e) {
492 show_message_ok(NULL, "Bad memory range", std::string("Error parsing memory range: ") + e.what(),
493 wxICON_EXCLAMATION);
494 return;
496 if(position->GetSelection() == 0) it.printer.position = memwatch_printer::PC_DISABLED;
497 else if(position->GetSelection() == 1) it.printer.position = memwatch_printer::PC_MEMORYWATCH;
498 else if(position->GetSelection() == 2) it.printer.position = memwatch_printer::PC_ONSCREEN;
499 else it.printer.position = memwatch_printer::PC_MEMORYWATCH;
500 it.signed_flag = false;
501 it.float_flag = false;
502 switch(type->GetSelection()) {
503 case 0: it.bytes = 0; break;
504 case 1: it.bytes = 1; it.signed_flag = !false; break;
505 case 2: it.bytes = 1; it.signed_flag = !true; break;
506 case 3: it.bytes = 2; it.signed_flag = !false; break;
507 case 4: it.bytes = 2; it.signed_flag = !true; break;
508 case 5: it.bytes = 3; it.signed_flag = !false; break;
509 case 6: it.bytes = 3; it.signed_flag = !true; break;
510 case 7: it.bytes = 4; it.signed_flag = !false; break;
511 case 8: it.bytes = 4; it.signed_flag = !true; break;
512 case 9: it.bytes = 4; it.float_flag = true; break;
513 case 10: it.bytes = 8; it.signed_flag = !false; break;
514 case 11: it.bytes = 8; it.signed_flag = !true; break;
515 case 12: it.bytes = 8; it.float_flag = true; break;
517 it.scale_div = 1ULL << scale->GetValue();
518 try {
519 it.printer.onscreen_fg_color = get_color(tostdstring(fg_color->GetValue()));
520 it.printer.onscreen_bg_color = get_color(tostdstring(bg_color->GetValue()));
521 it.printer.onscreen_halo_color = get_color(tostdstring(halo_color->GetValue()));
522 } catch(std::exception& e) {
523 show_message_ok(NULL, "Bad colors", std::string("Error parsing colors: ") + e.what(),
524 wxICON_EXCLAMATION);
525 return;
527 try {
528 inst.iqueue->run([this, &it]() {
529 CORE().mwatch->set(name, it);
531 } catch(std::exception& e) {
532 show_exception(NULL, "Bad values", "Error setting memory watch", e);
533 return;
535 EndModal(wxID_OK);
538 void wxeditor_memorywatch::on_cancel(wxCommandEvent& e)
540 CHECK_UI_THREAD;
541 EndModal(wxID_CANCEL);
544 class wxeditor_memorywatches : public wxDialog
546 public:
547 wxeditor_memorywatches(wxWindow* parent, emulator_instance& _inst);
548 bool ShouldPreventAppExit() const;
549 void on_memorywatch_change(wxCommandEvent& e);
550 void on_new(wxCommandEvent& e);
551 void on_rename(wxCommandEvent& e);
552 void on_delete(wxCommandEvent& e);
553 void on_edit(wxCommandEvent& e);
554 void on_close(wxCommandEvent& e);
555 private:
556 void refresh();
557 emulator_instance& inst;
558 //TODO: Make this a wxGrid.
559 wxListBox* watches;
560 wxButton* newbutton;
561 wxButton* renamebutton;
562 wxButton* deletebutton;
563 wxButton* editbutton;
564 wxButton* closebutton;
568 wxeditor_memorywatches::wxeditor_memorywatches(wxWindow* parent, emulator_instance& _inst)
569 : wxDialog(parent, wxID_ANY, wxT("lsnes: Edit memory watches"), wxDefaultPosition, wxSize(-1, -1)),
570 inst(_inst)
572 CHECK_UI_THREAD;
573 Centre();
574 wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
575 SetSizer(top_s);
577 top_s->Add(watches = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 300)), 1, wxGROW);
578 watches->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
579 wxCommandEventHandler(wxeditor_memorywatches::on_memorywatch_change), NULL, this);
581 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
582 pbutton_s->AddStretchSpacer();
583 pbutton_s->Add(newbutton = new wxButton(this, wxID_ANY, wxT("New")), 0, wxGROW);
584 pbutton_s->Add(editbutton = new wxButton(this, wxID_ANY, wxT("Edit")), 0, wxGROW);
585 pbutton_s->Add(renamebutton = new wxButton(this, wxID_ANY, wxT("Rename")), 0, wxGROW);
586 pbutton_s->Add(deletebutton = new wxButton(this, wxID_ANY, wxT("Delete")), 0, wxGROW);
587 pbutton_s->Add(closebutton = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
588 newbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
589 wxCommandEventHandler(wxeditor_memorywatches::on_new), NULL, this);
590 editbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
591 wxCommandEventHandler(wxeditor_memorywatches::on_edit), NULL, this);
592 renamebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
593 wxCommandEventHandler(wxeditor_memorywatches::on_rename), NULL, this);
594 deletebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
595 wxCommandEventHandler(wxeditor_memorywatches::on_delete), NULL, this);
596 closebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
597 wxCommandEventHandler(wxeditor_memorywatches::on_close), NULL, this);
598 top_s->Add(pbutton_s, 0, wxGROW);
600 pbutton_s->SetSizeHints(this);
601 top_s->SetSizeHints(this);
602 Fit();
604 refresh();
607 bool wxeditor_memorywatches::ShouldPreventAppExit() const
609 return false;
612 void wxeditor_memorywatches::on_memorywatch_change(wxCommandEvent& e)
614 CHECK_UI_THREAD;
615 std::string watch = tostdstring(watches->GetStringSelection());
616 editbutton->Enable(watch != "");
617 deletebutton->Enable(watch != "");
618 renamebutton->Enable(watch != "");
621 void wxeditor_memorywatches::on_new(wxCommandEvent& e)
623 CHECK_UI_THREAD;
624 try {
625 std::string newname = pick_text(this, "New watch", "Enter name for watch:");
626 if(newname == "")
627 return;
628 wxeditor_memorywatch* nwch = new wxeditor_memorywatch(this, inst, newname);
629 nwch->ShowModal();
630 nwch->Destroy();
631 refresh();
632 } catch(canceled_exception& e) {
633 //Ignore.
635 on_memorywatch_change(e);
638 void wxeditor_memorywatches::on_rename(wxCommandEvent& e)
640 CHECK_UI_THREAD;
641 std::string watch = tostdstring(watches->GetStringSelection());
642 if(watch == "")
643 return;
644 try {
645 bool exists = false;
646 std::string newname = pick_text(this, "Rename watch", "Enter New name for watch:");
647 inst.iqueue->run([watch, newname, &exists]() {
648 exists = !CORE().mwatch->rename(watch, newname);
650 if(exists)
651 show_message_ok(this, "Error", "The target watch already exists", wxICON_EXCLAMATION);
652 refresh();
653 } catch(canceled_exception& e) {
654 //Ignore.
656 on_memorywatch_change(e);
659 void wxeditor_memorywatches::on_delete(wxCommandEvent& e)
661 CHECK_UI_THREAD;
662 std::string watch = tostdstring(watches->GetStringSelection());
663 if(watch != "")
664 inst.iqueue->run([watch]() { CORE().mwatch->clear(watch); });
665 refresh();
666 on_memorywatch_change(e);
669 void wxeditor_memorywatches::on_edit(wxCommandEvent& e)
671 CHECK_UI_THREAD;
672 try {
673 std::string watch = tostdstring(watches->GetStringSelection());
674 if(watch == "")
675 return;
676 std::string wtxt;
677 wxeditor_memorywatch* ewch = new wxeditor_memorywatch(this, inst, watch);
678 ewch->ShowModal();
679 ewch->Destroy();
680 refresh();
681 } catch(canceled_exception& e) {
682 //Ignore.
684 on_memorywatch_change(e);
687 void wxeditor_memorywatches::on_close(wxCommandEvent& e)
689 CHECK_UI_THREAD;
690 EndModal(wxID_OK);
693 void wxeditor_memorywatches::refresh()
695 CHECK_UI_THREAD;
696 std::set<std::string> bind;
697 inst.iqueue->run([&bind]() {
698 bind = CORE().mwatch->enumerate();
700 watches->Clear();
701 for(auto i : bind)
702 watches->Append(towxstring(i));
703 if(watches->GetCount())
704 watches->SetSelection(0);
705 wxCommandEvent e;
706 on_memorywatch_change(e);
709 void wxeditor_memorywatches_display(wxWindow* parent, emulator_instance& inst)
711 CHECK_UI_THREAD;
712 modal_pause_holder hld;
713 wxDialog* editor;
714 try {
715 editor = new wxeditor_memorywatches(parent, inst);
716 editor->ShowModal();
717 } catch(...) {
718 return;
720 editor->Destroy();