1 //Gaah... wx/wx.h (contains something that breaks if included after snes/snes.hpp from bsnes v085.
5 #include <snes/snes.hpp>
6 #include <ui-libsnes/libsnes.hpp>
8 #include "core/moviedata.hpp"
9 #include "core/framerate.hpp"
10 #include "core/zip.hpp"
12 #include "plat-wxwidgets/platform.hpp"
13 #include "plat-wxwidgets/window_romselect.hpp"
15 #define ROM_SELECTS_BASE (wxID_HIGHEST + 0)
16 #define ROM_SELECTS_LAST (wxID_HIGHEST + 127)
17 #define ASK_FILENAME_BUTTON (wxID_HIGHEST + 128)
18 #define ASK_SRAMS_BASE (wxID_HIGHEST + 129)
19 #define ASK_SRAMS_LAST (wxID_HIGHEST + 255)
21 #define CONTROLLERTYPES_P1 4
22 #define CONTROLLERTYPES 7
23 #define CNAME_NONE "None"
24 #define CNAME_GAMEPAD "Gamepad"
25 #define CNAME_MULTITAP "Multitap"
26 #define CNAME_MOUSE "Mouse"
27 #define CNAME_SUPERSCOPE "Superscope"
28 #define CNAME_JUSTIFIER "Justifier"
29 #define CNAME_JUSTIFIERS "2 Justifiers"
30 #define TNAME_SNES "SNES"
31 #define TNAME_BSX_NS "BS-X (non-slotted)"
32 #define TNAME_BSX_S "BS-X (slotted)"
33 #define TNAME_SUFAMITURBO "Sufami Turbo"
34 #define TNAME_SGB "SGB"
35 #define RNAME_AUTO "Autodetect"
36 #define RNAME_NTSC "NTSC"
37 #define RNAME_PAL "PAL"
38 #define WNAME_SNES_MAIN "ROM"
39 #define WNAME_SNES_MAIN_XML "ROM XML"
40 #define WNAME_BS_MAIN "BS-X BIOS"
41 #define WNAME_BS_MAIN_XML "BS-X BIOS XML"
42 #define WNAME_BS_SLOTA "BS FLASH"
43 #define WNAME_BS_SLOTA_XML "BS FLASH XML"
44 #define WNAME_ST_MAIN "ST BIOS"
45 #define WNAME_ST_MAIN_XML "ST BIOS XML"
46 #define WNAME_ST_SLOTA "SLOT A ROM"
47 #define WNAME_ST_SLOTA_XML "SLOT A XML"
48 #define WNAME_ST_SLOTB "SLOT B ROM"
49 #define WNAME_ST_SLOTB_XML "SLOT B XML"
50 #define WNAME_SGB_MAIN "SGB BIOS"
51 #define WNAME_SGB_MAIN_XML "SGB BIOS XML"
52 #define WNAME_SGB_SLOTA "DMG ROM"
53 #define WNAME_SGB_SLOTA_XML "BMG XML"
58 class my_interfaced
: public SNES::Interface
60 string
path(SNES::Cartridge::Slot slot
, const string
&hint
)
66 void enable_slot(wxStaticText
* label
, wxTextCtrl
* filename
, wxButton
* ask
, wxCheckBox
* hcb
,
67 const std::string
& newlabel
)
69 label
->SetLabel(towxstring(newlabel
));
76 void disable_slot(wxStaticText
* label
, wxTextCtrl
* filename
, wxButton
* ask
, wxCheckBox
* hcb
)
78 label
->SetLabel(wxT(""));
84 std::string
sram_name(const nall::string
& _id
, SNES::Cartridge::Slot slotname
)
86 std::string
id(_id
, _id
.length());
87 if(slotname
== SNES::Cartridge::Slot::SufamiTurboA
)
88 return "slota." + id
.substr(1);
89 if(slotname
== SNES::Cartridge::Slot::SufamiTurboB
)
90 return "slotb." + id
.substr(1);
94 porttype_t
get_controller_type(const std::string
& s
)
98 if(s
== CNAME_GAMEPAD
)
100 if(s
== CNAME_MULTITAP
)
104 if(s
== CNAME_SUPERSCOPE
)
105 return PT_SUPERSCOPE
;
106 if(s
== CNAME_JUSTIFIER
)
108 if(s
== CNAME_JUSTIFIERS
)
109 return PT_JUSTIFIERS
;
113 struct loaded_slot
& get_rom_slot(struct loaded_rom
& rom
, unsigned index
)
116 case 0: return rom
.rom
;
117 case 1: return rom
.rom_xml
;
118 case 2: return rom
.slota
;
119 case 3: return rom
.slota_xml
;
120 case 4: return rom
.slotb
;
121 case 5: return rom
.slotb_xml
;
126 enum rom_region
region_from_string(const std::string
& str
)
128 if(str
== RNAME_NTSC
)
135 unsigned populate_region_choices(wxString
* array
)
137 array
[0] = wxT(RNAME_AUTO
);
138 array
[1] = wxT(RNAME_NTSC
);
139 array
[2] = wxT(RNAME_PAL
);
143 unsigned populate_system_choices(wxString
* array
)
145 array
[0] = wxT(TNAME_SNES
);
146 array
[1] = wxT(TNAME_BSX_NS
);
147 array
[2] = wxT(TNAME_BSX_S
);
148 array
[3] = wxT(TNAME_SUFAMITURBO
);
149 array
[4] = wxT(TNAME_SGB
);
153 bool check_present_roms(enum rom_type rtype
, unsigned flags
)
158 return ((flags
& 1) == 1);
160 case ROMTYPE_BSXSLOTTED
:
162 return ((flags
& 5) == 5);
163 case ROMTYPE_SUFAMITURBO
:
164 return ((flags
& 1) == 1) && ((flags
& 20) != 0);
170 wxString
romname(enum rom_type rtype
, unsigned index
)
175 case 0: return wxT(WNAME_SNES_MAIN
);
176 case 1: return wxT(WNAME_SNES_MAIN_XML
);
180 case ROMTYPE_BSXSLOTTED
:
182 case 0: return wxT(WNAME_BS_MAIN
);
183 case 1: return wxT(WNAME_BS_MAIN_XML
);
184 case 2: return wxT(WNAME_BS_SLOTA
);
185 case 3: return wxT(WNAME_BS_SLOTA_XML
);
188 case ROMTYPE_SUFAMITURBO
:
190 case 0: return wxT(WNAME_ST_MAIN
);
191 case 1: return wxT(WNAME_ST_MAIN_XML
);
192 case 2: return wxT(WNAME_ST_SLOTA
);
193 case 3: return wxT(WNAME_ST_SLOTA_XML
);
194 case 4: return wxT(WNAME_ST_SLOTB
);
195 case 5: return wxT(WNAME_ST_SLOTB_XML
);
200 case 0: return wxT(WNAME_SGB_MAIN
);
201 case 1: return wxT(WNAME_SGB_MAIN_XML
);
202 case 2: return wxT(WNAME_SGB_SLOTA
);
203 case 3: return wxT(WNAME_SGB_SLOTA_XML
);
207 if(index
== 0) return wxT("dummy");
213 unsigned romname_to_index(enum rom_type rtype
, const wxString
& name
)
215 for(unsigned i
= 0; i
< ROMSELECT_ROM_COUNT
; i
++)
216 if(romname(rtype
, i
) == name
)
218 return ROMSELECT_ROM_COUNT
;
221 unsigned fill_rom_names(enum rom_type rtype
, wxString
* array
)
224 for(unsigned i
= 0; i
< 6; i
++) {
225 wxString s
= romname(rtype
, i
);
232 enum rom_type
romtype_from_string(const std::string
& str
)
234 if(str
== TNAME_SNES
)
236 if(str
== TNAME_BSX_NS
)
238 if(str
== TNAME_BSX_S
)
239 return ROMTYPE_BSXSLOTTED
;
240 if(str
== TNAME_SUFAMITURBO
)
241 return ROMTYPE_SUFAMITURBO
;
247 bool has_forced_region(const std::string
& str
)
249 enum rom_type rtype
= romtype_from_string(str
);
250 return (rtype
!= ROMTYPE_SNES
&& rtype
!= ROMTYPE_SGB
);
255 wxwin_romselect::wxwin_romselect()
256 : wxFrame(NULL
, wxID_ANY
, wxT("Select ROM"), wxDefaultPosition
, wxSize(-1, -1),
257 wxMINIMIZE_BOX
| wxSYSTEM_MENU
| wxCAPTION
| wxCLIP_CHILDREN
| wxCLOSE_BOX
)
259 wxString rtchoices
[32];
260 wxString rrchoices
[32];
261 size_t systems
= populate_system_choices(rtchoices
);
262 size_t regions
= populate_region_choices(rrchoices
);
266 //The toplevel sizer contains three sizers:
267 //- The top bar having ROM type / Region selects.
268 //- The middle area having ROM filename boxes.
269 //- The bottom bar having OK/Quit buttons.
270 wxFlexGridSizer
* toplevel
= new wxFlexGridSizer(3, 1, 0, 0);
273 //The ROM type / Region selects.
274 wxBoxSizer
* selects
= new wxBoxSizer(wxHORIZONTAL
);
275 selects
->Add(new wxStaticText(this, wxID_ANY
, wxT("ROM type:")), 0, wxGROW
);
276 selects
->Add(romtype_combo
= new wxComboBox(this, wxID_ANY
, rtchoices
[0], wxDefaultPosition
, wxDefaultSize
,
277 systems
, rtchoices
, wxCB_READONLY
), 0, wxGROW
);
278 selects
->Add(new wxStaticText(this, wxID_ANY
, wxT("Region:")), 0, wxGROW
);
279 selects
->Add(region_combo
= new wxComboBox(this, wxID_ANY
, rrchoices
[0], wxDefaultPosition
, wxDefaultSize
,
280 regions
, rrchoices
, wxCB_READONLY
), 0, wxGROW
);
281 romtype_combo
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
282 wxCommandEventHandler(wxwin_romselect::on_romtype_change
), NULL
, this);
283 region_combo
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
284 wxCommandEventHandler(wxwin_romselect::on_romtype_change
), NULL
, this);
285 toplevel
->Add(selects
, 0, wxGROW
);
287 //ROM filename selects
288 wxFlexGridSizer
* romgrid
= new wxFlexGridSizer(ROMSELECT_ROM_COUNT
, 4, 0, 0);
289 for(unsigned i
= 0; i
< ROMSELECT_ROM_COUNT
; i
++) {
290 romgrid
->Add(rom_label
[i
] = new wxStaticText(this, wxID_ANY
, wxT("")), 0, wxGROW
);
291 romgrid
->Add(rom_name
[i
] = new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxSize(500, -1)),
293 romgrid
->Add(rom_change
[i
] = new wxButton(this, ROM_SELECTS_BASE
+ i
, wxT("...")), 0, wxGROW
);
294 romgrid
->Add(rom_headered
[i
] = new wxCheckBox(this, wxID_ANY
, wxT("Headered")), 0, wxGROW
);
295 rom_name
[i
]->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
296 wxCommandEventHandler(wxwin_romselect::on_filename_change
), NULL
, this);
297 rom_change
[i
]->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
298 wxCommandEventHandler(wxwin_romselect::on_ask_rom_filename
), NULL
, this);
299 rom_headered
[i
]->Disable();
301 toplevel
->Add(romgrid
, 1, wxGROW
);
304 wxBoxSizer
* buttons
= new wxBoxSizer(wxHORIZONTAL
);
305 buttons
->AddStretchSpacer();
306 buttons
->Add(open_rom
= new wxButton(this, wxID_OPEN
, wxT("Open ROM")), 0, wxALIGN_RIGHT
);
307 buttons
->Add(quit_button
= new wxButton(this, wxID_EXIT
, wxT("Quit")), 0, wxALIGN_RIGHT
);
308 open_rom
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
309 wxCommandEventHandler(wxwin_romselect::on_open_rom
), NULL
, this);
311 quit_button
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
312 wxCommandEventHandler(wxwin_romselect::on_quit
), NULL
, this);
313 toplevel
->Add(buttons
, 1, wxGROW
);
319 toplevel
->SetSizeHints(this);
323 wxwin_romselect::~wxwin_romselect()
327 void wxwin_romselect::set_rtype(std::string rtype
)
329 bool no_rtype
= (current_rtype
== "");
331 rtype
= tostdstring(romtype_combo
->GetValue());
332 if(rtype
== current_rtype
)
334 if(has_forced_region(rtype
)) {
335 region_combo
->Disable();
336 remembered_region
= tostdstring(region_combo
->GetValue());
338 if(remembered_region
!= "")
339 region_combo
->SetValue(towxstring(remembered_region
));
340 remembered_region
= "";
341 region_combo
->Enable();
343 wxString tmp
[ROMSELECT_ROM_COUNT
];
344 unsigned c
= fill_rom_names(romtype_from_string(rtype
), tmp
);
345 for(unsigned i
= 0; i
< c
; i
++)
346 enable_slot(rom_label
[i
], rom_name
[i
], rom_change
[i
], (i
& 1) ? NULL
: rom_headered
[i
],
347 tostdstring(tmp
[i
]));
348 for(unsigned i
= c
; i
< ROMSELECT_ROM_COUNT
; i
++)
349 disable_slot(rom_label
[i
], rom_name
[i
], rom_change
[i
], rom_headered
[i
]);
350 current_rtype
= rtype
;
354 void wxwin_romselect::on_ask_rom_filename(wxCommandEvent
& e
)
357 wxFileDialog
* d
= new wxFileDialog(this, towxstring(std::string("Choose ") + tostdstring(
358 rom_label
[e
.GetId() - ROM_SELECTS_BASE
]->GetLabel())), wxT("."));
359 if(d
->ShowModal() == wxID_CANCEL
) {
363 fname
= tostdstring(d
->GetPath());
365 fname
= pick_archive_member(this, fname
);
368 wxTextCtrl
* textbox
= rom_name
[e
.GetId() - ROM_SELECTS_BASE
];
370 textbox
->SetValue(towxstring(fname
));
371 on_filename_change(e
);
374 void wxwin_romselect::on_filename_change(wxCommandEvent
& e
)
377 enum rom_type rtype
= romtype_from_string(tostdstring(romtype_combo
->GetValue()));
379 for(unsigned i
= 0; i
< ROMSELECT_ROM_COUNT
; i
++)
380 flags
|= ((rom_name
[i
]->GetValue().Length() != 0) ? (1 << i
) : 0);
381 open_rom
->Enable(check_present_roms(rtype
, flags
));
384 void wxwin_romselect::on_romtype_change(wxCommandEvent
& e
)
386 set_rtype(tostdstring(romtype_combo
->GetValue()));
387 on_filename_change(e
);
390 void wxwin_romselect::on_quit(wxCommandEvent
& e
)
395 void wxwin_romselect::on_open_rom(wxCommandEvent
& e
)
398 rfiles
.base_file
= "";
399 rfiles
.rtype
= romtype_from_string(tostdstring(romtype_combo
->GetValue()));
400 rfiles
.region
= region_from_string(tostdstring(region_combo
->GetValue()));
401 rfiles
.rom
= tostdstring(rom_name
[0]->GetValue());
402 rfiles
.rom_xml
= tostdstring(rom_name
[1]->GetValue());
403 rfiles
.slota
= tostdstring(rom_name
[2]->GetValue());
404 rfiles
.slota_xml
= tostdstring(rom_name
[3]->GetValue());
405 rfiles
.slotb
= tostdstring(rom_name
[4]->GetValue());
406 rfiles
.slotb_xml
= tostdstring(rom_name
[5]->GetValue());
407 rfiles
.rom_headered
= rom_headered
[0]->GetValue();
408 rfiles
.slota_headered
= rom_headered
[2]->GetValue();
409 rfiles
.slotb_headered
= rom_headered
[4]->GetValue();
411 our_rom
= new loaded_rom(rfiles
);
412 } catch(std::exception
& e
) {
413 wxMessageDialog
* d
= new wxMessageDialog(this, towxstring(e
.what()),
414 wxT("Error loading ROM"), wxOK
| wxICON_EXCLAMATION
);
418 wxwin_patch
* projwin
= new wxwin_patch(*our_rom
);
422 //---------------------------------------------------
423 wxwin_patch::wxwin_patch(loaded_rom
& rom
)
424 : wxFrame(NULL
, wxID_ANY
, wxT("Patch ROM"), wxDefaultPosition
, wxSize(-1, -1),
425 wxMINIMIZE_BOX
| wxSYSTEM_MENU
| wxCAPTION
| wxCLIP_CHILDREN
| wxCLOSE_BOX
)
428 wxString targets
[ROMSELECT_ROM_COUNT
];
429 size_t target_count
= fill_rom_names(rom
.rtype
, targets
);
431 //Toplevel has 5 blocks:
432 //- Checksums for ROMs.
433 //- Patch what select.
438 wxFlexGridSizer
* toplevel
= new wxFlexGridSizer(5, 1, 0, 0);
442 wxFlexGridSizer
* hashes
= new wxFlexGridSizer(target_count
, 2, 0, 0);
443 for(unsigned i
= 0; i
< ROMSELECT_ROM_COUNT
; i
++)
445 for(unsigned i
= 0; i
< target_count
; i
++) {
446 std::string hash
= get_rom_slot(*our_rom
, i
).sha256
;
448 hash
= "<Not present>";
449 hashes
->Add(new wxStaticText(this, wxID_ANY
, targets
[i
]), 0, wxGROW
);
450 hashes
->Add(checksums
[i
] = new wxStaticText(this, wxID_ANY
, towxstring(hash
)), 0, wxGROW
);
452 toplevel
->Add(hashes
, 0, wxGROW
);
455 wxFlexGridSizer
* targetselect
= new wxFlexGridSizer(1, 2, 0, 0);
456 targetselect
->Add(new wxStaticText(this, wxID_ANY
, wxT("Patch what:")), 0, wxGROW
);
457 targetselect
->Add(patch_what
= new wxComboBox(this, wxID_ANY
, targets
[0], wxDefaultPosition
, wxDefaultSize
,
458 target_count
, targets
, wxCB_READONLY
), 0, wxGROW
);
459 toplevel
->Add(targetselect
, 0, wxGROW
);
462 wxFlexGridSizer
* patchsel
= new wxFlexGridSizer(1, 3, 0, 0);
463 patchsel
->Add(new wxStaticText(this, wxID_ANY
, wxT("File:")), 0, wxGROW
);
464 patchsel
->Add(patchfile
= new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxSize(500, -1)),
466 patchsel
->Add(choosefile
= new wxButton(this, wxID_ANY
, wxT("...")), 0, wxGROW
);
467 patchfile
->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
468 wxCommandEventHandler(wxwin_patch::on_patchfile_change
), NULL
, this);
469 choosefile
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
470 wxCommandEventHandler(wxwin_patch::on_ask_patchfile
), NULL
, this);
471 toplevel
->Add(patchsel
, 0, wxGROW
);
474 wxFlexGridSizer
* offsetselect
= new wxFlexGridSizer(1, 2, 0, 0);
475 offsetselect
->Add(new wxStaticText(this, wxID_ANY
, wxT("Patch offset:")), 0, wxGROW
);
476 offsetselect
->Add(patch_offset
= new wxTextCtrl(this, wxID_ANY
, wxT("")), 0, wxGROW
);
477 patch_offset
->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
478 wxCommandEventHandler(wxwin_patch::on_patchfile_change
), NULL
, this);
479 toplevel
->Add(offsetselect
, 0, wxGROW
);
482 wxBoxSizer
* buttonbar
= new wxBoxSizer(wxHORIZONTAL
);
483 buttonbar
->AddStretchSpacer();
484 wxButton
* thats_enough
= new wxButton(this, wxID_ANY
, wxT("Enough"));
485 buttonbar
->Add(thats_enough
, 0, wxGROW
);
486 thats_enough
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
487 wxCommandEventHandler(wxwin_patch::on_done
), NULL
, this);
488 dopatch
= new wxButton(this, wxID_ANY
, wxT("Patch"));
489 buttonbar
->Add(dopatch
, 0, wxGROW
);
490 dopatch
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
491 wxCommandEventHandler(wxwin_patch::on_do_patch
), NULL
, this);
493 wxButton
* quitbutton
= new wxButton(this, wxID_EXIT
, wxT("Quit"));
494 buttonbar
->Add(quitbutton
, 0, wxGROW
);
495 quitbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
496 wxCommandEventHandler(wxwin_patch::on_quit
), NULL
, this);
497 toplevel
->Add(buttonbar
, 0, wxGROW
);
499 patch_offset
->SetValue(wxT("0"));
501 hashes
->SetSizeHints(this);
502 targetselect
->SetSizeHints(this);
503 buttonbar
->SetSizeHints(this);
504 toplevel
->SetSizeHints(this);
508 void wxwin_patch::on_ask_patchfile(wxCommandEvent
& e
)
511 wxFileDialog
* d
= new wxFileDialog(this, wxT("Choose patch file"), wxT("."));
512 if(d
->ShowModal() == wxID_CANCEL
) {
516 fname
= tostdstring(d
->GetPath());
518 fname
= pick_archive_member(this, fname
);
521 patchfile
->SetValue(towxstring(fname
));
522 on_patchfile_change(e
);
525 wxwin_patch::~wxwin_patch()
529 void wxwin_patch::on_patchfile_change(wxCommandEvent
& e
)
532 ok
= ok
&& (patchfile
->GetValue().Length() != 0);
533 std::string offsetv
= tostdstring(patch_offset
->GetValue());
535 int32_t offset
= boost::lexical_cast
<int32_t>(offsetv
);
543 void wxwin_patch::on_do_patch(wxCommandEvent
& e
)
546 auto patch_contents
= read_file_relative(tostdstring(patchfile
->GetValue()), "");
547 size_t patch_index
= romname_to_index(our_rom
->rtype
, patch_what
->GetValue());
548 if(patch_index
> ROMSELECT_ROM_COUNT
)
549 throw std::runtime_error("Internal error: Patch WHAT?");
550 loaded_slot
& s
= get_rom_slot(*our_rom
, patch_index
);
551 std::string offsetv
= tostdstring(patch_offset
->GetValue());
552 int32_t offset
= boost::lexical_cast
<int32_t>(offsetv
);
553 s
.patch(patch_contents
, offset
);
554 checksums
[patch_index
]->SetLabel(towxstring(s
.sha256
));
555 } catch(std::exception
& e
) {
556 wxMessageDialog
* d
= new wxMessageDialog(this, towxstring(e
.what()),
557 wxT("Error patching ROM"), wxOK
| wxICON_EXCLAMATION
);
561 patchfile
->SetValue(wxT(""));
564 void wxwin_patch::on_quit(wxCommandEvent
& e
)
569 void wxwin_patch::on_done(wxCommandEvent
& e
)
572 SNES::interface
= &simple_interface
;
574 } catch(std::exception
& e
) {
575 wxMessageDialog
* d
= new wxMessageDialog(this, towxstring(e
.what()),
576 wxT("Error loading ROM"), wxOK
| wxICON_EXCLAMATION
);
580 messages
<< "Detected region: " << gtype::tostring(our_rom
->rtype
, our_rom
->region
) << std::endl
;
581 if(our_rom
->region
== REGION_PAL
)
582 set_nominal_framerate(322445.0/6448.0);
583 else if(our_rom
->region
== REGION_NTSC
)
584 set_nominal_framerate(10738636.0/178683.0);
586 messages
<< "--- Internal memory mappings ---" << std::endl
;
588 messages
<< "--- End of Startup --- " << std::endl
;
589 wxwin_project
* projwin
= new wxwin_project(*our_rom
);
593 //------------------------------------------------------------
595 wxwin_project::wxwin_project(loaded_rom
& rom
)
596 : wxFrame(NULL
, wxID_ANY
, wxT("Project settings"), wxDefaultPosition
, wxSize(-1, -1),
597 wxMINIMIZE_BOX
| wxSYSTEM_MENU
| wxCAPTION
| wxCLIP_CHILDREN
| wxCLOSE_BOX
)
600 wxString cchoices
[CONTROLLERTYPES
];
601 cchoices
[0] = wxT(CNAME_NONE
);
602 cchoices
[1] = wxT(CNAME_GAMEPAD
);
603 cchoices
[2] = wxT(CNAME_MULTITAP
);
604 cchoices
[3] = wxT(CNAME_MOUSE
);
605 cchoices
[4] = wxT(CNAME_SUPERSCOPE
);
606 cchoices
[5] = wxT(CNAME_JUSTIFIER
);
607 cchoices
[6] = wxT(CNAME_JUSTIFIERS
);
609 std::set
<std::string
> sram_set
= get_sram_set();
612 //6 Top-level blocks.
613 //- Radiobutton for load
614 //- Radiobutton for new.
615 //- Filename/Controllertypes/initRTC/Gamename/SRAMs.
616 //- Authors explanation.
619 wxFlexGridSizer
* toplevel
= new wxFlexGridSizer(6, 1, 0, 0);
622 //Radiobutton for load.
623 wxRadioButton
* file
= new wxRadioButton(this, wxID_ANY
, wxT("Load movie/savestate"), wxDefaultPosition
,
624 wxDefaultSize
, wxRB_GROUP
);
625 file
->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED
,
626 wxCommandEventHandler(wxwin_project::on_file_select
), NULL
, this);
627 toplevel
->Add(file
, 0, wxGROW
);
630 //Radiobutton for new proect.
631 wxRadioButton
* newp
= new wxRadioButton(this, wxID_ANY
, wxT("New project"));
632 newp
->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED
,
633 wxCommandEventHandler(wxwin_project::on_new_select
), NULL
, this);
634 toplevel
->Add(newp
, 0, wxGROW
);
636 //Filename/Controllertypes/Gamename/initRTC/SRAMs.
637 wxFlexGridSizer
* mainblock
= new wxFlexGridSizer(5 + sram_set
.size(), 2, 0, 0);
638 mainblock
->Add(new wxStaticText(this, wxID_ANY
, wxT("File to load:")), 0, wxGROW
);
639 wxFlexGridSizer
* fileblock
= new wxFlexGridSizer(1, 2, 0, 0);
640 fileblock
->Add(savefile
= new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxSize(500, -1)),
642 fileblock
->Add(ask_savefile
= new wxButton(this, ASK_FILENAME_BUTTON
, wxT("...")), 0, wxGROW
);
643 savefile
->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
644 wxCommandEventHandler(wxwin_project::on_filename_change
), NULL
, this);
645 ask_savefile
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
646 wxCommandEventHandler(wxwin_project::on_ask_filename
), NULL
, this);
647 mainblock
->Add(fileblock
, 0, wxGROW
);
648 mainblock
->Add(new wxStaticText(this, wxID_ANY
, wxT("Controller 1 Type:")), 0, wxGROW
);
649 mainblock
->Add(controller1type
= new wxComboBox(this, wxID_ANY
, cchoices
[1], wxDefaultPosition
, wxDefaultSize
,
650 CONTROLLERTYPES_P1
, cchoices
, wxCB_READONLY
), 0, wxGROW
);
651 mainblock
->Add(new wxStaticText(this, wxID_ANY
, wxT("Controller 2 Type:")), 0, wxGROW
);
652 mainblock
->Add(controller2type
= new wxComboBox(this, wxID_ANY
, cchoices
[0], wxDefaultPosition
, wxDefaultSize
,
653 CONTROLLERTYPES
, cchoices
, wxCB_READONLY
), 0, wxGROW
);
654 mainblock
->Add(new wxStaticText(this, wxID_ANY
, wxT("Initial RTC value:")), 0, wxGROW
);
655 wxFlexGridSizer
* initrtc
= new wxFlexGridSizer(1, 3, 0, 0);
656 initrtc
->Add(rtc_sec
= new wxTextCtrl(this, wxID_ANY
, wxT("1000000000"), wxDefaultPosition
, wxSize(150, -1)),
658 initrtc
->Add(new wxStaticText(this, wxID_ANY
, wxT(":")), 0, wxGROW
);
659 initrtc
->Add(rtc_subsec
= new wxTextCtrl(this, wxID_ANY
, wxT("0"), wxDefaultPosition
,
660 wxSize(150, -1)), 1, wxGROW
);
661 mainblock
->Add(initrtc
, 0, wxGROW
);
662 mainblock
->Add(new wxStaticText(this, wxID_ANY
, wxT("Game name:")), 0, wxGROW
);
663 mainblock
->Add(projectname
= new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxSize(400, -1)), 1,
666 for(auto i
: sram_set
) {
667 mainblock
->Add(new wxStaticText(this, wxID_ANY
, towxstring("SRAM " + i
)), 0, wxGROW
);
668 wxFlexGridSizer
* fileblock2
= new wxFlexGridSizer(1, 2, 0, 0);
669 fileblock2
->Add(sram_files
[i
] = new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
,
670 wxSize(500, -1)), 1, wxGROW
);
671 fileblock2
->Add(sram_choosers
[i
] = new wxButton(this, ASK_SRAMS_BASE
+ idx
, wxT("...")), 0, wxGROW
);
672 sram_files
[i
]->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
673 wxCommandEventHandler(wxwin_project::on_filename_change
), NULL
, this);
674 sram_choosers
[i
]->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
675 wxCommandEventHandler(wxwin_project::on_ask_filename
), NULL
, this);
676 mainblock
->Add(fileblock2
, 0, wxGROW
);
680 toplevel
->Add(mainblock
, 0, wxGROW
);
683 toplevel
->Add(new wxStaticText(this, wxID_ANY
, wxT("Authors (one per line):")), 0, wxGROW
);
684 toplevel
->Add(authors
= new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxDefaultSize
,
685 wxTE_MULTILINE
), 0, wxGROW
);
686 authors
->Connect(wxEVT_COMMAND_TEXT_UPDATED
, wxCommandEventHandler(wxwin_project::on_filename_change
), NULL
,
690 wxBoxSizer
* buttonbar
= new wxBoxSizer(wxHORIZONTAL
);
691 buttonbar
->AddStretchSpacer();
692 buttonbar
->Add(load
= new wxButton(this, wxID_ANY
, wxT("Load")), 0, wxGROW
);
693 buttonbar
->Add(quit
= new wxButton(this, wxID_EXIT
, wxT("Quit")), 0, wxGROW
);
694 load
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
695 wxCommandEventHandler(wxwin_project::on_load
), NULL
, this);
696 quit
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
697 wxCommandEventHandler(wxwin_project::on_quit
), NULL
, this);
698 toplevel
->Add(buttonbar
, 0, wxGROW
);
704 mainblock
->SetSizeHints(this);
705 toplevel
->SetSizeHints(this);
709 wxwin_project::~wxwin_project()
713 void wxwin_project::on_file_select(wxCommandEvent
& e
)
716 ask_savefile
->Enable();
717 controller1type
->Disable();
718 controller2type
->Disable();
720 rtc_subsec
->Disable();
721 projectname
->Disable();
723 load
->SetLabel(wxT("Load"));
725 for(auto i
: sram_files
)
727 for(auto i
: sram_choosers
)
729 on_filename_change(e
);
732 void wxwin_project::on_new_select(wxCommandEvent
& e
)
735 ask_savefile
->Disable();
736 controller1type
->Enable();
737 controller2type
->Enable();
739 rtc_subsec
->Enable();
740 projectname
->Enable();
742 load
->SetLabel(wxT("Start"));
743 on_filename_change(e
);
745 for(auto i
: sram_files
)
747 for(auto i
: sram_choosers
)
749 on_filename_change(e
);
752 void wxwin_project::on_ask_filename(wxCommandEvent
& e
)
755 if(id
== ASK_FILENAME_BUTTON
) {
757 wxFileDialog
* d
= new wxFileDialog(this, towxstring("Choose " + sram_names
[id
- ASK_SRAMS_BASE
]),
759 if(d
->ShowModal() == wxID_CANCEL
) {
763 fname
= tostdstring(d
->GetPath());
767 savefile
->SetValue(towxstring(fname
));
768 } else if(id
>= ASK_SRAMS_BASE
&& id
<= ASK_SRAMS_LAST
) {
770 wxFileDialog
* d
= new wxFileDialog(this, towxstring("Choose " + sram_names
[id
- ASK_SRAMS_BASE
]),
772 if(d
->ShowModal() == wxID_CANCEL
) {
776 fname
= tostdstring(d
->GetPath());
780 fname
= pick_archive_member(this, fname
);
783 sram_files
[sram_names
[id
- ASK_SRAMS_BASE
]]->SetValue(towxstring(fname
));
785 on_filename_change(e
);
788 void wxwin_project::on_filename_change(wxCommandEvent
& e
)
791 load
->Enable(savefile
->GetValue().Length() != 0);
794 boost::lexical_cast
<int64_t>(tostdstring(rtc_sec
->GetValue()));
795 if(boost::lexical_cast
<int64_t>(tostdstring(rtc_subsec
->GetValue())) < 0)
797 size_t lines
= authors
->GetNumberOfLines();
798 for(size_t i
= 0; i
< lines
; i
++) {
799 std::string l
= tostdstring(authors
->GetLineText(i
));
810 void wxwin_project::on_quit(wxCommandEvent
& e
)
815 void wxwin_project::on_load(wxCommandEvent
& e
)
819 boot_emulator(*our_rom
, *new moviefile(tostdstring(savefile
->GetValue())));
821 boot_emulator(*our_rom
, *new moviefile(make_movie()));
824 } catch(std::exception
& e
) {
825 wxMessageDialog
* d
= new wxMessageDialog(this, towxstring(e
.what()),
826 wxT("Error loading movie"), wxOK
| wxICON_EXCLAMATION
);
832 std::set
<std::string
> wxwin_project::get_sram_set()
834 std::set
<std::string
> r
;
835 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
836 SNES::Cartridge::NonVolatileRAM
& s
= SNES::cartridge
.nvram
[i
];
837 r
.insert(sram_name(s
.id
, s
.slot
));
842 struct moviefile
wxwin_project::make_movie()
845 f
.force_corrupt
= false;
846 f
.gametype
= gtype::togametype(our_rom
->rtype
, our_rom
->region
);
847 f
.port1
= get_controller_type(tostdstring(controller1type
->GetValue()));
848 f
.port2
= get_controller_type(tostdstring(controller2type
->GetValue()));
849 f
.coreversion
= bsnes_core_version
;
850 f
.gamename
= tostdstring(projectname
->GetValue());
851 f
.projectid
= get_random_hexstring(40);
853 f
.rom_sha256
= our_rom
->rom
.sha256
;
854 f
.romxml_sha256
= our_rom
->rom_xml
.sha256
;
855 f
.slota_sha256
= our_rom
->slota
.sha256
;
856 f
.slotaxml_sha256
= our_rom
->slota_xml
.sha256
;
857 f
.slotb_sha256
= our_rom
->slotb
.sha256
;
858 f
.slotbxml_sha256
= our_rom
->slotb_xml
.sha256
;
859 size_t lines
= authors
->GetNumberOfLines();
860 for(size_t i
= 0; i
< lines
; i
++) {
861 std::string l
= tostdstring(authors
->GetLineText(i
));
862 if(l
!= "" && l
!= "|")
863 f
.authors
.push_back(split_author(l
));
865 for(auto i
: sram_files
) {
866 std::string sf
= tostdstring(i
.second
->GetValue());
868 f
.movie_sram
[i
.first
] = read_file_relative(sf
, "");
870 f
.is_savestate
= false;
871 f
.movie_rtc_second
= f
.rtc_second
= boost::lexical_cast
<int64_t>(tostdstring(rtc_sec
->GetValue()));
872 f
.movie_rtc_subsecond
= f
.rtc_subsecond
= boost::lexical_cast
<int64_t>(tostdstring(rtc_subsec
->GetValue()));
873 if(f
.movie_rtc_subsecond
< 0)
874 throw std::runtime_error("RTC subsecond must be positive");
875 f
.input
.clear(f
.port1
, f
.port2
);