3 #include <wx/control.h>
4 #include <wx/combobox.h>
6 #include "core/controller.hpp"
7 #include "core/command.hpp"
8 #include "core/dispatch.hpp"
9 #include "core/instance.hpp"
10 #include "core/mainloop.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/project.hpp"
13 #include "core/ui-services.hpp"
14 #include "library/zip.hpp"
15 #include "library/minmax.hpp"
16 #include "library/json.hpp"
18 #include "platform/wxwidgets/platform.hpp"
19 #include "platform/wxwidgets/loadsave.hpp"
23 std::map
<unsigned, const portctrl::controller
*> get_controller_set(emulator_instance
& inst
)
25 std::map
<unsigned, const portctrl::controller
*> r
;
26 const portctrl::type_set
& s
= inst
.controls
->get_blank().porttypes();
27 for(unsigned i
= 0; i
< s
.number_of_controllers(); i
++) {
28 auto g
= s
.lcid_to_pcid(i
);
31 portctrl::controller_set
* pcs
= s
.port_type(g
.first
).controller_info
;
32 if(g
.second
>= pcs
->controllers
.size())
34 r
[i
] = &pcs
->controllers
[g
.second
];
39 std::string
summarize_controller(unsigned lcid
, const JSON::node
& c
)
44 s
<< "#" << (lcid
+ 1) << " [";
46 if(i
.type() == JSON::number
)
47 acnt
= max(acnt
, i
.as_uint() + 1);
48 if(i
.type() != JSON::string
)
61 s
<< acnt
<< " analogs";
67 class wxeditor_macro_1
: public wxDialog
70 wxeditor_macro_1(wxWindow
* parent
, emulator_instance
& _inst
, const std::string
& title
,
71 const portctrl::macro
& m
);
72 void on_ok(wxCommandEvent
& e
);
73 void on_cancel(wxCommandEvent
& e
);
74 void on_macro_edit(wxCommandEvent
& e
);
75 portctrl::macro
get_macro() { return curmacro
; }
77 emulator_instance
& inst
;
78 std::vector
<wxCheckBox
*> enabled
;
79 std::vector
<wxTextCtrl
*> macros
;
81 wxButton
* cancelbutton
;
82 wxRadioButton
* rb_overwrite
;
84 wxRadioButton
* rb_xor
;
85 portctrl::macro curmacro
;
89 wxeditor_macro_1::wxeditor_macro_1(wxWindow
* parent
, emulator_instance
& _inst
, const std::string
& title
,
90 const portctrl::macro
& m
)
91 : wxDialog(parent
, wxID_ANY
, towxstring(title
), wxDefaultPosition
, wxSize(-1, -1)), inst(_inst
)
97 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
101 for(auto i
: curmacro
.macros
)
102 ctrlsize
= max(ctrlsize
, (size_t)(i
.first
+ 1));
103 enabled
.resize(ctrlsize
);
104 macros
.resize(ctrlsize
);
105 for(auto i
: curmacro
.macros
) {
106 top_s
->Add(new wxStaticText(this, wxID_ANY
, towxstring(summarize_controller(i
.first
,
107 i
.second
._descriptor
))), 0, wxGROW
);
108 wxBoxSizer
* tmp
= new wxBoxSizer(wxHORIZONTAL
);
109 tmp
->Add(enabled
[i
.first
] = new wxCheckBox(this, wxID_ANY
, wxT("Enabled")), 0, wxGROW
);
110 enabled
[i
.first
]->SetValue(curmacro
.macros
.count(i
.first
) &&
111 curmacro
.macros
[i
.first
].enabled
);
112 tmp
->Add(macros
[i
.first
] = new wxTextCtrl(this, wxID_ANY
,
113 towxstring(curmacro
.macros
.count(i
.first
) ? curmacro
.macros
[i
.first
].orig
: ""),
114 wxDefaultPosition
, wxSize(400, -1)), 0, wxGROW
);
115 macros
[i
.first
]->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
116 wxCommandEventHandler(wxeditor_macro_1::on_macro_edit
), NULL
, this);
117 top_s
->Add(tmp
, 1, wxGROW
);
120 wxBoxSizer
* tmp2
= new wxBoxSizer(wxHORIZONTAL
);
121 rb_overwrite
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("Overwrite"), wxDefaultPosition
,
122 wxDefaultSize
, wxRB_GROUP
);
123 rb_or
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("OR"));
124 rb_xor
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("XOR"));
125 tmp2
->Add(rb_overwrite
, 0, wxGROW
);
126 tmp2
->Add(rb_or
, 0, wxGROW
);
127 tmp2
->Add(rb_xor
, 0, wxGROW
);
128 top_s
->Add(tmp2
, 0, wxGROW
);
130 switch(curmacro
.amode
) {
131 case portctrl::macro_data::AM_OVERWRITE
: rb_overwrite
->SetValue(true); break;
132 case portctrl::macro_data::AM_OR
: rb_or
->SetValue(true); break;
133 case portctrl::macro_data::AM_XOR
: rb_xor
->SetValue(true); break;
136 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
137 pbutton_s
->AddStretchSpacer();
138 pbutton_s
->Add(okbutton
= new wxButton(this, wxID_OK
, wxT("OK")), 0, wxGROW
);
139 pbutton_s
->Add(cancelbutton
= new wxButton(this, wxID_CANCEL
, wxT("Cancel")), 0, wxGROW
);
140 okbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
141 wxCommandEventHandler(wxeditor_macro_1::on_ok
), NULL
, this);
142 cancelbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
143 wxCommandEventHandler(wxeditor_macro_1::on_cancel
), NULL
, this);
144 top_s
->Add(pbutton_s
, 0, wxGROW
);
146 top_s
->SetSizeHints(this);
149 constructing
= false;
153 void wxeditor_macro_1::on_ok(wxCommandEvent
& e
)
157 if(rb_overwrite
->GetValue()) m
.amode
= portctrl::macro_data::AM_OVERWRITE
;
158 if(rb_or
->GetValue()) m
.amode
= portctrl::macro_data::AM_OR
;
159 if(rb_xor
->GetValue()) m
.amode
= portctrl::macro_data::AM_XOR
;
161 for(auto i
: curmacro
.macros
) {
164 m
.macros
[i
.first
] = portctrl::macro_data(tostdstring(macros
[i
.first
]->GetValue()),
165 curmacro
.macros
[i
.first
].get_descriptor(), i
.first
);
166 m
.macros
[i
.first
].enabled
= enabled
[i
.first
]->GetValue();
168 } catch(std::exception
& e
) {
169 wxMessageBox(towxstring(e
.what()), _T("Error parsing macro"), wxICON_EXCLAMATION
| wxOK
,
177 void wxeditor_macro_1::on_cancel(wxCommandEvent
& e
)
180 EndModal(wxID_CANCEL
);
183 void wxeditor_macro_1::on_macro_edit(wxCommandEvent
& e
)
189 auto c
= get_controller_set(inst
);
190 for(auto i
: curmacro
.macros
) {
191 if(!portctrl::macro_data::syntax_check(tostdstring(macros
[i
.first
]->GetValue()).c_str(),
192 curmacro
.macros
[i
.first
].get_descriptor()))
195 okbutton
->Enable(ret
);
199 class wxeditor_macro
: public wxDialog
202 wxeditor_macro(wxWindow
* parent
, emulator_instance
& _inst
);
203 bool ShouldPreventAppExit() const;
204 void on_close(wxCommandEvent
& e
);
205 void on_change(wxCommandEvent
& e
);
206 void on_add(wxCommandEvent
& e
);
207 void on_edit(wxCommandEvent
& e
);
208 void on_rename(wxCommandEvent
& e
);
209 void on_delete(wxCommandEvent
& e
);
210 void on_load(wxCommandEvent
& e
);
211 void on_save(wxCommandEvent
& e
);
213 bool do_edit(const std::string
& mname
, portctrl::macro
& m
);
215 emulator_instance
& inst
;
216 wxButton
* closebutton
;
218 wxButton
* editbutton
;
219 wxButton
* renamebutton
;
220 wxButton
* deletebutton
;
221 wxButton
* savebutton
;
222 wxButton
* loadbutton
;
224 std::vector
<std::string
> macronames
;
227 bool wxeditor_macro::ShouldPreventAppExit() const
232 wxeditor_macro::wxeditor_macro(wxWindow
* parent
, emulator_instance
& _inst
)
233 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Edit macros"), wxDefaultPosition
, wxSize(-1, -1)), inst(_inst
)
237 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
240 top_s
->Add(macros
= new wxListBox(this, wxID_ANY
, wxDefaultPosition
, wxSize(300, 400), 0, NULL
,
241 wxLB_SINGLE
), 1, wxGROW
);
242 macros
->Connect(wxEVT_COMMAND_LISTBOX_SELECTED
,
243 wxCommandEventHandler(wxeditor_macro::on_change
), NULL
, this);
245 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
246 pbutton_s
->Add(addbutton
= new wxButton(this, wxID_ANY
, wxT("Add")), 0, wxGROW
);
247 pbutton_s
->Add(editbutton
= new wxButton(this, wxID_ANY
, wxT("Edit")), 0, wxGROW
);
248 pbutton_s
->Add(renamebutton
= new wxButton(this, wxID_ANY
, wxT("Rename")), 0, wxGROW
);
249 pbutton_s
->Add(deletebutton
= new wxButton(this, wxID_ANY
, wxT("Delete")), 0, wxGROW
);
250 pbutton_s
->Add(savebutton
= new wxButton(this, wxID_ANY
, wxT("Save")), 0, wxGROW
);
251 pbutton_s
->Add(loadbutton
= new wxButton(this, wxID_ANY
, wxT("Load")), 0, wxGROW
);
252 pbutton_s
->AddStretchSpacer();
253 pbutton_s
->Add(closebutton
= new wxButton(this, wxID_OK
, wxT("Close")), 0, wxGROW
);
254 addbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
255 wxCommandEventHandler(wxeditor_macro::on_add
), NULL
, this);
256 editbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
257 wxCommandEventHandler(wxeditor_macro::on_edit
), NULL
, this);
258 renamebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
259 wxCommandEventHandler(wxeditor_macro::on_rename
), NULL
, this);
260 deletebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
261 wxCommandEventHandler(wxeditor_macro::on_delete
), NULL
, this);
262 savebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
263 wxCommandEventHandler(wxeditor_macro::on_save
), NULL
, this);
264 loadbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
265 wxCommandEventHandler(wxeditor_macro::on_load
), NULL
, this);
266 closebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
267 wxCommandEventHandler(wxeditor_macro::on_close
), NULL
, this);
268 top_s
->Add(pbutton_s
, 0, wxGROW
);
270 top_s
->SetSizeHints(this);
277 void wxeditor_macro::update()
280 std::set
<std::string
> macro_list
= inst
.controls
->enumerate_macro();
282 int sel
= macros
->GetSelection();
285 if(sel
!= wxNOT_FOUND
)
286 current
= macronames
[sel
];
289 for(auto i
: macro_list
) {
290 macronames
.push_back(i
);
291 macros
->Append(towxstring(i
));
296 if(!macro_list
.empty()) {
298 macros
->SetSelection(selpos
);
300 macros
->SetSelection(sel
);
302 macros
->SetSelection(idx
- 1);
308 void wxeditor_macro::on_close(wxCommandEvent
& e
)
314 void wxeditor_macro::on_change(wxCommandEvent
& e
)
317 int sel
= macros
->GetSelection();
318 editbutton
->Enable(sel
!= wxNOT_FOUND
);
319 deletebutton
->Enable(sel
!= wxNOT_FOUND
);
320 savebutton
->Enable(sel
!= wxNOT_FOUND
);
323 void wxeditor_macro::on_delete(wxCommandEvent
& e
)
326 int sel
= macros
->GetSelection();
327 if(sel
== wxNOT_FOUND
)
329 std::string macro
= macronames
[sel
];
330 inst
.controls
->erase_macro(macro
);
334 void wxeditor_macro::on_add(wxCommandEvent
& e
)
338 std::string mname
= pick_text(this, "Name new macro", "Enter name for the new macro:", "");
341 portctrl::macro _macro
;
342 _macro
.amode
= portctrl::macro_data::AM_XOR
;
343 auto c
= get_controller_set(inst
);
345 _macro
.macros
[i
.first
] = portctrl::macro_data("",
346 portctrl::macro_data::make_descriptor(*i
.second
), i
.first
);
347 _macro
.macros
[i
.first
].enabled
= false;
349 if(do_edit("", _macro
))
350 inst
.controls
->set_macro(mname
, _macro
);
351 } catch(canceled_exception
& e
) {
352 } catch(std::exception
& e
) {
353 wxMessageBox(towxstring(e
.what()), _T("Error creating macro"), wxICON_EXCLAMATION
| wxOK
, this);
358 void wxeditor_macro::on_edit(wxCommandEvent
& e
)
361 int sel
= macros
->GetSelection();
362 if(sel
== wxNOT_FOUND
)
364 std::string macro
= macronames
[sel
];
365 portctrl::macro _macro
;
367 _macro
= inst
.controls
->get_macro(macro
);
371 if(do_edit(macro
, _macro
))
372 inst
.controls
->set_macro(macro
, _macro
);
375 void wxeditor_macro::on_rename(wxCommandEvent
& e
)
378 int sel
= macros
->GetSelection();
379 if(sel
== wxNOT_FOUND
)
381 std::string macro
= macronames
[sel
];
383 std::string mname
= pick_text(this, "Rename macro", "Enter new name for the macro:", "");
386 inst
.controls
->rename_macro(macro
, mname
);
387 } catch(canceled_exception
& e
) {
388 } catch(std::exception
& e
) {
389 wxMessageBox(towxstring(e
.what()), _T("Error renaming macro"), wxICON_EXCLAMATION
| wxOK
, this);
394 void wxeditor_macro::on_load(wxCommandEvent
& e
)
398 std::string mname
= pick_text(this, "Name new macro", "Enter name for the new macro:", "");
401 std::string file
= choose_file_load(this, "Load macro from", UI_get_project_otherpath(inst
),
403 std::vector
<char> contents
= zip::readrel(file
, "");
404 portctrl::macro
m(JSON::node(std::string(contents
.begin(), contents
.end())));
405 inst
.controls
->set_macro(mname
, m
);
406 } catch(canceled_exception
& e
) {
407 } catch(std::exception
& e
) {
408 wxMessageBox(towxstring(e
.what()), _T("Error loading macro"), wxICON_EXCLAMATION
| wxOK
, this);
413 void wxeditor_macro::on_save(wxCommandEvent
& e
)
416 int sel
= macros
->GetSelection();
417 if(sel
== wxNOT_FOUND
)
419 std::string macro
= macronames
[sel
];
420 portctrl::macro
* _macro
;
422 _macro
= &inst
.controls
->get_macro(macro
);
426 std::string mdata
= _macro
->serialize().serialize();
427 //Okay, have the macro data, now prompt for file and save.
429 std::string tfile
= choose_file_save(this, "Save macro to", UI_get_project_otherpath(inst
),
431 std::ofstream
f(tfile
);
434 wxMessageBox(towxstring("Error saving macro"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, this);
435 } catch(canceled_exception
& e
) {
439 bool wxeditor_macro::do_edit(const std::string
& mname
, portctrl::macro
& m
)
442 wxeditor_macro_1
* editor
;
448 title
= "Editing macro " + mname
;
450 title
= "Create a new macro";
451 editor
= new wxeditor_macro_1(this, inst
, title
, m
);
452 ret
= (editor
->ShowModal() == wxID_OK
);
454 m
= editor
->get_macro();
462 void wxeditor_macro_display(wxWindow
* parent
, emulator_instance
& inst
)
465 modal_pause_holder hld
;
468 editor
= new wxeditor_macro(parent
, inst
);