1 #include "core/controller.hpp"
2 #include "core/movie.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/window.hpp"
7 #include "interface/controller.hpp"
8 #include "core/mainloop.hpp"
9 #include "platform/wxwidgets/platform.hpp"
10 #include "platform/wxwidgets/textrender.hpp"
11 #include "library/minmax.hpp"
12 #include "library/string.hpp"
13 #include "library/utf8.hpp"
19 #include <wx/control.h>
20 #include <wx/combobox.h>
21 #include <wx/statline.h>
23 class wxeditor_autohold
: public wxDialog
, public information_dispatch
26 wxeditor_autohold(wxWindow
* parent
);
27 ~wxeditor_autohold() throw();
28 bool ShouldPreventAppExit() const;
29 void on_wclose(wxCloseEvent
& e
);
30 void on_checkbox(wxCommandEvent
& e
);
31 void on_autohold_update(unsigned port
, unsigned controller
, unsigned ctrlnum
, bool newstate
);
32 void on_autofire_update(unsigned port
, unsigned controller
, unsigned ctrlnum
, unsigned duty
,
34 void on_autohold_reconfigure();
42 wxStaticText
* label
; //Used only by UI version.
43 wxCheckBox
* check
; //Used only by UI version.
44 wxCheckBox
* afcheck
; //Used only by UI version.
45 bool status
; //Used only by internal version.
46 bool afstatus
; //Used only by internal version.
47 unsigned logical
; //Logical controller. Internal only.
48 std::string name
; //Name. Internal only.
50 struct controller_double
59 std::map
<int, control_triple
> autoholds
;
60 std::vector
<controller_double
> panels
;
61 void update_controls();
68 wxeditor_autohold
* autohold_open
;
71 wxeditor_autohold::~wxeditor_autohold() throw() {}
73 wxeditor_autohold::wxeditor_autohold(wxWindow
* parent
)
74 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Autohold/Autofire"), wxDefaultPosition
, wxSize(-1, -1)),
75 information_dispatch("autohold-listener")
79 hsizer
= new wxBoxSizer(wxHORIZONTAL
);
81 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxeditor_autohold::on_wclose
));
83 hsizer
->SetSizeHints(this);
87 void wxeditor_autohold::on_autohold_update(unsigned port
, unsigned controller
, unsigned ctrlnum
, bool newstate
)
89 runuifun([this, port
, controller
, ctrlnum
, newstate
]() {
90 for(auto i
: this->autoholds
) {
91 if(i
.second
.port
!= port
) continue;
92 if(i
.second
.controller
!= controller
) continue;
93 if(i
.second
.index
!= ctrlnum
) continue;
94 i
.second
.check
->SetValue(newstate
);
99 void wxeditor_autohold::on_autofire_update(unsigned port
, unsigned controller
, unsigned ctrlnum
, unsigned duty
,
102 runuifun([this, port
, controller
, ctrlnum
, duty
]() {
103 for(auto i
: this->autoholds
) {
104 if(i
.second
.port
!= port
) continue;
105 if(i
.second
.controller
!= controller
) continue;
106 if(i
.second
.index
!= ctrlnum
) continue;
107 i
.second
.afcheck
->SetValue(duty
!= 0);
112 void wxeditor_autohold::on_autohold_reconfigure()
116 this->update_controls();
117 } catch(std::runtime_error
& e
) {
121 autohold_open
= NULL
;
128 void wxeditor_autohold::on_checkbox(wxCommandEvent
& e
)
131 if(!autoholds
.count(id
))
133 auto t
= autoholds
[id
];
134 bool isaf
= (t
.afid
== id
);
135 bool newstate
= isaf
? t
.afcheck
->IsChecked() : t
.check
->IsChecked();
137 runemufn([t
, newstate
, &state
, isaf
]() {
139 auto _state
= controls
.autofire2(t
.port
, t
.controller
, t
.index
);
140 state
= (_state
.first
!= 0);
141 if(lua_callback_do_button(t
.port
, t
.controller
, t
.index
, newstate
? "autofire 1 2" :
144 controls
.autofire2(t
.port
, t
.controller
, t
.index
, newstate
? 1 : 0, newstate
? 2 : 1);
147 state
= controls
.autohold2(t
.port
, t
.controller
, t
.index
);
148 if(lua_callback_do_button(t
.port
, t
.controller
, t
.index
, newstate
? "hold" : "unhold"))
150 controls
.autohold2(t
.port
, t
.controller
, t
.index
, newstate
);
155 t
.afcheck
->SetValue(state
);
157 t
.check
->SetValue(state
);
160 void wxeditor_autohold::update_controls()
162 for(auto i
: autoholds
) {
163 if(i
.first
!= i
.second
.afid
)
164 i
.second
.label
->Destroy();
165 if(i
.first
!= i
.second
.afid
)
166 i
.second
.check
->Destroy();
167 if(i
.first
== i
.second
.afid
)
168 i
.second
.afcheck
->Destroy();
170 for(auto i
: panels
) {
171 hsizer
->Detach(i
.panel
);
176 std::vector
<control_triple
> _autoholds
;
177 std::vector
<std::string
> _controller_labels
;
178 runemufn([&_autoholds
, &_controller_labels
](){
179 std::map
<std::string
, unsigned> next_in_class
;
180 controller_frame model
= controls
.get_blank();
181 const port_type_set
& pts
= model
.porttypes();
182 unsigned pcnt
= pts
.ports();
184 for(unsigned i
= 0;; i
++) {
185 auto pcid
= controls
.lcid_to_pcid(i
);
188 const port_type
& pt
= pts
.port_type(pcid
.first
);
189 const port_controller_set
& pci
= *(pt
.controller_info
);
190 if(pci
.controller_count
<= pcid
.second
|| !pci
.controllers
[pcid
.second
])
192 const port_controller
& pc
= *(pci
.controllers
[pcid
.second
]);
193 //First check that this has non-hidden buttons.
194 bool has_buttons
= false;
195 for(unsigned k
= 0; k
< pc
.button_count
; k
++) {
198 const port_controller_button
& pcb
= *(pc
.buttons
[k
]);
199 if(pcb
.type
== port_controller_button::TYPE_BUTTON
&& !pcb
.shadow
)
204 //Okay, a valid controller.
205 if(!next_in_class
.count(pc
.cclass
))
206 next_in_class
[pc
.cclass
] = 1;
207 uint32_t cnum
= next_in_class
[pc
.cclass
]++;
208 _controller_labels
.push_back((stringfmt() << pc
.cclass
<< "-" << cnum
).str());
209 for(unsigned k
= 0; k
< pc
.button_count
; k
++) {
212 const port_controller_button
& pcb
= *(pc
.buttons
[k
]);
213 if(pcb
.type
!= port_controller_button::TYPE_BUTTON
|| pcb
.shadow
)
215 struct control_triple t
;
217 t
.controller
= pcid
.second
;
219 t
.status
= controls
.autohold2(pcid
.first
, pcid
.second
, k
);
220 auto h
= controls
.autofire2(pcid
.first
, pcid
.second
, k
);
221 t
.afstatus
= (h
.first
> 0);
224 _autoholds
.push_back(t
);
229 int next_id
= wxID_HIGHEST
+ 1;
230 unsigned last_logical
= 0xFFFFFFFFUL
;
233 wxSizer
* current_t
= NULL
;
234 for(auto i
: _autoholds
) {
235 if(i
.logical
!= last_logical
) {
236 //New controller starts.
238 hsizer
->Add(current_p
);
239 current_t
->SetSizeHints(current_p
);
240 current_t
->Fit(current_p
);
243 current_p
= d
.panel
= new wxPanel(this, wxID_ANY
);
244 current_t
= d
.rtop
= new wxBoxSizer(wxVERTICAL
);
245 d
.panel
->SetSizer(d
.rtop
);
246 d
.box
= new wxStaticBox(d
.panel
, wxID_ANY
, towxstring(_controller_labels
[i
.logical
]));
247 d
.top
= new wxStaticBoxSizer(d
.box
, wxVERTICAL
);
249 d
.label
= new wxStaticText(d
.panel
, wxID_ANY
, towxstring(_controller_labels
[i
.logical
]));
252 current
= d
.grid
= new wxFlexGridSizer(0, 3, 0, 0);
256 last_logical
= i
.logical
;
258 wxStaticText
* label
= new wxStaticText(current_p
, wxID_ANY
, towxstring(i
.name
));
259 wxCheckBox
* check
= new wxCheckBox(current_p
, next_id
, wxT("Hold"));
260 wxCheckBox
* afcheck
= new wxCheckBox(current_p
, next_id
+ 1, wxT("Rapid"));
261 struct control_triple t
;
263 t
.controller
= i
.controller
;
268 t
.afid
= next_id
+ 1;
269 check
->SetValue(i
.status
);
270 check
->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED
, wxCommandEventHandler(wxeditor_autohold::on_checkbox
),
272 afcheck
->SetValue(i
.afstatus
);
273 afcheck
->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED
,
274 wxCommandEventHandler(wxeditor_autohold::on_checkbox
), NULL
, this);
277 current
->Add(afcheck
);
278 autoholds
[next_id
++] = t
;
279 autoholds
[next_id
++] = t
;
282 hsizer
->Add(current_p
);
283 current_t
->SetSizeHints(current_p
);
284 current_t
->Fit(current_p
);
286 if(_autoholds
.empty()) {
287 throw std::runtime_error("No controlers");
289 hsizer
->SetSizeHints(this);
295 bool wxeditor_autohold::ShouldPreventAppExit() const { return false; }
297 void wxeditor_autohold::on_wclose(wxCloseEvent
& e
)
301 autohold_open
= NULL
;
306 void wxeditor_autohold_display(wxWindow
* parent
)
310 wxeditor_autohold
* v
;
312 v
= new wxeditor_autohold(parent
);
313 } catch(std::runtime_error
& e
) {
314 wxMessageBox(_T("No controllers present"), _T("Error"), wxICON_EXCLAMATION
| wxOK
, parent
);