Fix scaling-related crashes
[lsnes.git] / src / platform / wxwidgets / settings-advanced.cpp
blobf48af40146cb70543d9fceda244bf2426119b51c
1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "core/instance.hpp"
3 #include "core/settings.hpp"
5 namespace
7 enum
9 wxID_CHANGE = wxID_HIGHEST + 1
12 class wxeditor_esettings_advanced : public settings_tab
14 public:
15 wxeditor_esettings_advanced(wxWindow* parent, emulator_instance& _inst);
16 ~wxeditor_esettings_advanced();
17 void on_change(wxCommandEvent& e);
18 void on_change2(wxMouseEvent& e);
19 void on_selchange(wxCommandEvent& e);
20 void on_setting_change(const settingvar::base& val);
21 void on_mouse(wxMouseEvent& e);
22 void on_popup_menu(wxCommandEvent& e);
23 void _refresh();
24 struct listener : public settingvar::listener
26 listener(settingvar::group& group, wxeditor_esettings_advanced& _obj)
27 : obj(_obj), grp(group)
29 group.add_listener(*this);
31 ~listener() throw()
33 grp.remove_listener(*this);
35 void on_setting_change(settingvar::group& grp, const settingvar::base& val)
37 obj.on_setting_change(val);
39 wxeditor_esettings_advanced& obj;
40 settingvar::group& grp;
42 private:
43 listener _listener;
44 void refresh();
45 std::set<std::string> settings;
46 std::map<std::string, std::string> values;
47 std::map<std::string, std::string> names;
48 std::map<int, std::string> selections;
49 std::string selected();
50 wxButton* changebutton;
51 wxListBox* _settings;
54 wxeditor_esettings_advanced::wxeditor_esettings_advanced(wxWindow* parent, emulator_instance& _inst)
55 : settings_tab(parent, _inst), _listener(*inst.settings, *this)
57 CHECK_UI_THREAD;
58 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
59 SetSizer(top_s);
61 top_s->Add(_settings = new wxListBox(this, wxID_ANY), 1, wxGROW);
62 _settings->SetMinSize(wxSize(300, 400));
63 _settings->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
64 wxCommandEventHandler(wxeditor_esettings_advanced::on_selchange), NULL, this);
65 _settings->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxeditor_esettings_advanced::on_mouse), NULL,
66 this);
67 _settings->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxeditor_esettings_advanced::on_mouse), NULL,
68 this);
70 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
71 pbutton_s->AddStretchSpacer();
72 pbutton_s->Add(changebutton = new wxButton(this, wxID_ANY, wxT("Change")), 0, wxGROW);
73 _settings->Connect(wxEVT_LEFT_DCLICK,
74 wxMouseEventHandler(wxeditor_esettings_advanced::on_change2), NULL, this);
75 changebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
76 wxCommandEventHandler(wxeditor_esettings_advanced::on_change), NULL, this);
77 top_s->Add(pbutton_s, 0, wxGROW);
79 refresh();
80 wxCommandEvent e;
81 on_selchange(e);
82 top_s->SetSizeHints(this);
83 Fit();
86 wxeditor_esettings_advanced::~wxeditor_esettings_advanced()
90 std::string change_value_of_boolean(const std::string& name, const settingvar::description& desc,
91 const std::string& current)
93 return string_to_bool(current) ? "0" : "1";
96 std::string change_value_of_enumeration(wxWindow* parent, const std::string& name,
97 const settingvar::description& desc, const std::string& current)
99 CHECK_UI_THREAD;
100 std::vector<std::string> valset;
101 unsigned dflt = 0;
102 for(unsigned i = 0; i <= desc._enumeration->max_val(); i++) {
103 valset.push_back(desc._enumeration->get(i));
104 if(desc._enumeration->get(i) == current)
105 dflt = i;
107 return pick_among(parent, "Set value to", "Set " + name + " to value:", valset, dflt);
110 std::string change_value_of_string(wxWindow* parent, const std::string& name,
111 const settingvar::description& desc, const std::string& current)
113 return pick_text(parent, "Set value to", "Set " + name + " to value:", current);
116 class numeric_inputbox : public wxDialog
118 public:
119 numeric_inputbox(wxWindow* parent, const std::string& name, int64_t minval, int64_t maxval,
120 const std::string& val)
121 : wxDialog(parent, wxID_ANY, wxT("Set value to"))
123 CHECK_UI_THREAD;
124 wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
125 SetSizer(s1);
126 s1->Add(new wxStaticText(this, wxID_ANY, towxstring("Set " + name + " to value:")), 0,
127 wxGROW);
129 s1->Add(sp = new wxSpinCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
130 wxSP_ARROW_KEYS, minval, maxval, parse_value<int64_t>(val)), 1, wxGROW);
132 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
133 pbutton_s->AddStretchSpacer();
134 wxButton* t;
135 pbutton_s->Add(t = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
136 t->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
137 wxCommandEventHandler(numeric_inputbox::on_button), NULL, this);
138 pbutton_s->Add(t = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
139 t->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
140 wxCommandEventHandler(numeric_inputbox::on_button), NULL, this);
141 s1->Add(pbutton_s, 0, wxGROW);
143 s1->SetSizeHints(this);
145 std::string get_value() { return (stringfmt() << sp->GetValue()).str(); }
146 void on_button(wxCommandEvent& e) { EndModal(e.GetId()); }
147 private:
148 wxSpinCtrl* sp;
151 class path_inputbox : public wxDialog
153 public:
154 path_inputbox(wxWindow* parent, const std::string& name, const std::string& val)
155 : wxDialog(parent, wxID_ANY, wxT("Set path to"))
157 CHECK_UI_THREAD;
158 wxButton* t;
159 wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
160 SetSizer(s1);
161 s1->Add(new wxStaticText(this, wxID_ANY, towxstring("Set " + name + " to value:")), 0,
162 wxGROW);
163 wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
164 s2->Add(pth = new wxTextCtrl(this, wxID_ANY, towxstring(val), wxDefaultPosition,
165 wxSize(400, -1)), 1, wxGROW);
166 s2->Add(t = new wxButton(this, wxID_HIGHEST + 1, wxT("...")), 0, wxGROW);
167 t->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
168 wxCommandEventHandler(path_inputbox::on_pbutton), NULL, this);
169 s1->Add(s2, 1, wxGROW);
171 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
172 pbutton_s->AddStretchSpacer();
173 pbutton_s->Add(t = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
174 t->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
175 wxCommandEventHandler(path_inputbox::on_button), NULL, this);
176 pbutton_s->Add(t = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
177 t->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
178 wxCommandEventHandler(path_inputbox::on_button), NULL, this);
179 s1->Add(pbutton_s, 0, wxGROW);
181 s1->SetSizeHints(this);
183 std::string get_value() { return tostdstring(pth->GetValue()); }
184 void on_pbutton(wxCommandEvent& e) {
185 wxDirDialog* d;
186 d = new wxDirDialog(this, wxT("Select project directory"),
187 pth->GetValue(), wxDD_DIR_MUST_EXIST);
188 if(d->ShowModal() == wxID_CANCEL) {
189 d->Destroy();
190 return;
192 pth->SetValue(d->GetPath());
193 d->Destroy();
195 void on_button(wxCommandEvent& e) {
196 switch(e.GetId()) {
197 case wxID_OK:
198 case wxID_CANCEL:
199 EndModal(e.GetId());
200 break;
203 private:
204 wxTextCtrl* pth;
207 std::string change_value_of_numeric(wxWindow* parent, const std::string& name,
208 const settingvar::description& desc, const std::string& current)
210 CHECK_UI_THREAD;
211 auto d = new numeric_inputbox(parent, name, desc.min_val, desc.max_val, current);
212 int x = d->ShowModal();
213 if(x == wxID_CANCEL) {
214 d->Destroy();
215 throw canceled_exception();
217 std::string v = d->get_value();
218 d->Destroy();
219 return v;
222 std::string change_value_of_path(wxWindow* parent, const std::string& name,
223 const settingvar::description& desc, const std::string& current)
225 CHECK_UI_THREAD;
226 auto d = new path_inputbox(parent, name, current);
227 int x = d->ShowModal();
228 if(x == wxID_CANCEL) {
229 d->Destroy();
230 throw canceled_exception();
232 std::string v = d->get_value();
233 d->Destroy();
234 return v;
237 void wxeditor_esettings_advanced::on_popup_menu(wxCommandEvent& e)
239 CHECK_UI_THREAD;
240 if(closing())
241 return;
242 if(e.GetId() == wxID_EDIT)
243 on_change(e);
246 void wxeditor_esettings_advanced::on_mouse(wxMouseEvent& e)
248 CHECK_UI_THREAD;
249 if(!e.RightUp() && !(e.LeftUp() && e.ControlDown()))
250 return;
251 if(selected() == "")
252 return;
253 wxMenu menu;
254 menu.Connect(wxEVT_COMMAND_MENU_SELECTED,
255 wxCommandEventHandler(wxeditor_esettings_advanced::on_popup_menu), NULL, this);
256 menu.Append(wxID_EDIT, towxstring("Change"));
257 PopupMenu(&menu);
260 void wxeditor_esettings_advanced::on_change2(wxMouseEvent& e)
262 CHECK_UI_THREAD;
263 wxCommandEvent e2;
264 on_change(e2);
267 void wxeditor_esettings_advanced::on_change(wxCommandEvent& e)
269 CHECK_UI_THREAD;
270 if(closing())
271 return;
272 std::string name = selected();
273 if(name == "")
274 return;
275 std::string value;
276 std::string err;
277 value = inst.setcache->get(name);
278 auto model = inst.setcache->get_description(name);
279 try {
280 switch(model.type) {
281 case settingvar::description::T_BOOLEAN:
282 value = change_value_of_boolean(name, model, value); break;
283 case settingvar::description::T_NUMERIC:
284 value = change_value_of_numeric(this, name, model, value); break;
285 case settingvar::description::T_STRING:
286 value = change_value_of_string(this, name, model, value); break;
287 case settingvar::description::T_PATH:
288 value = change_value_of_path(this, name, model, value); break;
289 case settingvar::description::T_ENUMERATION:
290 value = change_value_of_enumeration(this, name, model, value); break;
291 default:
292 value = change_value_of_string(this, name, model, value); break;
294 } catch(...) {
295 return;
297 inst.iqueue->run([this, name, value]() {
298 run_show_error(this, "Error setting value", "", [name, value]() {
299 CORE().setcache->set(name, value);
304 void wxeditor_esettings_advanced::on_selchange(wxCommandEvent& e)
306 CHECK_UI_THREAD;
307 if(closing())
308 return;
309 std::string sel = selected();
310 bool enable = (sel != "");
311 changebutton->Enable(enable);
314 void wxeditor_esettings_advanced::on_setting_change(const settingvar::base& val)
316 if(closing())
317 return;
318 runuifun([this, &val]() {
319 CHECK_UI_THREAD;
320 std::string setting = val.get_iname();
321 std::string value = val.str();
322 this->settings.insert(setting);
323 this->values[setting] = value;
324 this->_refresh();
328 void wxeditor_esettings_advanced::refresh()
330 CHECK_UI_THREAD;
331 if(closing())
332 return;
333 settings = inst.setcache->get_keys();
334 for(auto i : settings) {
335 values[i] = inst.setcache->get(i);
336 names[i] = inst.setcache->get_hname(i);
338 _refresh();
341 std::string wxeditor_esettings_advanced::selected()
343 CHECK_UI_THREAD;
344 if(closing())
345 return "";
346 int x = _settings->GetSelection();
347 if(selections.count(x))
348 return selections[x];
349 else
350 return "";
353 void wxeditor_esettings_advanced::_refresh()
355 CHECK_UI_THREAD;
356 if(closing())
357 return;
358 std::vector<wxString> strings;
359 std::multimap<std::string, std::string> sort;
360 int k = 0;
361 for(auto i : settings)
362 sort.insert(std::make_pair(names[i], i));
363 for(auto i : sort) {
364 //FIXME: Do something with this?
365 //auto description = inst.setcache->get_description(i.second);
366 strings.push_back(towxstring(names[i.second] + " (Value: " + values[i.second] + ")"));
367 selections[k++] = i.second;
369 _settings->Set(strings.size(), &strings[0]);
372 settings_tab_factory advanced_tab("Advanced", [](wxWindow* parent, emulator_instance& _inst) ->
373 settings_tab* {
374 return new wxeditor_esettings_advanced(parent, _inst);