3 #include <wx/control.h>
4 #include <wx/combobox.h>
5 #include <wx/statline.h>
6 #include <wx/spinctrl.h>
8 #include "core/controller.hpp"
9 #include "core/instance.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/multitrack.hpp"
12 #include "core/dispatch.hpp"
13 #include "core/window.hpp"
15 #include "interface/controller.hpp"
16 #include "core/mainloop.hpp"
17 #include "platform/wxwidgets/platform.hpp"
18 #include "platform/wxwidgets/textrender.hpp"
19 #include "library/minmax.hpp"
20 #include "library/string.hpp"
21 #include "library/utf8.hpp"
26 #define MTMODE_PRESERVE "Preserve"
27 #define MTMODE_OVERWRITE "Overwrite"
28 #define MTMODE_OR "OR"
29 #define MTMODE_XOR "XOR"
35 class wxeditor_multitrack
: public wxDialog
38 wxeditor_multitrack(wxWindow
* parent
, emulator_instance
& _inst
);
39 ~wxeditor_multitrack() throw();
40 bool ShouldPreventAppExit() const;
41 void on_wclose(wxCloseEvent
& e
);
42 void on_control(wxCommandEvent
& e
);
44 struct dispatch::target
<> ahreconfigure
;
45 struct dispatch::target
<bool> ahmodechange
;
46 struct dispatch::target
<unsigned, unsigned, int> ahmtchange
;
47 struct controller_info
54 struct controller_info2
60 emulator_instance
& inst
;
61 std::vector
<controller_info
> controllers
;
62 void update_controls();
64 wxFlexGridSizer
* vsizer
;
65 const portctrl::type_set
* typeset
;
70 wxeditor_multitrack
* multitrack_open
;
73 wxeditor_multitrack::~wxeditor_multitrack() throw() {}
75 wxeditor_multitrack::wxeditor_multitrack(wxWindow
* parent
, emulator_instance
& _inst
)
76 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Multitrack recording"), wxDefaultPosition
, wxSize(-1, -1)),
83 vsizer
= new wxFlexGridSizer(0, 2, 0, 0);
85 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxeditor_multitrack::on_wclose
));
87 vsizer
->SetSizeHints(this);
90 ahreconfigure
.set(inst
.dispatch
->autohold_reconfigure
, [this]() {
91 if(typeset
&& *typeset
== CORE().controls
->get_blank().porttypes())
92 return; //Don't reconfigure if no change.
93 CORE().mteditor
->config_altered();
96 this->update_controls();
97 } catch(std::runtime_error
& e
) {
101 multitrack_open
= NULL
;
102 inst
.iqueue
->run([]() { CORE().mteditor
->enable(false); });
108 ahmodechange
.set(inst
.dispatch
->mode_change
, [this](bool readonly
) {
109 runuifun([this, readonly
]() {
110 for(auto i
: controllers
)
111 i
.mode
->Enable(readonly
);
114 ahmtchange
.set(inst
.dispatch
->multitrack_change
, [this](unsigned port
, unsigned controller
,
116 runuifun([this, port
, controller
, state
]() {
117 for(auto i
: controllers
) {
118 if(i
.port
== port
&& i
.controller
== controller
) {
120 if(state
== multitrack_edit::MT_OR
)
121 cb
->SetStringSelection(towxstring(MTMODE_OR
));
122 if(state
== multitrack_edit::MT_OVERWRITE
)
123 cb
->SetStringSelection(towxstring(MTMODE_OVERWRITE
));
124 if(state
== multitrack_edit::MT_PRESERVE
)
125 cb
->SetStringSelection(towxstring(MTMODE_PRESERVE
));
126 if(state
== multitrack_edit::MT_XOR
)
127 cb
->SetStringSelection(towxstring(MTMODE_XOR
));
134 void wxeditor_multitrack::on_control(wxCommandEvent
& e
)
138 if(id
< wxID_HIGHEST
+ 1)
140 size_t ctrl
= id
- wxID_HIGHEST
- 1;
141 if(ctrl
>= controllers
.size())
143 controller_info
& ci
= controllers
[ctrl
];
144 std::string mode
= tostdstring(ci
.mode
->GetStringSelection());
145 inst
.iqueue
->run([ci
, mode
]() {
146 if(mode
== MTMODE_PRESERVE
)
147 CORE().mteditor
->set(ci
.port
, ci
.controller
, multitrack_edit::MT_PRESERVE
);
148 else if(mode
== MTMODE_OVERWRITE
)
149 CORE().mteditor
->set(ci
.port
, ci
.controller
, multitrack_edit::MT_OVERWRITE
);
150 else if(mode
== MTMODE_OR
)
151 CORE().mteditor
->set(ci
.port
, ci
.controller
, multitrack_edit::MT_OR
);
152 else if(mode
== MTMODE_XOR
)
153 CORE().mteditor
->set(ci
.port
, ci
.controller
, multitrack_edit::MT_XOR
);
157 void wxeditor_multitrack::update_controls()
160 bool readonly
= inst
.mlogic
->get_movie().readonly_mode();
162 for(auto i
: controllers
) {
163 vsizer
->Detach(i
.text
);
164 vsizer
->Detach(i
.mode
);
169 std::vector
<controller_info2
> info
;
170 inst
.iqueue
->run([this, &info
](){
171 std::map
<std::string
, unsigned> next_in_class
;
172 portctrl::frame model
= CORE().controls
->get_blank();
173 const portctrl::type_set
& pts
= model
.porttypes();
176 for(unsigned i
= 0;; i
++) {
177 auto pcid
= CORE().controls
->lcid_to_pcid(i
);
180 const portctrl::type
& pt
= pts
.port_type(pcid
.first
);
181 const portctrl::controller_set
& pci
= *(pt
.controller_info
);
182 if((ssize_t
)pci
.controllers
.size() <= pcid
.second
)
184 const portctrl::controller
& pc
= pci
.controllers
[pcid
.second
];
185 //First check that this has non-hidden stuff.
186 bool has_buttons
= false;
187 for(unsigned k
= 0; k
< pc
.buttons
.size(); k
++) {
188 const portctrl::button
& pcb
= pc
.buttons
[k
];
194 //Okay, a valid controller.
195 if(!next_in_class
.count(pc
.cclass
))
196 next_in_class
[pc
.cclass
] = 1;
197 uint32_t cnum
= next_in_class
[pc
.cclass
]++;
198 controller_info2 _info
;
199 _info
.name
= (stringfmt() << pc
.cclass
<< "-" << cnum
).str();
200 _info
.port
= pcid
.first
;
201 _info
.controller
= pcid
.second
;
202 info
.push_back(_info
);
207 throw std::runtime_error("No controllers");
210 struct controller_info _info
;
212 _info
.controller
= i
.controller
;
213 _info
.text
= new wxStaticText(this, wxID_ANY
, towxstring(i
.name
));
214 vsizer
->Add(_info
.text
, 0, wxGROW
);
215 std::vector
<wxString
> choices
;
216 choices
.push_back(towxstring(MTMODE_PRESERVE
));
217 choices
.push_back(towxstring(MTMODE_OVERWRITE
));
218 choices
.push_back(towxstring(MTMODE_OR
));
219 choices
.push_back(towxstring(MTMODE_XOR
));
220 _info
.mode
= new wxComboBox(this, wxID_HIGHEST
+ 1 + index
, choices
[0], wxDefaultPosition
,
221 wxDefaultSize
, choices
.size(), &choices
[0], wxCB_READONLY
);
222 _info
.mode
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
223 wxCommandEventHandler(wxeditor_multitrack::on_control
), NULL
, this);
225 _info
.mode
->Enable(false);
226 vsizer
->Add(_info
.mode
, 0, wxGROW
);
227 controllers
.push_back(_info
);
234 bool wxeditor_multitrack::ShouldPreventAppExit() const { return false; }
236 void wxeditor_multitrack::on_wclose(wxCloseEvent
& e
)
241 multitrack_open
= NULL
;
242 inst
.iqueue
->run([]() { CORE().mteditor
->enable(false); });
247 void wxeditor_multitrack_display(wxWindow
* parent
, emulator_instance
& inst
)
252 wxeditor_multitrack
* v
;
254 v
= new wxeditor_multitrack(parent
, inst
);
255 } catch(std::runtime_error
& e
) {
256 wxMessageBox(_T("No controllers present"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, parent
);
261 inst
.iqueue
->run([]() { CORE().mteditor
->enable(true); });