1 #include "core/controller.hpp"
2 #include "core/command.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/mainloop.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/project.hpp"
7 #include "library/zip.hpp"
8 #include "library/minmax.hpp"
9 #include "library/json.hpp"
11 #include "platform/wxwidgets/platform.hpp"
12 #include "platform/wxwidgets/loadsave.hpp"
16 #include <wx/control.h>
17 #include <wx/combobox.h>
21 std::map
<unsigned, const port_controller
*> get_controller_set()
23 std::map
<unsigned, const port_controller
*> r
;
24 const port_type_set
& s
= controls
.get_blank().porttypes();
25 for(unsigned i
= 0; i
< s
.number_of_controllers(); i
++) {
26 auto g
= s
.lcid_to_pcid(i
);
29 port_controller_set
* pcs
= s
.port_type(g
.first
).controller_info
;
30 if(g
.second
>= pcs
->controllers
.size())
32 r
[i
] = &pcs
->controllers
[g
.second
];
37 std::string
summarize_controller(unsigned lcid
, const JSON::node
& c
)
42 s
<< "#" << (lcid
+ 1) << " [";
44 if(i
.type() == JSON::number
)
45 acnt
= max(acnt
, i
.as_uint() + 1);
46 if(i
.type() != JSON::string
)
59 s
<< acnt
<< " analogs";
65 class wxeditor_macro_1
: public wxDialog
68 wxeditor_macro_1(wxWindow
* parent
, const std::string
& title
, const controller_macro
& m
);
69 void on_ok(wxCommandEvent
& e
);
70 void on_cancel(wxCommandEvent
& e
);
71 void on_macro_edit(wxCommandEvent
& e
);
72 controller_macro
get_macro() { return curmacro
; }
74 std::vector
<wxCheckBox
*> enabled
;
75 std::vector
<wxTextCtrl
*> macros
;
77 wxButton
* cancelbutton
;
78 wxRadioButton
* rb_overwrite
;
80 wxRadioButton
* rb_xor
;
81 controller_macro curmacro
;
85 wxeditor_macro_1::wxeditor_macro_1(wxWindow
* parent
, const std::string
& title
, const controller_macro
& m
)
86 : wxDialog(parent
, wxID_ANY
, towxstring(title
), wxDefaultPosition
, wxSize(-1, -1))
91 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
95 for(auto i
: curmacro
.macros
)
96 ctrlsize
= max(ctrlsize
, (size_t)(i
.first
+ 1));
97 enabled
.resize(ctrlsize
);
98 macros
.resize(ctrlsize
);
99 for(auto i
: curmacro
.macros
) {
100 top_s
->Add(new wxStaticText(this, wxID_ANY
, towxstring(summarize_controller(i
.first
,
101 i
.second
._descriptor
))), 0, wxGROW
);
102 wxBoxSizer
* tmp
= new wxBoxSizer(wxHORIZONTAL
);
103 tmp
->Add(enabled
[i
.first
] = new wxCheckBox(this, wxID_ANY
, wxT("Enabled")), 0, wxGROW
);
104 enabled
[i
.first
]->SetValue(curmacro
.macros
.count(i
.first
) &&
105 curmacro
.macros
[i
.first
].enabled
);
106 tmp
->Add(macros
[i
.first
] = new wxTextCtrl(this, wxID_ANY
,
107 towxstring(curmacro
.macros
.count(i
.first
) ? curmacro
.macros
[i
.first
].orig
: ""),
108 wxDefaultPosition
, wxSize(400, -1)), 0, wxGROW
);
109 macros
[i
.first
]->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
110 wxCommandEventHandler(wxeditor_macro_1::on_macro_edit
), NULL
, this);
111 top_s
->Add(tmp
, 1, wxGROW
);
114 wxBoxSizer
* tmp2
= new wxBoxSizer(wxHORIZONTAL
);
115 rb_overwrite
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("Overwrite"), wxDefaultPosition
,
116 wxDefaultSize
, wxRB_GROUP
);
117 rb_or
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("OR"));
118 rb_xor
= new wxRadioButton(this, wxID_HIGHEST
+ 1, wxT("XOR"));
119 tmp2
->Add(rb_overwrite
, 0, wxGROW
);
120 tmp2
->Add(rb_or
, 0, wxGROW
);
121 tmp2
->Add(rb_xor
, 0, wxGROW
);
122 top_s
->Add(tmp2
, 0, wxGROW
);
124 switch(curmacro
.amode
) {
125 case controller_macro_data::AM_OVERWRITE
: rb_overwrite
->SetValue(true); break;
126 case controller_macro_data::AM_OR
: rb_or
->SetValue(true); break;
127 case controller_macro_data::AM_XOR
: rb_xor
->SetValue(true); break;
130 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
131 pbutton_s
->AddStretchSpacer();
132 pbutton_s
->Add(okbutton
= new wxButton(this, wxID_OK
, wxT("OK")), 0, wxGROW
);
133 pbutton_s
->Add(cancelbutton
= new wxButton(this, wxID_CANCEL
, wxT("Cancel")), 0, wxGROW
);
134 okbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
135 wxCommandEventHandler(wxeditor_macro_1::on_ok
), NULL
, this);
136 cancelbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
137 wxCommandEventHandler(wxeditor_macro_1::on_cancel
), NULL
, this);
138 top_s
->Add(pbutton_s
, 0, wxGROW
);
140 top_s
->SetSizeHints(this);
143 constructing
= false;
147 void wxeditor_macro_1::on_ok(wxCommandEvent
& e
)
150 if(rb_overwrite
->GetValue()) m
.amode
= controller_macro_data::AM_OVERWRITE
;
151 if(rb_or
->GetValue()) m
.amode
= controller_macro_data::AM_OR
;
152 if(rb_xor
->GetValue()) m
.amode
= controller_macro_data::AM_XOR
;
154 for(auto i
: curmacro
.macros
) {
157 m
.macros
[i
.first
] = controller_macro_data(tostdstring(macros
[i
.first
]->GetValue()),
158 curmacro
.macros
[i
.first
].get_descriptor(), i
.first
);
159 m
.macros
[i
.first
].enabled
= enabled
[i
.first
]->GetValue();
161 } catch(std::exception
& e
) {
162 wxMessageBox(towxstring(e
.what()), _T("Error parsing macro"), wxICON_EXCLAMATION
| wxOK
,
170 void wxeditor_macro_1::on_cancel(wxCommandEvent
& e
)
172 EndModal(wxID_CANCEL
);
175 void wxeditor_macro_1::on_macro_edit(wxCommandEvent
& e
)
180 auto c
= get_controller_set();
181 for(auto i
: curmacro
.macros
) {
182 if(!controller_macro_data::syntax_check(tostdstring(macros
[i
.first
]->GetValue()).c_str(),
183 curmacro
.macros
[i
.first
].get_descriptor()))
186 okbutton
->Enable(ret
);
190 class wxeditor_macro
: public wxDialog
193 wxeditor_macro(wxWindow
* parent
);
194 bool ShouldPreventAppExit() const;
195 void on_close(wxCommandEvent
& e
);
196 void on_change(wxCommandEvent
& e
);
197 void on_add(wxCommandEvent
& e
);
198 void on_edit(wxCommandEvent
& e
);
199 void on_rename(wxCommandEvent
& e
);
200 void on_delete(wxCommandEvent
& e
);
201 void on_load(wxCommandEvent
& e
);
202 void on_save(wxCommandEvent
& e
);
204 bool do_edit(const std::string
& mname
, controller_macro
& m
);
206 wxButton
* closebutton
;
208 wxButton
* editbutton
;
209 wxButton
* renamebutton
;
210 wxButton
* deletebutton
;
211 wxButton
* savebutton
;
212 wxButton
* loadbutton
;
214 std::vector
<std::string
> macronames
;
217 bool wxeditor_macro::ShouldPreventAppExit() const
222 wxeditor_macro::wxeditor_macro(wxWindow
* parent
)
223 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Edit macros"), wxDefaultPosition
, wxSize(-1, -1))
226 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
229 top_s
->Add(macros
= new wxListBox(this, wxID_ANY
, wxDefaultPosition
, wxSize(300, 400), 0, NULL
,
230 wxLB_SINGLE
), 1, wxGROW
);
231 macros
->Connect(wxEVT_COMMAND_LISTBOX_SELECTED
,
232 wxCommandEventHandler(wxeditor_macro::on_change
), NULL
, this);
234 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
235 pbutton_s
->Add(addbutton
= new wxButton(this, wxID_ANY
, wxT("Add")), 0, wxGROW
);
236 pbutton_s
->Add(editbutton
= new wxButton(this, wxID_ANY
, wxT("Edit")), 0, wxGROW
);
237 pbutton_s
->Add(renamebutton
= new wxButton(this, wxID_ANY
, wxT("Rename")), 0, wxGROW
);
238 pbutton_s
->Add(deletebutton
= new wxButton(this, wxID_ANY
, wxT("Delete")), 0, wxGROW
);
239 pbutton_s
->Add(savebutton
= new wxButton(this, wxID_ANY
, wxT("Save")), 0, wxGROW
);
240 pbutton_s
->Add(loadbutton
= new wxButton(this, wxID_ANY
, wxT("Load")), 0, wxGROW
);
241 pbutton_s
->AddStretchSpacer();
242 pbutton_s
->Add(closebutton
= new wxButton(this, wxID_OK
, wxT("Close")), 0, wxGROW
);
243 addbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
244 wxCommandEventHandler(wxeditor_macro::on_add
), NULL
, this);
245 editbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
246 wxCommandEventHandler(wxeditor_macro::on_edit
), NULL
, this);
247 renamebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
248 wxCommandEventHandler(wxeditor_macro::on_rename
), NULL
, this);
249 deletebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
250 wxCommandEventHandler(wxeditor_macro::on_delete
), NULL
, this);
251 savebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
252 wxCommandEventHandler(wxeditor_macro::on_save
), NULL
, this);
253 loadbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
254 wxCommandEventHandler(wxeditor_macro::on_load
), NULL
, this);
255 closebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
256 wxCommandEventHandler(wxeditor_macro::on_close
), NULL
, this);
257 top_s
->Add(pbutton_s
, 0, wxGROW
);
259 top_s
->SetSizeHints(this);
266 void wxeditor_macro::update()
268 std::set
<std::string
> macro_list
= controls
.enumerate_macro();
270 int sel
= macros
->GetSelection();
273 if(sel
!= wxNOT_FOUND
)
274 current
= macronames
[sel
];
277 for(auto i
: macro_list
) {
278 macronames
.push_back(i
);
279 macros
->Append(towxstring(i
));
284 if(!macro_list
.empty()) {
286 macros
->SetSelection(selpos
);
288 macros
->SetSelection(sel
);
290 macros
->SetSelection(idx
- 1);
296 void wxeditor_macro::on_close(wxCommandEvent
& e
)
301 void wxeditor_macro::on_change(wxCommandEvent
& e
)
303 int sel
= macros
->GetSelection();
304 editbutton
->Enable(sel
!= wxNOT_FOUND
);
305 deletebutton
->Enable(sel
!= wxNOT_FOUND
);
306 savebutton
->Enable(sel
!= wxNOT_FOUND
);
309 void wxeditor_macro::on_delete(wxCommandEvent
& e
)
311 int sel
= macros
->GetSelection();
312 if(sel
== wxNOT_FOUND
)
314 std::string macro
= macronames
[sel
];
315 controls
.erase_macro(macro
);
319 void wxeditor_macro::on_add(wxCommandEvent
& e
)
322 std::string mname
= pick_text(this, "Name new macro", "Enter name for the new macro:", "");
325 controller_macro _macro
;
326 _macro
.amode
= controller_macro_data::AM_XOR
;
327 auto c
= get_controller_set();
329 _macro
.macros
[i
.first
] = controller_macro_data("",
330 controller_macro_data::make_descriptor(*i
.second
), i
.first
);
331 _macro
.macros
[i
.first
].enabled
= false;
333 if(do_edit("", _macro
))
334 controls
.set_macro(mname
, _macro
);
335 } catch(canceled_exception
& e
) {
336 } catch(std::exception
& e
) {
337 wxMessageBox(towxstring(e
.what()), _T("Error creating macro"), wxICON_EXCLAMATION
| wxOK
, this);
342 void wxeditor_macro::on_edit(wxCommandEvent
& e
)
344 int sel
= macros
->GetSelection();
345 if(sel
== wxNOT_FOUND
)
347 std::string macro
= macronames
[sel
];
348 controller_macro _macro
;
350 _macro
= controls
.get_macro(macro
);
354 if(do_edit(macro
, _macro
))
355 controls
.set_macro(macro
, _macro
);
358 void wxeditor_macro::on_rename(wxCommandEvent
& e
)
360 int sel
= macros
->GetSelection();
361 if(sel
== wxNOT_FOUND
)
363 std::string macro
= macronames
[sel
];
365 std::string mname
= pick_text(this, "Rename macro", "Enter new name for the macro:", "");
368 controls
.rename_macro(macro
, mname
);
369 } catch(canceled_exception
& e
) {
370 } catch(std::exception
& e
) {
371 wxMessageBox(towxstring(e
.what()), _T("Error renaming macro"), wxICON_EXCLAMATION
| wxOK
, this);
376 void wxeditor_macro::on_load(wxCommandEvent
& e
)
379 std::string mname
= pick_text(this, "Name new macro", "Enter name for the new macro:", "");
382 std::string file
= choose_file_load(this, "Load macro from", project_otherpath(), filetype_macro
);
383 std::vector
<char> contents
= read_file_relative(file
, "");
384 controller_macro
m(JSON::node(std::string(contents
.begin(), contents
.end())));
385 controls
.set_macro(mname
, m
);
386 } catch(canceled_exception
& e
) {
387 } catch(std::exception
& e
) {
388 wxMessageBox(towxstring(e
.what()), _T("Error loading macro"), wxICON_EXCLAMATION
| wxOK
, this);
393 void wxeditor_macro::on_save(wxCommandEvent
& e
)
395 int sel
= macros
->GetSelection();
396 if(sel
== wxNOT_FOUND
)
398 std::string macro
= macronames
[sel
];
399 controller_macro
* _macro
;
401 _macro
= &controls
.get_macro(macro
);
405 std::string mdata
= _macro
->serialize().serialize();
406 //Okay, have the macro data, now prompt for file and save.
408 std::string tfile
= choose_file_save(this, "Save macro to", project_otherpath(), filetype_macro
);
409 std::ofstream
f(tfile
);
412 wxMessageBox(towxstring("Error saving macro"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, this);
413 } catch(canceled_exception
& e
) {
417 bool wxeditor_macro::do_edit(const std::string
& mname
, controller_macro
& m
)
419 wxeditor_macro_1
* editor
;
425 title
= "Editing macro " + mname
;
427 title
= "Create a new macro";
428 editor
= new wxeditor_macro_1(this, title
, m
);
429 ret
= (editor
->ShowModal() == wxID_OK
);
431 m
= editor
->get_macro();
438 void wxeditor_macro_display(wxWindow
* parent
)
440 modal_pause_holder hld
;
443 editor
= new wxeditor_macro(parent
);