diff --git a/include/library/string.hpp b/include/library/string.hpp index a70decee..8249bdc4 100644 --- a/include/library/string.hpp +++ b/include/library/string.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -122,4 +123,32 @@ template<> inline std::string parse_value(const std::string& value) throw(std::b return value; } +template +class string_list +{ +public: + string_list(); + string_list(const std::list>& list); + bool empty(); + string_list strip_one() const; + size_t size() const; + const std::basic_string& operator[](size_t idx) const; + bool operator<(const string_list& x) const; + bool operator==(const string_list& x) const; + bool prefix_of(const string_list& x) const; + std::basic_string debug_name() const; +private: + string_list(const std::basic_string* array, size_t arrsize); + std::vector> v; +}; + +/** + * Split a string into substrings on some unicode codepoint. + */ +string_list split_on_codepoint(const std::string& s, char32_t cp); +/** + * Split a string into substrings on some unicode codepoint. + */ +string_list split_on_codepoint(const std::u32string& s, char32_t cp); + #endif diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 2c38135f..63c4f4cc 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -89,33 +89,33 @@ namespace controller_key* k; if(binding.mode == 0) { k = new controller_key(lsnes_mapper, (stringfmt() << "+controller " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" << binding.name).str()); promote_key(*k); k = new controller_key(lsnes_mapper, (stringfmt() << "hold-controller " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" - << binding.name << " (hold)").str()); + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" + << binding.name << "‣hold").str()); promote_key(*k); k = new controller_key(lsnes_mapper, (stringfmt() << "type-controller " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" - << binding.name << " (type)").str()); + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" + << binding.name << "‣type").str()); promote_key(*k); k = new controller_key(lsnes_mapper, (stringfmt() << "+autofire-controller " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" - << binding.name << " (autofire)").str()); + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" + << binding.name << "‣autofire").str()); promote_key(*k); k = new controller_key(lsnes_mapper, (stringfmt() << "autofire-controller " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" - << binding.name << " (autofire toggle)").str()); + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" + << binding.name << "‣autofire toggle").str()); promote_key(*k); } else if(binding.mode == 1) { k = new controller_key(lsnes_mapper, (stringfmt() << "designate-position " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" << binding.name).str()); promote_key(*k); } else if(binding.mode == 2) { k = new controller_key(lsnes_mapper, (stringfmt() << "controller-analog " << name).str(), - (stringfmt() << "Controller‣" << binding.cclass << "-" << binding.number << "‣" + (stringfmt() << "Controller‣" << binding.cclass << "‣#" << binding.number << "‣" << binding.name << " (axis)").str(), true); promote_key(*k); } diff --git a/src/emulation/test/ports.def b/src/emulation/test/ports.def index 74b01204..1dfdc4fb 100644 --- a/src/emulation/test/ports.def +++ b/src/emulation/test/ports.def @@ -14,7 +14,7 @@ ports = { },{ ["symbol"] = "ptype1", ["iname"] = "ptype1", ["hname"] = "ptype1", ["controllers"] = { { - ["name"] = "test1", ["class"] = "test1", ["buttons"] = { + ["name"] = "test1", ["class"] = "test", ["buttons"] = { {axis, "xlstick", -32768, 32767, true}, {axis, "ylstick", -32768, 32767, true}, {taxis, "ltrigger", 0, 255, false}, @@ -42,7 +42,7 @@ ports = { },{ ["symbol"] = "ptype2", ["iname"] = "ptype2", ["hname"] = "ptype2", ["controllers"] = { { - ["name"] = "test2", ["class"] = "test2", ["buttons"] = { + ["name"] = "test2", ["class"] = "test", ["buttons"] = { {axis, "xlstick", -32768, 32767, true}, {taxis, "ltrigger", 0, 255, false}, {axis, "ylstick", -32768, 32767, true}, diff --git a/src/library/string.cpp b/src/library/string.cpp index a362832c..706212f0 100644 --- a/src/library/string.cpp +++ b/src/library/string.cpp @@ -134,3 +134,162 @@ bool regex_match(const std::string& regexp, const std::string& str) throw(std::b { return regex(regexp, str); } + +namespace +{ + template + std::list> _split_on_codepoint(const std::basic_string& s, + const std::basic_string& cp) + { + std::list> ret; + size_t start = 0; + size_t end = 0; + size_t len = s.length(); + while(end < len) { + end = s.find(cp, start); + std::basic_string x; + if(end < len) { + x.resize(end - start); + std::copy(s.begin() + start, s.begin() + end, x.begin()); + start = end + cp.length(); + } else { + x.resize(len - start); + std::copy(s.begin() + start, s.end(), x.begin()); + } + ret.push_back(x); + } + return ret; + } +} + +template +string_list::string_list() +{ +} + +template +string_list::string_list(const std::list>& list) +{ + v.resize(list.size()); + std::copy(list.begin(), list.end(), v.begin()); +} + +template +bool string_list::empty() +{ + return (v.size() == 0); +} + +template +string_list string_list::strip_one() const +{ + return string_list(&v[0], (v.size() > 0) ? (v.size() - 1) : 0); +} + +template +size_t string_list::size() const +{ + return v.size(); +} + +template +const std::basic_string& string_list::operator[](size_t idx) const +{ + if(idx >= v.size()) + throw std::runtime_error("Index out of range"); + return v[idx]; +} + +template +string_list::string_list(const std::basic_string* array, size_t arrsize) +{ + v.resize(arrsize); + std::copy(array, array + arrsize, v.begin()); +} + +template +bool string_list::operator<(const string_list& x) const +{ + for(size_t i = 0; i < v.size() && i < x.v.size(); i++) + if(v[i] < x.v[i]) + return true; + else if(v[i] > x.v[i]) + return false; + return (v.size() < x.v.size()); +} + +template +bool string_list::operator==(const string_list& x) const +{ + if(v.size() != x.v.size()) + return false; + for(size_t i = 0; i < v.size(); i++) + if(v[i] != x.v[i]) + return false; + return true; +} + +template +bool string_list::prefix_of(const string_list& x) const +{ + if(v.size() > x.v.size()) + return false; + for(size_t i = 0; i < v.size(); i++) + if(v[i] != x.v[i]) + return false; + return true; +} + +namespace +{ + template std::basic_string separator(); + template<> std::basic_string separator() + { + return to_u8string(U"\u2023"); + } + + template<> std::basic_string separator() + { + return u"\u2023"; + } + + template<> std::basic_string separator() + { + return U"\u2023"; + } + + template<> std::basic_string separator() + { + return L"->"; + } +} + +template +std::basic_string string_list::debug_name() const +{ + std::basic_stringstream x; + for(size_t i = 0; i < v.size(); i++) + if(i != 0) + x << separator() << v[i]; + else + x << v[i]; + return x.str(); +} + +template class string_list; +template class string_list; +template class string_list; +template class string_list; + + +string_list split_on_codepoint(const std::string& s, char32_t cp) +{ + std::string _cp = to_u8string(std::u32string(1, cp)); + return _split_on_codepoint(s, _cp); +} + +string_list split_on_codepoint(const std::u32string& s, char32_t cp) +{ + std::u32string _cp(1, cp); + return _split_on_codepoint(s, _cp); +} diff --git a/src/platform/wxwidgets/settings-controllers.cpp b/src/platform/wxwidgets/settings-controllers.cpp index da562012..ea97bce5 100644 --- a/src/platform/wxwidgets/settings-controllers.cpp +++ b/src/platform/wxwidgets/settings-controllers.cpp @@ -1,6 +1,7 @@ #include "platform/wxwidgets/settings-common.hpp" #include "platform/wxwidgets/settings-keyentry.hpp" #include "core/keymapper.hpp" +#include "library/string.hpp" namespace { @@ -13,17 +14,15 @@ namespace void on_clearkey(wxCommandEvent& e); void on_change(wxCommandEvent& e); private: - wxListBox* category; - wxListBox* control; + wxTreeCtrl* controls; + std::map, wxTreeItemId> items; + std::map, std::string> names; + std::map, controller_key*> realitems; wxButton* set_button; wxButton* clear_button; - std::map categories; - std::map, std::string> itemlabels; - std::map, std::string> items; - std::map realitems; - void change_category(int cat); void refresh(); - std::pair splitkeyname(const std::string& kn); + string_list get_selection(); + wxTreeItemId get_item(const string_list& i); }; wxeditor_esettings_controllers::wxeditor_esettings_controllers(wxWindow* parent) @@ -33,76 +32,59 @@ namespace SetSizer(top_s); wxString empty[1]; - top_s->Add(category = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, empty), 1, - wxGROW); - top_s->Add(control = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, empty), 1, - wxGROW); - category->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, + top_s->Add(controls = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT), 1, wxGROW); + controls->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxCommandEventHandler(wxeditor_esettings_controllers::on_change), NULL, this); + controls->SetMinSize(wxSize(400, 300)); wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL); pbutton_s->AddStretchSpacer(); pbutton_s->Add(set_button = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW); set_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_esettings_controllers::on_setkey), NULL, this); + set_button->Enable(false); pbutton_s->Add(clear_button = new wxButton(this, wxID_ANY, wxT("Drop")), 0, wxGROW); clear_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_esettings_controllers::on_clearkey), NULL, this); + clear_button->Enable(false); top_s->Add(pbutton_s, 0, wxGROW); + items[string_list()] = controls->AddRoot(wxT("")); + refresh(); top_s->SetSizeHints(this); Fit(); } - std::pair wxeditor_esettings_controllers::splitkeyname(const std::string& kn) + wxTreeItemId wxeditor_esettings_controllers::get_item(const string_list& i) { - std::string tmp = kn; - size_t split = 0; - for(size_t itr = 0; itr < tmp.length() - 2 && itr < tmp.length(); itr++) { - unsigned char ch1 = tmp[itr]; - unsigned char ch2 = tmp[itr + 1]; - unsigned char ch3 = tmp[itr + 2]; - if(ch1 == 0xE2 && ch2 == 0x80 && ch3 == 0xA3) - split = itr; - } - if(split) - return std::make_pair(tmp.substr(0, split), tmp.substr(split + 3)); - else - return std::make_pair("(Uncategorized)", tmp); + if(i.size() == 1) + return items[string_list()]; + if(items.count(i) && items[i].IsOk()) + return items[i]; + return items[i] = controls->AppendItem(get_item(i.strip_one()), towxstring(i[i.size() - 1])); + } + + string_list wxeditor_esettings_controllers::get_selection() + { + if(closing()) + return string_list(); + string_list sel; + wxTreeItemId id = controls->GetSelection(); + for(auto i : items) + if(i.second == id) + sel = i.first; + return sel; } void wxeditor_esettings_controllers::on_change(wxCommandEvent& e) { if(closing()) return; - int c = category->GetSelection(); - if(c == wxNOT_FOUND) { - category->SetSelection(0); - change_category(0); - } else - change_category(c); - } - - void wxeditor_esettings_controllers::change_category(int cat) - { - if(closing()) - return; - std::map n; - for(auto i : itemlabels) - if(i.first.first == cat) - n[i.first.second] = i.second; - - for(size_t i = 0; i < control->GetCount(); i++) - if(n.count(i)) - control->SetString(i, towxstring(n[i])); - else - control->Delete(i--); - for(auto i : n) - if(i.first >= (int)control->GetCount()) - control->Append(towxstring(n[i.first])); - if(control->GetSelection() == wxNOT_FOUND && !control->IsEmpty()) - control->SetSelection(0); + string_list sel = get_selection(); + set_button->Enable(realitems.count(sel)); + clear_button->Enable(realitems.count(sel)); } wxeditor_esettings_controllers::~wxeditor_esettings_controllers() @@ -113,13 +95,14 @@ namespace { if(closing()) return; - std::string name = items[std::make_pair(category->GetSelection(), control->GetSelection())]; + string_list sel = get_selection(); + std::string name = names.count(sel) ? names[sel] : ""; if(name == "") { refresh(); return; } try { - controller_key* ik = realitems[name]; + controller_key* ik = realitems[sel]; if(!ik) { refresh(); return; @@ -130,7 +113,8 @@ namespace p->ShowModal(); std::string key = p->getkey(); p->Destroy(); - ik->append(key); + if(key != "") + ik->append(key); } catch(...) { } refresh(); @@ -140,13 +124,14 @@ namespace { if(closing()) return; - std::string name = items[std::make_pair(category->GetSelection(), control->GetSelection())]; + string_list sel = get_selection(); + std::string name = names.count(sel) ? names[sel] : ""; if(name == "") { refresh(); return; } try { - controller_key* ik = realitems[name]; + controller_key* ik = realitems[sel]; if(!ik) { refresh(); return; @@ -157,6 +142,10 @@ namespace while((tmp = ik->get_string(idx++)) != "") dropchoices.push_back(towxstring(tmp)); idx = 0; + if(dropchoices.size() == 0) { + refresh(); + return; + } if(dropchoices.size() > 1) { wxSingleChoiceDialog* d2 = new wxSingleChoiceDialog(this, towxstring("Select key to remove from set"), towxstring("Pick key to drop"), @@ -181,47 +170,41 @@ namespace if(closing()) return; std::map data; - std::map cat_set; - std::map cat_assign; - realitems.clear(); auto x = lsnes_mapper.get_controller_keys(); + realitems.clear(); for(auto y : x) { - realitems[y->get_name()] = y; + string_list key = split_on_codepoint(y->get_name(), U'\u2023'); + names[key] = y->get_name(); + realitems[key] = y; std::string tmp; unsigned idx = 0; while((tmp = y->get_string(idx++)) != "") data[y] += ((data[y] != "") ? ", " : "") + tmp; } - int cidx = 0; - for(auto i : realitems) { - std::pair j = splitkeyname(i.first); - if(!cat_set.count(j.first)) { - categories[cidx] = j.first; - cat_assign[j.first] = 0; - cat_set[j.first] = cidx++; + //Delete no longer present stuff. + for(auto i = items.rbegin(); i != items.rend(); i++) { + auto j = realitems.lower_bound(i->first); + if(j == realitems.end() || !i->first.prefix_of(j->first)) { + //Delete this item. + if(i->second.IsOk()) + controls->Delete(i->second); + items[i->first] = wxTreeItemId(); } - items[std::make_pair(cat_set[j.first], cat_assign[j.first])] = i.first; - std::string text = j.second; + } + for(auto i : realitems) { + string_list key = i.first; + std::string text = key[key.size() - 1]; if(data[i.second] == "") text = text + " (not set)"; else text = text + " (" + clean_keystring(data[i.second]) + ")"; - itemlabels[std::make_pair(cat_set[j.first], cat_assign[j.first])] = text; - cat_assign[j.first]++; + wxTreeItemId id = get_item(key); + controls->SetItemText(id, towxstring(text)); } - for(size_t i = 0; i < category->GetCount(); i++) - if(categories.count(i)) - category->SetString(i, towxstring(categories[i])); - else - category->Delete(i--); - for(auto i : categories) - if(i.first >= (int)category->GetCount()) - category->Append(towxstring(categories[i.first])); - if(category->GetSelection() == wxNOT_FOUND && !category->IsEmpty()) - category->SetSelection(0); - change_category(category->GetSelection()); + wxCommandEvent e; + on_change(e); } settings_tab_factory controllers("Controllers", [](wxWindow* parent) -> settings_tab* { diff --git a/src/platform/wxwidgets/settings-hotkeys.cpp b/src/platform/wxwidgets/settings-hotkeys.cpp index 3cf4d1e0..2165eb82 100644 --- a/src/platform/wxwidgets/settings-hotkeys.cpp +++ b/src/platform/wxwidgets/settings-hotkeys.cpp @@ -15,17 +15,15 @@ namespace void on_change(wxCommandEvent& e); void on_notify() { refresh(); } private: - wxListBox* category; - wxListBox* control; + wxTreeCtrl* controls; wxButton* pri_button; wxButton* sec_button; - std::map categories; - std::map, std::string> itemlabels; - std::map, std::string> items; - std::map realitems; - void change_category(int cat); + std::map, wxTreeItemId> items; + std::map, std::string> names; + std::map, inverse_bind*> realitems; void refresh(); - std::pair splitkeyname(const std::string& kn); + string_list get_selection(); + wxTreeItemId get_item(const string_list& i); }; @@ -34,13 +32,10 @@ namespace { wxSizer* top_s = new wxBoxSizer(wxVERTICAL); SetSizer(top_s); - wxString empty[1]; - top_s->Add(category = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, empty), 1, - wxGROW); - top_s->Add(control = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, empty), 1, - wxGROW); - category->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, + top_s->Add(controls = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT), 1, wxGROW); + controls->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxCommandEventHandler(wxeditor_esettings_hotkeys::on_change), NULL, this); wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL); @@ -48,64 +43,46 @@ namespace pbutton_s->Add(pri_button = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW); pri_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_esettings_hotkeys::on_add), NULL, this); + pri_button->Enable(false); pbutton_s->Add(sec_button = new wxButton(this, wxID_ANY, wxT("Drop")), 0, wxGROW); sec_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_esettings_hotkeys::on_drop), NULL, this); + sec_button->Enable(false); top_s->Add(pbutton_s, 0, wxGROW); + items[string_list()] = controls->AddRoot(wxT("")); + refresh(); top_s->SetSizeHints(this); Fit(); } - std::pair wxeditor_esettings_hotkeys::splitkeyname(const std::string& kn) + wxTreeItemId wxeditor_esettings_hotkeys::get_item(const string_list& i) { - std::string tmp = kn; - size_t split = 0; - for(size_t itr = 0; itr < tmp.length() - 2 && itr < tmp.length(); itr++) { - unsigned char ch1 = tmp[itr]; - unsigned char ch2 = tmp[itr + 1]; - unsigned char ch3 = tmp[itr + 2]; - if(ch1 == 0xE2 && ch2 == 0x80 && ch3 == 0xA3) - split = itr; - } - if(split) - return std::make_pair(tmp.substr(0, split), tmp.substr(split + 3)); - else - return std::make_pair("(Uncategorized)", tmp); + if(items.count(i) && items[i].IsOk()) + return items[i]; + return items[i] = controls->AppendItem(get_item(i.strip_one()), towxstring(i[i.size() - 1])); + } + + string_list wxeditor_esettings_hotkeys::get_selection() + { + if(closing()) + return string_list(); + string_list sel; + wxTreeItemId id = controls->GetSelection(); + for(auto i : items) + if(i.second == id) + sel = i.first; + return sel; } void wxeditor_esettings_hotkeys::on_change(wxCommandEvent& e) { if(closing()) return; - int c = category->GetSelection(); - if(c == wxNOT_FOUND) { - category->SetSelection(0); - change_category(0); - } else - change_category(c); - } - - void wxeditor_esettings_hotkeys::change_category(int cat) - { - if(closing()) - return; - std::map n; - for(auto i : itemlabels) - if(i.first.first == cat) - n[i.first.second] = i.second; - - for(size_t i = 0; i < control->GetCount(); i++) - if(n.count(i)) - control->SetString(i, towxstring(n[i])); - else - control->Delete(i--); - for(auto i : n) - if(i.first >= (int)control->GetCount()) - control->Append(towxstring(n[i.first])); - if(control->GetSelection() == wxNOT_FOUND) - control->SetSelection(0); + string_list sel = get_selection(); + pri_button->Enable(realitems.count(sel)); + sec_button->Enable(realitems.count(sel)); } wxeditor_esettings_hotkeys::~wxeditor_esettings_hotkeys() @@ -116,13 +93,14 @@ namespace { if(closing()) return; - std::string name = items[std::make_pair(category->GetSelection(), control->GetSelection())]; + string_list sel = get_selection(); + std::string name = names.count(sel) ? names[sel] : ""; if(name == "") { refresh(); return; } try { - inverse_bind* ik = realitems[name]; + inverse_bind* ik = realitems[sel]; if(!ik) { refresh(); return; @@ -134,7 +112,8 @@ namespace } std::string key = d->getkey(); d->Destroy(); - ik->append(key); + if(key != "") + ik->append(key); } catch(...) { } refresh(); @@ -144,13 +123,14 @@ namespace { if(closing()) return; - std::string name = items[std::make_pair(category->GetSelection(), control->GetSelection())]; + string_list sel = get_selection(); + std::string name = names.count(sel) ? names[sel] : ""; if(name == "") { refresh(); return; } try { - inverse_bind* ik = realitems[name]; + inverse_bind* ik = realitems[sel]; if(!ik) { refresh(); return; @@ -184,29 +164,31 @@ namespace if(closing()) return; std::map> data; - std::map cat_set; - std::map cat_assign; realitems.clear(); - itemlabels.clear(); auto x = lsnes_mapper.get_inverses(); for(auto y : x) { - realitems[y->getname()] = y; + string_list key = split_on_codepoint(y->getname(), U'\u2023'); + names[key] = y->getname(); + realitems[key] = y; key_specifier tmp; unsigned idx = 0; while((tmp = y->get(idx++))) data[y].push_back(tmp); } - - int cidx = 0; - for(auto i : realitems) { - std::pair j = splitkeyname(i.first); - if(!cat_set.count(j.first)) { - categories[cidx] = j.first; - cat_assign[j.first] = 0; - cat_set[j.first] = cidx++; + //Delete no longer present stuff. + for(auto i = items.rbegin(); i != items.rend(); i++) { + auto j = realitems.lower_bound(i->first); + if(j == realitems.end() || !i->first.prefix_of(j->first)) { + //Delete this item. + if(i->second.IsOk()) + controls->Delete(i->second); + items[i->first] = wxTreeItemId(); } - items[std::make_pair(cat_set[j.first], cat_assign[j.first])] = i.first; - std::string text = j.second; + } + //Update the rest. + for(auto i : realitems) { + string_list key = i.first; + std::string text = key[key.size() - 1]; auto& I = data[i.second]; if(I.empty()) text = text + " (not set)"; @@ -221,21 +203,9 @@ namespace } text = text + ")"; } - itemlabels[std::make_pair(cat_set[j.first], cat_assign[j.first])] = text; - cat_assign[j.first]++; + wxTreeItemId id = get_item(key); + controls->SetItemText(id, towxstring(text)); } - - for(size_t i = 0; i < category->GetCount(); i++) - if(categories.count(i)) - category->SetString(i, towxstring(categories[i])); - else - category->Delete(i--); - for(auto i : categories) - if(i.first >= (int)category->GetCount()) - category->Append(towxstring(categories[i.first])); - if(category->GetSelection() == wxNOT_FOUND) - category->SetSelection(0); - change_category(category->GetSelection()); } settings_tab_factory hotkeys("Hotkeys", [](wxWindow* parent) -> settings_tab* {