Make wrapper for boost::lexical_cast
[lsnes.git] / src / platform / wxwidgets / romselect.cpp
blobf52b234a512a5e692a1115ca07231698ff235fd4
1 //Gaah... wx/wx.h (contains something that breaks if included after snes/snes.hpp from bsnes v085.
2 #include <wx/wx.h>
3 #include <wx/dnd.h>
4 #include <wx/statbox.h>
5 #include <wx/notebook.h>
7 #include "lsnes.hpp"
9 #include "core/controller.hpp"
10 #include "core/instance.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/moviedata.hpp"
13 #include "core/framerate.hpp"
14 #include "core/project.hpp"
15 #include "core/random.hpp"
16 #include "core/rom.hpp"
17 #include "core/settings.hpp"
18 #include "core/window.hpp"
19 #include "interface/romtype.hpp"
20 #include "interface/setting.hpp"
21 #include "library/directory.hpp"
22 #include "library/string.hpp"
23 #include "library/zip.hpp"
25 #include "platform/wxwidgets/platform.hpp"
26 #include "platform/wxwidgets/loadsave.hpp"
29 #define ASK_SRAMS_BASE (wxID_HIGHEST + 129)
30 #define ASK_SRAMS_LAST (wxID_HIGHEST + 255)
32 namespace
34 std::string generate_project_id()
36 return (stringfmt() << time(NULL) << "_" << get_random_hexstring(4)).str();
39 class textboxloadfilename : public wxFileDropTarget
41 public:
42 textboxloadfilename(wxTextCtrl* _ctrl)
44 ctrl = _ctrl;
47 bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
49 CHECK_UI_THREAD;
50 if(filenames.Count() != 1)
51 return false;
52 ctrl->SetValue(filenames[0]);
53 return true;
55 private:
56 wxTextCtrl* ctrl;
59 struct setting_select
61 setting_select(wxWindow* parent, const core_setting& s);
62 wxWindow* get_label() { return label; }
63 wxWindow* get_control();
64 const core_setting& get_setting() { return setting; }
65 std::string read();
66 private:
67 wxStaticText* label;
68 wxTextCtrl* text;
69 wxCheckBox* check;
70 wxComboBox* combo;
71 core_setting setting;
74 setting_select::setting_select(wxWindow* parent, const core_setting& s)
75 : setting(s)
77 CHECK_UI_THREAD;
78 label = NULL;
79 if(!setting.is_boolean())
80 label = new wxStaticText(parent, wxID_ANY, towxstring(setting.hname));
81 else
82 label = new wxStaticText(parent, wxID_ANY, towxstring(""));
83 text = NULL;
84 combo = NULL;
85 check = NULL;
86 if(setting.is_boolean()) {
87 check = new wxCheckBox(parent, wxID_ANY, towxstring(setting.hname));
88 check->SetValue(s.dflt != "0");
89 } else if(setting.is_freetext()) {
90 text = new wxTextCtrl(parent, wxID_ANY, towxstring(setting.dflt), wxDefaultPosition,
91 wxSize(400, -1));
92 } else {
93 std::vector<wxString> _hvalues;
94 std::string dflt = "";
95 for(auto i : setting.values) {
96 _hvalues.push_back(towxstring(i.hname));
97 if(i.iname == setting.dflt)
98 dflt = i.hname;
100 combo = new wxComboBox(parent, wxID_ANY, towxstring(dflt), wxDefaultPosition,
101 wxDefaultSize, _hvalues.size(), &_hvalues[0], wxCB_READONLY);
105 wxWindow* setting_select::get_control()
107 if(text) return text;
108 if(check) return check;
109 if(combo) return combo;
110 return NULL;
113 std::string setting_select::read()
115 CHECK_UI_THREAD;
116 if(text) return tostdstring(text->GetValue());
117 if(check) return check->GetValue() ? "1" : "0";
118 if(combo) return setting.hvalue_to_ivalue(tostdstring(combo->GetValue()));
119 return "";
122 class wxwin_newproject : public wxDialog
124 public:
125 wxwin_newproject(wxWindow* parent, emulator_instance& _inst);
126 ~wxwin_newproject();
127 void on_ok(wxCommandEvent& e);
128 void on_cancel(wxCommandEvent& e);
129 void on_projname_edit(wxCommandEvent& e);
130 void on_memorywatch_select(wxCommandEvent& e);
131 void on_directory_select(wxCommandEvent& e);
132 void on_add(wxCommandEvent& e);
133 void on_remove(wxCommandEvent& e);
134 void on_up(wxCommandEvent& e);
135 void on_down(wxCommandEvent& e);
136 void on_luasel(wxCommandEvent& e);
137 private:
138 void reorder_scripts(int delta);
139 emulator_instance& inst;
140 wxTextCtrl* projname;
141 wxTextCtrl* memwatch;
142 wxTextCtrl* projdir;
143 wxTextCtrl* projpfx;
144 wxListBox* luascripts;
145 wxButton* swatch;
146 wxButton* sdir;
147 wxButton* addbutton;
148 wxButton* removebutton;
149 wxButton* upbutton;
150 wxButton* downbutton;
151 wxButton* okbutton;
152 wxButton* cancel;
155 wxwin_newproject::~wxwin_newproject()
159 wxwin_newproject::wxwin_newproject(wxWindow* parent, emulator_instance& _inst)
160 : wxDialog(parent, wxID_ANY, wxT("New Project"), wxDefaultPosition, wxSize(-1, -1),
161 wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX), inst(_inst)
163 CHECK_UI_THREAD;
164 Centre();
165 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
166 SetSizer(toplevel);
168 wxFlexGridSizer* c_s = new wxFlexGridSizer(1, 2, 0, 0);
169 c_s->Add(new wxStaticText(this, wxID_ANY, wxT("Project name:")), 0, wxGROW);
170 c_s->Add(projname = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
171 wxGROW);
172 projname->Connect(wxEVT_COMMAND_TEXT_UPDATED,
173 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
174 toplevel->Add(c_s);
176 wxFlexGridSizer* c4_s = new wxFlexGridSizer(1, 3, 0, 0);
177 c4_s->Add(new wxStaticText(this, wxID_ANY, wxT("Directory:")), 0, wxGROW);
178 c4_s->Add(projdir = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
179 wxGROW);
180 projdir->Connect(wxEVT_COMMAND_TEXT_UPDATED,
181 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
182 c4_s->Add(sdir = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
183 sdir->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
184 wxCommandEventHandler(wxwin_newproject::on_directory_select), NULL, this);
185 toplevel->Add(c4_s);
187 wxFlexGridSizer* c5_s = new wxFlexGridSizer(1, 2, 0, 0);
188 c5_s->Add(new wxStaticText(this, wxID_ANY, wxT("Prefix:")), 0, wxGROW);
189 c5_s->Add(projpfx = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
190 wxGROW);
191 projpfx->Connect(wxEVT_COMMAND_TEXT_UPDATED,
192 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
193 toplevel->Add(c5_s);
195 wxFlexGridSizer* c2_s = new wxFlexGridSizer(1, 3, 0, 0);
196 c2_s->Add(new wxStaticText(this, wxID_ANY, wxT("Memory watch:")), 0, wxGROW);
197 c2_s->Add(memwatch = new wxTextCtrl(this, wxID_ANY, wxT(""),
198 wxDefaultPosition, wxSize(350, -1)), 1, wxGROW);
200 c2_s->Add(swatch = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
201 swatch->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
202 wxCommandEventHandler(wxwin_newproject::on_memorywatch_select), NULL, this);
203 toplevel->Add(c2_s);
205 toplevel->Add(new wxStaticText(this, wxID_ANY, wxT("Autoload lua scripts:")), 0, wxGROW);
206 toplevel->Add(luascripts = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 100)), 1,
207 wxEXPAND);
208 luascripts->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
209 wxCommandEventHandler(wxwin_newproject::on_luasel), NULL, this);
211 wxFlexGridSizer* c3_s = new wxFlexGridSizer(1, 4, 0, 0);
212 c3_s->Add(addbutton = new wxButton(this, wxID_ANY, wxT("Add")), 1, wxGROW);
213 addbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
214 wxCommandEventHandler(wxwin_newproject::on_add), NULL, this);
215 c3_s->Add(removebutton = new wxButton(this, wxID_ANY, wxT("Remove")), 1, wxGROW);
216 removebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
217 wxCommandEventHandler(wxwin_newproject::on_remove), NULL, this);
218 removebutton->Disable();
219 c3_s->Add(upbutton = new wxButton(this, wxID_ANY, wxT("Up")), 1, wxGROW);
220 upbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
221 wxCommandEventHandler(wxwin_newproject::on_up), NULL, this);
222 upbutton->Disable();
223 c3_s->Add(downbutton = new wxButton(this, wxID_ANY, wxT("Down")), 1, wxGROW);
224 downbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
225 wxCommandEventHandler(wxwin_newproject::on_down), NULL, this);
226 downbutton->Disable();
227 toplevel->Add(c3_s);
229 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
230 buttonbar->Add(okbutton = new wxButton(this, wxID_ANY, wxT("OK")), 0, wxGROW);
231 buttonbar->AddStretchSpacer();
232 buttonbar->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
233 okbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
234 wxCommandEventHandler(wxwin_newproject::on_ok), NULL, this);
235 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
236 wxCommandEventHandler(wxwin_newproject::on_cancel), NULL, this);
237 toplevel->Add(buttonbar, 0, wxGROW);
238 //This gets re-enabled later if needed.
239 okbutton->Disable();
241 toplevel->SetSizeHints(this);
242 Fit();
245 void wxwin_newproject::on_ok(wxCommandEvent& e)
247 CHECK_UI_THREAD;
248 if(!inst.mlogic) {
249 show_message_ok(this, "Error", "Can't start project without movie", wxICON_EXCLAMATION);
250 return;
252 project_info pinfo(*inst.dispatch);
253 pinfo.id = generate_project_id();
254 pinfo.name = tostdstring(projname->GetValue());
255 pinfo.rom = inst.rom->get_pack_filename();
256 pinfo.last_save = "";
257 pinfo.directory = tostdstring(projdir->GetValue());
258 pinfo.prefix = tostdstring(projpfx->GetValue());
259 auto& m = inst.mlogic->get_mfile();
260 pinfo.gametype = m.gametype->get_name();
261 pinfo.settings = m.settings;
262 pinfo.coreversion = m.coreversion;
263 pinfo.gamename = m.gamename;
264 pinfo.authors = m.authors;
265 pinfo.movie_sram = m.movie_sram;
266 pinfo.anchor_savestate = m.anchor_savestate;
267 pinfo.movie_rtc_second = m.movie_rtc_second;
268 pinfo.movie_rtc_subsecond = m.movie_rtc_subsecond;
269 pinfo.projectid = m.projectid;
270 pinfo.active_branch = 0;
271 pinfo.next_branch = 0;
272 inst.project->copy_watches(pinfo);
273 inst.project->copy_macros(pinfo, *inst.controls);
274 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
275 pinfo.roms[i] = inst.rom->get_rom(i).filename;
276 pinfo.romimg_sha256[i] = m.romimg_sha256[i];
277 pinfo.romxml_sha256[i] = m.romxml_sha256[i];
278 pinfo.namehint[i] = m.namehint[i];
280 for(unsigned i = 0; i < luascripts->GetCount(); i++)
281 pinfo.luascripts.push_back(tostdstring(luascripts->GetString(i)));
282 if(memwatch->GetValue().length() == 0)
283 goto no_watch;
284 try {
285 std::istream& in = zip::openrel(tostdstring(memwatch->GetValue()), "");
286 while(in) {
287 std::string wname;
288 std::string wexpr;
289 std::getline(in, wname);
290 std::getline(in, wexpr);
291 pinfo.watches[strip_CR(wname)] = strip_CR(wexpr);
293 delete &in;
294 } catch(std::exception& e) {
295 show_message_ok(this, "Error", std::string("Can't load memory watch: ") + e.what(),
296 wxICON_EXCLAMATION);
297 return;
299 no_watch:
300 project_info* pinfo2 = new project_info(pinfo);
301 pinfo2->flush();
302 project_info* old_proj = inst.project->get();
303 inst.project->set(pinfo2, true);
304 if(old_proj)
305 delete old_proj;
306 EndModal(wxID_OK);
309 void wxwin_newproject::on_cancel(wxCommandEvent& e)
311 CHECK_UI_THREAD;
312 EndModal(wxID_CANCEL);
315 void wxwin_newproject::on_memorywatch_select(wxCommandEvent& e)
317 CHECK_UI_THREAD;
318 try {
319 std::string lwch = choose_file_load(this, "Select memory watch file", ".", filetype_watch);
320 try {
321 auto& p = zip::openrel(lwch, "");
322 delete &p;
323 } catch(std::exception& e) {
324 show_message_ok(this, "File not found", "File '" + lwch + "' can't be opened",
325 wxICON_EXCLAMATION);
326 return;
328 memwatch->SetValue(towxstring(lwch));
329 } catch(...) {
333 void wxwin_newproject::on_projname_edit(wxCommandEvent& e)
335 bool ok = true;
336 ok = ok && (projname->GetValue().length() > 0);
337 ok = ok && (projdir->GetValue().length() > 0);
338 ok = ok && (projpfx->GetValue().length() > 0);
339 ok = ok && directory::is_directory(tostdstring(projdir->GetValue()));
340 okbutton->Enable(ok);
343 void wxwin_newproject::on_add(wxCommandEvent& e)
345 CHECK_UI_THREAD;
346 try {
347 std::string luascript = choose_file_load(this, "Pick lua script", ".", filetype_lua_script);
348 try {
349 auto& p = zip::openrel(luascript, "");
350 delete &p;
351 } catch(std::exception& e) {
352 show_message_ok(this, "File not found", "File '" + luascript + "' can't be opened",
353 wxICON_EXCLAMATION);
354 return;
356 luascripts->Append(towxstring(luascript));
357 } catch(...) {
361 void wxwin_newproject::on_remove(wxCommandEvent& e)
363 CHECK_UI_THREAD;
364 int sel = luascripts->GetSelection();
365 int count = luascripts->GetCount();
366 luascripts->Delete(sel);
367 if(sel < count - 1)
368 luascripts->SetSelection(sel);
369 else if(count > 1)
370 luascripts->SetSelection(count - 2);
371 else
372 luascripts->SetSelection(wxNOT_FOUND);
373 on_luasel(e);
376 void wxwin_newproject::reorder_scripts(int delta)
378 CHECK_UI_THREAD;
379 int sel = luascripts->GetSelection();
380 int count = luascripts->GetCount();
381 if(sel == wxNOT_FOUND || sel + delta >= count || sel + delta < 0)
382 return;
383 wxString a = luascripts->GetString(sel);
384 wxString b = luascripts->GetString(sel + delta);
385 luascripts->SetString(sel, b);
386 luascripts->SetString(sel + delta, a);
387 luascripts->SetSelection(sel + delta);
390 void wxwin_newproject::on_up(wxCommandEvent& e)
392 CHECK_UI_THREAD;
393 reorder_scripts(-1);
394 on_luasel(e);
397 void wxwin_newproject::on_down(wxCommandEvent& e)
399 CHECK_UI_THREAD;
400 reorder_scripts(1);
401 on_luasel(e);
404 void wxwin_newproject::on_luasel(wxCommandEvent& e)
406 CHECK_UI_THREAD;
407 int sel = luascripts->GetSelection();
408 int count = luascripts->GetCount();
409 removebutton->Enable(sel != wxNOT_FOUND);
410 upbutton->Enable(sel != wxNOT_FOUND && sel > 0);
411 downbutton->Enable(sel != wxNOT_FOUND && sel < count - 1);
414 void wxwin_newproject::on_directory_select(wxCommandEvent& e)
416 CHECK_UI_THREAD;
417 wxDirDialog* d = new wxDirDialog(this, wxT("Select project directory"), projdir->GetValue(),
418 wxDD_DIR_MUST_EXIST);
419 if(d->ShowModal() == wxID_CANCEL) {
420 d->Destroy();
421 return;
423 projdir->SetValue(d->GetPath());
424 d->Destroy();
427 int get_setting_class(const core_setting& a)
429 if(a.is_boolean())
430 return 0;
431 if(a.is_freetext())
432 return 2;
433 return 1;
436 bool compare_settings(const std::pair<std::string, core_setting*>& a,
437 const std::pair<std::string, core_setting*>& b)
439 int aclass = get_setting_class(*a.second);
440 int bclass = get_setting_class(*b.second);
441 if(aclass < bclass) return true;
442 if(aclass > bclass) return false;
443 if(a.second->hname < b.second->hname) return true;
444 if(a.second->hname > b.second->hname) return false;
445 return false;
448 std::vector<std::pair<std::string, core_setting*>> sort_settingblock(std::map<std::string,
449 core_setting>& block)
451 std::vector<std::pair<std::string, core_setting*>> ret;
452 for(auto& i : block)
453 ret.push_back(std::make_pair(i.first, &i.second));
454 std::sort(ret.begin(), ret.end(), compare_settings);
455 return ret;
459 class wxwin_project : public wxDialog
461 public:
462 wxwin_project(emulator_instance& _inst);
463 ~wxwin_project();
464 void on_file_select(wxCommandEvent& e);
465 void on_new_select(wxCommandEvent& e);
466 void on_filename_change(wxCommandEvent& e);
467 void on_ask_filename(wxCommandEvent& e);
468 void on_quit(wxCommandEvent& e);
469 void on_load(wxCommandEvent& e);
470 private:
471 struct moviefile& make_movie();
472 emulator_instance& inst;
473 std::map<std::string, wxTextCtrl*> sram_files;
474 std::map<std::string, wxButton*> sram_choosers;
475 std::map<std::string, setting_select> settings;
476 wxTextCtrl* projectname;
477 wxTextCtrl* prefix;
478 wxTextCtrl* rtc_sec;
479 wxTextCtrl* rtc_subsec;
480 wxTextCtrl* authors;
481 wxButton* load;
482 wxButton* quit;
483 std::map<unsigned, std::string> sram_names;
488 void show_projectwindow(wxWindow* modwin, emulator_instance& inst)
490 CHECK_UI_THREAD;
491 if(inst.rom->isnull()) {
492 show_message_ok(modwin, "Can't start new movie", "No ROM loaded", wxICON_EXCLAMATION);
493 return;
495 wxwin_project* projwin = new wxwin_project(inst);
496 projwin->ShowModal();
497 projwin->Destroy();
500 //------------------------------------------------------------
502 wxwin_project::wxwin_project(emulator_instance& _inst)
503 : wxDialog(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
504 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX), inst(_inst)
506 CHECK_UI_THREAD;
507 std::vector<wxString> cchoices;
509 std::set<std::string> sram_set = inst.rom->srams();
511 Centre();
512 //2 Top-level block.
513 //- Notebook
514 //- Button bar.
515 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
516 SetSizer(toplevel);
517 wxPanel* new_panel = new wxPanel(this);
519 //The new page.
520 //3 Page-level blocks.
521 //- Controllertypes/initRTC/Gamename/SRAMs.
522 //- Authors explanation.
523 //- Authors
524 wxFlexGridSizer* new_sizer = new wxFlexGridSizer(3, 1, 0, 0);
525 new_panel->SetSizer(new_sizer);
526 //Controllertypes/Gamename/initRTC/SRAMs.
527 auto settingblock = inst.rom->get_settings().settings;
528 wxFlexGridSizer* mainblock = new wxFlexGridSizer(4 + settingblock.size() + sram_set.size(), 2, 0, 0);
529 auto _settingblock = sort_settingblock(settingblock);
530 for(auto i : _settingblock) {
531 settings.insert(std::make_pair(i.second->iname, setting_select(new_panel, *i.second)));
532 mainblock->Add(settings.find(i.second->iname)->second.get_label());
533 mainblock->Add(settings.find(i.second->iname)->second.get_control());
535 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Initial RTC value:")), 0, wxGROW);
536 wxFlexGridSizer* initrtc = new wxFlexGridSizer(1, 3, 0, 0);
537 initrtc->Add(rtc_sec = new wxTextCtrl(new_panel, wxID_ANY, wxT("1000000000"), wxDefaultPosition,
538 wxSize(150, -1)), 1, wxGROW);
539 initrtc->Add(new wxStaticText(new_panel, wxID_ANY, wxT(":")), 0, wxGROW);
540 initrtc->Add(rtc_subsec = new wxTextCtrl(new_panel, wxID_ANY, wxT("0"), wxDefaultPosition,
541 wxSize(150, -1)), 1, wxGROW);
542 mainblock->Add(initrtc, 0, wxGROW);
543 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Game name:")), 0, wxGROW);
544 mainblock->Add(projectname = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)),
545 1, wxGROW);
546 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Save prefix:")), 0, wxGROW);
547 mainblock->Add(prefix = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
548 wxGROW);
549 unsigned idx = 0;
550 sram_set.insert("");
551 for(auto i : sram_set) {
552 std::string name = "SRAM " + i;
553 if(i == "")
554 name = "Anchor savestate";
555 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, towxstring(name)), 0, wxGROW);
556 wxFlexGridSizer* fileblock2 = new wxFlexGridSizer(1, 2, 0, 0);
557 fileblock2->Add(sram_files[i] = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition,
558 wxSize(500, -1)), 1, wxGROW);
559 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
560 fileblock2->Add(sram_choosers[i] = new wxButton(new_panel, ASK_SRAMS_BASE + idx, wxT("Pick")), 0,
561 wxGROW);
562 sram_files[i]->Connect(wxEVT_COMMAND_TEXT_UPDATED,
563 wxCommandEventHandler(wxwin_project::on_filename_change), NULL, this);
564 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
565 sram_choosers[i]->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
566 wxCommandEventHandler(wxwin_project::on_ask_filename), NULL, this);
567 mainblock->Add(fileblock2, 0, wxGROW);
568 sram_names[idx] = i;
569 idx++;
571 new_sizer->Add(mainblock, 0, wxGROW);
573 //Authors
574 new_sizer->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Authors (one per line):")), 0, wxGROW);
575 new_sizer->Add(authors = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
576 wxTE_MULTILINE), 0, wxGROW);
577 authors->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxwin_project::on_filename_change), NULL,
578 this);
580 toplevel->Add(new_panel, 1, wxGROW);
582 //Button bar.
583 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
584 buttonbar->Add(load = new wxButton(this, wxID_ANY, wxT("Load")), 0, wxGROW);
585 buttonbar->AddStretchSpacer();
586 buttonbar->Add(quit = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
587 load->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
588 wxCommandEventHandler(wxwin_project::on_load), NULL, this);
589 quit->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
590 wxCommandEventHandler(wxwin_project::on_quit), NULL, this);
591 toplevel->Add(buttonbar, 0, wxGROW);
593 //This gets re-enabled later if needed.
594 load->Disable();
595 wxCommandEvent e2;
596 on_filename_change(e2);
598 mainblock->SetSizeHints(this);
599 new_sizer->SetSizeHints(this);
600 toplevel->SetSizeHints(this);
601 Fit();
604 wxwin_project::~wxwin_project()
608 void wxwin_project::on_ask_filename(wxCommandEvent& e)
610 CHECK_UI_THREAD;
611 int id = e.GetId();
612 try {
613 if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
614 std::string fname = pick_file_member(this, "Choose " + sram_names[id - ASK_SRAMS_BASE], ".");
615 sram_files[sram_names[id - ASK_SRAMS_BASE]]->SetValue(towxstring(fname));
617 on_filename_change(e);
618 } catch(canceled_exception& e) {
622 void wxwin_project::on_filename_change(wxCommandEvent& e)
624 CHECK_UI_THREAD;
625 try {
626 raw_lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
627 if(raw_lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
628 throw 42;
629 size_t lines = authors->GetNumberOfLines();
630 for(size_t i = 0; i < lines; i++) {
631 std::string l = tostdstring(authors->GetLineText(i));
632 if(l == "|")
633 throw 43;
635 load->Enable();
636 } catch(...) {
637 load->Disable();
641 void wxwin_project::on_quit(wxCommandEvent& e)
643 EndModal(0);
646 void wxwin_project::on_load(wxCommandEvent& e)
648 CHECK_UI_THREAD;
649 try {
650 moviefile& mov = make_movie();
651 mov.start_paused = false;
652 rrdata_set tmp_rdata;
653 mov.save("$MEMORY:wxwidgets-romload-tmp", 0, true, tmp_rdata, false);
654 inst.iqueue->queue("load-state $MEMORY:wxwidgets-romload-tmp");
655 EndModal(0);
656 } catch(std::exception& e) {
657 show_message_ok(this, "Error loading movie", e.what(), wxICON_EXCLAMATION);
658 return;
662 struct moviefile& wxwin_project::make_movie()
664 CHECK_UI_THREAD;
665 moviefile& f = *new moviefile;
666 f.force_corrupt = false;
667 f.gametype = &inst.rom->get_sysregion();
668 for(auto i : settings) {
669 f.settings[i.first] = i.second.read();
670 if(!i.second.get_setting().validate(f.settings[i.first]))
671 throw std::runtime_error((stringfmt() << "Bad value for setting " << i.first).str());
673 f.coreversion = inst.rom->get_core_identifier();
674 f.gamename = tostdstring(projectname->GetValue());
675 f.projectid = get_random_hexstring(40);
676 set_mprefix_for_project(f.projectid, tostdstring(prefix->GetValue()));
677 f.rerecords = "0";
678 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
679 auto& img = inst.rom->get_rom(i);
680 auto& xml = inst.rom->get_markup(i);
681 f.romimg_sha256[i] = img.sha_256.read();
682 f.romxml_sha256[i] = xml.sha_256.read();
683 f.namehint[i] = img.namehint;
685 size_t lines = authors->GetNumberOfLines();
686 for(size_t i = 0; i < lines; i++) {
687 std::string l = tostdstring(authors->GetLineText(i));
688 if(l != "" && l != "|")
689 f.authors.push_back(split_author(l));
691 for(auto i : sram_files) {
692 std::string sf = tostdstring(i.second->GetValue());
693 std::vector<char>* target;
694 if(i.first != "")
695 target = &(f.movie_sram[i.first]);
696 else
697 target = &(f.anchor_savestate);
699 if(sf != "") {
700 if(moviefile::is_movie_or_savestate(sf)) {
701 moviefile::sram_extractor e(sf);
702 e.read(i.first, *target);
703 } else
704 *target = zip::readrel(sf, "");
707 f.movie_rtc_second = f.dyn.rtc_second = raw_lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
708 f.movie_rtc_subsecond = f.dyn.rtc_subsecond =
709 raw_lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
710 if(f.movie_rtc_subsecond < 0)
711 throw std::runtime_error("RTC subsecond must be positive");
712 auto ctrldata = inst.rom->controllerconfig(f.settings);
713 portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
714 f.create_default_branch(ports);
715 return f;
718 void open_new_project_window(wxWindow* parent, emulator_instance& inst)
720 CHECK_UI_THREAD;
721 if(inst.rom->isnull()) {
722 show_message_ok(parent, "Can't start new project", "No ROM loaded", wxICON_EXCLAMATION);
723 return;
725 wxwin_newproject* projwin = new wxwin_newproject(parent, inst);
726 projwin->ShowModal();
727 projwin->Destroy();