Make various instance stuff to take references to other instance objs
[lsnes.git] / src / platform / wxwidgets / romselect.cpp
blobfb42a0691551ea4a581c59f82365a6925b4edd9d
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"
24 #include <boost/lexical_cast.hpp>
26 #include "platform/wxwidgets/platform.hpp"
27 #include "platform/wxwidgets/loadsave.hpp"
30 #define ASK_SRAMS_BASE (wxID_HIGHEST + 129)
31 #define ASK_SRAMS_LAST (wxID_HIGHEST + 255)
33 namespace
35 std::string generate_project_id()
37 return (stringfmt() << time(NULL) << "_" << get_random_hexstring(4)).str();
40 class textboxloadfilename : public wxFileDropTarget
42 public:
43 textboxloadfilename(wxTextCtrl* _ctrl)
45 ctrl = _ctrl;
48 bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
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 label = NULL;
78 if(!setting.is_boolean())
79 label = new wxStaticText(parent, wxID_ANY, towxstring(setting.hname));
80 else
81 label = new wxStaticText(parent, wxID_ANY, towxstring(""));
82 text = NULL;
83 combo = NULL;
84 check = NULL;
85 if(setting.is_boolean()) {
86 check = new wxCheckBox(parent, wxID_ANY, towxstring(setting.hname));
87 check->SetValue(s.dflt != "0");
88 } else if(setting.is_freetext()) {
89 text = new wxTextCtrl(parent, wxID_ANY, towxstring(setting.dflt), wxDefaultPosition,
90 wxSize(400, -1));
91 } else {
92 std::vector<wxString> _hvalues;
93 std::string dflt = "";
94 for(auto i : setting.values) {
95 _hvalues.push_back(towxstring(i.hname));
96 if(i.iname == setting.dflt)
97 dflt = i.hname;
99 combo = new wxComboBox(parent, wxID_ANY, towxstring(dflt), wxDefaultPosition,
100 wxDefaultSize, _hvalues.size(), &_hvalues[0], wxCB_READONLY);
104 wxWindow* setting_select::get_control()
106 if(text) return text;
107 if(check) return check;
108 if(combo) return combo;
109 return NULL;
112 std::string setting_select::read()
114 if(text) return tostdstring(text->GetValue());
115 if(check) return check->GetValue() ? "1" : "0";
116 if(combo) return setting.hvalue_to_ivalue(tostdstring(combo->GetValue()));
117 return "";
120 class wxwin_newproject : public wxDialog
122 public:
123 wxwin_newproject(wxWindow* parent);
124 ~wxwin_newproject();
125 void on_ok(wxCommandEvent& e);
126 void on_cancel(wxCommandEvent& e);
127 void on_projname_edit(wxCommandEvent& e);
128 void on_memorywatch_select(wxCommandEvent& e);
129 void on_directory_select(wxCommandEvent& e);
130 void on_add(wxCommandEvent& e);
131 void on_remove(wxCommandEvent& e);
132 void on_up(wxCommandEvent& e);
133 void on_down(wxCommandEvent& e);
134 void on_luasel(wxCommandEvent& e);
135 private:
136 void reorder_scripts(int delta);
137 wxTextCtrl* projname;
138 wxTextCtrl* memwatch;
139 wxTextCtrl* projdir;
140 wxTextCtrl* projpfx;
141 wxListBox* luascripts;
142 wxButton* swatch;
143 wxButton* sdir;
144 wxButton* addbutton;
145 wxButton* removebutton;
146 wxButton* upbutton;
147 wxButton* downbutton;
148 wxButton* okbutton;
149 wxButton* cancel;
152 wxwin_newproject::~wxwin_newproject()
156 wxwin_newproject::wxwin_newproject(wxWindow* parent)
157 : wxDialog(parent, wxID_ANY, wxT("New Project"), wxDefaultPosition, wxSize(-1, -1),
158 wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
160 Centre();
161 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
162 SetSizer(toplevel);
164 wxFlexGridSizer* c_s = new wxFlexGridSizer(1, 2, 0, 0);
165 c_s->Add(new wxStaticText(this, wxID_ANY, wxT("Project name:")), 0, wxGROW);
166 c_s->Add(projname = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
167 wxGROW);
168 projname->Connect(wxEVT_COMMAND_TEXT_UPDATED,
169 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
170 toplevel->Add(c_s);
172 wxFlexGridSizer* c4_s = new wxFlexGridSizer(1, 3, 0, 0);
173 c4_s->Add(new wxStaticText(this, wxID_ANY, wxT("Directory:")), 0, wxGROW);
174 c4_s->Add(projdir = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
175 wxGROW);
176 projdir->Connect(wxEVT_COMMAND_TEXT_UPDATED,
177 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
178 c4_s->Add(sdir = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
179 sdir->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
180 wxCommandEventHandler(wxwin_newproject::on_directory_select), NULL, this);
181 toplevel->Add(c4_s);
183 wxFlexGridSizer* c5_s = new wxFlexGridSizer(1, 2, 0, 0);
184 c5_s->Add(new wxStaticText(this, wxID_ANY, wxT("Prefix:")), 0, wxGROW);
185 c5_s->Add(projpfx = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
186 wxGROW);
187 projpfx->Connect(wxEVT_COMMAND_TEXT_UPDATED,
188 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
189 toplevel->Add(c5_s);
191 wxFlexGridSizer* c2_s = new wxFlexGridSizer(1, 3, 0, 0);
192 c2_s->Add(new wxStaticText(this, wxID_ANY, wxT("Memory watch:")), 0, wxGROW);
193 c2_s->Add(memwatch = new wxTextCtrl(this, wxID_ANY, wxT(""),
194 wxDefaultPosition, wxSize(350, -1)), 1, wxGROW);
196 c2_s->Add(swatch = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
197 swatch->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
198 wxCommandEventHandler(wxwin_newproject::on_memorywatch_select), NULL, this);
199 toplevel->Add(c2_s);
201 toplevel->Add(new wxStaticText(this, wxID_ANY, wxT("Autoload lua scripts:")), 0, wxGROW);
202 toplevel->Add(luascripts = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 100)), 1,
203 wxEXPAND);
204 luascripts->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
205 wxCommandEventHandler(wxwin_newproject::on_luasel), NULL, this);
207 wxFlexGridSizer* c3_s = new wxFlexGridSizer(1, 4, 0, 0);
208 c3_s->Add(addbutton = new wxButton(this, wxID_ANY, wxT("Add")), 1, wxGROW);
209 addbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
210 wxCommandEventHandler(wxwin_newproject::on_add), NULL, this);
211 c3_s->Add(removebutton = new wxButton(this, wxID_ANY, wxT("Remove")), 1, wxGROW);
212 removebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
213 wxCommandEventHandler(wxwin_newproject::on_remove), NULL, this);
214 removebutton->Disable();
215 c3_s->Add(upbutton = new wxButton(this, wxID_ANY, wxT("Up")), 1, wxGROW);
216 upbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
217 wxCommandEventHandler(wxwin_newproject::on_up), NULL, this);
218 upbutton->Disable();
219 c3_s->Add(downbutton = new wxButton(this, wxID_ANY, wxT("Down")), 1, wxGROW);
220 downbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
221 wxCommandEventHandler(wxwin_newproject::on_down), NULL, this);
222 downbutton->Disable();
223 toplevel->Add(c3_s);
225 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
226 buttonbar->Add(okbutton = new wxButton(this, wxID_ANY, wxT("OK")), 0, wxGROW);
227 buttonbar->AddStretchSpacer();
228 buttonbar->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
229 okbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
230 wxCommandEventHandler(wxwin_newproject::on_ok), NULL, this);
231 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
232 wxCommandEventHandler(wxwin_newproject::on_cancel), NULL, this);
233 toplevel->Add(buttonbar, 0, wxGROW);
234 //This gets re-enabled later if needed.
235 okbutton->Disable();
237 toplevel->SetSizeHints(this);
238 Fit();
241 void wxwin_newproject::on_ok(wxCommandEvent& e)
243 if(!lsnes_instance.mlogic) {
244 show_message_ok(this, "Error", "Can't start project without movie", wxICON_EXCLAMATION);
245 return;
247 project_info pinfo;
248 pinfo.id = generate_project_id();
249 pinfo.name = tostdstring(projname->GetValue());
250 pinfo.rom = our_rom.load_filename;
251 pinfo.last_save = "";
252 pinfo.directory = tostdstring(projdir->GetValue());
253 pinfo.prefix = tostdstring(projpfx->GetValue());
254 auto& m = lsnes_instance.mlogic.get_mfile();
255 pinfo.gametype = m.gametype->get_name();
256 pinfo.settings = m.settings;
257 pinfo.coreversion = m.coreversion;
258 pinfo.gamename = m.gamename;
259 pinfo.authors = m.authors;
260 pinfo.movie_sram = m.movie_sram;
261 pinfo.anchor_savestate = m.anchor_savestate;
262 pinfo.movie_rtc_second = m.movie_rtc_second;
263 pinfo.movie_rtc_subsecond = m.movie_rtc_subsecond;
264 pinfo.projectid = m.projectid;
265 pinfo.active_branch = 0;
266 pinfo.next_branch = 0;
267 lsnes_instance.project.copy_watches(pinfo);
268 lsnes_instance.project.copy_macros(pinfo, lsnes_instance.controls);
269 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
270 pinfo.roms[i] = our_rom.romimg[i].filename;
271 pinfo.romimg_sha256[i] = m.romimg_sha256[i];
272 pinfo.romxml_sha256[i] = m.romxml_sha256[i];
273 pinfo.namehint[i] = m.namehint[i];
275 for(unsigned i = 0; i < luascripts->GetCount(); i++)
276 pinfo.luascripts.push_back(tostdstring(luascripts->GetString(i)));
277 if(memwatch->GetValue().length() == 0)
278 goto no_watch;
279 try {
280 std::istream& in = zip::openrel(tostdstring(memwatch->GetValue()), "");
281 while(in) {
282 std::string wname;
283 std::string wexpr;
284 std::getline(in, wname);
285 std::getline(in, wexpr);
286 pinfo.watches[strip_CR(wname)] = strip_CR(wexpr);
288 delete &in;
289 } catch(std::exception& e) {
290 show_message_ok(this, "Error", std::string("Can't load memory watch: ") + e.what(),
291 wxICON_EXCLAMATION);
292 return;
294 no_watch:
295 project_info* pinfo2 = new project_info(pinfo);
296 pinfo2->flush();
297 project_info* old_proj = lsnes_instance.project.get();
298 lsnes_instance.project.set(pinfo2, true);
299 if(old_proj)
300 delete old_proj;
301 EndModal(wxID_OK);
304 void wxwin_newproject::on_cancel(wxCommandEvent& e)
306 EndModal(wxID_CANCEL);
309 void wxwin_newproject::on_memorywatch_select(wxCommandEvent& e)
311 try {
312 std::string lwch = choose_file_load(this, "Select memory watch file", ".", filetype_watch);
313 try {
314 auto& p = zip::openrel(lwch, "");
315 delete &p;
316 } catch(std::exception& e) {
317 show_message_ok(this, "File not found", "File '" + lwch + "' can't be opened",
318 wxICON_EXCLAMATION);
319 return;
321 memwatch->SetValue(towxstring(lwch));
322 } catch(...) {
326 void wxwin_newproject::on_projname_edit(wxCommandEvent& e)
328 bool ok = true;
329 ok = ok && (projname->GetValue().length() > 0);
330 ok = ok && (projdir->GetValue().length() > 0);
331 ok = ok && (projpfx->GetValue().length() > 0);
332 ok = ok && directory::is_directory(tostdstring(projdir->GetValue()));
333 okbutton->Enable(ok);
336 void wxwin_newproject::on_add(wxCommandEvent& e)
338 try {
339 std::string luascript = choose_file_load(this, "Pick lua script", ".", filetype_lua_script);
340 try {
341 auto& p = zip::openrel(luascript, "");
342 delete &p;
343 } catch(std::exception& e) {
344 show_message_ok(this, "File not found", "File '" + luascript + "' can't be opened",
345 wxICON_EXCLAMATION);
346 return;
348 luascripts->Append(towxstring(luascript));
349 } catch(...) {
353 void wxwin_newproject::on_remove(wxCommandEvent& e)
355 int sel = luascripts->GetSelection();
356 int count = luascripts->GetCount();
357 luascripts->Delete(sel);
358 if(sel < count - 1)
359 luascripts->SetSelection(sel);
360 else if(count > 1)
361 luascripts->SetSelection(count - 2);
362 else
363 luascripts->SetSelection(wxNOT_FOUND);
364 on_luasel(e);
367 void wxwin_newproject::reorder_scripts(int delta)
369 int sel = luascripts->GetSelection();
370 int count = luascripts->GetCount();
371 if(sel == wxNOT_FOUND || sel + delta >= count || sel + delta < 0)
372 return;
373 wxString a = luascripts->GetString(sel);
374 wxString b = luascripts->GetString(sel + delta);
375 luascripts->SetString(sel, b);
376 luascripts->SetString(sel + delta, a);
377 luascripts->SetSelection(sel + delta);
380 void wxwin_newproject::on_up(wxCommandEvent& e)
382 reorder_scripts(-1);
383 on_luasel(e);
386 void wxwin_newproject::on_down(wxCommandEvent& e)
388 reorder_scripts(1);
389 on_luasel(e);
392 void wxwin_newproject::on_luasel(wxCommandEvent& e)
394 int sel = luascripts->GetSelection();
395 int count = luascripts->GetCount();
396 removebutton->Enable(sel != wxNOT_FOUND);
397 upbutton->Enable(sel != wxNOT_FOUND && sel > 0);
398 downbutton->Enable(sel != wxNOT_FOUND && sel < count - 1);
401 void wxwin_newproject::on_directory_select(wxCommandEvent& e)
403 wxDirDialog* d = new wxDirDialog(this, wxT("Select project directory"), projdir->GetValue(),
404 wxDD_DIR_MUST_EXIST);
405 if(d->ShowModal() == wxID_CANCEL) {
406 d->Destroy();
407 return;
409 projdir->SetValue(d->GetPath());
410 d->Destroy();
413 int get_setting_class(const core_setting& a)
415 if(a.is_boolean())
416 return 0;
417 if(a.is_freetext())
418 return 2;
419 return 1;
422 bool compare_settings(const std::pair<std::string, core_setting*>& a,
423 const std::pair<std::string, core_setting*>& b)
425 int aclass = get_setting_class(*a.second);
426 int bclass = get_setting_class(*b.second);
427 if(aclass < bclass) return true;
428 if(aclass > bclass) return false;
429 if(a.second->hname < b.second->hname) return true;
430 if(a.second->hname > b.second->hname) return false;
431 return false;
434 std::vector<std::pair<std::string, core_setting*>> sort_settingblock(std::map<std::string,
435 core_setting>& block)
437 std::vector<std::pair<std::string, core_setting*>> ret;
438 for(auto& i : block)
439 ret.push_back(std::make_pair(i.first, &i.second));
440 std::sort(ret.begin(), ret.end(), compare_settings);
441 return ret;
445 class wxwin_project : public wxDialog
447 public:
448 wxwin_project();
449 ~wxwin_project();
450 void on_file_select(wxCommandEvent& e);
451 void on_new_select(wxCommandEvent& e);
452 void on_filename_change(wxCommandEvent& e);
453 void on_ask_filename(wxCommandEvent& e);
454 void on_quit(wxCommandEvent& e);
455 void on_load(wxCommandEvent& e);
456 private:
457 struct moviefile& make_movie();
458 std::map<std::string, wxTextCtrl*> sram_files;
459 std::map<std::string, wxButton*> sram_choosers;
460 std::map<std::string, setting_select> settings;
461 wxTextCtrl* projectname;
462 wxTextCtrl* prefix;
463 wxTextCtrl* rtc_sec;
464 wxTextCtrl* rtc_subsec;
465 wxTextCtrl* authors;
466 wxButton* load;
467 wxButton* quit;
468 std::map<unsigned, std::string> sram_names;
473 void show_projectwindow(wxWindow* modwin)
475 if(!our_rom.rtype) {
476 show_message_ok(modwin, "Can't start new movie", "No ROM loaded", wxICON_EXCLAMATION);
477 return;
479 wxwin_project* projwin = new wxwin_project();
480 projwin->ShowModal();
481 projwin->Destroy();
484 //------------------------------------------------------------
486 wxwin_project::wxwin_project()
487 : wxDialog(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
488 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
490 std::vector<wxString> cchoices;
492 std::set<std::string> sram_set = our_rom.rtype->srams();
494 Centre();
495 //2 Top-level block.
496 //- Notebook
497 //- Button bar.
498 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
499 SetSizer(toplevel);
500 wxPanel* new_panel = new wxPanel(this);
502 //The new page.
503 //3 Page-level blocks.
504 //- Controllertypes/initRTC/Gamename/SRAMs.
505 //- Authors explanation.
506 //- Authors
507 wxFlexGridSizer* new_sizer = new wxFlexGridSizer(3, 1, 0, 0);
508 new_panel->SetSizer(new_sizer);
509 //Controllertypes/Gamename/initRTC/SRAMs.
510 auto settingblock = our_rom.rtype->get_settings().settings;
511 wxFlexGridSizer* mainblock = new wxFlexGridSizer(4 + settingblock.size() + sram_set.size(), 2, 0, 0);
512 auto _settingblock = sort_settingblock(settingblock);
513 for(auto i : _settingblock) {
514 settings.insert(std::make_pair(i.second->iname, setting_select(new_panel, *i.second)));
515 mainblock->Add(settings.find(i.second->iname)->second.get_label());
516 mainblock->Add(settings.find(i.second->iname)->second.get_control());
518 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Initial RTC value:")), 0, wxGROW);
519 wxFlexGridSizer* initrtc = new wxFlexGridSizer(1, 3, 0, 0);
520 initrtc->Add(rtc_sec = new wxTextCtrl(new_panel, wxID_ANY, wxT("1000000000"), wxDefaultPosition,
521 wxSize(150, -1)), 1, wxGROW);
522 initrtc->Add(new wxStaticText(new_panel, wxID_ANY, wxT(":")), 0, wxGROW);
523 initrtc->Add(rtc_subsec = new wxTextCtrl(new_panel, wxID_ANY, wxT("0"), wxDefaultPosition,
524 wxSize(150, -1)), 1, wxGROW);
525 mainblock->Add(initrtc, 0, wxGROW);
526 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Game name:")), 0, wxGROW);
527 mainblock->Add(projectname = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)),
528 1, wxGROW);
529 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Save prefix:")), 0, wxGROW);
530 mainblock->Add(prefix = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
531 wxGROW);
532 unsigned idx = 0;
533 sram_set.insert("");
534 for(auto i : sram_set) {
535 std::string name = "SRAM " + i;
536 if(i == "")
537 name = "Anchor savestate";
538 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, towxstring(name)), 0, wxGROW);
539 wxFlexGridSizer* fileblock2 = new wxFlexGridSizer(1, 2, 0, 0);
540 fileblock2->Add(sram_files[i] = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition,
541 wxSize(500, -1)), 1, wxGROW);
542 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
543 fileblock2->Add(sram_choosers[i] = new wxButton(new_panel, ASK_SRAMS_BASE + idx, wxT("Pick")), 0,
544 wxGROW);
545 sram_files[i]->Connect(wxEVT_COMMAND_TEXT_UPDATED,
546 wxCommandEventHandler(wxwin_project::on_filename_change), NULL, this);
547 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
548 sram_choosers[i]->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
549 wxCommandEventHandler(wxwin_project::on_ask_filename), NULL, this);
550 mainblock->Add(fileblock2, 0, wxGROW);
551 sram_names[idx] = i;
552 idx++;
554 new_sizer->Add(mainblock, 0, wxGROW);
556 //Authors
557 new_sizer->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Authors (one per line):")), 0, wxGROW);
558 new_sizer->Add(authors = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
559 wxTE_MULTILINE), 0, wxGROW);
560 authors->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxwin_project::on_filename_change), NULL,
561 this);
563 toplevel->Add(new_panel, 1, wxGROW);
565 //Button bar.
566 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
567 buttonbar->Add(load = new wxButton(this, wxID_ANY, wxT("Load")), 0, wxGROW);
568 buttonbar->AddStretchSpacer();
569 buttonbar->Add(quit = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
570 load->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
571 wxCommandEventHandler(wxwin_project::on_load), NULL, this);
572 quit->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
573 wxCommandEventHandler(wxwin_project::on_quit), NULL, this);
574 toplevel->Add(buttonbar, 0, wxGROW);
576 //This gets re-enabled later if needed.
577 load->Disable();
578 wxCommandEvent e2;
579 on_filename_change(e2);
581 mainblock->SetSizeHints(this);
582 new_sizer->SetSizeHints(this);
583 toplevel->SetSizeHints(this);
584 Fit();
587 wxwin_project::~wxwin_project()
591 void wxwin_project::on_ask_filename(wxCommandEvent& e)
593 int id = e.GetId();
594 try {
595 if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
596 std::string fname = pick_file_member(this, "Choose " + sram_names[id - ASK_SRAMS_BASE], ".");
597 sram_files[sram_names[id - ASK_SRAMS_BASE]]->SetValue(towxstring(fname));
599 on_filename_change(e);
600 } catch(canceled_exception& e) {
604 void wxwin_project::on_filename_change(wxCommandEvent& e)
606 try {
607 boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
608 if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
609 throw 42;
610 size_t lines = authors->GetNumberOfLines();
611 for(size_t i = 0; i < lines; i++) {
612 std::string l = tostdstring(authors->GetLineText(i));
613 if(l == "|")
614 throw 43;
616 load->Enable();
617 } catch(...) {
618 load->Disable();
622 void wxwin_project::on_quit(wxCommandEvent& e)
624 EndModal(0);
627 void wxwin_project::on_load(wxCommandEvent& e)
629 try {
630 moviefile& mov = make_movie();
631 mov.start_paused = false;
632 rrdata_set tmp_rdata;
633 mov.save("$MEMORY:wxwidgets-romload-tmp", 0, true, tmp_rdata);
634 lsnes_instance.iqueue.queue("load-state $MEMORY:wxwidgets-romload-tmp");
635 EndModal(0);
636 } catch(std::exception& e) {
637 show_message_ok(this, "Error loading movie", e.what(), wxICON_EXCLAMATION);
638 return;
642 struct moviefile& wxwin_project::make_movie()
644 moviefile& f = *new moviefile;
645 f.force_corrupt = false;
646 f.gametype = &our_rom.rtype->combine_region(*our_rom.region);
647 for(auto i : settings) {
648 f.settings[i.first] = i.second.read();
649 if(!i.second.get_setting().validate(f.settings[i.first]))
650 throw std::runtime_error((stringfmt() << "Bad value for setting " << i.first).str());
652 f.coreversion = our_rom.rtype->get_core_identifier();
653 f.gamename = tostdstring(projectname->GetValue());
654 f.projectid = get_random_hexstring(40);
655 set_mprefix_for_project(f.projectid, tostdstring(prefix->GetValue()));
656 f.rerecords = "0";
657 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
658 f.romimg_sha256[i] = our_rom.romimg[i].sha_256.read();
659 f.romxml_sha256[i] = our_rom.romxml[i].sha_256.read();
660 f.namehint[i] = our_rom.romimg[i].namehint;
662 size_t lines = authors->GetNumberOfLines();
663 for(size_t i = 0; i < lines; i++) {
664 std::string l = tostdstring(authors->GetLineText(i));
665 if(l != "" && l != "|")
666 f.authors.push_back(split_author(l));
668 for(auto i : sram_files) {
669 std::string sf = tostdstring(i.second->GetValue());
670 if(i.first != "") {
671 if(sf != "")
672 f.movie_sram[i.first] = zip::readrel(sf, "");
673 } else {
674 if(sf != "")
675 f.anchor_savestate = zip::readrel(sf, "");
678 f.is_savestate = false;
679 f.movie_rtc_second = f.rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
680 f.movie_rtc_subsecond = f.rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
681 if(f.movie_rtc_subsecond < 0)
682 throw std::runtime_error("RTC subsecond must be positive");
683 auto ctrldata = our_rom.rtype->controllerconfig(f.settings);
684 port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
685 f.create_default_branch(ports);
686 return f;
689 void open_new_project_window(wxWindow* parent)
691 if(our_rom.rtype->isnull()) {
692 show_message_ok(parent, "Can't start new project", "No ROM loaded", wxICON_EXCLAMATION);
693 return;
695 wxwin_newproject* projwin = new wxwin_newproject(parent);
696 projwin->ShowModal();
697 projwin->Destroy();