3 #include <wx/control.h>
4 #include <wx/combobox.h>
5 #include <wx/spinctrl.h>
7 #include "core/command.hpp"
8 #include "core/dispatch.hpp"
9 #include "core/mainloop.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/project.hpp"
12 #include "library/zip.hpp"
13 #include "library/json.hpp"
16 #include "platform/wxwidgets/platform.hpp"
19 class wxeditor_action
: public wxDialog
22 wxeditor_action(wxWindow
* parent
, const std::string
& label
, const std::list
<interface_action_param
>& _params
);
23 std::vector
<interface_action_paramval
> get_results() { return results
; }
24 void on_ok(wxCommandEvent
& e
);
25 void on_cancel(wxCommandEvent
& e
);
26 void on_change(wxCommandEvent
& e
);
30 std::list
<interface_action_param
> params
;
31 std::list
<wxWindow
*> controls
;
32 std::vector
<interface_action_paramval
> results
;
35 wxeditor_action::wxeditor_action(wxWindow
* parent
, const std::string
& label
,
36 const std::list
<interface_action_param
>& _params
)
37 : wxDialog(parent
, wxID_ANY
, towxstring("lsnes: Action " + label
), wxDefaultPosition
, wxSize(-1, -1))
43 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
46 for(auto i
: params
) {
48 if((r
= regex("string(:(.*))?", i
.model
))) {
49 wxBoxSizer
* tmp1
= new wxBoxSizer(wxHORIZONTAL
);
50 tmp1
->Add(new wxStaticText(this, wxID_ANY
, towxstring(i
.name
)), 0, wxGROW
);
51 wxTextCtrl
* tmp2
= new wxTextCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
,
53 controls
.push_back(tmp2
);
54 tmp1
->Add(tmp2
, 1, wxGROW
);
55 tmp2
->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
56 wxCommandEventHandler(wxeditor_action::on_change
), NULL
, this);
57 top_s
->Add(tmp1
, 0, wxGROW
);
58 } else if((r
= regex("int:(-?[0-9]+),(-?[0-9]+)", i
.model
))) {
61 low
= parse_value
<int64_t>(r
[1]);
62 high
= parse_value
<int64_t>(r
[2]);
64 show_message_ok(this, "Internal error", (stringfmt() << "Unknown limits in '"
65 << i
.model
<< "'.").str(), wxICON_EXCLAMATION
);
68 wxBoxSizer
* tmp1
= new wxBoxSizer(wxHORIZONTAL
);
69 tmp1
->Add(new wxStaticText(this, wxID_ANY
, towxstring(i
.name
)), 0, wxGROW
);
70 wxSpinCtrl
* tmp2
= new wxSpinCtrl(this, wxID_ANY
, wxT(""), wxDefaultPosition
, wxDefaultSize
,
71 wxSP_ARROW_KEYS
, low
, high
, low
);
72 controls
.push_back(tmp2
);
73 tmp1
->Add(tmp2
, 1, wxGROW
);
74 tmp2
->Connect(wxEVT_COMMAND_TEXT_UPDATED
,
75 wxCommandEventHandler(wxeditor_action::on_change
), NULL
, this);
76 top_s
->Add(tmp1
, 0, wxGROW
);
77 } else if((r
= regex("enum:(.*)", i
.model
))) {
78 std::vector
<wxString
> choices
;
82 if(i
.type() == JSON::string
)
83 choices
.push_back(towxstring(i
.as_string8()));
84 else if(i
.type() == JSON::array
)
85 choices
.push_back(towxstring(i
.index(1).as_string8()));
87 throw std::runtime_error("Choice not array nor string");
89 } catch(std::exception
& e
) {
90 show_message_ok(this, "Internal error", (stringfmt() << "JSON parse error parsing "
91 << "model: " << e
.what()).str(), wxICON_EXCLAMATION
);
94 wxBoxSizer
* tmp1
= new wxBoxSizer(wxHORIZONTAL
);
95 tmp1
->Add(new wxStaticText(this, wxID_ANY
, towxstring(i
.name
)), 0, wxGROW
);
96 wxComboBox
* tmp2
= new wxComboBox(this, wxID_ANY
, choices
[0], wxDefaultPosition
,
97 wxDefaultSize
, choices
.size(), &choices
[0], wxCB_READONLY
);
98 controls
.push_back(tmp2
);
99 tmp1
->Add(tmp2
, 1, wxGROW
);
100 tmp2
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
101 wxCommandEventHandler(wxeditor_action::on_change
), NULL
, this);
102 top_s
->Add(tmp1
, 0, wxGROW
);
103 } else if(regex_match("bool", i
.model
)) {
104 wxCheckBox
* tmp2
= new wxCheckBox(this, wxID_ANY
, towxstring(i
.name
));
105 controls
.push_back(tmp2
);
106 top_s
->Add(tmp2
, 0, wxGROW
);
107 } else if(regex_match("toggle", i
.model
)) {
108 //Nothing for toggles.
110 show_message_ok(this, "Internal error", (stringfmt() << "Unknown parameter model in '"
111 << i
.model
<< "'.").str(), wxICON_EXCLAMATION
);
116 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
117 pbutton_s
->AddStretchSpacer();
118 pbutton_s
->Add(ok
= new wxButton(this, wxID_OK
, wxT("OK")), 0, wxGROW
);
119 pbutton_s
->Add(cancel
= new wxButton(this, wxID_CANCEL
, wxT("Cancel")), 0, wxGROW
);
120 ok
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
121 wxCommandEventHandler(wxeditor_action::on_ok
), NULL
, this);
122 cancel
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
123 wxCommandEventHandler(wxeditor_action::on_cancel
), NULL
, this);
124 top_s
->Add(pbutton_s
, 0, wxGROW
);
126 top_s
->SetSizeHints(this);
131 void wxeditor_action::on_ok(wxCommandEvent
& e
)
134 std::list
<interface_action_param
>::iterator i
;
135 std::list
<wxWindow
*>::iterator j
;
136 for(i
= params
.begin(), j
= controls
.begin(); i
!= params
.end() && j
!= controls
.end(); i
++, j
++) {
138 interface_action_paramval pv
;
139 if((r
= regex("string(:(.*))?", i
->model
))) {
142 p
= tostdstring(reinterpret_cast<wxTextCtrl
*>(*j
)->GetValue());
143 if(r
[2] != "" && !regex_match(r
[2], p
)) {
144 show_message_ok(this, "Error in parameters",
145 (stringfmt() << "String (" << i
->name
<< ") does not satisfy "
146 << "constraints.").str(), wxICON_EXCLAMATION
);
150 show_message_ok(this, "Internal error", (stringfmt() << "Bad constraint in '"
151 << i
->model
<< "'.").str(), wxICON_EXCLAMATION
);
155 } else if((r
= regex("int:([0-9]+),([0-9]+)", i
->model
))) {
156 int64_t low
, high
, v
;
158 low
= parse_value
<int64_t>(r
[1]);
159 high
= parse_value
<int64_t>(r
[2]);
161 show_message_ok(this, "Internal error", (stringfmt() << "Unknown limits in '"
162 << i
->model
<< "'.").str(), wxICON_EXCLAMATION
);
165 v
= reinterpret_cast<wxSpinCtrl
*>(*j
)->GetValue();
166 if(v
< low
|| v
> high
) {
167 show_message_ok(this, "Error in parameters",
168 (stringfmt() << "Integer (" << i
->name
<< ") out of range.").str(),
173 } else if((r
= regex("enum:(.*)", i
->model
))) {
174 int v
= reinterpret_cast<wxComboBox
*>(*j
)->GetSelection();
175 if(v
== wxNOT_FOUND
) {
176 show_message_ok(this, "Error in parameters",
177 (stringfmt() << "No selection for '" << i
->name
<< "'.").str(),
182 } else if(regex_match("bool", i
->model
)) {
183 pv
.b
= reinterpret_cast<wxCheckBox
*>(*j
)->GetValue();
184 } else if(regex_match("toggle", i
->model
)) {
187 show_message_ok(this, "Internal error", (stringfmt() << "Unknown parameter model in '"
188 << i
->model
<< "'.").str(), wxICON_EXCLAMATION
);
191 results
.push_back(pv
);
196 void wxeditor_action::on_cancel(wxCommandEvent
& e
)
199 EndModal(wxID_CANCEL
);
202 void wxeditor_action::on_change(wxCommandEvent
& e
)
205 std::list
<interface_action_param
>::iterator i
;
206 std::list
<wxWindow
*>::iterator j
;
207 for(i
= params
.begin(), j
= controls
.begin(); i
!= params
.end() && j
!= controls
.end(); i
++, j
++) {
209 if((r
= regex("string(:(.*))?", i
->model
))) {
211 std::string p
= tostdstring(reinterpret_cast<wxTextCtrl
*>(*j
)->GetValue());
212 if(r
[2] != "" && !regex_match(r
[2], p
)) {
218 } else if((r
= regex("int:([0-9]+),([0-9]+)", i
->model
))) {
219 int64_t low
, high
, v
;
221 low
= parse_value
<int64_t>(r
[1]);
222 high
= parse_value
<int64_t>(r
[2]);
226 v
= reinterpret_cast<wxSpinCtrl
*>(*j
)->GetValue();
227 if(v
< low
|| v
> high
)
229 } else if((r
= regex("enum:(.*)", i
->model
))) {
230 if(reinterpret_cast<wxComboBox
*>(*j
)->GetSelection() == wxNOT_FOUND
)
232 } else if(regex_match("bool", i
->model
)) {
233 } else if(regex_match("toggle", i
->model
)) {
245 std::vector
<interface_action_paramval
> prompt_action_params(wxWindow
* parent
, const std::string
& label
,
246 const std::list
<interface_action_param
>& params
)
249 //Empty special case.
251 return std::vector
<interface_action_paramval
>();
252 //Another special case.
253 if(params
.size() == 1 && params
.begin()->model
== std::string("toggle")) {
254 std::vector
<interface_action_paramval
> x
;
255 x
.push_back(interface_action_paramval());
258 modal_pause_holder hld
;
260 wxeditor_action
* f
= new wxeditor_action(parent
, label
, params
);
261 int r
= f
->ShowModal();
262 if(r
== wxID_CANCEL
) {
264 throw canceled_exception();
266 auto p
= f
->get_results();
269 } catch(canceled_exception
& e
) {
272 throw canceled_exception();