Use helper class to simplify per-instance external vars
[lsnes.git] / src / platform / wxwidgets / settings-common.cpp
blob8c033e05470f9b03190b2050c867bcd483c0856c
1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "core/instance.hpp"
3 #include "core/instance-map.hpp"
4 #include "core/keymapper.hpp"
6 namespace
8 std::map<std::string, settings_tab_factory*>& _factories()
10 static std::map<std::string, settings_tab_factory*> x;
11 return x;
14 class wxeditor_esettings2;
15 instance_map<wxeditor_esettings2> sdialogs;
19 settings_tab_factory::settings_tab_factory(const std::string& tabname,
20 std::function<settings_tab*(wxWindow* parent, emulator_instance& inst)> create_fn)
21 : _tabname(tabname), _create_fn(create_fn)
23 _factories()[_tabname] = this;
26 settings_tab_factory::~settings_tab_factory()
28 _factories().erase(_tabname);
31 std::list<settings_tab_factory*> settings_tab_factory::factories()
33 std::list<settings_tab_factory*> f;
34 for(auto i : _factories())
35 f.push_back(i.second);
36 return f;
39 settings_menu::settings_menu(wxWindow* win, emulator_instance& _inst, int id)
40 : inst(_inst)
42 parent = win;
43 items[id] = NULL;
44 Append(id, towxstring("All as tabs..."));
45 win->Connect(id++, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(settings_menu::on_selected), NULL,
46 this);
47 AppendSeparator();
48 for(auto i : settings_tab_factory::factories()) {
49 items[id] = i;
50 Append(id, towxstring(i->get_name() + "..."));
51 win->Connect(id++, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(settings_menu::on_selected),
52 NULL, this);
56 void settings_menu::on_selected(wxCommandEvent& e)
58 int id = e.GetId();
59 if(!items.count(id))
60 return;
61 display_settings_dialog(parent, inst, items[id]);
64 namespace
66 volatile bool keygrab_active = false;
67 std::string pkey;
68 std::function<void(std::string key)> keygrab_callback;
70 class keygrabber : public keyboard::event_listener
72 public:
73 keygrabber()
75 keygrab_active = false;
77 void on_key_event(keyboard::modifier_set& mods, keyboard::key& key, keyboard::event& event)
79 if(!keygrab_active)
80 return;
81 uint32_t dev = event.get_change_mask();
82 auto subkeys = key.get_subkeys();
83 for(unsigned i = 0; i < 16 && i < subkeys.size(); i++) {
84 std::string pname = key.get_name() + subkeys[i];
85 if(((dev >> (2 * i)) & 3) == 3)
86 pkey = pname;
87 if(((dev >> (2 * i)) & 3) == 2) {
88 if(pkey == pname) {
89 keygrab_active = false;
90 std::string tmp = pkey;
91 runuifun([this, tmp]() { this->keygrab_callback(tmp); });
92 } else
93 pkey = "";
97 volatile bool keygrab_active;
98 std::string pkey;
99 std::function<void(std::string key)> keygrab_callback;
102 class wxeditor_esettings2 : public wxDialog
104 public:
105 wxeditor_esettings2(emulator_instance& _inst, wxWindow* parent, settings_tab_factory* singletab);
106 ~wxeditor_esettings2();
107 bool ShouldPreventAppExit() const;
108 void on_close(wxCommandEvent& e);
109 void on_notify();
110 private:
111 emulator_instance& inst;
112 wxNotebook* tabset;
113 wxButton* closebutton;
114 std::list<settings_tab*> tabs;
115 std::string get_title(settings_tab_factory* singletab);
116 public:
117 keygrabber keygrab;
120 std::string wxeditor_esettings2::get_title(settings_tab_factory* singletab)
122 if(!singletab)
123 return "lsnes: Configuration";
124 else
125 return "lsnes: Configuration: " + singletab->get_name();
128 wxeditor_esettings2::wxeditor_esettings2(emulator_instance& _inst, wxWindow* parent,
129 settings_tab_factory* singletab)
130 : wxDialog(parent, wxID_ANY, towxstring(get_title(singletab)), wxDefaultPosition, wxSize(-1, -1),
131 wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX | wxRESIZE_BORDER), inst(_inst)
133 //Grab keys to prevent the joystick driver from running who knows what commands.
134 inst.keyboard->set_exclusive(&keygrab);
136 Centre();
137 wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
138 SetSizer(top_s);
140 if(singletab) {
141 //If this throws, let it throw through.
142 settings_tab* t = singletab->create(this, inst);
143 top_s->Add(t, 1, wxGROW);
144 t->set_notify([this]() { this->on_notify(); });
145 tabs.push_back(t);
146 } else {
147 int created = 0;
148 tabset = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
149 for(auto i : settings_tab_factory::factories()) {
150 settings_tab* t;
151 try {
152 t = i->create(tabset, inst);
153 } catch(...) {
154 continue;
156 tabset->AddPage(t, towxstring(i->get_name()));
157 t->set_notify([this]() { this->on_notify(); });
158 tabs.push_back(t);
159 created++;
161 top_s->Add(tabset, 1, wxGROW);
162 if(!created)
163 throw std::runtime_error("Nothing to configure here, move along");
166 wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
167 pbutton_s->AddStretchSpacer();
168 pbutton_s->Add(closebutton = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
169 closebutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
170 wxCommandEventHandler(wxeditor_esettings2::on_close), NULL, this);
171 top_s->Add(pbutton_s, 0, wxGROW);
173 top_s->SetSizeHints(this);
174 Fit();
177 wxeditor_esettings2::~wxeditor_esettings2()
179 for(auto i : tabs)
180 i->notify_close();
181 inst.keyboard->set_exclusive(NULL);
182 sdialogs.remove(inst);
185 bool wxeditor_esettings2::ShouldPreventAppExit() const
187 return false;
190 void wxeditor_esettings2::on_close(wxCommandEvent& e)
192 for(auto i : tabs)
193 i->on_close();
194 EndModal(wxID_OK);
197 void wxeditor_esettings2::on_notify()
199 for(auto i : tabs)
200 i->on_notify();
204 void display_settings_dialog(wxWindow* parent, emulator_instance& inst, settings_tab_factory* singletab)
206 modal_pause_holder hld;
207 wxDialog* editor;
208 try {
209 try {
210 editor = sdialogs.create(inst, parent, singletab);
211 } catch(std::exception& e) {
212 std::string title = "Configure";
213 if(singletab)
214 title = "Configure " + singletab->get_name();
215 show_message_ok(parent, title, e.what(), wxICON_EXCLAMATION);
216 return;
218 editor->ShowModal();
219 } catch(...) {
220 return;
222 editor->Destroy();
223 do_save_configuration();
226 void settings_activate_keygrab(emulator_instance& inst, std::function<void(std::string key)> callback)
228 auto s = sdialogs.lookup(inst);
229 if(!s) return;
230 s->keygrab.keygrab_callback = callback;
231 s->keygrab.keygrab_active = true;
234 void settings_deactivate_keygrab(emulator_instance& inst)
236 auto s = sdialogs.lookup(inst);
237 if(!s) return;
238 s->keygrab.keygrab_active = false;