Use tree control instead of pair of listboxes in hotkeys&controls
This commit is contained in:
parent
408002eec1
commit
be852e63e1
6 changed files with 327 additions and 186 deletions
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -122,4 +123,32 @@ template<> inline std::string parse_value(const std::string& value) throw(std::b
|
|||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class string_list
|
||||
{
|
||||
public:
|
||||
string_list();
|
||||
string_list(const std::list<std::basic_string<T>>& list);
|
||||
bool empty();
|
||||
string_list strip_one() const;
|
||||
size_t size() const;
|
||||
const std::basic_string<T>& operator[](size_t idx) const;
|
||||
bool operator<(const string_list<T>& x) const;
|
||||
bool operator==(const string_list<T>& x) const;
|
||||
bool prefix_of(const string_list<T>& x) const;
|
||||
std::basic_string<T> debug_name() const;
|
||||
private:
|
||||
string_list(const std::basic_string<T>* array, size_t arrsize);
|
||||
std::vector<std::basic_string<T>> v;
|
||||
};
|
||||
|
||||
/**
|
||||
* Split a string into substrings on some unicode codepoint.
|
||||
*/
|
||||
string_list<char> split_on_codepoint(const std::string& s, char32_t cp);
|
||||
/**
|
||||
* Split a string into substrings on some unicode codepoint.
|
||||
*/
|
||||
string_list<char32_t> split_on_codepoint(const std::u32string& s, char32_t cp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -134,3 +134,162 @@ bool regex_match(const std::string& regexp, const std::string& str) throw(std::b
|
|||
{
|
||||
return regex(regexp, str);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename ch>
|
||||
std::list<std::basic_string<ch>> _split_on_codepoint(const std::basic_string<ch>& s,
|
||||
const std::basic_string<ch>& cp)
|
||||
{
|
||||
std::list<std::basic_string<ch>> 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<ch> 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<typename T>
|
||||
string_list<T>::string_list()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
string_list<T>::string_list(const std::list<std::basic_string<T>>& list)
|
||||
{
|
||||
v.resize(list.size());
|
||||
std::copy(list.begin(), list.end(), v.begin());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool string_list<T>::empty()
|
||||
{
|
||||
return (v.size() == 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
string_list<T> string_list<T>::strip_one() const
|
||||
{
|
||||
return string_list<T>(&v[0], (v.size() > 0) ? (v.size() - 1) : 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t string_list<T>::size() const
|
||||
{
|
||||
return v.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const std::basic_string<T>& string_list<T>::operator[](size_t idx) const
|
||||
{
|
||||
if(idx >= v.size())
|
||||
throw std::runtime_error("Index out of range");
|
||||
return v[idx];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
string_list<T>::string_list(const std::basic_string<T>* array, size_t arrsize)
|
||||
{
|
||||
v.resize(arrsize);
|
||||
std::copy(array, array + arrsize, v.begin());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool string_list<T>::operator<(const string_list<T>& 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<typename T>
|
||||
bool string_list<T>::operator==(const string_list<T>& 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<typename T>
|
||||
bool string_list<T>::prefix_of(const string_list<T>& 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<typename T> std::basic_string<T> separator();
|
||||
template<> std::basic_string<char> separator()
|
||||
{
|
||||
return to_u8string(U"\u2023");
|
||||
}
|
||||
|
||||
template<> std::basic_string<char16_t> separator()
|
||||
{
|
||||
return u"\u2023";
|
||||
}
|
||||
|
||||
template<> std::basic_string<char32_t> separator()
|
||||
{
|
||||
return U"\u2023";
|
||||
}
|
||||
|
||||
template<> std::basic_string<wchar_t> separator()
|
||||
{
|
||||
return L"->";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::basic_string<T> string_list<T>::debug_name() const
|
||||
{
|
||||
std::basic_stringstream<T> x;
|
||||
for(size_t i = 0; i < v.size(); i++)
|
||||
if(i != 0)
|
||||
x << separator<T>() << v[i];
|
||||
else
|
||||
x << v[i];
|
||||
return x.str();
|
||||
}
|
||||
|
||||
template class string_list<char>;
|
||||
template class string_list<wchar_t>;
|
||||
template class string_list<char16_t>;
|
||||
template class string_list<char32_t>;
|
||||
|
||||
|
||||
string_list<char> split_on_codepoint(const std::string& s, char32_t cp)
|
||||
{
|
||||
std::string _cp = to_u8string(std::u32string(1, cp));
|
||||
return _split_on_codepoint<char>(s, _cp);
|
||||
}
|
||||
|
||||
string_list<char32_t> split_on_codepoint(const std::u32string& s, char32_t cp)
|
||||
{
|
||||
std::u32string _cp(1, cp);
|
||||
return _split_on_codepoint<char32_t>(s, _cp);
|
||||
}
|
||||
|
|
|
@ -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<string_list<char>, wxTreeItemId> items;
|
||||
std::map<string_list<char>, std::string> names;
|
||||
std::map<string_list<char>, controller_key*> realitems;
|
||||
wxButton* set_button;
|
||||
wxButton* clear_button;
|
||||
std::map<int, std::string> categories;
|
||||
std::map<std::pair<int, int>, std::string> itemlabels;
|
||||
std::map<std::pair<int, int>, std::string> items;
|
||||
std::map<std::string, controller_key*> realitems;
|
||||
void change_category(int cat);
|
||||
void refresh();
|
||||
std::pair<std::string, std::string> splitkeyname(const std::string& kn);
|
||||
string_list<char> get_selection();
|
||||
wxTreeItemId get_item(const string_list<char>& 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<char>()] = controls->AddRoot(wxT(""));
|
||||
|
||||
refresh();
|
||||
top_s->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> wxeditor_esettings_controllers::splitkeyname(const std::string& kn)
|
||||
wxTreeItemId wxeditor_esettings_controllers::get_item(const string_list<char>& 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<char>()];
|
||||
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<char> wxeditor_esettings_controllers::get_selection()
|
||||
{
|
||||
if(closing())
|
||||
return string_list<char>();
|
||||
string_list<char> 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<int, std::string> 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<char> 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<char> 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<char> 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<controller_key*, std::string> data;
|
||||
std::map<std::string, int> cat_set;
|
||||
std::map<std::string, int> cat_assign;
|
||||
realitems.clear();
|
||||
auto x = lsnes_mapper.get_controller_keys();
|
||||
realitems.clear();
|
||||
for(auto y : x) {
|
||||
realitems[y->get_name()] = y;
|
||||
string_list<char> 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<std::string, std::string> 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<char> 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* {
|
||||
|
|
|
@ -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<int, std::string> categories;
|
||||
std::map<std::pair<int, int>, std::string> itemlabels;
|
||||
std::map<std::pair<int, int>, std::string> items;
|
||||
std::map<std::string, inverse_bind*> realitems;
|
||||
void change_category(int cat);
|
||||
std::map<string_list<char>, wxTreeItemId> items;
|
||||
std::map<string_list<char>, std::string> names;
|
||||
std::map<string_list<char>, inverse_bind*> realitems;
|
||||
void refresh();
|
||||
std::pair<std::string, std::string> splitkeyname(const std::string& kn);
|
||||
string_list<char> get_selection();
|
||||
wxTreeItemId get_item(const string_list<char>& 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<char>()] = controls->AddRoot(wxT(""));
|
||||
|
||||
refresh();
|
||||
top_s->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> wxeditor_esettings_hotkeys::splitkeyname(const std::string& kn)
|
||||
wxTreeItemId wxeditor_esettings_hotkeys::get_item(const string_list<char>& 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<char> wxeditor_esettings_hotkeys::get_selection()
|
||||
{
|
||||
if(closing())
|
||||
return string_list<char>();
|
||||
string_list<char> 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<int, std::string> 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<char> 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<char> 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<char> 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<inverse_bind*, std::list<key_specifier>> data;
|
||||
std::map<std::string, int> cat_set;
|
||||
std::map<std::string, int> cat_assign;
|
||||
realitems.clear();
|
||||
itemlabels.clear();
|
||||
auto x = lsnes_mapper.get_inverses();
|
||||
for(auto y : x) {
|
||||
realitems[y->getname()] = y;
|
||||
string_list<char> 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<std::string, std::string> 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<char> 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* {
|
||||
|
|
Loading…
Add table
Reference in a new issue