Fix scaling-related crashes
[lsnes.git] / src / platform / wxwidgets / settings-controllers.cpp
blob7c05089b84cf58a45f42e8014fbc4253284ace03
1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "platform/wxwidgets/settings-keyentry.hpp"
3 #include "core/instance.hpp"
4 #include "core/keymapper.hpp"
5 #include "library/string.hpp"
7 namespace
9 enum
11 wxID_ADDKEY = wxID_HIGHEST + 1,
12 wxID_DROPKEY
15 class wxeditor_esettings_controllers : public settings_tab
17 public:
18 wxeditor_esettings_controllers(wxWindow* parent, emulator_instance& _inst);
19 ~wxeditor_esettings_controllers();
20 void on_setkey(wxCommandEvent& e);
21 void on_clearkey(wxCommandEvent& e);
22 void on_change(wxCommandEvent& e);
23 void on_mouse(wxMouseEvent& e);
24 void on_popup_menu(wxCommandEvent& e);
25 private:
26 wxTreeCtrl* controls;
27 std::map<string_list<char>, wxTreeItemId> items;
28 std::map<string_list<char>, std::string> names;
29 std::map<string_list<char>, keyboard::ctrlrkey*> realitems;
30 wxButton* set_button;
31 wxButton* clear_button;
32 void refresh();
33 string_list<char> get_selection();
34 wxTreeItemId get_item(const string_list<char>& i);
37 wxeditor_esettings_controllers::wxeditor_esettings_controllers(wxWindow* parent, emulator_instance& _inst)
38 : settings_tab(parent, _inst)
40 CHECK_UI_THREAD;
41 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
42 SetSizer(top_s);
44 top_s->Add(controls = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
45 wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT), 1, wxGROW);
46 controls->SetMinSize(wxSize(300, 400));
47 controls->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED,
48 wxCommandEventHandler(wxeditor_esettings_controllers::on_change), NULL, this);
49 controls->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxeditor_esettings_controllers::on_mouse), NULL,
50 this);
51 controls->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxeditor_esettings_controllers::on_mouse), NULL,
52 this);
53 controls->SetMinSize(wxSize(400, 300));
55 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
56 pbutton_s->AddStretchSpacer();
57 pbutton_s->Add(set_button = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW);
58 set_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
59 wxCommandEventHandler(wxeditor_esettings_controllers::on_setkey), NULL, this);
60 set_button->Enable(false);
61 pbutton_s->Add(clear_button = new wxButton(this, wxID_ANY, wxT("Drop")), 0, wxGROW);
62 clear_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
63 wxCommandEventHandler(wxeditor_esettings_controllers::on_clearkey), NULL, this);
64 clear_button->Enable(false);
65 top_s->Add(pbutton_s, 0, wxGROW);
67 items[string_list<char>()] = controls->AddRoot(wxT(""));
69 refresh();
70 top_s->SetSizeHints(this);
71 Fit();
74 wxTreeItemId wxeditor_esettings_controllers::get_item(const string_list<char>& i)
76 CHECK_UI_THREAD;
77 if(i.size() == 1)
78 return items[string_list<char>()];
79 if(items.count(i) && items[i].IsOk())
80 return items[i];
81 return items[i] = controls->AppendItem(get_item(i.strip_one()), towxstring(i[i.size() - 1]));
84 string_list<char> wxeditor_esettings_controllers::get_selection()
86 CHECK_UI_THREAD;
87 if(closing())
88 return string_list<char>();
89 string_list<char> sel;
90 wxTreeItemId id = controls->GetSelection();
91 for(auto i : items)
92 if(i.second == id)
93 sel = i.first;
94 return sel;
97 void wxeditor_esettings_controllers::on_change(wxCommandEvent& e)
99 CHECK_UI_THREAD;
100 if(closing())
101 return;
102 string_list<char> sel = get_selection();
103 set_button->Enable(realitems.count(sel));
104 clear_button->Enable(realitems.count(sel));
107 wxeditor_esettings_controllers::~wxeditor_esettings_controllers()
111 void wxeditor_esettings_controllers::on_setkey(wxCommandEvent& e)
113 CHECK_UI_THREAD;
114 if(closing())
115 return;
116 string_list<char> sel = get_selection();
117 std::string name = names.count(sel) ? names[sel] : "";
118 if(name == "") {
119 refresh();
120 return;
122 try {
123 keyboard::ctrlrkey* ik = realitems[sel];
124 if(!ik) {
125 refresh();
126 return;
128 bool axis = ik->is_axis();
129 std::string wtitle = (axis ? "Specify axis for " : "Specify key for ") + name;
130 press_button_dialog* p = new press_button_dialog(this, inst, wtitle, axis);
131 p->ShowModal();
132 std::string key = p->getkey();
133 p->Destroy();
134 if(key != "")
135 ik->append(key);
136 } catch(...) {
138 refresh();
141 void wxeditor_esettings_controllers::on_clearkey(wxCommandEvent& e)
143 CHECK_UI_THREAD;
144 if(closing())
145 return;
146 string_list<char> sel = get_selection();
147 std::string name = names.count(sel) ? names[sel] : "";
148 if(name == "") {
149 refresh();
150 return;
152 try {
153 keyboard::ctrlrkey* ik = realitems[sel];
154 if(!ik) {
155 refresh();
156 return;
158 std::vector<wxString> dropchoices;
159 std::string tmp;
160 unsigned idx = 0;
161 while((tmp = ik->get_string(idx++)) != "")
162 dropchoices.push_back(towxstring(tmp));
163 idx = 0;
164 if(dropchoices.size() == 0) {
165 refresh();
166 return;
168 if(dropchoices.size() > 1) {
169 wxSingleChoiceDialog* d2 = new wxSingleChoiceDialog(this,
170 towxstring("Select key to remove from set"), towxstring("Pick key to drop"),
171 dropchoices.size(), &dropchoices[0]);
172 if(d2->ShowModal() == wxID_CANCEL) {
173 d2->Destroy();
174 refresh();
175 return;
177 idx = d2->GetSelection();
178 d2->Destroy();
180 auto g = ik->get(idx);
181 ik->remove(g.first, g.second);
182 } catch(...) {
184 refresh();
187 void wxeditor_esettings_controllers::on_popup_menu(wxCommandEvent& e)
189 CHECK_UI_THREAD;
190 if(closing())
191 return;
192 if(e.GetId() == wxID_ADDKEY)
193 on_setkey(e);
194 else if(e.GetId() >= wxID_DROPKEY) {
195 string_list<char> sel = get_selection();
196 if(!realitems.count(sel))
197 return;
198 keyboard::ctrlrkey* ik = realitems[sel];
199 if(!ik)
200 return;
201 auto g = ik->get(e.GetId() - wxID_DROPKEY);
202 ik->remove(g.first, g.second);
204 refresh();
207 void wxeditor_esettings_controllers::on_mouse(wxMouseEvent& e)
209 CHECK_UI_THREAD;
210 if(!e.RightUp() && !(e.LeftUp() && e.ControlDown()))
211 return;
212 string_list<char> sel = get_selection();
213 if(!realitems.count(sel))
214 return;
215 keyboard::ctrlrkey* ik = realitems[sel];
216 if(!ik)
217 return;
219 wxMenu menu;
220 menu.Connect(wxEVT_COMMAND_MENU_SELECTED,
221 wxCommandEventHandler(wxeditor_esettings_controllers::on_popup_menu), NULL, this);
222 menu.Append(wxID_ADDKEY, towxstring("Add new key"));
223 bool first = true;
224 unsigned idx = 0;
225 std::string tmp;
226 while((tmp = ik->get_string(idx++)) != "") {
227 if(first)
228 menu.AppendSeparator();
229 first = false;
230 menu.Append(wxID_DROPKEY + idx - 1, towxstring("Drop " + tmp));
232 PopupMenu(&menu);
235 void wxeditor_esettings_controllers::refresh()
237 CHECK_UI_THREAD;
238 if(closing())
239 return;
240 std::map<keyboard::ctrlrkey*, std::string> data;
241 auto x = inst.mapper->get_controller_keys();
242 realitems.clear();
243 for(auto y : x) {
244 string_list<char> key = split_on_codepoint(y->get_name(), U'\u2023');
245 names[key] = y->get_name();
246 realitems[key] = y;
247 std::string tmp;
248 unsigned idx = 0;
249 while((tmp = y->get_string(idx++)) != "")
250 data[y] += ((data[y] != "") ? ", " : "") + tmp;
253 //Delete no longer present stuff.
254 for(auto i = items.rbegin(); i != items.rend(); i++) {
255 auto j = realitems.lower_bound(i->first);
256 if(j == realitems.end() || !i->first.prefix_of(j->first)) {
257 //Delete this item.
258 if(i->second.IsOk())
259 controls->Delete(i->second);
260 items[i->first] = wxTreeItemId();
263 for(auto i : realitems) {
264 string_list<char> key = i.first;
265 std::string text = key[key.size() - 1];
266 if(data[i.second] == "")
267 text = text + " (not set)";
268 else
269 text = text + " (" + clean_keystring(data[i.second]) + ")";
270 wxTreeItemId id = get_item(key);
271 controls->SetItemText(id, towxstring(text));
274 wxCommandEvent e;
275 on_change(e);
278 settings_tab_factory controllers("Controllers", [](wxWindow* parent, emulator_instance& _inst) ->
279 settings_tab* {
280 return new wxeditor_esettings_controllers(parent, _inst);