Make various instance stuff to take references to other instance objs
[lsnes.git] / src / platform / wxwidgets / editor-memorywatch.cpp
blobcbb338ba483353776d3ba8b462ccab8232822d16
1 #include "core/instance.hpp"
2 #include "core/moviedata.hpp"
3 #include "core/memorywatch.hpp"
4 #include "core/memorymanip.hpp"
5 #include "core/project.hpp"
7 #include "platform/wxwidgets/platform.hpp"
8 #include "platform/wxwidgets/loadsave.hpp"
10 #include <wx/wx.h>
11 #include <wx/statline.h>
12 #include <wx/event.h>
13 #include <wx/control.h>
14 #include <wx/combobox.h>
15 #include <wx/radiobut.h>
16 #include <wx/spinctrl.h>
18 #include "library/string.hpp"
19 #include "library/hex.hpp"
20 #include "interface/romtype.hpp"
24 std::string main_expr;
25 std::string format;
26 unsigned memread_bytes; //0 if not memory read.
27 bool memread_signed_flag;
28 bool memread_float_flag;
29 int memread_endianess;
30 uint64_t memread_scale_div;
31 uint64_t memread_addr_base;
32 uint64_t memread_addr_size;
33 enum position_category {
34 PC_DISABLED,
35 PC_MEMORYWATCH,
36 PC_ONSCREEN
37 } position;
38 std::string enabled; //Ignored for disabled.
39 std::string onscreen_xpos;
40 std::string onscreen_ypos;
41 bool onscreen_alt_origin_x;
42 bool onscreen_alt_origin_y;
43 bool onscreen_cliprange_x;
44 bool onscreen_cliprange_y;
45 std::string onscreen_font; //"" is system default.
46 int64_t onscreen_fg_color;
47 int64_t onscreen_bg_color;
48 int64_t onscreen_halo_color;
52 namespace
54 int log2i(uint64_t v)
56 unsigned l = 0;
57 while(v > 1) {
58 v >>= 1;
59 l++;
61 return l;
64 template<class T>
65 class label_control
67 public:
68 label_control()
70 lbl = NULL;
71 ctrl = NULL;
73 template<typename... U> label_control(wxWindow* parent, const std::string& label, U... args)
75 lbl = new wxStaticText(parent, wxID_ANY, towxstring(label));
76 ctrl = new T(parent, args...);
78 void show(bool state)
80 lbl->Show(state);
81 ctrl->Show(state);
83 void enable(bool state)
85 lbl->Enable(state);
86 ctrl->Enable(state);
88 void add(wxSizer* s, bool prop = false)
90 s->Add(lbl, 0, wxALIGN_CENTER_VERTICAL);
91 s->Add(ctrl, prop ? 1 : 0, wxGROW);
93 void add_cb(std::function<void(wxStaticText* l, T* c)> cb)
95 cb(lbl, ctrl);
97 wxStaticText* label() { return lbl; }
98 T* operator->() { return ctrl; }
99 private:
100 wxStaticText* lbl;
101 T* ctrl;
104 std::string format_color(int64_t x)
106 return framebuffer::color::stringify(x);
109 int64_t get_color(std::string x)
111 return framebuffer::color(x).asnumber();
115 class wxeditor_memorywatch : public wxDialog
117 public:
118 wxeditor_memorywatch(wxWindow* parent, const std::string& name);
119 bool ShouldPreventAppExit() const;
120 void on_position_change(wxCommandEvent& e);
121 void on_fontsel(wxCommandEvent& e);
122 void on_ok(wxCommandEvent& e);
123 void on_cancel(wxCommandEvent& e);
124 void enable_condenable2(wxCommandEvent& e);
125 private:
126 void enable_for_pos(memwatch_printer::position_category p);
127 void enable_for_addr(bool is_addr);
128 void enable_for_vma(bool free, uint64_t _base, uint64_t _size);
129 void enable_condenable();
130 memwatch_printer::position_category get_poscategory();
131 label_control<wxComboBox> type;
132 label_control<wxTextCtrl> expr;
133 label_control<wxTextCtrl> format;
134 label_control<wxComboBox> endianess;
135 label_control<wxSpinCtrl> scale;
136 label_control<wxComboBox> vma;
137 label_control<wxTextCtrl> addrbase;
138 label_control<wxTextCtrl> addrsize;
139 label_control<wxComboBox> position;
140 wxCheckBox* cond_enable;
141 wxTextCtrl* enabled;
142 label_control<wxTextCtrl> xpos;
143 label_control<wxTextCtrl> ypos;
144 wxCheckBox* alt_origin_x;
145 wxCheckBox* alt_origin_y;
146 wxCheckBox* cliprange_x;
147 wxCheckBox* cliprange_y;
148 label_control<wxTextCtrl> font;
149 wxButton* font_sel;
150 label_control<wxTextCtrl> fg_color;
151 label_control<wxTextCtrl> bg_color;
152 label_control<wxTextCtrl> halo_color;
153 wxButton* ok;
154 wxButton* cancel;
155 std::string name;
156 std::string old_addrbase;
157 std::string old_addrsize;
158 bool was_free;
159 std::map<int, std::pair<uint64_t, uint64_t>> vmas_available;
162 wxeditor_memorywatch::wxeditor_memorywatch(wxWindow* parent, const std::string& _name)
163 : wxDialog(parent, wxID_ANY, towxstring("Edit memory watch '" + _name + "'")), name(_name)
165 Center();
166 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
167 SetSizer(top_s);
169 //Type.
170 wxSizer* s1 = new wxBoxSizer(wxHORIZONTAL);
171 type = label_control<wxComboBox>(this, "Data type", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
172 nullptr, wxCB_READONLY);
173 type.add(s1);
174 type->Append("(Expression)");
175 type->Append("Signed byte");
176 type->Append("Unsigned byte");
177 type->Append("Signed word");
178 type->Append("Unsigned word");
179 type->Append("Signed 3-byte");
180 type->Append("Unsigned 3-byte");
181 type->Append("Signed dword");
182 type->Append("Unsigned dword");
183 type->Append("Float");
184 type->Append("Signed qword");
185 type->Append("Unsigned qword");
186 type->Append("Double");
187 type->SetSelection(3);
188 type->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
189 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
190 endianess = label_control<wxComboBox>(this, "Endian:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
191 0, nullptr, wxCB_READONLY);
192 endianess.add(s1, true);
193 endianess->Append(wxT("Little"));
194 endianess->Append(wxT("Host"));
195 endianess->Append(wxT("Big"));
196 endianess->SetSelection(0);
197 scale = label_control<wxSpinCtrl>(this, "Scale bits:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
198 wxSP_ARROW_KEYS, 0, 63, 0);
199 scale.add(s1);
200 top_s->Add(s1, 1, wxGROW);
202 //Memory range.
203 wxSizer* s5 = new wxBoxSizer(wxHORIZONTAL);
204 vma = label_control<wxComboBox>(this, "Memory:", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0,
205 nullptr, wxCB_READONLY);
206 vma.add(s5, true);
207 vma->Append(wxT("(All)"));
208 auto i = lsnes_instance.memory.get_regions();
209 for(auto j : i) {
210 int id = vma->GetCount();
211 vma->Append(towxstring(j->name));
212 vmas_available[id] = std::make_pair(j->base, j->size);
214 vma->SetSelection(0);
215 vma->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
216 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
217 addrbase = label_control<wxTextCtrl>(this, "Base:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
218 addrbase.add(s5, true);
219 addrsize = label_control<wxTextCtrl>(this, "Size:", wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(100, -1));
220 addrsize.add(s5, true);
221 top_s->Add(s5, 1, wxGROW);
223 //Expression.
224 wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
225 expr = label_control<wxTextCtrl>(this, "Address:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
226 expr.add(s2, true);
227 top_s->Add(s2, 1, wxGROW);
229 //Format:
230 wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
231 format = label_control<wxTextCtrl>(this, "Format:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
232 format.add(s3, true);
233 top_s->Add(s3, 1, wxGROW);
235 wxSizer* sx = new wxBoxSizer(wxVERTICAL);
236 sx->Add(1, 11);
237 top_s->Add(sx, 0, wxGROW);
239 wxSizer* s6 = new wxBoxSizer(wxHORIZONTAL);
240 position = label_control<wxComboBox>(this, "Position: ", wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
241 0, nullptr, wxCB_READONLY);
242 position.add(s6, true);
243 position->Append(wxT("Disabled"));
244 position->Append(wxT("Memory watch"));
245 position->Append(wxT("On screen"));
246 position->SetSelection(1);
247 position->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
248 wxCommandEventHandler(wxeditor_memorywatch::on_position_change), NULL, this);
249 top_s->Add(s6, 0, wxGROW);
251 wxSizer* s7 = new wxBoxSizer(wxHORIZONTAL);
252 s7->Add(cond_enable = new wxCheckBox(this, wxID_ANY, wxT("Conditional on: ")), 0, wxGROW);
253 s7->Add(enabled = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1, wxGROW);
254 cond_enable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
255 wxCommandEventHandler(wxeditor_memorywatch::enable_condenable2), NULL, this);
256 top_s->Add(s7, 0, wxGROW);
258 wxSizer* s8 = new wxBoxSizer(wxHORIZONTAL);
260 xpos = label_control<wxTextCtrl>(this, "X:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
261 xpos.add(s8, true);
262 s8->Add(alt_origin_x = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
263 s8->Add(cliprange_x = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
264 top_s->Add(s8, 0, wxGROW);
266 wxSizer* s9 = new wxBoxSizer(wxHORIZONTAL);
267 ypos = label_control<wxTextCtrl>(this, "Y:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
268 ypos.add(s9, true);
269 s9->Add(alt_origin_y = new wxCheckBox(this, wxID_ANY, wxT("Alt. origin")), 0, wxGROW);
270 s9->Add(cliprange_y = new wxCheckBox(this, wxID_ANY, wxT("Clip range")), 0, wxGROW);
271 top_s->Add(s9, 0, wxGROW);
273 wxSizer* s10 = new wxBoxSizer(wxHORIZONTAL);
274 font = label_control<wxTextCtrl>(this, "Font:", wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1));
275 font.add(s10, true);
276 s10->Add(font_sel = new wxButton(this, wxID_ANY, wxT("...")), 0, wxGROW);
277 font_sel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
278 wxCommandEventHandler(wxeditor_memorywatch::on_fontsel), NULL, this);
279 top_s->Add(s10, 0, wxGROW);
281 wxSizer* s11 = new wxBoxSizer(wxHORIZONTAL);
282 fg_color = label_control<wxTextCtrl>(this, "Foreground:", wxID_ANY, wxT("#FFFFFF"),
283 wxDefaultPosition, wxSize(100, -1));
284 fg_color.add(s11, true);
285 bg_color = label_control<wxTextCtrl>(this, "Background:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
286 wxSize(100, -1));
287 bg_color.add(s11, true);
288 halo_color = label_control<wxTextCtrl>(this, "Halo:", wxID_ANY, wxT("transparent"), wxDefaultPosition,
289 wxSize(100, -1));
290 halo_color.add(s11, true);
291 top_s->Add(s11, 0, wxGROW);
293 wxSizer* s12 = new wxBoxSizer(wxHORIZONTAL);
294 s12->AddStretchSpacer();
295 s12->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
296 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_ok), NULL, this);
297 s12->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
298 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_memorywatch::on_cancel), NULL,
299 this);
300 top_s->Add(s12, 0, wxGROW);
302 memwatch_item it(lsnes_instance.memory);
303 bool had_it = false;
304 try {
305 it = lsnes_instance.mwatch.get(name);
306 had_it = true;
307 } catch(...) {
309 if(had_it) {
310 expr->SetValue(towxstring(it.expr));
311 format->SetValue(towxstring(it.format));
312 cond_enable->SetValue(it.printer.cond_enable);
313 enabled->SetValue(it.printer.enabled);
314 xpos->SetValue(it.printer.onscreen_xpos);
315 ypos->SetValue(it.printer.onscreen_ypos);
316 alt_origin_x->SetValue(it.printer.onscreen_alt_origin_x);
317 alt_origin_y->SetValue(it.printer.onscreen_alt_origin_y);
318 cliprange_x->SetValue(it.printer.onscreen_cliprange_x);
319 cliprange_y->SetValue(it.printer.onscreen_cliprange_y);
320 endianess->SetSelection(it.endianess + 1);
321 addrbase->SetValue(towxstring(hex::to<uint64_t>(it.addr_base)));
322 addrsize->SetValue(towxstring(hex::to<uint64_t>(it.addr_size)));
323 if(it.printer.position == memwatch_printer::PC_DISABLED) position->SetSelection(0);
324 if(it.printer.position == memwatch_printer::PC_MEMORYWATCH) position->SetSelection(1);
325 if(it.printer.position == memwatch_printer::PC_ONSCREEN) position->SetSelection(2);
326 switch(it.bytes) {
327 case 0: type->SetSelection(0); break;
328 case 1: type->SetSelection(it.signed_flag ? 1 : 2); break;
329 case 2: type->SetSelection(it.signed_flag ? 3 : 4); break;
330 case 3: type->SetSelection(it.signed_flag ? 5 : 6); break;
331 case 4: type->SetSelection(it.float_flag ? 9 : (it.signed_flag ? 7 : 8)); break;
332 case 8: type->SetSelection(it.float_flag ? 12 : (it.signed_flag ? 11 : 10)); break;
334 scale->SetValue(log2i(it.scale_div));
335 for(auto j : vmas_available) {
336 if(j.second.first == it.addr_base && j.second.second == it.addr_size)
337 vma->SetSelection(j.first);
339 font->SetValue(it.printer.onscreen_font);
340 fg_color->SetValue(towxstring(format_color(it.printer.onscreen_fg_color)));
341 bg_color->SetValue(towxstring(format_color(it.printer.onscreen_bg_color)));
342 halo_color->SetValue(towxstring(format_color(it.printer.onscreen_halo_color)));
345 wxCommandEvent e;
346 on_position_change(e);
347 top_s->SetSizeHints(this);
348 Fit();
351 bool wxeditor_memorywatch::ShouldPreventAppExit() const
353 return false;
356 memwatch_printer::position_category wxeditor_memorywatch::get_poscategory()
358 if(position->GetSelection() == 0) return memwatch_printer::PC_DISABLED;
359 if(position->GetSelection() == 1) return memwatch_printer::PC_MEMORYWATCH;
360 if(position->GetSelection() == 2) return memwatch_printer::PC_ONSCREEN;
361 return memwatch_printer::PC_DISABLED; //NOTREACHED.
364 void wxeditor_memorywatch::enable_for_pos(memwatch_printer::position_category p)
366 bool full_disable = (p == memwatch_printer::PC_DISABLED);
367 cond_enable->Enable(!full_disable);
368 enabled->Enable(cond_enable->GetValue() && !full_disable);
369 xpos.enable(p == memwatch_printer::PC_ONSCREEN);
370 ypos.enable(p == memwatch_printer::PC_ONSCREEN);
371 alt_origin_x->Enable(p == memwatch_printer::PC_ONSCREEN);
372 alt_origin_y->Enable(p == memwatch_printer::PC_ONSCREEN);
373 cliprange_x->Enable(p == memwatch_printer::PC_ONSCREEN);
374 cliprange_y->Enable(p == memwatch_printer::PC_ONSCREEN);
375 font.enable(p == memwatch_printer::PC_ONSCREEN);
376 font_sel->Enable(p == memwatch_printer::PC_ONSCREEN);
377 fg_color.enable(p == memwatch_printer::PC_ONSCREEN);
378 bg_color.enable(p == memwatch_printer::PC_ONSCREEN);
379 halo_color.enable(p == memwatch_printer::PC_ONSCREEN);
382 void wxeditor_memorywatch::enable_condenable()
384 memwatch_printer::position_category p = get_poscategory();
385 bool full_disable = (p == memwatch_printer::PC_DISABLED);
386 enabled->Enable(cond_enable->GetValue() && !full_disable);
389 void wxeditor_memorywatch::enable_condenable2(wxCommandEvent& e)
391 enable_condenable();
394 void wxeditor_memorywatch::enable_for_addr(bool is_addr)
396 expr.label()->SetLabel(towxstring(is_addr ? "Address:" : "Expr:"));
397 endianess.enable(is_addr);
398 scale.enable(is_addr);
399 vma.enable(is_addr);
400 addrbase.enable(is_addr && was_free);
401 addrsize.enable(is_addr && was_free);
402 Fit();
405 void wxeditor_memorywatch::enable_for_vma(bool free, uint64_t _base, uint64_t _size)
407 //TODO: Set default endian.
408 if(!free && !was_free) {
409 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
410 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
411 } else if(free && !was_free) {
412 addrbase->SetValue(towxstring(old_addrbase));
413 addrsize->SetValue(towxstring(old_addrsize));
414 addrbase.enable(true);
415 addrsize.enable(true);
416 } else if(!free && was_free) {
417 old_addrbase = tostdstring(addrbase->GetValue());
418 old_addrsize = tostdstring(addrsize->GetValue());
419 addrbase->SetValue(towxstring((stringfmt() << std::hex << _base).str()));
420 addrsize->SetValue(towxstring((stringfmt() << std::hex << _size).str()));
421 addrbase.enable(false);
422 addrsize.enable(false);
424 was_free = free;
427 void wxeditor_memorywatch::on_position_change(wxCommandEvent& e)
429 enable_for_pos(get_poscategory());
430 int vmasel = vma->GetSelection();
431 if(vmasel == 0)
432 enable_for_vma(true, 0, 0);
433 else if(vmas_available.count(vmasel)) {
434 enable_for_vma(false, vmas_available[vmasel].first, vmas_available[vmasel].second);
435 } else {
436 vma->SetSelection(0);
437 enable_for_vma(true, 0, 0);
439 enable_for_addr(type->GetSelection() != 0);
442 void wxeditor_memorywatch::on_fontsel(wxCommandEvent& e)
444 try {
445 std::string filename = choose_file_load(this, "Choose font file", lsnes_instance.project.otherpath(),
446 filetype_font);
447 font->SetValue(towxstring(filename));
448 } catch(canceled_exception& e) {
452 void wxeditor_memorywatch::on_ok(wxCommandEvent& e)
454 memwatch_item it(lsnes_instance.memory);
455 it.expr = tostdstring(expr->GetValue());
456 it.format = tostdstring(format->GetValue());
457 it.printer.cond_enable = cond_enable->GetValue();
458 it.printer.enabled = tostdstring(enabled->GetValue());
459 it.printer.onscreen_xpos = tostdstring(xpos->GetValue());
460 it.printer.onscreen_ypos = tostdstring(ypos->GetValue());
461 it.printer.onscreen_alt_origin_x = alt_origin_x->GetValue();
462 it.printer.onscreen_alt_origin_y = alt_origin_y->GetValue();
463 it.printer.onscreen_cliprange_x = cliprange_x->GetValue();
464 it.printer.onscreen_cliprange_y = cliprange_y->GetValue();
465 it.printer.onscreen_font = tostdstring(font->GetValue());
466 it.endianess = endianess->GetSelection() - 1;
467 try {
468 it.addr_base = hex::from<uint64_t>(tostdstring(addrbase->GetValue()));
469 it.addr_size = hex::from<uint64_t>(tostdstring(addrsize->GetValue()));
470 } catch(std::exception& e) {
471 show_message_ok(NULL, "Bad memory range", std::string("Error parsing memory range: ") + e.what(),
472 wxICON_EXCLAMATION);
473 return;
475 if(position->GetSelection() == 0) it.printer.position = memwatch_printer::PC_DISABLED;
476 else if(position->GetSelection() == 1) it.printer.position = memwatch_printer::PC_MEMORYWATCH;
477 else if(position->GetSelection() == 2) it.printer.position = memwatch_printer::PC_ONSCREEN;
478 else it.printer.position = memwatch_printer::PC_MEMORYWATCH;
479 it.signed_flag = false;
480 it.float_flag = false;
481 switch(type->GetSelection()) {
482 case 0: it.bytes = 0; break;
483 case 1: it.bytes = 1; it.signed_flag = !false; break;
484 case 2: it.bytes = 1; it.signed_flag = !true; break;
485 case 3: it.bytes = 2; it.signed_flag = !false; break;
486 case 4: it.bytes = 2; it.signed_flag = !true; break;
487 case 5: it.bytes = 3; it.signed_flag = !false; break;
488 case 6: it.bytes = 3; it.signed_flag = !true; break;
489 case 7: it.bytes = 4; it.signed_flag = !false; break;
490 case 8: it.bytes = 4; it.signed_flag = !true; break;
491 case 9: it.bytes = 4; it.float_flag = true; break;
492 case 10: it.bytes = 8; it.signed_flag = !false; break;
493 case 11: it.bytes = 8; it.signed_flag = !true; break;
494 case 12: it.bytes = 8; it.float_flag = true; break;
496 it.scale_div = 1ULL << scale->GetValue();
497 try {
498 it.printer.onscreen_fg_color = get_color(tostdstring(fg_color->GetValue()));
499 it.printer.onscreen_bg_color = get_color(tostdstring(bg_color->GetValue()));
500 it.printer.onscreen_halo_color = get_color(tostdstring(halo_color->GetValue()));
501 } catch(std::exception& e) {
502 show_message_ok(NULL, "Bad colors", std::string("Error parsing colors: ") + e.what(),
503 wxICON_EXCLAMATION);
504 return;
506 bool did_error = false;
507 std::string error;
508 lsnes_instance.iqueue.run([this, &it, &did_error, &error]() {
509 try {
510 lsnes_instance.mwatch.set(name, it);
511 } catch(std::exception& e) {
512 did_error = true;
513 error = e.what();
516 if(did_error) {
517 show_message_ok(NULL, "Bad values", std::string("Error setting memory watch: ") + error,
518 wxICON_EXCLAMATION);
519 return;
521 EndModal(wxID_OK);
524 void wxeditor_memorywatch::on_cancel(wxCommandEvent& e)
526 EndModal(wxID_CANCEL);
529 class wxeditor_memorywatches : public wxDialog
531 public:
532 wxeditor_memorywatches(wxWindow* parent);
533 bool ShouldPreventAppExit() const;
534 void on_memorywatch_change(wxCommandEvent& e);
535 void on_new(wxCommandEvent& e);
536 void on_rename(wxCommandEvent& e);
537 void on_delete(wxCommandEvent& e);
538 void on_edit(wxCommandEvent& e);
539 void on_close(wxCommandEvent& e);
540 private:
541 void refresh();
542 //TODO: Make this a wxGrid.
543 wxListBox* watches;
544 wxButton* newbutton;
545 wxButton* renamebutton;
546 wxButton* deletebutton;
547 wxButton* editbutton;
548 wxButton* closebutton;
552 wxeditor_memorywatches::wxeditor_memorywatches(wxWindow* parent)
553 : wxDialog(parent, wxID_ANY, wxT("lsnes: Edit memory watches"), wxDefaultPosition, wxSize(-1, -1))
555 Centre();
556 wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
557 SetSizer(top_s);
559 top_s->Add(watches = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 300)), 1, wxGROW);
560 watches->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
561 wxCommandEventHandler(wxeditor_memorywatches::on_memorywatch_change), NULL, this);
563 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
564 pbutton_s->AddStretchSpacer();
565 pbutton_s->Add(newbutton = new wxButton(this, wxID_ANY, wxT("New")), 0, wxGROW);
566 pbutton_s->Add(editbutton = new wxButton(this, wxID_ANY, wxT("Edit")), 0, wxGROW);
567 pbutton_s->Add(renamebutton = new wxButton(this, wxID_ANY, wxT("Rename")), 0, wxGROW);
568 pbutton_s->Add(deletebutton = new wxButton(this, wxID_ANY, wxT("Delete")), 0, wxGROW);
569 pbutton_s->Add(closebutton = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
570 newbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
571 wxCommandEventHandler(wxeditor_memorywatches::on_new), NULL, this);
572 editbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
573 wxCommandEventHandler(wxeditor_memorywatches::on_edit), NULL, this);
574 renamebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
575 wxCommandEventHandler(wxeditor_memorywatches::on_rename), NULL, this);
576 deletebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
577 wxCommandEventHandler(wxeditor_memorywatches::on_delete), NULL, this);
578 closebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
579 wxCommandEventHandler(wxeditor_memorywatches::on_close), NULL, this);
580 top_s->Add(pbutton_s, 0, wxGROW);
582 pbutton_s->SetSizeHints(this);
583 top_s->SetSizeHints(this);
584 Fit();
586 refresh();
589 bool wxeditor_memorywatches::ShouldPreventAppExit() const
591 return false;
594 void wxeditor_memorywatches::on_memorywatch_change(wxCommandEvent& e)
596 std::string watch = tostdstring(watches->GetStringSelection());
597 editbutton->Enable(watch != "");
598 deletebutton->Enable(watch != "");
599 renamebutton->Enable(watch != "");
602 void wxeditor_memorywatches::on_new(wxCommandEvent& e)
604 try {
605 std::string newname = pick_text(this, "New watch", "Enter name for watch:");
606 if(newname == "")
607 return;
608 wxeditor_memorywatch* nwch = new wxeditor_memorywatch(this, newname);
609 nwch->ShowModal();
610 nwch->Destroy();
611 refresh();
612 } catch(canceled_exception& e) {
613 //Ignore.
615 on_memorywatch_change(e);
618 void wxeditor_memorywatches::on_rename(wxCommandEvent& e)
620 std::string watch = tostdstring(watches->GetStringSelection());
621 if(watch == "")
622 return;
623 try {
624 bool exists = false;
625 std::string newname = pick_text(this, "Rename watch", "Enter New name for watch:");
626 lsnes_instance.iqueue.run([watch, newname, &exists]() {
627 exists = !lsnes_instance.mwatch.rename(watch, newname);
629 if(exists)
630 show_message_ok(this, "Error", "The target watch already exists", wxICON_EXCLAMATION);
631 refresh();
632 } catch(canceled_exception& e) {
633 //Ignore.
635 on_memorywatch_change(e);
638 void wxeditor_memorywatches::on_delete(wxCommandEvent& e)
640 std::string watch = tostdstring(watches->GetStringSelection());
641 if(watch != "")
642 lsnes_instance.iqueue.run([watch]() { lsnes_instance.mwatch.clear(watch); });
643 refresh();
644 on_memorywatch_change(e);
647 void wxeditor_memorywatches::on_edit(wxCommandEvent& e)
649 try {
650 std::string watch = tostdstring(watches->GetStringSelection());
651 if(watch == "")
652 return;
653 std::string wtxt;
654 wxeditor_memorywatch* ewch = new wxeditor_memorywatch(this, watch);
655 ewch->ShowModal();
656 ewch->Destroy();
657 refresh();
658 } catch(canceled_exception& e) {
659 //Ignore.
661 on_memorywatch_change(e);
664 void wxeditor_memorywatches::on_close(wxCommandEvent& e)
666 EndModal(wxID_OK);
669 void wxeditor_memorywatches::refresh()
671 std::set<std::string> bind;
672 lsnes_instance.iqueue.run([&bind]() {
673 bind = lsnes_instance.mwatch.enumerate();
675 watches->Clear();
676 for(auto i : bind)
677 watches->Append(towxstring(i));
678 if(watches->GetCount())
679 watches->SetSelection(0);
680 wxCommandEvent e;
681 on_memorywatch_change(e);
684 void wxeditor_memorywatches_display(wxWindow* parent)
686 modal_pause_holder hld;
687 wxDialog* editor;
688 try {
689 editor = new wxeditor_memorywatches(parent);
690 editor->ShowModal();
691 } catch(...) {
692 return;
694 editor->Destroy();