1 #include "core/controller.hpp"
2 #include "core/movie.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/multitrack.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/window.hpp"
8 #include "interface/controller.hpp"
9 #include "core/mainloop.hpp"
10 #include "platform/wxwidgets/platform.hpp"
11 #include "platform/wxwidgets/textrender.hpp"
12 #include "library/minmax.hpp"
13 #include "library/string.hpp"
14 #include "library/utf8.hpp"
20 #include <wx/control.h>
21 #include <wx/combobox.h>
22 #include <wx/statline.h>
23 #include <wx/spinctrl.h>
25 #define MTMODE_PRESERVE "Preserve"
26 #define MTMODE_OVERWRITE "Overwrite"
27 #define MTMODE_OR "OR"
28 #define MTMODE_XOR "XOR"
34 class wxeditor_multitrack
: public wxDialog
37 wxeditor_multitrack(wxWindow
* parent
);
38 ~wxeditor_multitrack() throw();
39 bool ShouldPreventAppExit() const;
40 void on_wclose(wxCloseEvent
& e
);
41 void on_control(wxCommandEvent
& e
);
43 struct dispatch::target
<> ahreconfigure
;
44 struct dispatch::target
<bool> ahmodechange
;
45 struct dispatch::target
<unsigned, unsigned, int> ahmtchange
;
46 struct controller_info
53 struct controller_info2
59 std::vector
<controller_info
> controllers
;
60 void update_controls();
62 wxFlexGridSizer
* vsizer
;
63 const port_type_set
* typeset
;
68 wxeditor_multitrack
* multitrack_open
;
71 wxeditor_multitrack::~wxeditor_multitrack() throw() {}
73 wxeditor_multitrack::wxeditor_multitrack(wxWindow
* parent
)
74 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Multitrack recording"), wxDefaultPosition
, wxSize(-1, -1))
79 vsizer
= new wxFlexGridSizer(0, 2, 0, 0);
81 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxeditor_multitrack::on_wclose
));
83 vsizer
->SetSizeHints(this);
86 ahreconfigure
.set(notify_autohold_reconfigure
, [this]() {
87 if(typeset
&& *typeset
== controls
.get_blank().porttypes())
88 return; //Don't reconfigure if no change.
89 multitrack_editor
.config_altered();
92 this->update_controls();
93 } catch(std::runtime_error
& e
) {
97 multitrack_open
= NULL
;
98 runemufn([]() { multitrack_editor
.enable(false); });
104 ahmodechange
.set(notify_mode_change
, [this](bool readonly
) {
105 runuifun([this, readonly
]() {
106 for(auto i
: controllers
)
107 i
.mode
->Enable(readonly
);
110 ahmtchange
.set(notify_multitrack_change
, [this](unsigned port
, unsigned controller
, int state
) {
111 runuifun([this, port
, controller
, state
]() {
112 for(auto i
: controllers
) {
113 if(i
.port
== port
&& i
.controller
== controller
) {
115 if(state
== multitrack_edit::MT_OR
)
116 cb
->SetStringSelection(towxstring(MTMODE_OR
));
117 if(state
== multitrack_edit::MT_OVERWRITE
)
118 cb
->SetStringSelection(towxstring(MTMODE_OVERWRITE
));
119 if(state
== multitrack_edit::MT_PRESERVE
)
120 cb
->SetStringSelection(towxstring(MTMODE_PRESERVE
));
121 if(state
== multitrack_edit::MT_XOR
)
122 cb
->SetStringSelection(towxstring(MTMODE_XOR
));
129 void wxeditor_multitrack::on_control(wxCommandEvent
& e
)
132 if(id
< wxID_HIGHEST
+ 1)
134 size_t ctrl
= id
- wxID_HIGHEST
- 1;
135 if(ctrl
>= controllers
.size())
137 controller_info
& ci
= controllers
[ctrl
];
138 std::string mode
= tostdstring(ci
.mode
->GetStringSelection());
139 runemufn([ci
, mode
]() {
140 if(mode
== MTMODE_PRESERVE
)
141 multitrack_editor
.set(ci
.port
, ci
.controller
, multitrack_edit::MT_PRESERVE
);
142 else if(mode
== MTMODE_OVERWRITE
)
143 multitrack_editor
.set(ci
.port
, ci
.controller
, multitrack_edit::MT_OVERWRITE
);
144 else if(mode
== MTMODE_OR
)
145 multitrack_editor
.set(ci
.port
, ci
.controller
, multitrack_edit::MT_OR
);
146 else if(mode
== MTMODE_XOR
)
147 multitrack_editor
.set(ci
.port
, ci
.controller
, multitrack_edit::MT_XOR
);
151 void wxeditor_multitrack::update_controls()
153 bool readonly
= movb
.get_movie().readonly_mode();
155 for(auto i
: controllers
) {
156 vsizer
->Detach(i
.text
);
157 vsizer
->Detach(i
.mode
);
162 std::vector
<controller_info2
> info
;
163 runemufn([this, &info
](){
164 std::map
<std::string
, unsigned> next_in_class
;
165 controller_frame model
= controls
.get_blank();
166 const port_type_set
& pts
= model
.porttypes();
169 for(unsigned i
= 0;; i
++) {
170 auto pcid
= controls
.lcid_to_pcid(i
);
173 const port_type
& pt
= pts
.port_type(pcid
.first
);
174 const port_controller_set
& pci
= *(pt
.controller_info
);
175 if((ssize_t
)pci
.controllers
.size() <= pcid
.second
)
177 const port_controller
& pc
= pci
.controllers
[pcid
.second
];
178 //First check that this has non-hidden stuff.
179 bool has_buttons
= false;
180 for(unsigned k
= 0; k
< pc
.buttons
.size(); k
++) {
181 const port_controller_button
& pcb
= pc
.buttons
[k
];
187 //Okay, a valid controller.
188 if(!next_in_class
.count(pc
.cclass
))
189 next_in_class
[pc
.cclass
] = 1;
190 uint32_t cnum
= next_in_class
[pc
.cclass
]++;
191 controller_info2 _info
;
192 _info
.name
= (stringfmt() << pc
.cclass
<< "-" << cnum
).str();
193 _info
.port
= pcid
.first
;
194 _info
.controller
= pcid
.second
;
195 info
.push_back(_info
);
200 throw std::runtime_error("No controllers");
203 struct controller_info _info
;
205 _info
.controller
= i
.controller
;
206 _info
.text
= new wxStaticText(this, wxID_ANY
, towxstring(i
.name
));
207 vsizer
->Add(_info
.text
, 0, wxGROW
);
208 std::vector
<wxString
> choices
;
209 choices
.push_back(towxstring(MTMODE_PRESERVE
));
210 choices
.push_back(towxstring(MTMODE_OVERWRITE
));
211 choices
.push_back(towxstring(MTMODE_OR
));
212 choices
.push_back(towxstring(MTMODE_XOR
));
213 _info
.mode
= new wxComboBox(this, wxID_HIGHEST
+ 1 + index
, choices
[0], wxDefaultPosition
,
214 wxDefaultSize
, choices
.size(), &choices
[0], wxCB_READONLY
);
215 _info
.mode
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
216 wxCommandEventHandler(wxeditor_multitrack::on_control
), NULL
, this);
218 _info
.mode
->Enable(false);
219 vsizer
->Add(_info
.mode
, 0, wxGROW
);
220 controllers
.push_back(_info
);
227 bool wxeditor_multitrack::ShouldPreventAppExit() const { return false; }
229 void wxeditor_multitrack::on_wclose(wxCloseEvent
& e
)
233 multitrack_open
= NULL
;
234 runemufn([]() { multitrack_editor
.enable(false); });
239 void wxeditor_multitrack_display(wxWindow
* parent
)
243 wxeditor_multitrack
* v
;
245 v
= new wxeditor_multitrack(parent
);
246 } catch(std::runtime_error
& e
) {
247 wxMessageBox(_T("No controllers present"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, parent
);
252 runemufn([]() { multitrack_editor
.enable(true); });