Canvas KeyBindings support
- use new built-in KeyBinding in Widget, Menu
This commit is contained in:
parent
13d22271a0
commit
3d47bc2325
4 changed files with 79 additions and 155 deletions
|
@ -281,117 +281,45 @@ ModifierKeys.Meta = (ModifierKeys.Meta_L | ModifierKeys.Meta_R);
|
||||||
#ModifierKeys.Super = (ModifierKeys.Super_L | ModifierKeys.Super_R);
|
#ModifierKeys.Super = (ModifierKeys.Super_L | ModifierKeys.Super_R);
|
||||||
#ModifierKeys.Hyper = (ModifierKeys.Hyper_L | ModifierKeys.Hyper_R);
|
#ModifierKeys.Hyper = (ModifierKeys.Hyper_L | ModifierKeys.Hyper_R);
|
||||||
|
|
||||||
var Shortcut = {
|
var parseShortcut = func(s)
|
||||||
new: func(modifiers, keys...) {
|
{
|
||||||
var m = {
|
if (size(s) == 0) {
|
||||||
parents: [Shortcut],
|
return "shortcut string is empty";
|
||||||
modifiers: modifiers,
|
}
|
||||||
keys: keys,
|
|
||||||
};
|
|
||||||
if (m.modifiers == nil) {
|
|
||||||
m.modifiers = [];
|
|
||||||
m.keys = [];
|
|
||||||
} elsif (isa(m.modifiers, Shortcut)) {
|
|
||||||
var shortcut = m.modifiers;
|
|
||||||
m.modifiers = shortcut.modifiers;
|
|
||||||
m.keys = shortcut.keys;
|
|
||||||
} elsif (typeof(m.modifiers) == "scalar") {
|
|
||||||
var res = m.parseString(m.modifiers);
|
|
||||||
if (typeof(res) == "scalar") {
|
|
||||||
logprint(LOG_ALERT, "keyboard.Shortcut.parseString failed parsing '" ~ m.modifiers ~ "' with the following reason:");
|
|
||||||
logprint(LOG_ALERT, "\t" ~ res);
|
|
||||||
m.modifiers = [];
|
|
||||||
m.keys = [];
|
|
||||||
} else {
|
|
||||||
m.modifiers = res[0];
|
|
||||||
m.keys = res[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
},
|
|
||||||
|
|
||||||
parseString: func(s) {
|
var baseKey = nil;
|
||||||
if (size(s) == 0) {
|
var modifiers = [];
|
||||||
return "shortcut string is empty";
|
var input = split("+", s);
|
||||||
|
foreach (var key; input) {
|
||||||
|
if (string.match(key, "<*>")) {
|
||||||
|
append(modifiers, substr(key, 1, size(key) - 2));
|
||||||
|
} else {
|
||||||
|
baseKey = key;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var found = [];
|
|
||||||
var modifiers = [];
|
|
||||||
var input = split("+", s);
|
|
||||||
foreach (var key; input) {
|
|
||||||
if (string.match(key, "<*>")) {
|
|
||||||
append(modifiers, substr(key, 1, size(key) - 2));
|
|
||||||
} else {
|
|
||||||
append(found, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var newmodifiers = [];
|
|
||||||
foreach (var mod; modifiers) {
|
|
||||||
if (ModifierKeys[mod] == nil) {
|
|
||||||
return "Unknown modifier key '" ~ mod ~ "' !";
|
|
||||||
} else {
|
|
||||||
append(newmodifiers, ModifierKeys[mod]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var newfound = [];
|
|
||||||
foreach (var key; found) {
|
|
||||||
if (PrintableKeys[key] == nil) {
|
|
||||||
if (FunctionKeys[key] == nil) {
|
|
||||||
return "Unknown key '" ~ key ~ "' !";
|
|
||||||
} else {
|
|
||||||
append(newfound, FunctionKeys[key]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
append(newfound, PrintableKeys[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [newmodifiers, newfound];
|
|
||||||
},
|
|
||||||
|
|
||||||
match: func(keys, shift=0, ctrl=0, alt=0, meta=0) {
|
var modMask = 0;
|
||||||
if (typeof(keys) != "vector") {
|
foreach (var mod; modifiers) {
|
||||||
keys = [keys];
|
var mm = ModifierKeys[mod];
|
||||||
|
if (mm == nil) {
|
||||||
|
logprint(LOG_ALERT, "Unknown modifier key '" ~ mod ~ "' !");
|
||||||
|
} else {
|
||||||
|
modMask = modMask + mm;
|
||||||
}
|
}
|
||||||
if (!me.modifiers and !me.keys) {
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
var match = 1;
|
|
||||||
match &= contains(me.modifiers, ModifierKeys["Shift"]) == shift;
|
|
||||||
match &= contains(me.modifiers, ModifierKeys["Ctrl"]) == ctrl;
|
|
||||||
match &= contains(me.modifiers, ModifierKeys["Alt"]) == alt;
|
|
||||||
match &= contains(me.modifiers, ModifierKeys["Meta"]) == meta;
|
|
||||||
match &= size(keys) == size(me.keys);
|
|
||||||
if (!match) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < size(keys); i += 1) {
|
|
||||||
match &= contains(me.keys, keys[i]);
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
},
|
|
||||||
|
|
||||||
repr: func {
|
var keyCode = PrintableKeys[baseKey];
|
||||||
if (!me.modifiers and !me.keys) {
|
if (keyCode == nil) {
|
||||||
return "";
|
keyCode = FunctionKeys[baseKey];
|
||||||
}
|
}
|
||||||
var names = [];
|
|
||||||
foreach (var mod; me.modifiers) {
|
if (keyCode == nil) {
|
||||||
append(names, findKeyName(mod));
|
logprint(LOG_ALERT, "Unknown key '" ~ baseKey ~ "'");
|
||||||
}
|
}
|
||||||
foreach (var key; me.keys) {
|
|
||||||
append(names, findKeyName(key));
|
return [modMask, keyCode];
|
||||||
}
|
}
|
||||||
return string.join(" + ", names);
|
|
||||||
},
|
|
||||||
|
|
||||||
equals: func(other) {
|
|
||||||
return me.modifiers == other.modifiers and me.keys == other.keys;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var findKeyName = func(key) {
|
var findKeyName = func(key) {
|
||||||
foreach (var mod; keys(ModifierKeys)) {
|
foreach (var mod; keys(ModifierKeys)) {
|
||||||
|
@ -412,7 +340,8 @@ var findKeyName = func(key) {
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
var namesToKeys = func(strings...) {
|
var namesToKeys = func(strings...)
|
||||||
|
{
|
||||||
var res = [];
|
var res = [];
|
||||||
foreach (var s; strings) {
|
foreach (var s; strings) {
|
||||||
var key = ModifierKeys[s] or PrintableKeys[s] or FunctionKeys[s];
|
var key = ModifierKeys[s] or PrintableKeys[s] or FunctionKeys[s];
|
||||||
|
@ -425,22 +354,39 @@ var namesToKeys = func(strings...) {
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
var Binding = {
|
# here we're extendin the built-in KeyBinding class defined in NasalCanvas.cxx,
|
||||||
new: func(shortcut, f) {
|
# with some helper functions which rely on the tables defined above.
|
||||||
var m = {
|
|
||||||
parents: [Binding],
|
KeyBinding['fromShortcut'] = func(shortcutString, cb = nil)
|
||||||
f: f,
|
{
|
||||||
shortcut: shortcut,
|
if (!isstr(shortcutString)) {
|
||||||
};
|
return nil;
|
||||||
return m;
|
|
||||||
},
|
|
||||||
|
|
||||||
fire: func(e) {
|
|
||||||
debug.dump(e);
|
|
||||||
if (isfunc(me.f)) {
|
|
||||||
me.f(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var res = KeyBinding.new();
|
||||||
|
var t = parseShortcut(shortcutString);
|
||||||
|
|
||||||
|
res.modifiers = t[0];
|
||||||
|
res.keyCode = t[1];
|
||||||
|
|
||||||
|
if (!isfunc(cb)) {
|
||||||
|
logprint(LOG_ALERT, "callback argument to KeyBinding.fromShortcut is not a function")
|
||||||
|
} else {
|
||||||
|
res.addBinding(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
KeyBinding['repr'] = func(kb)
|
||||||
|
{
|
||||||
|
var names = [];
|
||||||
|
foreach (var mod; keys(ModifierKeys)) {
|
||||||
|
if (kb.modifiers & ModifierKeys[mod]) {
|
||||||
|
append(names, "<" ~ mod ~ ">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append(names, findKeyName(kb.keyCode));
|
||||||
|
return string.join(" + ", names);
|
||||||
|
};
|
||||||
|
|
|
@ -167,11 +167,14 @@ gui.MenuItem = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setShortcut: func(shortcut) {
|
setShortcut: func(shortcut) {
|
||||||
me._shortcut = keyboard.Shortcut.new(shortcut);
|
if (!isstr(shortcut)) {
|
||||||
if (me._parent_menu != nil and me._parent_menu._canvas_item != nil and me._cb != nil) {
|
logprint(LOG_ALERT, "Menu.setShortcut: invalid shortcut");
|
||||||
me._parent_menu._canvas_item.bindShortcut(me._shortcut, me._cb);
|
return;
|
||||||
}
|
}
|
||||||
me._view.setShortcut(me, me._shortcut);
|
|
||||||
|
me._keyBinding = KeyBinding.fromShortcut(shortcut, me._cb);
|
||||||
|
getDesktop().addKeyBinding(me._keyBinding);
|
||||||
|
me._view.setShortcut(me, KeyBinding.repr(me._keyBinding));
|
||||||
return me.update();
|
return me.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -198,6 +201,9 @@ gui.MenuItem = {
|
||||||
|
|
||||||
setCallback: func(cb = nil) {
|
setCallback: func(cb = nil) {
|
||||||
me._cb = cb;
|
me._cb = cb;
|
||||||
|
if (me._keyBinding) {
|
||||||
|
me._keyBinding.addBinding(cb);
|
||||||
|
}
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -143,34 +143,6 @@ gui.Widget = {
|
||||||
me._view._root.setVisible(visible);
|
me._view._root.setVisible(visible);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
bindShortcut: func(s, f)
|
|
||||||
{
|
|
||||||
if (!isa(s, keyboard.Shortcut)) {
|
|
||||||
s = keyboard.Shortcut.new(s);
|
|
||||||
}
|
|
||||||
foreach (var b; me._bindings) {
|
|
||||||
if (b.shortcut.equals(s)) {
|
|
||||||
b.f = f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
append(me._bindings, keyboard.Binding.new(s, f));
|
|
||||||
# add listener when first binding is added
|
|
||||||
# if this happens before the view is set, we instead do it in _setView below
|
|
||||||
if ((size(me._bindings) == 1) and me._view) {
|
|
||||||
me._view._root.addEventListener("keydown", func(e) me._onKeyPressed(e));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onKeyPressed: func(e) {
|
|
||||||
foreach (var b; me._bindings) {
|
|
||||||
if (b.shortcut.match(keyboard.findKeyName(e.keyCode), e.shiftKey, e.ctrlKey, e.altKey, e.metaKey)) {
|
|
||||||
b.fire(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_setView: func(view)
|
_setView: func(view)
|
||||||
{
|
{
|
||||||
me._view = view;
|
me._view = view;
|
||||||
|
|
|
@ -1397,7 +1397,7 @@ DefaultStyle.widgets["menu-item"] = {
|
||||||
|
|
||||||
setShortcut: func(model, shortcut) {
|
setShortcut: func(model, shortcut) {
|
||||||
if (shortcut != nil) {
|
if (shortcut != nil) {
|
||||||
me._shortcut.setText(shortcut.repr());
|
me._shortcut.setText(shortcut);
|
||||||
}
|
}
|
||||||
return me._updateLayoutSizes(model);
|
return me._updateLayoutSizes(model);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue