3 #include <wx/statline.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;
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 {
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;
76 template<typename
... U
> label_control(wxWindow
* parent
, const std::string
& label
, U
... args
)
79 lbl
= new wxStaticText(parent
, wxID_ANY
, towxstring(label
));
80 ctrl
= new T(parent
, args
...);
88 void enable(bool state
)
94 void add(wxSizer
* s
, bool prop
= false)
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
)
104 wxStaticText
* label() { return lbl
; }
105 T
* operator->() { return 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
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
);
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
;
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
;
158 label_control
<wxTextCtrl
> fg_color
;
159 label_control
<wxTextCtrl
> bg_color
;
160 label_control
<wxTextCtrl
> halo_color
;
164 std::string old_addrbase
;
165 std::string old_addrsize
;
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
)
175 wxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
179 wxSizer
* s1
= new wxBoxSizer(wxHORIZONTAL
);
180 type
= label_control
<wxComboBox
>(this, "Data type", wxID_ANY
, wxT(""), wxDefaultPosition
, wxDefaultSize
, 0,
181 nullptr, wxCB_READONLY
);
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);
209 top_s
->Add(s1
, 1, wxGROW
);
212 wxSizer
* s5
= new wxBoxSizer(wxHORIZONTAL
);
213 vma
= label_control
<wxComboBox
>(this, "Memory:", wxID_ANY
, wxT(""), wxDefaultPosition
, wxDefaultSize
, 0,
214 nullptr, wxCB_READONLY
);
216 vma
->Append(wxT("(All)"));
217 auto i
= inst
.memory
->get_regions();
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
);
239 wxSizer
* s2
= new wxBoxSizer(wxHORIZONTAL
);
240 expr
= label_control
<wxTextCtrl
>(this, "Address:", wxID_ANY
, wxT(""), wxDefaultPosition
, wxSize(400, -1));
242 top_s
->Add(s2
, 1, wxGROW
);
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
);
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));
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));
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));
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
,
302 bg_color
.add(s11
, true);
303 halo_color
= label_control
<wxTextCtrl
>(this, "Halo:", wxID_ANY
, wxT("transparent"), wxDefaultPosition
,
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
,
315 top_s
->Add(s12
, 0, wxGROW
);
320 it
= inst
.mwatch
->get(name
);
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);
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
)));
361 on_position_change(e
);
362 top_s
->SetSizeHints(this);
366 bool wxeditor_memorywatch::ShouldPreventAppExit() const
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
)
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()
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
)
411 void wxeditor_memorywatch::enable_for_addr(bool is_addr
)
414 expr
.label()->SetLabel(towxstring(is_addr
? "Address:" : "Expr:"));
415 endianess
.enable(is_addr
);
416 scale
.enable(is_addr
);
418 addrbase
.enable(is_addr
&& was_free
);
419 addrsize
.enable(is_addr
&& was_free
);
423 void wxeditor_memorywatch::enable_for_vma(bool free
, uint64_t _base
, uint64_t _size
)
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);
446 void wxeditor_memorywatch::on_position_change(wxCommandEvent
& e
)
449 enable_for_pos(get_poscategory());
450 int vmasel
= vma
->GetSelection();
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
);
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
)
466 std::string filename
= choose_file_load(this, "Choose font file", UI_get_project_otherpath(inst
),
468 font
->SetValue(towxstring(filename
));
469 } catch(canceled_exception
& e
) {
473 void wxeditor_memorywatch::on_ok(wxCommandEvent
& e
)
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;
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(),
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();
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(),
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
);
539 void wxeditor_memorywatch::on_cancel(wxCommandEvent
& e
)
542 EndModal(wxID_CANCEL
);
545 class wxeditor_memorywatches
: public wxDialog
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
);
558 emulator_instance
& inst
;
559 //TODO: Make this a wxGrid.
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)),
575 wxFlexGridSizer
* top_s
= new wxFlexGridSizer(2, 1, 0, 0);
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);
608 bool wxeditor_memorywatches::ShouldPreventAppExit() const
613 void wxeditor_memorywatches::on_memorywatch_change(wxCommandEvent
& e
)
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
)
626 std::string newname
= pick_text(this, "New watch", "Enter name for watch:");
629 wxeditor_memorywatch
* nwch
= new wxeditor_memorywatch(this, inst
, newname
);
633 } catch(canceled_exception
& e
) {
636 on_memorywatch_change(e
);
639 void wxeditor_memorywatches::on_rename(wxCommandEvent
& e
)
642 std::string watch
= tostdstring(watches
->GetStringSelection());
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
);
652 show_message_ok(this, "Error", "The target watch already exists", wxICON_EXCLAMATION
);
654 } catch(canceled_exception
& e
) {
657 on_memorywatch_change(e
);
660 void wxeditor_memorywatches::on_delete(wxCommandEvent
& e
)
663 std::string watch
= tostdstring(watches
->GetStringSelection());
665 inst
.iqueue
->run([watch
]() { CORE().mwatch
->clear(watch
); });
667 on_memorywatch_change(e
);
670 void wxeditor_memorywatches::on_edit(wxCommandEvent
& e
)
674 std::string watch
= tostdstring(watches
->GetStringSelection());
678 wxeditor_memorywatch
* ewch
= new wxeditor_memorywatch(this, inst
, watch
);
682 } catch(canceled_exception
& e
) {
685 on_memorywatch_change(e
);
688 void wxeditor_memorywatches::on_close(wxCommandEvent
& e
)
694 void wxeditor_memorywatches::refresh()
697 std::set
<std::string
> bind
;
698 inst
.iqueue
->run([&bind
]() {
699 bind
= CORE().mwatch
->enumerate();
703 watches
->Append(towxstring(i
));
704 if(watches
->GetCount())
705 watches
->SetSelection(0);
707 on_memorywatch_change(e
);
710 void wxeditor_memorywatches_display(wxWindow
* parent
, emulator_instance
& inst
)
713 modal_pause_holder hld
;
716 editor
= new wxeditor_memorywatches(parent
, inst
);