Merge branch 'rr1-maint'

Conflicts:
	src/platform/wxwidgets/mainwindow.cpp
This commit is contained in:
Ilari Liusvaara 2012-02-20 21:19:53 +02:00
commit 7d19748ed2
8 changed files with 690 additions and 193 deletions

View file

@ -396,4 +396,73 @@ public:
std::runtime_error);
};
class inverse_key
{
public:
/**
* Create inverse key.
*
* Parameter command: Command this is for.
* Parameter name: Name of inverse key.
*/
inverse_key(const std::string& command, const std::string& name) throw(std::bad_alloc);
/**
* Destructor.
*/
~inverse_key();
/**
* Get set of inverse keys.
*
* Returns: The set of all inverses.
*/
static std::set<inverse_key*> get_ikeys() throw(std::bad_alloc);
/**
* Find by command.
*
* Parameter command: The command.
* Returns: The instance.
*/
static inverse_key* get_for(const std::string& command) throw(std::bad_alloc);
/**
* Get keyspec.
*
* Parameter primary: If true, get the primary key, else secondary key.
* Returns: The keyspec.
*/
std::string get(bool primary) throw(std::bad_alloc);
/**
* Clear key (if primary is cleared, secondary becomes primary).
*
* Parameter primary: If true, clear the primary, else the secondary.
*/
void clear(bool primary) throw(std::bad_alloc);
/**
* Set key.
*
* Parameter keyspec: The new keyspec.
* Parameter primary: If true, set the primary, else the secondary.
*/
void set(std::string keyspec, bool primary) throw(std::bad_alloc);
/**
* Notify updated mapping.
*/
static void notify_update(const std::string& keyspec, const std::string& command);
/**
* Get name for command.
*
* Returns: The name.
*/
std::string getname() throw(std::bad_alloc);
private:
inverse_key(const inverse_key&);
inverse_key& operator=(const inverse_key&);
static std::set<inverse_key*>& ikeys();
static std::map<std::string, inverse_key*>& forkey();
void addkey(const std::string& keyspec);
std::string cmd;
std::string oname;
std::string primary_spec;
std::string secondary_spec;
};
#endif

View file

@ -30,6 +30,8 @@ void _runuifun_async(void (*fn)(void*), void* arg);
void wxeditor_axes_display(wxWindow* parent);
void wxeditor_authors_display(wxWindow* parent);
void wxeditor_settings_display(wxWindow* parent);
void wxeditor_hotkeys_display(wxWindow* parent);
std::string wxeditor_keyselect(wxWindow* parent, bool clearable);
//Auxillary windows.
void wxwindow_memorysearch_display();

View file

@ -191,7 +191,7 @@ namespace
for(size_t i = 0; i < MAX_LOGICAL_BUTTONS; ++i)
for(int j = 0; j < 3; ++j)
for(unsigned k = 0; k < 8; ++k) {
std::string x, y;
std::string x, y, expx;
char cstr[2] = {0, 0};
cstr[0] = 49 + k;
switch(j) {
@ -207,21 +207,32 @@ namespace
};
x = x + cstr + get_logical_button_name(i);
y = cstr + get_logical_button_name(i);
expx = std::string("Controller X ") + get_logical_button_name(i);
expx[11] = 49 + k;
our_commands.insert(new button_action(x, j, k, y));
if(j == 0)
our_icommands.insert(new inverse_key(x, expx));
}
for(unsigned k = 0; k < 8; ++k) {
std::string x = "controllerXanalog";
std::string expx = "Controller X analog function";
x[10] = 49 + k;
expx[11] = 49 + k;
our_commands.insert(new analog_action(x, k));
our_icommands.insert(new inverse_key(x, expx));
}
}
~button_action_helper()
{
for(auto i : our_commands)
delete i;
for(auto i : our_icommands)
delete i;
our_commands.clear();
our_icommands.clear();
}
std::set<command*> our_commands;
std::set<inverse_key*> our_icommands;
} bah;
}

View file

@ -72,6 +72,13 @@ namespace
[]() throw(std::bad_alloc, std::runtime_error) {
keymapper::dumpbindings();
});
function_ptr_command<> show_inverse("show-inverse", "Show inverse bindings",
"Syntax: show-inverse\nShow inversebindings that are currently active.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
for(auto i : inverse_key::get_ikeys())
messages << i->getname() << ":" << i->get(true) << ":" << i->get(false) << std::endl;
});
}
std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc)
@ -774,7 +781,11 @@ namespace
return k;
}
std::map<triple, keybind_data*> keybindings;
std::map<triple, keybind_data*>& keybindings()
{
static std::map<triple, keybind_data*> x;
return x;
}
}
void keymapper::bind(std::string mod, std::string modmask, std::string keyname, std::string command)
@ -786,28 +797,30 @@ void keymapper::bind(std::string mod, std::string modmask, std::string keyname,
if(!modifier_set::valid(_mod, _modmask))
throw std::runtime_error("Invalid modifiers");
auto g = keygroup::lookup(keyname);
if(!keybindings.count(k)) {
keybindings[k] = new keybind_data;
keybindings[k]->mod = _mod;
keybindings[k]->modmask = _modmask;
keybindings[k]->group = g.first;
keybindings[k]->subkey = g.second;
if(!keybindings().count(k)) {
keybindings()[k] = new keybind_data;
keybindings()[k]->mod = _mod;
keybindings()[k]->modmask = _modmask;
keybindings()[k]->group = g.first;
keybindings()[k]->subkey = g.second;
}
keybindings[k]->command = command;
keybindings()[k]->command = command;
inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, command);
}
void keymapper::unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error)
{
triple k(mod, modmask, keyname);
if(!keybindings.count(k))
if(!keybindings().count(k))
throw std::runtime_error("Key is not bound");
delete keybindings[k];
keybindings.erase(k);
delete keybindings()[k];
keybindings().erase(k);
inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, "");
}
void keymapper::dumpbindings() throw(std::bad_alloc)
{
for(auto i : keybindings) {
for(auto i : keybindings()) {
messages << "bind-key ";
if(i.first.a != "" || i.first.b != "")
messages << i.first.a << "/" << i.first.b << " ";
@ -818,7 +831,7 @@ void keymapper::dumpbindings() throw(std::bad_alloc)
std::set<std::string> keymapper::get_bindings() throw(std::bad_alloc)
{
std::set<std::string> r;
for(auto i : keybindings)
for(auto i : keybindings())
r.insert(i.first.a + "/" + i.first.b + "|" + i.first.c);
return r;
}
@ -831,9 +844,9 @@ std::string keymapper::get_command_for(const std::string& keyspec) throw(std::ba
} catch(std::exception& e) {
return "";
}
if(!keybindings.count(k))
if(!keybindings().count(k))
return "";
return keybindings[k]->command;
return keybindings()[k]->command;
}
void keymapper::bind_for(const std::string& keyspec, const std::string& cmd) throw(std::bad_alloc, std::runtime_error)
@ -845,3 +858,123 @@ void keymapper::bind_for(const std::string& keyspec, const std::string& cmd) thr
else
unbind(k.a, k.b, k.c);
}
inverse_key::inverse_key(const std::string& command, const std::string& name) throw(std::bad_alloc)
{
cmd = command;
oname = name;
ikeys().insert(this);
forkey()[cmd] = this;
//Search the keybindings for matches.
auto b = keymapper::get_bindings();
for(auto c : b)
if(keymapper::get_command_for(c) == cmd)
addkey(c);
}
inverse_key::~inverse_key()
{
ikeys().erase(this);
forkey().erase(cmd);
}
std::set<inverse_key*> inverse_key::get_ikeys() throw(std::bad_alloc)
{
return ikeys();
}
std::string inverse_key::getname() throw(std::bad_alloc)
{
return oname;
}
inverse_key* inverse_key::get_for(const std::string& command) throw(std::bad_alloc)
{
return forkey().count(command) ? forkey()[command] : NULL;
}
std::set<inverse_key*>& inverse_key::ikeys()
{
static std::set<inverse_key*> x;
return x;
}
std::map<std::string, inverse_key*>& inverse_key::forkey()
{
static std::map<std::string, inverse_key*> x;
return x;
}
std::string inverse_key::get(bool primary) throw(std::bad_alloc)
{
return primary ? primary_spec : secondary_spec;
}
void inverse_key::clear(bool primary) throw(std::bad_alloc)
{
if(primary) {
keymapper::bind_for(primary_spec, "");
primary_spec = secondary_spec;
secondary_spec = "";
} else {
keymapper::bind_for(secondary_spec, "");
secondary_spec = "";
}
//Search the keybindings for matches.
auto b = keymapper::get_bindings();
for(auto c : b)
if(keymapper::get_command_for(c) == cmd)
addkey(c);
}
void inverse_key::set(std::string keyspec, bool primary) throw(std::bad_alloc)
{
if(keyspec == "") {
clear(primary);
return;
}
if(!primary && (primary_spec == "" || primary_spec == keyspec))
primary = true;
if(primary) {
if(primary_spec != "")
keymapper::bind_for(primary_spec, "");
primary_spec = keyspec;
keymapper::bind_for(primary_spec, cmd);
} else {
if(secondary_spec != "")
keymapper::bind_for(secondary_spec, "");
secondary_spec = keyspec;
keymapper::bind_for(secondary_spec, cmd);
}
}
void inverse_key::addkey(const std::string& keyspec)
{
if(primary_spec == "" || primary_spec == keyspec)
primary_spec = keyspec;
else if(secondary_spec == "")
secondary_spec = keyspec;
}
void inverse_key::notify_update(const std::string& keyspec, const std::string& command)
{
for(auto k : ikeys()) {
bool u = false;
if(k->primary_spec == keyspec || k->secondary_spec == keyspec) {
if(command == "" || command != k->cmd) {
//Unbound.
k->primary_spec = "";
k->secondary_spec = "";
u = true;
}
} else if(command == k->cmd)
k->addkey(keyspec);
if(u) {
auto b = keymapper::get_bindings();
for(auto c : b)
if(keymapper::get_command_for(c) == k->cmd)
k->addkey(c);
}
}
}

View file

@ -430,7 +430,7 @@ namespace
});
function_ptr_command<> save_jukebox_prev("cycle-jukebox-backward", "Cycle save jukebox backwards",
"Syntax: cycle-jukebox-backwards\nCycle save jukebox backwards\n",
"Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
[]() throw(std::bad_alloc, std::runtime_error) {
if(save_jukebox_pointer == 0)
save_jukebox_pointer = save_jukebox.size() - 1;
@ -443,7 +443,7 @@ namespace
});
function_ptr_command<> save_jukebox_next("cycle-jukebox-forward", "Cycle save jukebox forwards",
"Syntax: cycle-jukebox-forwards\nCycle save jukebox forwards\n",
"Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
[]() throw(std::bad_alloc, std::runtime_error) {
if(save_jukebox_pointer == save_jukebox.size() - 1)
save_jukebox_pointer = 0;
@ -645,6 +645,87 @@ namespace
});
inverse_key ipause_emulator("pause-emulator", "(Un)pause");
inverse_key ijback("cycle-jukebox-backward", "Cycle slot backwards");
inverse_key ijforward("cycle-jukebox-forward", "Cycle slot forwards");
inverse_key iloadj("load-jukebox", "load selected slot");
inverse_key isavej("save-jukebox", "Save selected slot");
inverse_key iadvframe("+advance-frame", "Advance frame");
inverse_key iadvsubframe("+advance-poll", "Advance subframe");
inverse_key iskiplag("advance-skiplag", "Advance to next poll");
inverse_key ireset("reset", "System reset");
inverse_key iset_rwmode("set-rwmode", "Switch to read/write");
inverse_key itoggle_romode("set-romode", "Switch to read-only");
inverse_key itoggle_rwmode("toggle-rwmode", "Toggle read-only");
inverse_key irepaint("repaint", "Repaint screen");
inverse_key itogglepause("toggle-pause-on-end", "Toggle pause-on-end");
inverse_key irewind_movie("rewind-movie", "Rewind movie");
inverse_key icancel_saves("cancel-saves", "Cancel pending saves");
inverse_key iload1("load ${project}1.lsmv", "Load slot 1");
inverse_key iload2("load ${project}2.lsmv", "Load slot 2");
inverse_key iload3("load ${project}3.lsmv", "Load slot 3");
inverse_key iload4("load ${project}4.lsmv", "Load slot 4");
inverse_key iload5("load ${project}5.lsmv", "Load slot 5");
inverse_key iload6("load ${project}6.lsmv", "Load slot 6");
inverse_key iload7("load ${project}7.lsmv", "Load slot 7");
inverse_key iload8("load ${project}8.lsmv", "Load slot 8");
inverse_key iload9("load ${project}9.lsmv", "Load slot 9");
inverse_key iload10("load ${project}10.lsmv", "Load slot 10");
inverse_key iload11("load ${project}11.lsmv", "Load slot 11");
inverse_key iload12("load ${project}12.lsmv", "Load slot 12");
inverse_key iload13("load ${project}13.lsmv", "Load slot 13");
inverse_key iload14("load ${project}14.lsmv", "Load slot 14");
inverse_key iload15("load ${project}15.lsmv", "Load slot 15");
inverse_key iload16("load ${project}16.lsmv", "Load slot 16");
inverse_key iload17("load ${project}17.lsmv", "Load slot 17");
inverse_key iload18("load ${project}18.lsmv", "Load slot 18");
inverse_key iload19("load ${project}19.lsmv", "Load slot 19");
inverse_key iload20("load ${project}20.lsmv", "Load slot 20");
inverse_key iload21("load ${project}21.lsmv", "Load slot 21");
inverse_key iload22("load ${project}22.lsmv", "Load slot 22");
inverse_key iload23("load ${project}23.lsmv", "Load slot 23");
inverse_key iload24("load ${project}24.lsmv", "Load slot 24");
inverse_key iload25("load ${project}25.lsmv", "Load slot 25");
inverse_key iload26("load ${project}26.lsmv", "Load slot 26");
inverse_key iload27("load ${project}27.lsmv", "Load slot 27");
inverse_key iload28("load ${project}28.lsmv", "Load slot 28");
inverse_key iload29("load ${project}29.lsmv", "Load slot 29");
inverse_key iload30("load ${project}30.lsmv", "Load slot 30");
inverse_key iload31("load ${project}31.lsmv", "Load slot 31");
inverse_key iload32("load ${project}32.lsmv", "Load slot 32");
inverse_key isave1("save-state ${project}1.lsmv", "Save slot 1");
inverse_key isave2("save-state ${project}2.lsmv", "Save slot 2");
inverse_key isave3("save-state ${project}3.lsmv", "Save slot 3");
inverse_key isave4("save-state ${project}4.lsmv", "Save slot 4");
inverse_key isave5("save-state ${project}5.lsmv", "Save slot 5");
inverse_key isave6("save-state ${project}6.lsmv", "Save slot 6");
inverse_key isave7("save-state ${project}7.lsmv", "Save slot 7");
inverse_key isave8("save-state ${project}8.lsmv", "Save slot 8");
inverse_key isave9("save-state ${project}9.lsmv", "Save slot 9");
inverse_key isave10("save-state ${project}10.lsmv", "Save slot 10");
inverse_key isave11("save-state ${project}11.lsmv", "Save slot 11");
inverse_key isave12("save-state ${project}12.lsmv", "Save slot 12");
inverse_key isave13("save-state ${project}13.lsmv", "Save slot 13");
inverse_key isave14("save-state ${project}14.lsmv", "Save slot 14");
inverse_key isave15("save-state ${project}15.lsmv", "Save slot 15");
inverse_key isave16("save-state ${project}16.lsmv", "Save slot 16");
inverse_key isave17("save-state ${project}17.lsmv", "Save slot 17");
inverse_key isave18("save-state ${project}18.lsmv", "Save slot 18");
inverse_key isave19("save-state ${project}19.lsmv", "Save slot 19");
inverse_key isave20("save-state ${project}20.lsmv", "Save slot 20");
inverse_key isave21("save-state ${project}21.lsmv", "Save slot 21");
inverse_key isave22("save-state ${project}22.lsmv", "Save slot 22");
inverse_key isave23("save-state ${project}23.lsmv", "Save slot 23");
inverse_key isave24("save-state ${project}24.lsmv", "Save slot 24");
inverse_key isave25("save-state ${project}25.lsmv", "Save slot 25");
inverse_key isave26("save-state ${project}26.lsmv", "Save slot 26");
inverse_key isave27("save-state ${project}27.lsmv", "Save slot 27");
inverse_key isave28("save-state ${project}28.lsmv", "Save slot 28");
inverse_key isave29("save-state ${project}29.lsmv", "Save slot 29");
inverse_key isave30("save-state ${project}30.lsmv", "Save slot 30");
inverse_key isave31("save-state ${project}31.lsmv", "Save slot 31");
inverse_key isave32("save-state ${project}32.lsmv", "Save slot 32");
bool on_quit_prompt = false;
class mywindowcallbacks : public information_dispatch
{

View file

@ -140,6 +140,9 @@ namespace
throw std::runtime_error("Bad sound setting");
});
inverse_key ienable_sound("enable-sound on", "Enable sound");
inverse_key idisable_sound("enable-sound off", "Disable sound");
function_ptr_command<const std::string&> set_sound_device("set-sound-device", "Set sound device",
"Syntax: set-sound-device <id>\nSet sound device to <id>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {

View file

@ -0,0 +1,365 @@
#include "platform/wxwidgets/platform.hpp"
#include "core/keymapper.hpp"
#include <wx/wx.h>
namespace
{
struct keyentry_mod_data
{
wxCheckBox* pressed;
wxCheckBox* unmasked;
unsigned tmpflags;
};
class wxdialog_keyentry : public wxDialog
{
public:
wxdialog_keyentry(wxWindow* parent, const std::string& title, bool clearable);
void on_change_setting(wxCommandEvent& e);
void on_ok(wxCommandEvent& e);
void on_cancel(wxCommandEvent& e);
void on_clear(wxCommandEvent& e);
std::string getkey();
private:
std::map<std::string, keyentry_mod_data> modifiers;
wxComboBox* mainkey;
wxButton* ok;
wxButton* cancel;
wxButton* clear;
bool cleared;
};
class wxdialog_hotkeys;
class hotkey
{
public:
hotkey(wxdialog_hotkeys* h, wxWindow* win, wxSizer* s, inverse_key* ikey, unsigned o);
void update(const std::string& primary, const std::string& secondary);
inverse_key* get_associated();
std::string get_title();
private:
wxButton* primaryb;
wxButton* secondaryb;
inverse_key* associated;
std::string title;
};
class wxdialog_hotkeys : public wxDialog
{
public:
wxdialog_hotkeys(wxWindow* parent);
~wxdialog_hotkeys();
void on_close(wxCommandEvent& e);
void on_reconfig(wxCommandEvent& e);
private:
void update();
wxScrolledWindow* scroll;
wxSizer* scroll_sizer;
std::map<unsigned, hotkey*> hotkeys;
wxButton* close;
};
wxdialog_keyentry::wxdialog_keyentry(wxWindow* parent, const std::string& title, bool clearable)
: wxDialog(parent, wxID_ANY, towxstring(title), wxDefaultPosition, wxSize(-1, -1))
{
std::vector<wxString> keych;
std::set<std::string> mods, keys;
cleared = false;
runemufn([&mods, &keys]() { mods = modifier::get_set(); keys = keygroup::get_keys(); });
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s);
wxFlexGridSizer* t_s = new wxFlexGridSizer(mods.size() + 1, 3, 0, 0);
for(auto i : mods) {
t_s->Add(new wxStaticText(this, wxID_ANY, towxstring(i)), 0, wxGROW);
keyentry_mod_data m;
t_s->Add(m.pressed = new wxCheckBox(this, wxID_ANY, wxT("Pressed")), 0, wxGROW);
t_s->Add(m.unmasked = new wxCheckBox(this, wxID_ANY, wxT("Unmasked")), 0, wxGROW);
m.pressed->Disable();
modifiers[i] = m;
m.pressed->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
m.unmasked->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
}
for(auto i : keys)
keych.push_back(towxstring(i));
t_s->Add(new wxStaticText(this, wxID_ANY, wxT("Key")), 0, wxGROW);
t_s->Add(mainkey = new wxComboBox(this, wxID_ANY, keych[0], wxDefaultPosition, wxDefaultSize,
keych.size(), &keych[0], wxCB_READONLY), 1, wxGROW);
mainkey->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
top_s->Add(t_s);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
if(clearable)
pbutton_s->Add(clear = new wxButton(this, wxID_OK, wxT("Clear")), 0, wxGROW);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
pbutton_s->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_ok), NULL, this);
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_cancel), NULL, this);
if(clearable)
clear->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_clear), NULL, this);
top_s->Add(pbutton_s, 0, wxGROW);
t_s->SetSizeHints(this);
top_s->SetSizeHints(this);
Fit();
}
#define TMPFLAG_UNMASKED 65
#define TMPFLAG_UNMASKED_LINK_CHILD 2
#define TMPFLAG_UNMASKED_LINK_PARENT 68
#define TMPFLAG_PRESSED 8
#define TMPFLAG_PRESSED_LINK_CHILD 16
#define TMPFLAG_PRESSED_LINK_PARENT 32
void wxdialog_keyentry::on_change_setting(wxCommandEvent& e)
{
for(auto& i : modifiers)
i.second.tmpflags = 0;
for(auto& i : modifiers) {
modifier* m = NULL;
try {
m = &modifier::lookup(i.first);
} catch(...) {
i.second.pressed->Disable();
i.second.unmasked->Disable();
continue;
}
std::string j = m->linked_name();
if(i.second.unmasked->GetValue())
i.second.tmpflags |= TMPFLAG_UNMASKED;
if(j != "") {
if(modifiers[j].unmasked->GetValue())
i.second.tmpflags |= TMPFLAG_UNMASKED_LINK_PARENT;
if(i.second.unmasked->GetValue())
modifiers[j].tmpflags |= TMPFLAG_UNMASKED_LINK_CHILD;
}
if(i.second.pressed->GetValue())
i.second.tmpflags |= TMPFLAG_PRESSED;
if(j != "") {
if(modifiers[j].pressed->GetValue())
i.second.tmpflags |= TMPFLAG_PRESSED_LINK_PARENT;
if(i.second.pressed->GetValue())
modifiers[j].tmpflags |= TMPFLAG_PRESSED_LINK_CHILD;
}
}
for(auto& i : modifiers) {
//Unmasked is to be enabled if neither unmasked link flag is set.
if(i.second.tmpflags & ((TMPFLAG_UNMASKED_LINK_CHILD | TMPFLAG_UNMASKED_LINK_PARENT) & ~64)) {
i.second.unmasked->SetValue(false);
i.second.unmasked->Disable();
} else
i.second.unmasked->Enable();
//Pressed is to be enabled if:
//- This modifier is unmasked or parent is unmasked.
//- Parent nor child is not pressed.
if(((i.second.tmpflags & (TMPFLAG_UNMASKED | TMPFLAG_UNMASKED_LINK_PARENT |
TMPFLAG_PRESSED_LINK_CHILD | TMPFLAG_PRESSED_LINK_PARENT)) & 112) == 64)
i.second.pressed->Enable();
else {
i.second.pressed->SetValue(false);
i.second.pressed->Disable();
}
}
}
void wxdialog_keyentry::on_ok(wxCommandEvent& e)
{
EndModal(wxID_OK);
}
void wxdialog_keyentry::on_clear(wxCommandEvent& e)
{
cleared = true;
EndModal(wxID_OK);
}
void wxdialog_keyentry::on_cancel(wxCommandEvent& e)
{
EndModal(wxID_CANCEL);
}
std::string wxdialog_keyentry::getkey()
{
if(cleared)
return "";
std::string x;
bool f;
f = true;
for(auto i : modifiers) {
if(i.second.pressed->GetValue()) {
if(!f)
x = x + ",";
f = false;
x = x + i.first;
}
}
x = x + "/";
f = true;
for(auto i : modifiers) {
if(i.second.unmasked->GetValue()) {
if(!f)
x = x + ",";
f = false;
x = x + i.first;
}
}
x = x + "|" + tostdstring(mainkey->GetValue());
return x;
}
wxdialog_hotkeys::wxdialog_hotkeys(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("Hotkeys"), wxDefaultPosition, wxSize(-1, -1))
{
scroll = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1));
scroll->SetMinSize(wxSize(-1, 500));
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s);
scroll_sizer = new wxFlexGridSizer(0, 3, 0, 0);
scroll->SetSizer(scroll_sizer);
//Obtain all the inverses.
std::set<inverse_key*> inverses;
runemufn([&inverses]() {
auto x = inverse_key::get_ikeys();
for(auto y : x)
inverses.insert(y);
});
unsigned y = 0;
for(auto x : inverses) {
hotkeys[y] = new hotkey(this, scroll, scroll_sizer, x, y);
y++;
}
update();
top_s->Add(scroll);
scroll->SetScrollRate(0, 20);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(close = new wxButton(this, wxID_CANCEL, wxT("Close")), 0, wxGROW);
close->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_hotkeys::on_close), NULL, this);
top_s->Add(pbutton_s, 0, wxGROW);
scroll_sizer->SetSizeHints(this);
top_s->SetSizeHints(this);
scroll_sizer->Layout();
top_s->Layout();
Fit();
}
void wxdialog_hotkeys::on_reconfig(wxCommandEvent& e)
{
int id = e.GetId();
if(id <= wxID_HIGHEST)
return;
unsigned button = (id - wxID_HIGHEST - 1) / 2;
bool primflag = (((id - wxID_HIGHEST - 1) % 2) == 0);
if(!hotkeys.count(button))
return;
wxdialog_keyentry* d = new wxdialog_keyentry(this, "Specify key for " + hotkeys[button]->
get_title(), true);
if(d->ShowModal() == wxID_CANCEL) {
d->Destroy();
return;
}
std::string key = d->getkey();
d->Destroy();
if(key != "")
hotkeys[button]->get_associated()->set(key, primflag);
else
hotkeys[button]->get_associated()->clear(primflag);
update();
}
void wxdialog_hotkeys::update()
{
std::map<inverse_key*, std::pair<std::string, std::string>> data;
runemufn([&data]() {
auto x = inverse_key::get_ikeys();
for(auto y : x)
data[y] = std::make_pair(y->get(true), y->get(false));
});
for(auto i : hotkeys) {
inverse_key* j = i.second->get_associated();
if(!data.count(j))
continue;
auto y = data[j];
i.second->update(y.first, y.second);
}
}
wxdialog_hotkeys::~wxdialog_hotkeys()
{
for(auto i : hotkeys)
delete i.second;
}
void wxdialog_hotkeys::on_close(wxCommandEvent& e)
{
EndModal(wxID_OK);
}
hotkey::hotkey(wxdialog_hotkeys* h, wxWindow* win, wxSizer* s, inverse_key* ikey, unsigned o)
{
title = ikey->getname();
s->Add(new wxStaticText(win, wxID_ANY, towxstring(title)), 0, wxGROW);
s->Add(primaryb = new wxButton(win, wxID_HIGHEST + 1 + 2 * o, wxT("(none)"), wxDefaultPosition,
wxSize(200, -1)), 0, wxGROW);
s->Add(secondaryb = new wxButton(win, wxID_HIGHEST + 2 + 2 * o, wxT("(none)"), wxDefaultPosition,
wxSize(200, -1)), 0, wxGROW);
primaryb->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_hotkeys::on_reconfig), NULL, h);
secondaryb->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_hotkeys::on_reconfig), NULL, h);
associated = ikey;
}
inverse_key* hotkey::get_associated()
{
return associated;
}
std::string hotkey::get_title()
{
return title;
}
void hotkey::update(const std::string& primary, const std::string& secondary)
{
primaryb->SetLabel((primary != "") ? towxstring(primary) : towxstring("(none)"));
secondaryb->SetLabel((secondary != "") ? towxstring(secondary) : towxstring("(none)"));
}
}
std::string wxeditor_keyselect(wxWindow* parent, bool clearable)
{
wxdialog_keyentry* d = new wxdialog_keyentry(parent, "Specify key", clearable);
if(d->ShowModal() == wxID_CANCEL) {
d->Destroy();
throw canceled_exception();
}
std::string key = d->getkey();
d->Destroy();
return key;
}
void wxeditor_hotkeys_display(wxWindow* parent)
{
modal_pause_holder hld;
wxdialog_hotkeys* d = new wxdialog_hotkeys(parent);
d->ShowModal();
d->Destroy();
}

View file

@ -72,7 +72,8 @@ enum
wxID_EDIT_JUKEBOX,
wxID_MEMORY_SEARCH,
wxID_CANCEL_SAVES,
wxID_LOAD_LIBRARY
wxID_LOAD_LIBRARY,
wxID_EDIT_HOTKEYS
};
@ -411,171 +412,6 @@ namespace
{
runuifun([ahmenu]() { ahmenu->reconfigure(); });
}
struct keyentry_mod_data
{
wxCheckBox* pressed;
wxCheckBox* unmasked;
unsigned tmpflags;
};
class wxdialog_keyentry : public wxDialog
{
public:
wxdialog_keyentry(wxWindow* parent);
void on_change_setting(wxCommandEvent& e);
void on_ok(wxCommandEvent& e);
void on_cancel(wxCommandEvent& e);
std::string getkey();
private:
std::map<std::string, keyentry_mod_data> modifiers;
wxComboBox* mainkey;
wxButton* ok;
wxButton* cancel;
};
wxdialog_keyentry::wxdialog_keyentry(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("Specify key"), wxDefaultPosition, wxSize(-1, -1))
{
std::vector<wxString> keych;
std::set<std::string> mods, keys;
runemufn([&mods, &keys]() { mods = modifier::get_set(); keys = keygroup::get_keys(); });
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s);
wxFlexGridSizer* t_s = new wxFlexGridSizer(mods.size() + 1, 3, 0, 0);
for(auto i : mods) {
t_s->Add(new wxStaticText(this, wxID_ANY, towxstring(i)), 0, wxGROW);
keyentry_mod_data m;
t_s->Add(m.pressed = new wxCheckBox(this, wxID_ANY, wxT("Pressed")), 0, wxGROW);
t_s->Add(m.unmasked = new wxCheckBox(this, wxID_ANY, wxT("Unmasked")), 0, wxGROW);
m.pressed->Disable();
modifiers[i] = m;
m.pressed->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
m.unmasked->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
}
for(auto i : keys)
keych.push_back(towxstring(i));
t_s->Add(new wxStaticText(this, wxID_ANY, wxT("Key")), 0, wxGROW);
t_s->Add(mainkey = new wxComboBox(this, wxID_ANY, keych[0], wxDefaultPosition, wxDefaultSize,
keych.size(), &keych[0], wxCB_READONLY), 1, wxGROW);
mainkey->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(wxdialog_keyentry::on_change_setting), NULL, this);
top_s->Add(t_s);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
pbutton_s->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_ok), NULL, this);
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_cancel), NULL, this);
top_s->Add(pbutton_s, 0, wxGROW);
t_s->SetSizeHints(this);
top_s->SetSizeHints(this);
Fit();
}
#define TMPFLAG_UNMASKED 65
#define TMPFLAG_UNMASKED_LINK_CHILD 2
#define TMPFLAG_UNMASKED_LINK_PARENT 68
#define TMPFLAG_PRESSED 8
#define TMPFLAG_PRESSED_LINK_CHILD 16
#define TMPFLAG_PRESSED_LINK_PARENT 32
void wxdialog_keyentry::on_change_setting(wxCommandEvent& e)
{
for(auto& i : modifiers)
i.second.tmpflags = 0;
for(auto& i : modifiers) {
modifier* m = NULL;
try {
m = &modifier::lookup(i.first);
} catch(...) {
i.second.pressed->Disable();
i.second.unmasked->Disable();
continue;
}
std::string j = m->linked_name();
if(i.second.unmasked->GetValue())
i.second.tmpflags |= TMPFLAG_UNMASKED;
if(j != "") {
if(modifiers[j].unmasked->GetValue())
i.second.tmpflags |= TMPFLAG_UNMASKED_LINK_PARENT;
if(i.second.unmasked->GetValue())
modifiers[j].tmpflags |= TMPFLAG_UNMASKED_LINK_CHILD;
}
if(i.second.pressed->GetValue())
i.second.tmpflags |= TMPFLAG_PRESSED;
if(j != "") {
if(modifiers[j].pressed->GetValue())
i.second.tmpflags |= TMPFLAG_PRESSED_LINK_PARENT;
if(i.second.pressed->GetValue())
modifiers[j].tmpflags |= TMPFLAG_PRESSED_LINK_CHILD;
}
}
for(auto& i : modifiers) {
//Unmasked is to be enabled if neither unmasked link flag is set.
if(i.second.tmpflags & ((TMPFLAG_UNMASKED_LINK_CHILD | TMPFLAG_UNMASKED_LINK_PARENT) & ~64)) {
i.second.unmasked->SetValue(false);
i.second.unmasked->Disable();
} else
i.second.unmasked->Enable();
//Pressed is to be enabled if:
//- This modifier is unmasked or parent is unmasked.
//- Parent nor child is not pressed.
if(((i.second.tmpflags & (TMPFLAG_UNMASKED | TMPFLAG_UNMASKED_LINK_PARENT |
TMPFLAG_PRESSED_LINK_CHILD | TMPFLAG_PRESSED_LINK_PARENT)) & 112) == 64)
i.second.pressed->Enable();
else {
i.second.pressed->SetValue(false);
i.second.pressed->Disable();
}
}
}
void wxdialog_keyentry::on_ok(wxCommandEvent& e)
{
EndModal(wxID_OK);
}
void wxdialog_keyentry::on_cancel(wxCommandEvent& e)
{
EndModal(wxID_CANCEL);
}
std::string wxdialog_keyentry::getkey()
{
std::string x;
bool f;
f = true;
for(auto i : modifiers) {
if(i.second.pressed->GetValue()) {
if(!f)
x = x + ",";
f = false;
x = x + i.first;
}
}
x = x + "/";
f = true;
for(auto i : modifiers) {
if(i.second.unmasked->GetValue()) {
if(!f)
x = x + ",";
f = false;
x = x + i.first;
}
}
x = x + "|" + tostdstring(mainkey->GetValue());
return x;
}
}
void boot_emulator(loaded_rom& rom, moviefile& movie)
@ -829,6 +665,7 @@ wxwin_mainwindow::wxwin_mainwindow()
menu_start(wxT("Settings"));
menu_entry(wxID_EDIT_AXES, wxT("Configure axes"));
menu_entry(wxID_EDIT_SETTINGS, wxT("Configure settings"));
menu_entry(wxID_EDIT_HOTKEYS, wxT("Configure hotkeys"));
menu_entry(wxID_EDIT_KEYBINDINGS, wxT("Configure keybindings"));
menu_entry(wxID_EDIT_ALIAS, wxT("Configure aliases"));
menu_entry(wxID_EDIT_JUKEBOX, wxT("Configure jukebox"));
@ -986,6 +823,9 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
case wxID_EDIT_SETTINGS:
wxeditor_settings_display(this);
return;
case wxID_EDIT_HOTKEYS:
wxeditor_hotkeys_display(this);
return;
case wxID_EDIT_KEYBINDINGS: {
modal_pause_holder hld;
std::set<std::string> bind;
@ -995,15 +835,8 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
for(auto i : bind)
choices.push_back(i);
std::string key = pick_among(this, "Select binding", "Select keybinding to edit", choices);
if(key == NEW_KEYBINDING) {
wxdialog_keyentry* d2 = new wxdialog_keyentry(this);
if(d2->ShowModal() == wxID_CANCEL) {
d2->Destroy();
throw canceled_exception();
}
key = d2->getkey();
d2->Destroy();
}
if(key == NEW_KEYBINDING)
key = wxeditor_keyselect(this, false);
std::string old_command_value;
runemufn([&old_command_value, key]() { old_command_value = keymapper::get_command_for(key); });
std::string newcommand = pick_text(this, "Edit binding", "Enter new command for binding:",