Force some configuration windows to be larger
[lsnes.git] / src / platform / wxwidgets / settings-hotkeys.cpp
blob8e30186ec455a731116342464f5973ecea8d2748
1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "platform/wxwidgets/settings-keyentry.hpp"
3 #include "core/command.hpp"
4 #include "core/keymapper.hpp"
6 namespace
8 enum
10 wxID_ADDKEY = wxID_HIGHEST + 1,
11 wxID_DROPKEY
14 class wxeditor_esettings_hotkeys : public settings_tab
16 public:
17 wxeditor_esettings_hotkeys(wxWindow* parent);
18 ~wxeditor_esettings_hotkeys();
19 void on_add(wxCommandEvent& e);
20 void on_drop(wxCommandEvent& e);
21 void on_change(wxCommandEvent& e);
22 void on_notify() { refresh(); }
23 void on_mouse(wxMouseEvent& e);
24 void on_popup_menu(wxCommandEvent& e);
25 private:
26 wxTreeCtrl* controls;
27 wxButton* pri_button;
28 wxButton* sec_button;
29 std::map<string_list<char>, wxTreeItemId> items;
30 std::map<string_list<char>, std::string> names;
31 std::map<string_list<char>, keyboard::invbind*> realitems;
32 void refresh();
33 string_list<char> get_selection();
34 wxTreeItemId get_item(const string_list<char>& i);
38 wxeditor_esettings_hotkeys::wxeditor_esettings_hotkeys(wxWindow* parent)
39 : settings_tab(parent)
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(500, 400));
47 controls->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED,
48 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_change), NULL, this);
49 controls->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxeditor_esettings_hotkeys::on_mouse), NULL,
50 this);
51 controls->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxeditor_esettings_hotkeys::on_mouse), NULL,
52 this);
54 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
55 pbutton_s->AddStretchSpacer();
56 pbutton_s->Add(pri_button = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW);
57 pri_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
58 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_add), NULL, this);
59 pri_button->Enable(false);
60 pbutton_s->Add(sec_button = new wxButton(this, wxID_ANY, wxT("Drop")), 0, wxGROW);
61 sec_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
62 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_drop), NULL, this);
63 sec_button->Enable(false);
64 top_s->Add(pbutton_s, 0, wxGROW);
66 items[string_list<char>()] = controls->AddRoot(wxT(""));
68 refresh();
69 top_s->SetSizeHints(this);
70 Fit();
73 wxTreeItemId wxeditor_esettings_hotkeys::get_item(const string_list<char>& i)
75 if(items.count(i) && items[i].IsOk())
76 return items[i];
77 return items[i] = controls->AppendItem(get_item(i.strip_one()), towxstring(i[i.size() - 1]));
80 string_list<char> wxeditor_esettings_hotkeys::get_selection()
82 if(closing())
83 return string_list<char>();
84 string_list<char> sel;
85 wxTreeItemId id = controls->GetSelection();
86 for(auto i : items)
87 if(i.second == id)
88 sel = i.first;
89 return sel;
92 void wxeditor_esettings_hotkeys::on_change(wxCommandEvent& e)
94 if(closing())
95 return;
96 string_list<char> sel = get_selection();
97 pri_button->Enable(realitems.count(sel));
98 sec_button->Enable(realitems.count(sel));
101 wxeditor_esettings_hotkeys::~wxeditor_esettings_hotkeys()
105 void wxeditor_esettings_hotkeys::on_add(wxCommandEvent& e)
107 if(closing())
108 return;
109 string_list<char> sel = get_selection();
110 std::string name = names.count(sel) ? names[sel] : "";
111 if(name == "") {
112 refresh();
113 return;
115 try {
116 keyboard::invbind* ik = realitems[sel];
117 if(!ik) {
118 refresh();
119 return;
121 key_entry_dialog* d = new key_entry_dialog(this, "Specify key for " + name, "", false);
122 if(d->ShowModal() == wxID_CANCEL) {
123 d->Destroy();
124 return;
126 std::string key = d->getkey();
127 d->Destroy();
128 if(key != "")
129 ik->append(key);
130 } catch(...) {
132 refresh();
135 void wxeditor_esettings_hotkeys::on_drop(wxCommandEvent& e)
137 if(closing())
138 return;
139 string_list<char> sel = get_selection();
140 std::string name = names.count(sel) ? names[sel] : "";
141 if(name == "") {
142 refresh();
143 return;
145 try {
146 keyboard::invbind* ik = realitems[sel];
147 if(!ik) {
148 refresh();
149 return;
151 std::vector<wxString> dropchoices;
152 keyboard::keyspec tmp;
153 unsigned idx = 0;
154 while((tmp = (std::string)ik->get(idx++)))
155 dropchoices.push_back(towxstring(clean_keystring(tmp)));
156 idx = 0;
157 if(dropchoices.size() > 1) {
158 wxSingleChoiceDialog* d2 = new wxSingleChoiceDialog(this,
159 towxstring("Select key to remove from set"), towxstring("Pick key to drop"),
160 dropchoices.size(), &dropchoices[0]);
161 if(d2->ShowModal() == wxID_CANCEL) {
162 d2->Destroy();
163 refresh();
164 return;
166 idx = d2->GetSelection();
167 d2->Destroy();
169 ik->clear(idx);
170 } catch(...) {
172 refresh();
175 void wxeditor_esettings_hotkeys::on_popup_menu(wxCommandEvent& e)
177 if(closing())
178 return;
179 if(e.GetId() == wxID_ADDKEY)
180 on_add(e);
181 else if(e.GetId() >= wxID_DROPKEY) {
182 string_list<char> sel = get_selection();
183 if(!realitems.count(sel))
184 return;
185 keyboard::invbind* ik = realitems[sel];
186 if(!ik)
187 return;
188 ik->clear(e.GetId() - wxID_DROPKEY);
190 refresh();
193 void wxeditor_esettings_hotkeys::on_mouse(wxMouseEvent& e)
195 if(!e.RightUp() && !(e.LeftUp() && e.ControlDown()))
196 return;
197 string_list<char> sel = get_selection();
198 if(!realitems.count(sel))
199 return;
200 keyboard::invbind* ik = realitems[sel];
201 if(!ik)
202 return;
204 wxMenu menu;
205 menu.Connect(wxEVT_COMMAND_MENU_SELECTED,
206 wxCommandEventHandler(wxeditor_esettings_hotkeys::on_popup_menu), NULL, this);
207 menu.Append(wxID_ADDKEY, towxstring("Add new key"));
208 bool first = true;
209 unsigned idx = 0;
210 keyboard::keyspec tmp;
211 while((tmp = ik->get(idx++))) {
212 if(first)
213 menu.AppendSeparator();
214 first = false;
215 menu.Append(wxID_DROPKEY + idx - 1, towxstring("Drop " + clean_keystring(tmp)));
217 PopupMenu(&menu);
220 void wxeditor_esettings_hotkeys::refresh()
222 if(closing())
223 return;
224 std::map<keyboard::invbind*, std::list<keyboard::keyspec>> data;
225 realitems.clear();
226 auto x = lsnes_mapper.get_inverses();
227 for(auto y : x) {
228 string_list<char> key = split_on_codepoint(y->getname(), U'\u2023');
229 names[key] = y->getname();
230 realitems[key] = y;
231 keyboard::keyspec tmp;
232 unsigned idx = 0;
233 while((tmp = y->get(idx++)))
234 data[y].push_back(tmp);
236 //Delete no longer present stuff.
237 for(auto i = items.rbegin(); i != items.rend(); i++) {
238 auto j = realitems.lower_bound(i->first);
239 if(j == realitems.end() || !i->first.prefix_of(j->first)) {
240 //Delete this item.
241 if(i->second.IsOk())
242 controls->Delete(i->second);
243 items[i->first] = wxTreeItemId();
246 //Update the rest.
247 for(auto i : realitems) {
248 string_list<char> key = i.first;
249 std::string text = key[key.size() - 1];
250 auto& I = data[i.second];
251 if(I.empty())
252 text = text + " (not set)";
253 else if(I.size() == 1)
254 text = text + " (" + clean_keystring(*I.begin()) + ")";
255 else {
256 text = text + " (";
257 for(auto i = I.begin(); i != I.end(); i++) {
258 if(i != I.begin())
259 text = text + ", ";
260 text = text + clean_keystring(*i);
262 text = text + ")";
264 wxTreeItemId id = get_item(key);
265 controls->SetItemText(id, towxstring(text));
269 settings_tab_factory hotkeys("Hotkeys", [](wxWindow* parent) -> settings_tab* {
270 return new wxeditor_esettings_hotkeys(parent);