3 #include <wx/control.h>
4 #include <wx/combobox.h>
5 #include <wx/statline.h>
7 #include "core/controller.hpp"
8 #include "core/dispatch.hpp"
9 #include "core/instance.hpp"
10 #include "core/mainloop.hpp"
11 #include "core/movie.hpp"
12 #include "core/moviedata.hpp"
13 #include "core/window.hpp"
15 #include "interface/controller.hpp"
16 #include "platform/wxwidgets/platform.hpp"
17 #include "platform/wxwidgets/textrender.hpp"
18 #include "library/minmax.hpp"
19 #include "library/string.hpp"
20 #include "library/utf8.hpp"
21 #include "lua/lua.hpp"
26 class wxeditor_autohold
: public wxDialog
29 wxeditor_autohold(wxWindow
* parent
, emulator_instance
& _inst
);
30 ~wxeditor_autohold() throw();
31 bool ShouldPreventAppExit() const;
32 void on_wclose(wxCloseEvent
& e
);
33 void on_checkbox(wxCommandEvent
& e
);
35 struct dispatch::target
<unsigned, unsigned, unsigned, bool> ahupdate
;
36 struct dispatch::target
<unsigned, unsigned, unsigned, unsigned, unsigned> afupdate
;
37 struct dispatch::target
<> ahreconfigure
;
45 wxStaticText
* label
; //Used only by UI version.
46 wxCheckBox
* check
; //Used only by UI version.
47 wxCheckBox
* afcheck
; //Used only by UI version.
48 bool status
; //Used only by internal version.
49 bool afstatus
; //Used only by internal version.
50 unsigned logical
; //Logical controller. Internal only.
51 std::string name
; //Name. Internal only.
53 struct controller_double
62 emulator_instance
& inst
;
63 std::map
<int, control_triple
> autoholds
;
64 std::vector
<controller_double
> panels
;
65 void update_controls();
72 wxeditor_autohold
* autohold_open
;
75 wxeditor_autohold::~wxeditor_autohold() throw() {}
77 wxeditor_autohold::wxeditor_autohold(wxWindow
* parent
, emulator_instance
& _inst
)
78 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Autohold/Autofire"), wxDefaultPosition
, wxSize(-1, -1)),
84 hsizer
= new wxBoxSizer(wxHORIZONTAL
);
86 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxeditor_autohold::on_wclose
));
88 hsizer
->SetSizeHints(this);
91 ahupdate
.set(inst
.dispatch
->autohold_update
, [this](unsigned port
, unsigned controller
,
92 unsigned ctrlnum
, bool newstate
) {
93 runuifun([this, port
, controller
, ctrlnum
, newstate
]() {
95 for(auto i
: this->autoholds
) {
96 if(i
.second
.port
!= port
) continue;
97 if(i
.second
.controller
!= controller
) continue;
98 if(i
.second
.index
!= ctrlnum
) continue;
99 i
.second
.check
->SetValue(newstate
);
103 afupdate
.set(inst
.dispatch
->autofire_update
, [this](unsigned port
, unsigned controller
,
104 unsigned ctrlnum
, unsigned duty
, unsigned cyclelen
) {
105 runuifun([this, port
, controller
, ctrlnum
, duty
]() {
107 for(auto i
: this->autoholds
) {
108 if(i
.second
.port
!= port
) continue;
109 if(i
.second
.controller
!= controller
) continue;
110 if(i
.second
.index
!= ctrlnum
) continue;
111 i
.second
.afcheck
->SetValue(duty
!= 0);
115 ahreconfigure
.set(inst
.dispatch
->autohold_reconfigure
, [this]() {
119 this->update_controls();
120 } catch(std::runtime_error
& e
) {
124 autohold_open
= NULL
;
132 void wxeditor_autohold::on_checkbox(wxCommandEvent
& e
)
136 if(!autoholds
.count(id
))
138 auto t
= autoholds
[id
];
139 bool isaf
= (t
.afid
== id
);
140 bool newstate
= isaf
? t
.afcheck
->IsChecked() : t
.check
->IsChecked();
142 inst
.iqueue
->run([t
, newstate
, &state
, isaf
]() {
145 auto _state
= core
.controls
->autofire2(t
.port
, t
.controller
, t
.index
);
146 state
= (_state
.first
!= 0);
147 if(core
.lua2
->callback_do_button(t
.port
, t
.controller
, t
.index
, newstate
? "autofire 1 2" :
150 core
.controls
->autofire2(t
.port
, t
.controller
, t
.index
, newstate
? 1 : 0, newstate
? 2 : 1);
153 state
= core
.controls
->autohold2(t
.port
, t
.controller
, t
.index
);
154 if(core
.lua2
->callback_do_button(t
.port
, t
.controller
, t
.index
, newstate
? "hold" : "unhold"))
156 core
.controls
->autohold2(t
.port
, t
.controller
, t
.index
, newstate
);
161 t
.afcheck
->SetValue(state
);
163 t
.check
->SetValue(state
);
166 void wxeditor_autohold::update_controls()
169 for(auto i
: autoholds
) {
170 if(i
.first
!= i
.second
.afid
)
171 i
.second
.label
->Destroy();
172 if(i
.first
!= i
.second
.afid
)
173 i
.second
.check
->Destroy();
174 if(i
.first
== i
.second
.afid
)
175 i
.second
.afcheck
->Destroy();
177 for(auto i
: panels
) {
178 hsizer
->Detach(i
.panel
);
183 std::vector
<control_triple
> _autoholds
;
184 std::vector
<std::string
> _controller_labels
;
185 inst
.iqueue
->run([&_autoholds
, &_controller_labels
](){
187 std::map
<std::string
, unsigned> next_in_class
;
188 portctrl::frame model
= core
.controls
->get_blank();
189 const portctrl::type_set
& pts
= model
.porttypes();
191 for(unsigned i
= 0;; i
++) {
192 auto pcid
= core
.controls
->lcid_to_pcid(i
);
195 const portctrl::type
& pt
= pts
.port_type(pcid
.first
);
196 const portctrl::controller_set
& pci
= *(pt
.controller_info
);
197 if((ssize_t
)pci
.controllers
.size() <= pcid
.second
)
199 const portctrl::controller
& pc
= pci
.controllers
[pcid
.second
];
200 //First check that this has non-hidden buttons.
201 bool has_buttons
= false;
202 for(unsigned k
= 0; k
< pc
.buttons
.size(); k
++) {
203 const portctrl::button
& pcb
= pc
.buttons
[k
];
204 if(pcb
.type
== portctrl::button::TYPE_BUTTON
&& !pcb
.shadow
)
209 //Okay, a valid controller.
210 if(!next_in_class
.count(pc
.cclass
))
211 next_in_class
[pc
.cclass
] = 1;
212 uint32_t cnum
= next_in_class
[pc
.cclass
]++;
213 _controller_labels
.push_back((stringfmt() << pc
.cclass
<< "-" << cnum
).str());
214 for(unsigned k
= 0; k
< pc
.buttons
.size(); k
++) {
215 const portctrl::button
& pcb
= pc
.buttons
[k
];
216 if(pcb
.type
!= portctrl::button::TYPE_BUTTON
|| pcb
.shadow
)
218 struct control_triple t
;
220 t
.controller
= pcid
.second
;
222 t
.status
= core
.controls
->autohold2(pcid
.first
, pcid
.second
, k
);
223 auto h
= core
.controls
->autofire2(pcid
.first
, pcid
.second
, k
);
224 t
.afstatus
= (h
.first
> 0);
227 _autoholds
.push_back(t
);
232 int next_id
= wxID_HIGHEST
+ 1;
233 unsigned last_logical
= 0xFFFFFFFFUL
;
234 wxSizer
* current
= NULL
;
235 wxPanel
* current_p
= NULL
;
236 wxSizer
* current_t
= NULL
;
237 for(auto i
: _autoholds
) {
238 if(i
.logical
!= last_logical
) {
239 //New controller starts.
241 hsizer
->Add(current_p
);
242 current_t
->SetSizeHints(current_p
);
243 current_t
->Fit(current_p
);
246 current_p
= d
.panel
= new wxPanel(this, wxID_ANY
);
247 current_t
= d
.rtop
= new wxBoxSizer(wxVERTICAL
);
248 d
.panel
->SetSizer(d
.rtop
);
249 d
.box
= new wxStaticBox(d
.panel
, wxID_ANY
, towxstring(_controller_labels
[i
.logical
]));
250 d
.top
= new wxStaticBoxSizer(d
.box
, wxVERTICAL
);
252 d
.label
= new wxStaticText(d
.panel
, wxID_ANY
, towxstring(_controller_labels
[i
.logical
]));
255 current
= d
.grid
= new wxFlexGridSizer(0, 3, 0, 0);
259 last_logical
= i
.logical
;
261 wxStaticText
* label
= new wxStaticText(current_p
, wxID_ANY
, towxstring(i
.name
));
262 wxCheckBox
* check
= new wxCheckBox(current_p
, next_id
, wxT("Hold"));
263 wxCheckBox
* afcheck
= new wxCheckBox(current_p
, next_id
+ 1, wxT("Rapid"));
264 struct control_triple t
;
266 t
.controller
= i
.controller
;
271 t
.afid
= next_id
+ 1;
272 check
->SetValue(i
.status
);
273 check
->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED
, wxCommandEventHandler(wxeditor_autohold::on_checkbox
),
275 afcheck
->SetValue(i
.afstatus
);
276 afcheck
->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED
,
277 wxCommandEventHandler(wxeditor_autohold::on_checkbox
), NULL
, this);
280 current
->Add(afcheck
);
281 autoholds
[next_id
++] = t
;
282 autoholds
[next_id
++] = t
;
285 hsizer
->Add(current_p
);
286 current_t
->SetSizeHints(current_p
);
287 current_t
->Fit(current_p
);
289 if(_autoholds
.empty()) {
290 throw std::runtime_error("No controlers");
292 hsizer
->SetSizeHints(this);
298 bool wxeditor_autohold::ShouldPreventAppExit() const { return false; }
300 void wxeditor_autohold::on_wclose(wxCloseEvent
& e
)
305 autohold_open
= NULL
;
310 void wxeditor_autohold_display(wxWindow
* parent
, emulator_instance
& inst
)
315 wxeditor_autohold
* v
;
317 v
= new wxeditor_autohold(parent
, inst
);
318 } catch(std::runtime_error
& e
) {
319 wxMessageBox(_T("No controllers present"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, parent
);