Upload UI
[lsnes.git] / src / platform / wxwidgets / editor-memorywatch.cpp
blob6654eed2bcbff7f8f7fcaba14c77b9bd4a4a991c
1 #include "core/moviedata.hpp"
2 #include "core/memorywatch.hpp"
4 #include "platform/wxwidgets/platform.hpp"
6 #include <wx/wx.h>
7 #include <wx/event.h>
8 #include <wx/control.h>
9 #include <wx/combobox.h>
10 #include <wx/radiobut.h>
12 #include "library/string.hpp"
13 #include "interface/romtype.hpp"
15 class wxeditor_watchexpr : public wxDialog
17 public:
18 wxeditor_watchexpr(wxWindow* parent, const std::string& name, const std::string& expr);
19 bool ShouldPreventAppExit() const;
20 void on_ok(wxCommandEvent& e);
21 void on_cancel(wxCommandEvent& e);
22 void on_rb_structured(wxCommandEvent& e);
23 void on_rb_arbitrary(wxCommandEvent& e);
24 void on_rb_busaddr(wxCommandEvent& e);
25 void on_rb_mapaddr(wxCommandEvent& e);
26 void on_addr_change(wxCommandEvent& e);
27 std::string get_expr();
28 private:
29 std::string out;
30 wxRadioButton* structured;
31 wxRadioButton* arbitrary;
32 wxComboBox* typesel;
33 wxRadioButton* busaddr;
34 wxRadioButton* mapaddr;
35 wxTextCtrl* addr;
36 wxCheckBox* hex;
37 wxTextCtrl* watchtxt;
38 wxButton* ok;
39 wxButton* cancel;
42 int memorywatch_recognize_typech(char ch)
44 switch(ch) {
45 case 'b': return 0;
46 case 'B': return 1;
47 case 'w': return 2;
48 case 'W': return 3;
49 case 'o': return 4;
50 case 'O': return 5;
51 case 'd': return 6;
52 case 'D': return 7;
53 case 'q': return 8;
54 case 'Q': return 9;
55 case 'f': return 10;
56 case 'F': return 11;
57 default: return 0;
61 wxeditor_watchexpr::wxeditor_watchexpr(wxWindow* parent, const std::string& name, const std::string& expr)
62 : wxDialog(parent, wxID_ANY, towxstring("lsnes: Edit watch " + name), wxDefaultPosition, wxSize(-1, -1))
64 wxString types[] = {
65 wxT("Signed byte"), wxT("Unsigned byte"), wxT("Signed word"), wxT("Unsigned word"),
66 wxT("Signed onehalfword"), wxT("Unsigned onehalfword"), wxT("Signed doubleword"),
67 wxT("Unsigned doubleword"), wxT("Signed quadword"), wxT("Unsigned quadword"),
68 wxT("Float"), wxT("double")
71 Centre();
72 wxFlexGridSizer* top_s = new wxFlexGridSizer(9, 1, 0, 0);
73 SetSizer(top_s);
75 top_s->Add(structured = new wxRadioButton(this, wxID_ANY, wxT("Value"), wxDefaultPosition, wxDefaultSize,
76 wxRB_GROUP), 0, wxGROW);
77 top_s->Add(arbitrary = new wxRadioButton(this, wxID_ANY, wxT("Expression"), wxDefaultPosition, wxDefaultSize,
78 0), 0, wxGROW);
79 top_s->Add(typesel = new wxComboBox(this, wxID_ANY, types[0], wxDefaultPosition, wxDefaultSize,
80 12, types, wxCB_READONLY), 0, wxGROW);
81 top_s->Add(busaddr = new wxRadioButton(this, wxID_ANY, wxT("Bus address"), wxDefaultPosition, wxDefaultSize,
82 wxRB_GROUP), 0, wxGROW);
83 top_s->Add(mapaddr = new wxRadioButton(this, wxID_ANY, wxT("Map address"), wxDefaultPosition, wxDefaultSize,
84 0), 0, wxGROW);
85 top_s->Add(addr = new wxTextCtrl(this, wxID_ANY, towxstring(""), wxDefaultPosition, wxSize(200, -1)), 0,
86 wxGROW);
87 top_s->Add(hex = new wxCheckBox(this, wxID_ANY, towxstring("Hex formatting")), 0, wxGROW);
88 top_s->Add(watchtxt = new wxTextCtrl(this, wxID_ANY, towxstring(expr), wxDefaultPosition, wxSize(400, -1)), 1,
89 wxGROW);
90 structured->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
91 wxCommandEventHandler(wxeditor_watchexpr::on_rb_structured), NULL, this);
92 arbitrary->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
93 wxCommandEventHandler(wxeditor_watchexpr::on_rb_arbitrary), NULL, this);
94 busaddr->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
95 wxCommandEventHandler(wxeditor_watchexpr::on_rb_busaddr), NULL, this);
96 mapaddr->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
97 wxCommandEventHandler(wxeditor_watchexpr::on_rb_mapaddr), NULL, this);
98 addr->Connect(wxEVT_COMMAND_TEXT_UPDATED,
99 wxCommandEventHandler(wxeditor_watchexpr::on_addr_change), NULL, this);
100 addr->SetMaxLength(16);
101 watchtxt->Connect(wxEVT_COMMAND_TEXT_UPDATED,
102 wxCommandEventHandler(wxeditor_watchexpr::on_addr_change), NULL, this);
104 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
105 pbutton_s->AddStretchSpacer();
106 pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("Ok")), 0, wxGROW);
107 pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
108 ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
109 wxCommandEventHandler(wxeditor_watchexpr::on_ok), NULL, this);
110 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
111 wxCommandEventHandler(wxeditor_watchexpr::on_cancel), NULL, this);
112 top_s->Add(pbutton_s);
114 pbutton_s->SetSizeHints(this);
115 top_s->SetSizeHints(this);
116 Fit();
118 regex_results r;
119 if(expr == "") {
120 structured->SetValue(true);
121 busaddr->SetValue(our_rom.rtype->get_bus_map().second);
122 mapaddr->SetValue(!our_rom.rtype->get_bus_map().second);
123 busaddr->Enable(our_rom.rtype->get_bus_map().second);
124 watchtxt->Disable();
125 } else if(r = regex("C0x([0-9A-Fa-f]{1,16})z([bBwWdDqQ])(H([0-9A-Ga-g]))?", expr)) {
126 structured->SetValue(true);
127 mapaddr->SetValue(true);
128 busaddr->Enable(our_rom.rtype->get_bus_map().second);
129 watchtxt->Disable();
130 std::string addr2 = r[1];
131 char* end;
132 char buf[512];
133 std::copy(addr2.begin(), addr2.end(), buf);
134 uint64_t parsed = strtoull(buf, &end, 16);
135 auto r2 = our_rom.rtype->get_bus_map();
136 if(parsed >= r2.first && parsed < r2.first + r2.second) {
137 parsed -= r2.first;
138 busaddr->SetValue(true);
140 addr->SetValue(towxstring((stringfmt() << std::hex << parsed).str()));
141 typesel->SetSelection(memorywatch_recognize_typech(r[2][0]));
142 hex->SetValue(r[3] != "");
143 } else {
144 arbitrary->SetValue(true);
145 (our_rom.rtype->get_bus_map().second ? busaddr : mapaddr)->SetValue(true);
146 mapaddr->Disable();
147 busaddr->Disable();
148 hex->Disable();
149 watchtxt->Enable();
151 wxCommandEvent e;
152 on_addr_change(e);
155 bool wxeditor_watchexpr::ShouldPreventAppExit() const
157 return false;
160 void wxeditor_watchexpr::on_ok(wxCommandEvent& e)
162 const char* letters = "bBwWoOdDqQfF";
163 const char* hexwidths = "22446688GGGG";
164 if(structured->GetValue()) {
165 std::string hexmod;
166 std::string addr2 = tostdstring(addr->GetValue());
167 char* end;
168 uint64_t parsed = strtoull(addr2.c_str(), &end, 16);
169 if(busaddr->GetValue())
170 parsed += our_rom.rtype->get_bus_map().first;
171 if(hex->GetValue())
172 hexmod = std::string("H") + hexwidths[typesel->GetSelection()];
173 out = (stringfmt() << "C0x" << std::hex << parsed << "z" << letters[typesel->GetSelection()]
174 << hexmod).str();
175 } else
176 out = tostdstring(watchtxt->GetValue());
177 EndModal(wxID_OK);
180 void wxeditor_watchexpr::on_cancel(wxCommandEvent& e)
182 EndModal(wxID_CANCEL);
185 void wxeditor_watchexpr::on_rb_arbitrary(wxCommandEvent& e)
187 typesel->Disable();
188 busaddr->Disable();
189 mapaddr->Disable();
190 addr->Disable();
191 hex->Disable();
192 watchtxt->Enable();
193 on_addr_change(e);
196 void wxeditor_watchexpr::on_rb_structured(wxCommandEvent& e)
198 typesel->Enable();
199 busaddr->Enable(our_rom.rtype->get_bus_map().second);
200 mapaddr->Enable();
201 addr->Enable();
202 hex->Enable();
203 watchtxt->Disable();
204 on_addr_change(e);
207 void wxeditor_watchexpr::on_rb_busaddr(wxCommandEvent& e)
209 on_addr_change(e);
212 void wxeditor_watchexpr::on_rb_mapaddr(wxCommandEvent& e)
214 on_addr_change(e);
217 void wxeditor_watchexpr::on_addr_change(wxCommandEvent& e)
219 if(structured->GetValue()) {
220 std::string addr2 = tostdstring(addr->GetValue());
221 if(!regex_match("[0-9A-Fa-f]{1,16}", addr2)) {
222 ok->Enable(false);
223 return;
225 char* end;
226 uint64_t parsed = strtoull(addr2.c_str(), &end, 16);
227 if(busaddr->GetValue() && parsed >= our_rom.rtype->get_bus_map().second) {
228 ok->Enable(false);
229 return;
231 ok->Enable(true);
232 } else
233 ok->Enable(tostdstring(watchtxt->GetValue()) != "");
237 std::string wxeditor_watchexpr::get_expr()
239 return out;
243 std::string memorywatch_edit_watchexpr(wxWindow* parent, const std::string& name, const std::string& expr)
245 wxeditor_watchexpr* d = new wxeditor_watchexpr(parent, name, expr);
246 if(d->ShowModal() != wxID_OK) {
247 d->Destroy();
248 throw canceled_exception();
250 std::string out = d->get_expr();
251 d->Destroy();
252 return out;
255 class wxeditor_memorywatch : public wxDialog
257 public:
258 wxeditor_memorywatch(wxWindow* parent);
259 bool ShouldPreventAppExit() const;
260 void on_memorywatch_change(wxCommandEvent& e);
261 void on_new(wxCommandEvent& e);
262 void on_rename(wxCommandEvent& e);
263 void on_delete(wxCommandEvent& e);
264 void on_edit(wxCommandEvent& e);
265 void on_close(wxCommandEvent& e);
266 private:
267 void refresh();
268 wxListBox* watches;
269 wxButton* newbutton;
270 wxButton* renamebutton;
271 wxButton* deletebutton;
272 wxButton* editbutton;
273 wxButton* closebutton;
277 wxeditor_memorywatch::wxeditor_memorywatch(wxWindow* parent)
278 : wxDialog(parent, wxID_ANY, wxT("lsnes: Edit memory watches"), wxDefaultPosition, wxSize(-1, -1))
280 Centre();
281 wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
282 SetSizer(top_s);
284 top_s->Add(watches = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 300)), 1, wxGROW);
285 watches->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
286 wxCommandEventHandler(wxeditor_memorywatch::on_memorywatch_change), NULL, this);
288 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
289 pbutton_s->AddStretchSpacer();
290 pbutton_s->Add(newbutton = new wxButton(this, wxID_ANY, wxT("New")), 0, wxGROW);
291 pbutton_s->Add(editbutton = new wxButton(this, wxID_ANY, wxT("Edit")), 0, wxGROW);
292 pbutton_s->Add(renamebutton = new wxButton(this, wxID_ANY, wxT("Rename")), 0, wxGROW);
293 pbutton_s->Add(deletebutton = new wxButton(this, wxID_ANY, wxT("Delete")), 0, wxGROW);
294 pbutton_s->Add(closebutton = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
295 newbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
296 wxCommandEventHandler(wxeditor_memorywatch::on_new), NULL, this);
297 editbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
298 wxCommandEventHandler(wxeditor_memorywatch::on_edit), NULL, this);
299 renamebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
300 wxCommandEventHandler(wxeditor_memorywatch::on_rename), NULL, this);
301 deletebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
302 wxCommandEventHandler(wxeditor_memorywatch::on_delete), NULL, this);
303 closebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
304 wxCommandEventHandler(wxeditor_memorywatch::on_close), NULL, this);
305 top_s->Add(pbutton_s, 0, wxGROW);
307 pbutton_s->SetSizeHints(this);
308 top_s->SetSizeHints(this);
309 Fit();
311 refresh();
314 bool wxeditor_memorywatch::ShouldPreventAppExit() const
316 return false;
319 void wxeditor_memorywatch::on_memorywatch_change(wxCommandEvent& e)
321 std::string watch = tostdstring(watches->GetStringSelection());
322 editbutton->Enable(watch != "");
323 deletebutton->Enable(watch != "");
324 renamebutton->Enable(watch != "");
327 void wxeditor_memorywatch::on_new(wxCommandEvent& e)
329 try {
330 std::string newname = pick_text(this, "New watch", "Enter name for watch:");
331 if(newname == "")
332 return;
333 std::string newtext = memorywatch_edit_watchexpr(this, newname, "");
334 if(newtext != "")
335 runemufn([newname, newtext]() { set_watchexpr_for(newname, newtext); });
336 refresh();
337 } catch(canceled_exception& e) {
338 //Ignore.
340 on_memorywatch_change(e);
343 void wxeditor_memorywatch::on_rename(wxCommandEvent& e)
345 std::string watch = tostdstring(watches->GetStringSelection());
346 if(watch == "")
347 return;
348 try {
349 bool exists = false;
350 std::string newname = pick_text(this, "Rename watch", "Enter New name for watch:");
351 runemufn([watch, newname, &exists]() {
352 std::string x = get_watchexpr_for(watch);
353 std::string y = get_watchexpr_for(newname);
354 if(y != "")
355 exists = true;
356 else {
357 set_watchexpr_for(watch, "");
358 set_watchexpr_for(newname, x);
361 if(exists)
362 show_message_ok(this, "Error", "The target watch already exists", wxICON_EXCLAMATION);
363 refresh();
364 } catch(canceled_exception& e) {
365 //Ignore.
367 on_memorywatch_change(e);
370 void wxeditor_memorywatch::on_delete(wxCommandEvent& e)
372 std::string watch = tostdstring(watches->GetStringSelection());
373 if(watch != "")
374 runemufn([watch]() { set_watchexpr_for(watch, ""); });
375 refresh();
376 on_memorywatch_change(e);
379 void wxeditor_memorywatch::on_edit(wxCommandEvent& e)
381 std::string watch = tostdstring(watches->GetStringSelection());
382 if(watch == "")
383 return;
384 try {
385 std::string wtxt;
386 runemufn([watch, &wtxt]() { wtxt = get_watchexpr_for(watch); });
387 wtxt = memorywatch_edit_watchexpr(this, watch, wtxt);
388 if(wtxt != "")
389 runemufn([watch, wtxt]() { set_watchexpr_for(watch, wtxt); });
390 refresh();
391 } catch(canceled_exception& e) {
392 //Ignore.
394 on_memorywatch_change(e);
397 void wxeditor_memorywatch::on_close(wxCommandEvent& e)
399 EndModal(wxID_OK);
402 void wxeditor_memorywatch::refresh()
404 std::map<std::string, std::string> bind;
405 runemufn([&bind]() {
406 std::set<std::string> x = get_watches();
407 for(auto i : x)
408 bind[i] = get_watchexpr_for(i);
410 watches->Clear();
411 for(auto i : bind)
412 watches->Append(towxstring(i.first));
413 if(watches->GetCount())
414 watches->SetSelection(0);
415 wxCommandEvent e;
416 on_memorywatch_change(e);
419 void wxeditor_memorywatch_display(wxWindow* parent)
421 modal_pause_holder hld;
422 wxDialog* editor;
423 try {
424 editor = new wxeditor_memorywatch(parent);
425 editor->ShowModal();
426 } catch(...) {
428 editor->Destroy();