If initsram/initstate points to LSS file, pull the matching member
[lsnes.git] / src / platform / wxwidgets / romselect.cpp
blob2ee2a8951b06982870f44442e801d288e7b949db
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 CHECK_UI_THREAD;
51 if(filenames.Count() != 1)
52 return false;
53 ctrl->SetValue(filenames[0]);
54 return true;
56 private:
57 wxTextCtrl* ctrl;
60 struct setting_select
62 setting_select(wxWindow* parent, const core_setting& s);
63 wxWindow* get_label() { return label; }
64 wxWindow* get_control();
65 const core_setting& get_setting() { return setting; }
66 std::string read();
67 private:
68 wxStaticText* label;
69 wxTextCtrl* text;
70 wxCheckBox* check;
71 wxComboBox* combo;
72 core_setting setting;
75 setting_select::setting_select(wxWindow* parent, const core_setting& s)
76 : setting(s)
78 CHECK_UI_THREAD;
79 label = NULL;
80 if(!setting.is_boolean())
81 label = new wxStaticText(parent, wxID_ANY, towxstring(setting.hname));
82 else
83 label = new wxStaticText(parent, wxID_ANY, towxstring(""));
84 text = NULL;
85 combo = NULL;
86 check = NULL;
87 if(setting.is_boolean()) {
88 check = new wxCheckBox(parent, wxID_ANY, towxstring(setting.hname));
89 check->SetValue(s.dflt != "0");
90 } else if(setting.is_freetext()) {
91 text = new wxTextCtrl(parent, wxID_ANY, towxstring(setting.dflt), wxDefaultPosition,
92 wxSize(400, -1));
93 } else {
94 std::vector<wxString> _hvalues;
95 std::string dflt = "";
96 for(auto i : setting.values) {
97 _hvalues.push_back(towxstring(i.hname));
98 if(i.iname == setting.dflt)
99 dflt = i.hname;
101 combo = new wxComboBox(parent, wxID_ANY, towxstring(dflt), wxDefaultPosition,
102 wxDefaultSize, _hvalues.size(), &_hvalues[0], wxCB_READONLY);
106 wxWindow* setting_select::get_control()
108 if(text) return text;
109 if(check) return check;
110 if(combo) return combo;
111 return NULL;
114 std::string setting_select::read()
116 CHECK_UI_THREAD;
117 if(text) return tostdstring(text->GetValue());
118 if(check) return check->GetValue() ? "1" : "0";
119 if(combo) return setting.hvalue_to_ivalue(tostdstring(combo->GetValue()));
120 return "";
123 class wxwin_newproject : public wxDialog
125 public:
126 wxwin_newproject(wxWindow* parent, emulator_instance& _inst);
127 ~wxwin_newproject();
128 void on_ok(wxCommandEvent& e);
129 void on_cancel(wxCommandEvent& e);
130 void on_projname_edit(wxCommandEvent& e);
131 void on_memorywatch_select(wxCommandEvent& e);
132 void on_directory_select(wxCommandEvent& e);
133 void on_add(wxCommandEvent& e);
134 void on_remove(wxCommandEvent& e);
135 void on_up(wxCommandEvent& e);
136 void on_down(wxCommandEvent& e);
137 void on_luasel(wxCommandEvent& e);
138 private:
139 void reorder_scripts(int delta);
140 emulator_instance& inst;
141 wxTextCtrl* projname;
142 wxTextCtrl* memwatch;
143 wxTextCtrl* projdir;
144 wxTextCtrl* projpfx;
145 wxListBox* luascripts;
146 wxButton* swatch;
147 wxButton* sdir;
148 wxButton* addbutton;
149 wxButton* removebutton;
150 wxButton* upbutton;
151 wxButton* downbutton;
152 wxButton* okbutton;
153 wxButton* cancel;
156 wxwin_newproject::~wxwin_newproject()
160 wxwin_newproject::wxwin_newproject(wxWindow* parent, emulator_instance& _inst)
161 : wxDialog(parent, wxID_ANY, wxT("New Project"), wxDefaultPosition, wxSize(-1, -1),
162 wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX), inst(_inst)
164 CHECK_UI_THREAD;
165 Centre();
166 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
167 SetSizer(toplevel);
169 wxFlexGridSizer* c_s = new wxFlexGridSizer(1, 2, 0, 0);
170 c_s->Add(new wxStaticText(this, wxID_ANY, wxT("Project name:")), 0, wxGROW);
171 c_s->Add(projname = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
172 wxGROW);
173 projname->Connect(wxEVT_COMMAND_TEXT_UPDATED,
174 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
175 toplevel->Add(c_s);
177 wxFlexGridSizer* c4_s = new wxFlexGridSizer(1, 3, 0, 0);
178 c4_s->Add(new wxStaticText(this, wxID_ANY, wxT("Directory:")), 0, wxGROW);
179 c4_s->Add(projdir = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
180 wxGROW);
181 projdir->Connect(wxEVT_COMMAND_TEXT_UPDATED,
182 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
183 c4_s->Add(sdir = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
184 sdir->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
185 wxCommandEventHandler(wxwin_newproject::on_directory_select), NULL, this);
186 toplevel->Add(c4_s);
188 wxFlexGridSizer* c5_s = new wxFlexGridSizer(1, 2, 0, 0);
189 c5_s->Add(new wxStaticText(this, wxID_ANY, wxT("Prefix:")), 0, wxGROW);
190 c5_s->Add(projpfx = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
191 wxGROW);
192 projpfx->Connect(wxEVT_COMMAND_TEXT_UPDATED,
193 wxCommandEventHandler(wxwin_newproject::on_projname_edit), NULL, this);
194 toplevel->Add(c5_s);
196 wxFlexGridSizer* c2_s = new wxFlexGridSizer(1, 3, 0, 0);
197 c2_s->Add(new wxStaticText(this, wxID_ANY, wxT("Memory watch:")), 0, wxGROW);
198 c2_s->Add(memwatch = new wxTextCtrl(this, wxID_ANY, wxT(""),
199 wxDefaultPosition, wxSize(350, -1)), 1, wxGROW);
201 c2_s->Add(swatch = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
202 swatch->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
203 wxCommandEventHandler(wxwin_newproject::on_memorywatch_select), NULL, this);
204 toplevel->Add(c2_s);
206 toplevel->Add(new wxStaticText(this, wxID_ANY, wxT("Autoload lua scripts:")), 0, wxGROW);
207 toplevel->Add(luascripts = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 100)), 1,
208 wxEXPAND);
209 luascripts->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
210 wxCommandEventHandler(wxwin_newproject::on_luasel), NULL, this);
212 wxFlexGridSizer* c3_s = new wxFlexGridSizer(1, 4, 0, 0);
213 c3_s->Add(addbutton = new wxButton(this, wxID_ANY, wxT("Add")), 1, wxGROW);
214 addbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
215 wxCommandEventHandler(wxwin_newproject::on_add), NULL, this);
216 c3_s->Add(removebutton = new wxButton(this, wxID_ANY, wxT("Remove")), 1, wxGROW);
217 removebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
218 wxCommandEventHandler(wxwin_newproject::on_remove), NULL, this);
219 removebutton->Disable();
220 c3_s->Add(upbutton = new wxButton(this, wxID_ANY, wxT("Up")), 1, wxGROW);
221 upbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
222 wxCommandEventHandler(wxwin_newproject::on_up), NULL, this);
223 upbutton->Disable();
224 c3_s->Add(downbutton = new wxButton(this, wxID_ANY, wxT("Down")), 1, wxGROW);
225 downbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
226 wxCommandEventHandler(wxwin_newproject::on_down), NULL, this);
227 downbutton->Disable();
228 toplevel->Add(c3_s);
230 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
231 buttonbar->Add(okbutton = new wxButton(this, wxID_ANY, wxT("OK")), 0, wxGROW);
232 buttonbar->AddStretchSpacer();
233 buttonbar->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
234 okbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
235 wxCommandEventHandler(wxwin_newproject::on_ok), NULL, this);
236 cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
237 wxCommandEventHandler(wxwin_newproject::on_cancel), NULL, this);
238 toplevel->Add(buttonbar, 0, wxGROW);
239 //This gets re-enabled later if needed.
240 okbutton->Disable();
242 toplevel->SetSizeHints(this);
243 Fit();
246 void wxwin_newproject::on_ok(wxCommandEvent& e)
248 CHECK_UI_THREAD;
249 if(!inst.mlogic) {
250 show_message_ok(this, "Error", "Can't start project without movie", wxICON_EXCLAMATION);
251 return;
253 project_info pinfo(*inst.dispatch);
254 pinfo.id = generate_project_id();
255 pinfo.name = tostdstring(projname->GetValue());
256 pinfo.rom = inst.rom->load_filename;
257 pinfo.last_save = "";
258 pinfo.directory = tostdstring(projdir->GetValue());
259 pinfo.prefix = tostdstring(projpfx->GetValue());
260 auto& m = inst.mlogic->get_mfile();
261 pinfo.gametype = m.gametype->get_name();
262 pinfo.settings = m.settings;
263 pinfo.coreversion = m.coreversion;
264 pinfo.gamename = m.gamename;
265 pinfo.authors = m.authors;
266 pinfo.movie_sram = m.movie_sram;
267 pinfo.anchor_savestate = m.anchor_savestate;
268 pinfo.movie_rtc_second = m.movie_rtc_second;
269 pinfo.movie_rtc_subsecond = m.movie_rtc_subsecond;
270 pinfo.projectid = m.projectid;
271 pinfo.active_branch = 0;
272 pinfo.next_branch = 0;
273 inst.project->copy_watches(pinfo);
274 inst.project->copy_macros(pinfo, *inst.controls);
275 for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
276 pinfo.roms[i] = inst.rom->romimg[i].filename;
277 pinfo.romimg_sha256[i] = m.romimg_sha256[i];
278 pinfo.romxml_sha256[i] = m.romxml_sha256[i];
279 pinfo.namehint[i] = m.namehint[i];
281 for(unsigned i = 0; i < luascripts->GetCount(); i++)
282 pinfo.luascripts.push_back(tostdstring(luascripts->GetString(i)));
283 if(memwatch->GetValue().length() == 0)
284 goto no_watch;
285 try {
286 std::istream& in = zip::openrel(tostdstring(memwatch->GetValue()), "");
287 while(in) {
288 std::string wname;
289 std::string wexpr;
290 std::getline(in, wname);
291 std::getline(in, wexpr);
292 pinfo.watches[strip_CR(wname)] = strip_CR(wexpr);
294 delete &in;
295 } catch(std::exception& e) {
296 show_message_ok(this, "Error", std::string("Can't load memory watch: ") + e.what(),
297 wxICON_EXCLAMATION);
298 return;
300 no_watch:
301 project_info* pinfo2 = new project_info(pinfo);
302 pinfo2->flush();
303 project_info* old_proj = inst.project->get();
304 inst.project->set(pinfo2, true);
305 if(old_proj)
306 delete old_proj;
307 EndModal(wxID_OK);
310 void wxwin_newproject::on_cancel(wxCommandEvent& e)
312 CHECK_UI_THREAD;
313 EndModal(wxID_CANCEL);
316 void wxwin_newproject::on_memorywatch_select(wxCommandEvent& e)
318 CHECK_UI_THREAD;
319 try {
320 std::string lwch = choose_file_load(this, "Select memory watch file", ".", filetype_watch);
321 try {
322 auto& p = zip::openrel(lwch, "");
323 delete &p;
324 } catch(std::exception& e) {
325 show_message_ok(this, "File not found", "File '" + lwch + "' can't be opened",
326 wxICON_EXCLAMATION);
327 return;
329 memwatch->SetValue(towxstring(lwch));
330 } catch(...) {
334 void wxwin_newproject::on_projname_edit(wxCommandEvent& e)
336 bool ok = true;
337 ok = ok && (projname->GetValue().length() > 0);
338 ok = ok && (projdir->GetValue().length() > 0);
339 ok = ok && (projpfx->GetValue().length() > 0);
340 ok = ok && directory::is_directory(tostdstring(projdir->GetValue()));
341 okbutton->Enable(ok);
344 void wxwin_newproject::on_add(wxCommandEvent& e)
346 CHECK_UI_THREAD;
347 try {
348 std::string luascript = choose_file_load(this, "Pick lua script", ".", filetype_lua_script);
349 try {
350 auto& p = zip::openrel(luascript, "");
351 delete &p;
352 } catch(std::exception& e) {
353 show_message_ok(this, "File not found", "File '" + luascript + "' can't be opened",
354 wxICON_EXCLAMATION);
355 return;
357 luascripts->Append(towxstring(luascript));
358 } catch(...) {
362 void wxwin_newproject::on_remove(wxCommandEvent& e)
364 CHECK_UI_THREAD;
365 int sel = luascripts->GetSelection();
366 int count = luascripts->GetCount();
367 luascripts->Delete(sel);
368 if(sel < count - 1)
369 luascripts->SetSelection(sel);
370 else if(count > 1)
371 luascripts->SetSelection(count - 2);
372 else
373 luascripts->SetSelection(wxNOT_FOUND);
374 on_luasel(e);
377 void wxwin_newproject::reorder_scripts(int delta)
379 CHECK_UI_THREAD;
380 int sel = luascripts->GetSelection();
381 int count = luascripts->GetCount();
382 if(sel == wxNOT_FOUND || sel + delta >= count || sel + delta < 0)
383 return;
384 wxString a = luascripts->GetString(sel);
385 wxString b = luascripts->GetString(sel + delta);
386 luascripts->SetString(sel, b);
387 luascripts->SetString(sel + delta, a);
388 luascripts->SetSelection(sel + delta);
391 void wxwin_newproject::on_up(wxCommandEvent& e)
393 CHECK_UI_THREAD;
394 reorder_scripts(-1);
395 on_luasel(e);
398 void wxwin_newproject::on_down(wxCommandEvent& e)
400 CHECK_UI_THREAD;
401 reorder_scripts(1);
402 on_luasel(e);
405 void wxwin_newproject::on_luasel(wxCommandEvent& e)
407 CHECK_UI_THREAD;
408 int sel = luascripts->GetSelection();
409 int count = luascripts->GetCount();
410 removebutton->Enable(sel != wxNOT_FOUND);
411 upbutton->Enable(sel != wxNOT_FOUND && sel > 0);
412 downbutton->Enable(sel != wxNOT_FOUND && sel < count - 1);
415 void wxwin_newproject::on_directory_select(wxCommandEvent& e)
417 CHECK_UI_THREAD;
418 wxDirDialog* d = new wxDirDialog(this, wxT("Select project directory"), projdir->GetValue(),
419 wxDD_DIR_MUST_EXIST);
420 if(d->ShowModal() == wxID_CANCEL) {
421 d->Destroy();
422 return;
424 projdir->SetValue(d->GetPath());
425 d->Destroy();
428 int get_setting_class(const core_setting& a)
430 if(a.is_boolean())
431 return 0;
432 if(a.is_freetext())
433 return 2;
434 return 1;
437 bool compare_settings(const std::pair<std::string, core_setting*>& a,
438 const std::pair<std::string, core_setting*>& b)
440 int aclass = get_setting_class(*a.second);
441 int bclass = get_setting_class(*b.second);
442 if(aclass < bclass) return true;
443 if(aclass > bclass) return false;
444 if(a.second->hname < b.second->hname) return true;
445 if(a.second->hname > b.second->hname) return false;
446 return false;
449 std::vector<std::pair<std::string, core_setting*>> sort_settingblock(std::map<std::string,
450 core_setting>& block)
452 std::vector<std::pair<std::string, core_setting*>> ret;
453 for(auto& i : block)
454 ret.push_back(std::make_pair(i.first, &i.second));
455 std::sort(ret.begin(), ret.end(), compare_settings);
456 return ret;
460 class wxwin_project : public wxDialog
462 public:
463 wxwin_project(emulator_instance& _inst);
464 ~wxwin_project();
465 void on_file_select(wxCommandEvent& e);
466 void on_new_select(wxCommandEvent& e);
467 void on_filename_change(wxCommandEvent& e);
468 void on_ask_filename(wxCommandEvent& e);
469 void on_quit(wxCommandEvent& e);
470 void on_load(wxCommandEvent& e);
471 private:
472 struct moviefile& make_movie();
473 emulator_instance& inst;
474 std::map<std::string, wxTextCtrl*> sram_files;
475 std::map<std::string, wxButton*> sram_choosers;
476 std::map<std::string, setting_select> settings;
477 wxTextCtrl* projectname;
478 wxTextCtrl* prefix;
479 wxTextCtrl* rtc_sec;
480 wxTextCtrl* rtc_subsec;
481 wxTextCtrl* authors;
482 wxButton* load;
483 wxButton* quit;
484 std::map<unsigned, std::string> sram_names;
489 void show_projectwindow(wxWindow* modwin, emulator_instance& inst)
491 CHECK_UI_THREAD;
492 if(inst.rom->isnull()) {
493 show_message_ok(modwin, "Can't start new movie", "No ROM loaded", wxICON_EXCLAMATION);
494 return;
496 wxwin_project* projwin = new wxwin_project(inst);
497 projwin->ShowModal();
498 projwin->Destroy();
501 //------------------------------------------------------------
503 wxwin_project::wxwin_project(emulator_instance& _inst)
504 : wxDialog(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
505 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX), inst(_inst)
507 CHECK_UI_THREAD;
508 std::vector<wxString> cchoices;
510 std::set<std::string> sram_set = inst.rom->srams();
512 Centre();
513 //2 Top-level block.
514 //- Notebook
515 //- Button bar.
516 wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
517 SetSizer(toplevel);
518 wxPanel* new_panel = new wxPanel(this);
520 //The new page.
521 //3 Page-level blocks.
522 //- Controllertypes/initRTC/Gamename/SRAMs.
523 //- Authors explanation.
524 //- Authors
525 wxFlexGridSizer* new_sizer = new wxFlexGridSizer(3, 1, 0, 0);
526 new_panel->SetSizer(new_sizer);
527 //Controllertypes/Gamename/initRTC/SRAMs.
528 auto settingblock = inst.rom->get_settings().settings;
529 wxFlexGridSizer* mainblock = new wxFlexGridSizer(4 + settingblock.size() + sram_set.size(), 2, 0, 0);
530 auto _settingblock = sort_settingblock(settingblock);
531 for(auto i : _settingblock) {
532 settings.insert(std::make_pair(i.second->iname, setting_select(new_panel, *i.second)));
533 mainblock->Add(settings.find(i.second->iname)->second.get_label());
534 mainblock->Add(settings.find(i.second->iname)->second.get_control());
536 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Initial RTC value:")), 0, wxGROW);
537 wxFlexGridSizer* initrtc = new wxFlexGridSizer(1, 3, 0, 0);
538 initrtc->Add(rtc_sec = new wxTextCtrl(new_panel, wxID_ANY, wxT("1000000000"), wxDefaultPosition,
539 wxSize(150, -1)), 1, wxGROW);
540 initrtc->Add(new wxStaticText(new_panel, wxID_ANY, wxT(":")), 0, wxGROW);
541 initrtc->Add(rtc_subsec = new wxTextCtrl(new_panel, wxID_ANY, wxT("0"), wxDefaultPosition,
542 wxSize(150, -1)), 1, wxGROW);
543 mainblock->Add(initrtc, 0, wxGROW);
544 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Game name:")), 0, wxGROW);
545 mainblock->Add(projectname = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)),
546 1, wxGROW);
547 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Save prefix:")), 0, wxGROW);
548 mainblock->Add(prefix = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
549 wxGROW);
550 unsigned idx = 0;
551 sram_set.insert("");
552 for(auto i : sram_set) {
553 std::string name = "SRAM " + i;
554 if(i == "")
555 name = "Anchor savestate";
556 mainblock->Add(new wxStaticText(new_panel, wxID_ANY, towxstring(name)), 0, wxGROW);
557 wxFlexGridSizer* fileblock2 = new wxFlexGridSizer(1, 2, 0, 0);
558 fileblock2->Add(sram_files[i] = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition,
559 wxSize(500, -1)), 1, wxGROW);
560 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
561 fileblock2->Add(sram_choosers[i] = new wxButton(new_panel, ASK_SRAMS_BASE + idx, wxT("Pick")), 0,
562 wxGROW);
563 sram_files[i]->Connect(wxEVT_COMMAND_TEXT_UPDATED,
564 wxCommandEventHandler(wxwin_project::on_filename_change), NULL, this);
565 sram_files[i]->SetDropTarget(new textboxloadfilename(sram_files[i]));
566 sram_choosers[i]->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
567 wxCommandEventHandler(wxwin_project::on_ask_filename), NULL, this);
568 mainblock->Add(fileblock2, 0, wxGROW);
569 sram_names[idx] = i;
570 idx++;
572 new_sizer->Add(mainblock, 0, wxGROW);
574 //Authors
575 new_sizer->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Authors (one per line):")), 0, wxGROW);
576 new_sizer->Add(authors = new wxTextCtrl(new_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
577 wxTE_MULTILINE), 0, wxGROW);
578 authors->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxwin_project::on_filename_change), NULL,
579 this);
581 toplevel->Add(new_panel, 1, wxGROW);
583 //Button bar.
584 wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
585 buttonbar->Add(load = new wxButton(this, wxID_ANY, wxT("Load")), 0, wxGROW);
586 buttonbar->AddStretchSpacer();
587 buttonbar->Add(quit = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
588 load->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
589 wxCommandEventHandler(wxwin_project::on_load), NULL, this);
590 quit->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
591 wxCommandEventHandler(wxwin_project::on_quit), NULL, this);
592 toplevel->Add(buttonbar, 0, wxGROW);
594 //This gets re-enabled later if needed.
595 load->Disable();
596 wxCommandEvent e2;
597 on_filename_change(e2);
599 mainblock->SetSizeHints(this);
600 new_sizer->SetSizeHints(this);
601 toplevel->SetSizeHints(this);
602 Fit();
605 wxwin_project::~wxwin_project()
609 void wxwin_project::on_ask_filename(wxCommandEvent& e)
611 CHECK_UI_THREAD;
612 int id = e.GetId();
613 try {
614 if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
615 std::string fname = pick_file_member(this, "Choose " + sram_names[id - ASK_SRAMS_BASE], ".");
616 sram_files[sram_names[id - ASK_SRAMS_BASE]]->SetValue(towxstring(fname));
618 on_filename_change(e);
619 } catch(canceled_exception& e) {
623 void wxwin_project::on_filename_change(wxCommandEvent& e)
625 CHECK_UI_THREAD;
626 try {
627 boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
628 if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
629 throw 42;
630 size_t lines = authors->GetNumberOfLines();
631 for(size_t i = 0; i < lines; i++) {
632 std::string l = tostdstring(authors->GetLineText(i));
633 if(l == "|")
634 throw 43;
636 load->Enable();
637 } catch(...) {
638 load->Disable();
642 void wxwin_project::on_quit(wxCommandEvent& e)
644 EndModal(0);
647 void wxwin_project::on_load(wxCommandEvent& e)
649 CHECK_UI_THREAD;
650 try {
651 moviefile& mov = make_movie();
652 mov.start_paused = false;
653 rrdata_set tmp_rdata;
654 mov.save("$MEMORY:wxwidgets-romload-tmp", 0, true, tmp_rdata);
655 inst.iqueue->queue("load-state $MEMORY:wxwidgets-romload-tmp");
656 EndModal(0);
657 } catch(std::exception& e) {
658 show_message_ok(this, "Error loading movie", e.what(), wxICON_EXCLAMATION);
659 return;
663 struct moviefile& wxwin_project::make_movie()
665 CHECK_UI_THREAD;
666 moviefile& f = *new moviefile;
667 f.force_corrupt = false;
668 f.gametype = &inst.rom->get_sysregion();
669 for(auto i : settings) {
670 f.settings[i.first] = i.second.read();
671 if(!i.second.get_setting().validate(f.settings[i.first]))
672 throw std::runtime_error((stringfmt() << "Bad value for setting " << i.first).str());
674 f.coreversion = inst.rom->get_core_identifier();
675 f.gamename = tostdstring(projectname->GetValue());
676 f.projectid = get_random_hexstring(40);
677 set_mprefix_for_project(f.projectid, tostdstring(prefix->GetValue()));
678 f.rerecords = "0";
679 for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
680 f.romimg_sha256[i] = inst.rom->romimg[i].sha_256.read();
681 f.romxml_sha256[i] = inst.rom->romxml[i].sha_256.read();
682 f.namehint[i] = inst.rom->romimg[i].namehint;
684 size_t lines = authors->GetNumberOfLines();
685 for(size_t i = 0; i < lines; i++) {
686 std::string l = tostdstring(authors->GetLineText(i));
687 if(l != "" && l != "|")
688 f.authors.push_back(split_author(l));
690 for(auto i : sram_files) {
691 std::string sf = tostdstring(i.second->GetValue());
692 std::vector<char>* target;
693 if(i.first != "")
694 target = &(f.movie_sram[i.first]);
695 else
696 target = &(f.anchor_savestate);
698 if(sf != "") {
699 if(moviefile::is_movie_or_savestate(sf)) {
700 moviefile::sram_extractor e(sf);
701 e.read(i.first, *target);
702 } else
703 *target = zip::readrel(sf, "");
706 f.is_savestate = false;
707 f.movie_rtc_second = f.rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
708 f.movie_rtc_subsecond = f.rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
709 if(f.movie_rtc_subsecond < 0)
710 throw std::runtime_error("RTC subsecond must be positive");
711 auto ctrldata = inst.rom->controllerconfig(f.settings);
712 portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
713 f.create_default_branch(ports);
714 return f;
717 void open_new_project_window(wxWindow* parent, emulator_instance& inst)
719 CHECK_UI_THREAD;
720 if(inst.rom->isnull()) {
721 show_message_ok(parent, "Can't start new project", "No ROM loaded", wxICON_EXCLAMATION);
722 return;
724 wxwin_newproject* projwin = new wxwin_newproject(parent, inst);
725 projwin->ShowModal();
726 projwin->Destroy();