If initsram/initstate points to LSS file, pull the matching member
[lsnes.git] / src / platform / wxwidgets / settings-hotkeys.cpp
blob2f34927373a8e746bcb333d3f06ac5070f883d74
1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "platform/wxwidgets/settings-keyentry.hpp"
3 #include "core/command.hpp"
4 #include "core/instance.hpp"
5 #include "core/keymapper.hpp"
7 namespace
9 enum
11 wxID_ADDKEY = wxID_HIGHEST + 1,
12 wxID_DROPKEY
15 class wxeditor_esettings_hotkeys : public settings_tab
17 public:
18 wxeditor_esettings_hotkeys(wxWindow* parent, emulator_instance& _inst);
19 ~wxeditor_esettings_hotkeys();
20 void on_add(wxCommandEvent& e);
21 void on_drop(wxCommandEvent& e);
22 void on_change(wxCommandEvent& e);
23 void on_notify() { refresh(); }
24 void on_mouse(wxMouseEvent& e);
25 void on_popup_menu(wxCommandEvent& e);
26 private:
27 wxTreeCtrl* controls;
28 wxButton* pri_button;
29 wxButton* sec_button;
30 std::map<string_list<char>, wxTreeItemId> items;
31 std::map<string_list<char>, std::string> names;
32 std::map<string_list<char>, keyboard::invbind*> realitems;
33 void refresh();
34 string_list<char> get_selection();
35 wxTreeItemId get_item(const string_list<char>& i);
39 wxeditor_esettings_hotkeys::wxeditor_esettings_hotkeys(wxWindow* parent, emulator_instance& _inst)
40 : settings_tab(parent, _inst)
42 CHECK_UI_THREAD;
43 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
44 SetSizer(top_s);
46 top_s->Add(controls = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
47 wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT), 1, wxGROW);
48 controls->SetMinSize(wxSize(500, 400));
49 controls->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED,
50 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_change), NULL, this);
51 controls->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxeditor_esettings_hotkeys::on_mouse), NULL,
52 this);
53 controls->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxeditor_esettings_hotkeys::on_mouse), NULL,
54 this);
56 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
57 pbutton_s->AddStretchSpacer();
58 pbutton_s->Add(pri_button = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW);
59 pri_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
60 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_add), NULL, this);
61 pri_button->Enable(false);
62 pbutton_s->Add(sec_button = new wxButton(this, wxID_ANY, wxT("Drop")), 0, wxGROW);
63 sec_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
64 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_drop), NULL, this);
65 sec_button->Enable(false);
66 top_s->Add(pbutton_s, 0, wxGROW);
68 items[string_list<char>()] = controls->AddRoot(wxT(""));
70 refresh();
71 top_s->SetSizeHints(this);
72 Fit();
75 wxTreeItemId wxeditor_esettings_hotkeys::get_item(const string_list<char>& i)
77 CHECK_UI_THREAD;
78 if(items.count(i) && items[i].IsOk())
79 return items[i];
80 return items[i] = controls->AppendItem(get_item(i.strip_one()), towxstring(i[i.size() - 1]));
83 string_list<char> wxeditor_esettings_hotkeys::get_selection()
85 CHECK_UI_THREAD;
86 if(closing())
87 return string_list<char>();
88 string_list<char> sel;
89 wxTreeItemId id = controls->GetSelection();
90 for(auto i : items)
91 if(i.second == id)
92 sel = i.first;
93 return sel;
96 void wxeditor_esettings_hotkeys::on_change(wxCommandEvent& e)
98 CHECK_UI_THREAD;
99 if(closing())
100 return;
101 string_list<char> sel = get_selection();
102 pri_button->Enable(realitems.count(sel));
103 sec_button->Enable(realitems.count(sel));
106 wxeditor_esettings_hotkeys::~wxeditor_esettings_hotkeys()
110 void wxeditor_esettings_hotkeys::on_add(wxCommandEvent& e)
112 CHECK_UI_THREAD;
113 if(closing())
114 return;
115 string_list<char> sel = get_selection();
116 std::string name = names.count(sel) ? names[sel] : "";
117 if(name == "") {
118 refresh();
119 return;
121 try {
122 keyboard::invbind* ik = realitems[sel];
123 if(!ik) {
124 refresh();
125 return;
127 key_entry_dialog* d = new key_entry_dialog(this, inst, "Specify key for " + name, "", false);
128 if(d->ShowModal() == wxID_CANCEL) {
129 d->Destroy();
130 return;
132 std::string key = d->getkey();
133 d->Destroy();
134 if(key != "")
135 ik->append(key);
136 } catch(...) {
138 refresh();
141 void wxeditor_esettings_hotkeys::on_drop(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::invbind* ik = realitems[sel];
154 if(!ik) {
155 refresh();
156 return;
158 std::vector<wxString> dropchoices;
159 keyboard::keyspec tmp;
160 unsigned idx = 0;
161 while((tmp = (std::string)ik->get(idx++)))
162 dropchoices.push_back(towxstring(clean_keystring(tmp)));
163 idx = 0;
164 if(dropchoices.size() > 1) {
165 wxSingleChoiceDialog* d2 = new wxSingleChoiceDialog(this,
166 towxstring("Select key to remove from set"), towxstring("Pick key to drop"),
167 dropchoices.size(), &dropchoices[0]);
168 if(d2->ShowModal() == wxID_CANCEL) {
169 d2->Destroy();
170 refresh();
171 return;
173 idx = d2->GetSelection();
174 d2->Destroy();
176 ik->clear(idx);
177 } catch(...) {
179 refresh();
182 void wxeditor_esettings_hotkeys::on_popup_menu(wxCommandEvent& e)
184 CHECK_UI_THREAD;
185 if(closing())
186 return;
187 if(e.GetId() == wxID_ADDKEY)
188 on_add(e);
189 else if(e.GetId() >= wxID_DROPKEY) {
190 string_list<char> sel = get_selection();
191 if(!realitems.count(sel))
192 return;
193 keyboard::invbind* ik = realitems[sel];
194 if(!ik)
195 return;
196 ik->clear(e.GetId() - wxID_DROPKEY);
198 refresh();
201 void wxeditor_esettings_hotkeys::on_mouse(wxMouseEvent& e)
203 CHECK_UI_THREAD;
204 if(!e.RightUp() && !(e.LeftUp() && e.ControlDown()))
205 return;
206 string_list<char> sel = get_selection();
207 if(!realitems.count(sel))
208 return;
209 keyboard::invbind* ik = realitems[sel];
210 if(!ik)
211 return;
213 wxMenu menu;
214 menu.Connect(wxEVT_COMMAND_MENU_SELECTED,
215 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_popup_menu), NULL, this);
216 menu.Append(wxID_ADDKEY, towxstring("Add new key"));
217 bool first = true;
218 unsigned idx = 0;
219 keyboard::keyspec tmp;
220 while((tmp = ik->get(idx++))) {
221 if(first)
222 menu.AppendSeparator();
223 first = false;
224 menu.Append(wxID_DROPKEY + idx - 1, towxstring("Drop " + clean_keystring(tmp)));
226 PopupMenu(&menu);
229 void wxeditor_esettings_hotkeys::refresh()
231 CHECK_UI_THREAD;
232 if(closing())
233 return;
234 std::map<keyboard::invbind*, std::list<keyboard::keyspec>> data;
235 realitems.clear();
236 auto x = inst.mapper->get_inverses();
237 for(auto y : x) {
238 string_list<char> key = split_on_codepoint(y->getname(), U'\u2023');
239 names[key] = y->getname();
240 realitems[key] = y;
241 keyboard::keyspec tmp;
242 unsigned idx = 0;
243 while((tmp = y->get(idx++)))
244 data[y].push_back(tmp);
246 //Delete no longer present stuff.
247 for(auto i = items.rbegin(); i != items.rend(); i++) {
248 auto j = realitems.lower_bound(i->first);
249 if(j == realitems.end() || !i->first.prefix_of(j->first)) {
250 //Delete this item.
251 if(i->second.IsOk())
252 controls->Delete(i->second);
253 items[i->first] = wxTreeItemId();
256 //Update the rest.
257 for(auto i : realitems) {
258 string_list<char> key = i.first;
259 std::string text = key[key.size() - 1];
260 auto& I = data[i.second];
261 if(I.empty())
262 text = text + " (not set)";
263 else if(I.size() == 1)
264 text = text + " (" + clean_keystring(*I.begin()) + ")";
265 else {
266 text = text + " (";
267 for(auto i = I.begin(); i != I.end(); i++) {
268 if(i != I.begin())
269 text = text + ", ";
270 text = text + clean_keystring(*i);
272 text = text + ")";
274 wxTreeItemId id = get_item(key);
275 controls->SetItemText(id, towxstring(text));
279 settings_tab_factory hotkeys("Hotkeys", [](wxWindow* parent, emulator_instance& _inst) -> settings_tab* {
280 return new wxeditor_esettings_hotkeys(parent, _inst);