Added real keyboard shortcut support for menu items
This commit is contained in:
parent
66fcfce8af
commit
2cf388e674
6 changed files with 77 additions and 35 deletions
|
@ -16,10 +16,35 @@ var Element = {
|
||||||
var obj = {
|
var obj = {
|
||||||
parents: [Element, PropertyElement, ghost],
|
parents: [Element, PropertyElement, ghost],
|
||||||
_node: props.wrapNode(ghost._node_ghost),
|
_node: props.wrapNode(ghost._node_ghost),
|
||||||
|
_bindings: [],
|
||||||
};
|
};
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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));
|
||||||
|
if (size(me._bindings) == 1) {
|
||||||
|
obj.addEventListener("keydown", func(e) obj.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getType: func () {
|
getType: func () {
|
||||||
return me._node.getName();
|
return me._node.getName();
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
gui.MenuItem = {
|
gui.MenuItem = {
|
||||||
# @description Create a new menu item widget
|
# @description Create a new menu item widget
|
||||||
# @cfg_field text: str Text of the new menu item
|
# @cfg_field text: str Text of the new menu item
|
||||||
# @cfg_field shortcut: str String representation of the keyboard shortcut for the item
|
# @cfg_field shortcut: str String representation of the keyboard shortcut for the item
|
||||||
# @cfg_field cb: callable Function / method to call when the item is clicked
|
# @cfg_field cb: callable Function / method to call when the item is clicked
|
||||||
# @cfg_field icon: str Path of an icon to be displayed (relative to the path in `canvas.style._dir_widgets`)
|
# @cfg_field icon: str Path of an icon to be displayed (relative to the path in `canvas.style._dir_widgets`)
|
||||||
# @cfg_field enabled: bool Initial state of the menu item: enabled (1) or disabled (0)
|
# @cfg_field enabled: bool Initial state of the menu item: enabled (1) or disabled (0)
|
||||||
|
@ -24,7 +24,7 @@ gui.MenuItem = {
|
||||||
var cfg = Config.new(cfg);
|
var cfg = Config.new(cfg);
|
||||||
var m = gui.Widget.new(gui.MenuItem);
|
var m = gui.Widget.new(gui.MenuItem);
|
||||||
m._text = cfg.get("text", "Menu item");
|
m._text = cfg.get("text", "Menu item");
|
||||||
m._shortcut = cfg.get("shortcut", "");
|
m._shortcut = cfg.get("shortcut", nil);
|
||||||
m._cb = cfg.get("cb", nil);
|
m._cb = cfg.get("cb", nil);
|
||||||
m._icon = cfg.get("icon", nil);
|
m._icon = cfg.get("icon", nil);
|
||||||
m._enabled = cfg.get("enabled", 1);
|
m._enabled = cfg.get("enabled", 1);
|
||||||
|
@ -38,9 +38,9 @@ gui.MenuItem = {
|
||||||
m.setLayoutSizeHint([64, 24]);
|
m.setLayoutSizeHint([64, 24]);
|
||||||
m.setLayoutMaximumSize([1024, 24]);
|
m.setLayoutMaximumSize([1024, 24]);
|
||||||
|
|
||||||
m._view.setText(m, m._text);
|
m.setText(m._text);
|
||||||
m._view.setIcon(m._icon);
|
m.setIcon(m._icon);
|
||||||
m._view.setShortcut(m, m._shortcut);
|
m.setShortcut(m._shortcut);
|
||||||
return m;
|
return m;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -110,11 +110,21 @@ gui.MenuItem = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setShortcut: func(shortcut) {
|
setShortcut: func(shortcut) {
|
||||||
me._shortcut = shortcut;
|
me._shortcut = keyboard.Shortcut.new(shortcut);
|
||||||
me._view.setShortcut(me, shortcut);
|
if (me._parent_menu != nil and me._parent_menu._canvas_item != nil and me._cb != nil) {
|
||||||
|
me._parent_menu._canvas_item.bindShortcut(me._shortcut, me._cb);
|
||||||
|
}
|
||||||
|
me._view.setShortcut(me, me._shortcut);
|
||||||
return me.update();
|
return me.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setParentMenu: func(m) {
|
||||||
|
me._parent_menu = m;
|
||||||
|
if (me._parent_menu != nil and me._parent_menu._canvas_item != nil and me._cb != nil) {
|
||||||
|
me._parent_menu._canvas_item.bindShortcut(me._shortcut, me._cb);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
setIcon: func(icon) {
|
setIcon: func(icon) {
|
||||||
me._icon = icon;
|
me._icon = icon;
|
||||||
me._view.setIcon(icon);
|
me._view.setIcon(icon);
|
||||||
|
@ -153,16 +163,24 @@ gui.Menu = {
|
||||||
m._root = m._canvas.createGroup();
|
m._root = m._canvas.createGroup();
|
||||||
m._layout = VBoxLayout.new();
|
m._layout = VBoxLayout.new();
|
||||||
m._layout.setSpacing(0);
|
m._layout.setSpacing(0);
|
||||||
|
m._canvas_item = nil;
|
||||||
m.setLayout(m._layout);
|
m.setLayout(m._layout);
|
||||||
m.hide();
|
m.hide();
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setCanvasItem: func(item) {
|
||||||
|
me._canvas_item = item;
|
||||||
|
for (var i = 0; i < me._layout.count(); i += 1) {
|
||||||
|
me._layout.itemAt(i)._setParentMenu(me);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
# @description Add the given menu item to the menu (normally a `canvas.gui.MenuItem`, but can be any `canvas.gui.Widget` in theory)
|
# @description Add the given menu item to the menu (normally a `canvas.gui.MenuItem`, but can be any `canvas.gui.Widget` in theory)
|
||||||
# @return canvas.gui.Menu Return me to enable method chaining
|
# @return canvas.gui.Menu Return me to enable method chaining
|
||||||
addItem: func(item) {
|
addItem: func(item) {
|
||||||
item._parent_menu = me;
|
item._setParentMenu(me);
|
||||||
me._layout.addItem(item);
|
me._layout.addItem(item);
|
||||||
me.setSize(me._layout.minimumSize()[0], me._layout.minimumSize()[1]);
|
me.setSize(me._layout.minimumSize()[0], me._layout.minimumSize()[1]);
|
||||||
return me;
|
return me;
|
||||||
|
@ -175,7 +193,7 @@ gui.Menu = {
|
||||||
# @param icon: str optional Path to the icon (relative to canvas.style._dir_widgets) or nil if none should be displayed
|
# @param icon: str optional Path to the icon (relative to canvas.style._dir_widgets) or nil if none should be displayed
|
||||||
# @param enabled: bool optional Whether the item should be enabled (1) or disabled (0)
|
# @param enabled: bool optional Whether the item should be enabled (1) or disabled (0)
|
||||||
# @return canvas.gui.MenuItem The item that was created
|
# @return canvas.gui.MenuItem The item that was created
|
||||||
createItem: func(text = nil, cb = nil, shortcut = "", icon = nil, enabled = 1) {
|
createItem: func(text = nil, cb = nil, shortcut = nil, icon = nil, enabled = 1) {
|
||||||
if (text == nil) {
|
if (text == nil) {
|
||||||
die("cannot create a menu item without text");
|
die("cannot create a menu item without text");
|
||||||
}
|
}
|
||||||
|
@ -198,7 +216,7 @@ gui.Menu = {
|
||||||
if (menu == nil) {
|
if (menu == nil) {
|
||||||
die("cannot create a submenu item without submenu");
|
die("cannot create a submenu item without submenu");
|
||||||
}
|
}
|
||||||
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: nil, shortcut: "", icon: icon, enabled: enabled});
|
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: nil, shortcut: nil, icon: icon, enabled: enabled});
|
||||||
item.setMenu(menu);
|
item.setMenu(menu);
|
||||||
me.addItem(item);
|
me.addItem(item);
|
||||||
return item;
|
return item;
|
||||||
|
|
|
@ -141,6 +141,9 @@ gui.Widget = {
|
||||||
{
|
{
|
||||||
me._view._root.setVisible(visible);
|
me._view._root.setVisible(visible);
|
||||||
},
|
},
|
||||||
|
bindShortcut: func(s, f) {
|
||||||
|
me._view._root.bindShortcut(s, f);
|
||||||
|
},
|
||||||
_setView: func(view)
|
_setView: func(view)
|
||||||
{
|
{
|
||||||
me._view = view;
|
me._view = view;
|
||||||
|
@ -170,6 +173,11 @@ gui.Widget = {
|
||||||
me._trigger("mouse-leave");
|
me._trigger("mouse-leave");
|
||||||
me._onStateChange();
|
me._onStateChange();
|
||||||
});
|
});
|
||||||
|
root.addEventListener("keypress", func(e) {
|
||||||
|
if (me._focused) {
|
||||||
|
root.onKeyPressed(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
_trigger: func(type, data = nil)
|
_trigger: func(type, data = nil)
|
||||||
{
|
{
|
||||||
|
|
|
@ -900,7 +900,7 @@ DefaultStyle.widgets["menu-item"] = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setShortcut: func(model, shortcut) {
|
setShortcut: func(model, shortcut) {
|
||||||
me._shortcut.setText(shortcut);
|
me._shortcut.setText(shortcut.repr());
|
||||||
return me._updateLayoutSizes(model);
|
return me._updateLayoutSizes(model);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,12 @@ gui.widgets.LineEdit = {
|
||||||
m._selection_end = 0;
|
m._selection_end = 0;
|
||||||
|
|
||||||
m.context_menu = gui.Menu.new();
|
m.context_menu = gui.Menu.new();
|
||||||
m.context_menu.createItem(text: "Copy", cb: func() { m.copy(); }, shortcut: "Ctrl+C");
|
m.context_menu.createItem(text: "Copy", cb: func() { m.copy(); }, shortcut: "<Ctrl>+C");
|
||||||
m.context_menu.createItem(text: "Cut", cb: func() { m.cut(); }, shortcut: "Ctrl+X");
|
m.context_menu.createItem(text: "Cut", cb: func() { m.cut(); }, shortcut: "<Ctrl>+X");
|
||||||
m.context_menu.createItem(text: "Paste", cb: func() { m.paste(); }, shortcut: "Ctrl+V");
|
m.context_menu.createItem(text: "Paste", cb: func() { m.paste(); }, shortcut: "<Ctrl>+V");
|
||||||
m.context_menu.createItem(text: "Clear", cb: func() { m.clear(); }, shortcut: "Ctrl+D");
|
m.context_menu.createItem(text: "Clear", cb: func() { m.clear(); }, shortcut: "<Ctrl>+D");
|
||||||
m.context_menu.createItem(text: "Select all", cb: func() { m.selectAll(); }, shortcut: "Ctrl+A");
|
m.context_menu.createItem(text: "Select all", cb: func() { m.selectAll(); }, shortcut: "<Ctrl>+A");
|
||||||
|
m.context_menu.setCanvasItem(m);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
},
|
},
|
||||||
|
@ -182,7 +183,11 @@ gui.widgets.LineEdit = {
|
||||||
call(gui.Widget._setView, [view], me);
|
call(gui.Widget._setView, [view], me);
|
||||||
|
|
||||||
var el = view._root;
|
var el = view._root;
|
||||||
el.addEventListener("keypress", func (e) me.insert(e.key));
|
el.addEventListener("keypress", func (e) {
|
||||||
|
if (!e.ctrlKey and !e.altKey and !e.metaKey) {
|
||||||
|
me.insert(e.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
el.addEventListener("keydown", func (e)
|
el.addEventListener("keydown", func (e)
|
||||||
{
|
{
|
||||||
if( me._view == nil )
|
if( me._view == nil )
|
||||||
|
@ -202,19 +207,6 @@ gui.widgets.LineEdit = {
|
||||||
me.home();
|
me.home();
|
||||||
else if( e.key == "End" )
|
else if( e.key == "End" )
|
||||||
me.end();
|
me.end();
|
||||||
else if (e.ctrlKey) {
|
|
||||||
if (e.keyCode == `c`) {
|
|
||||||
me.copy();
|
|
||||||
} elsif (e.keyCode == `v`) {
|
|
||||||
me.paste();
|
|
||||||
} elsif (e.keyCode == `x`) {
|
|
||||||
me.cut();
|
|
||||||
} elsif (e.keyCode == `d`) {
|
|
||||||
me.clear();
|
|
||||||
} elsif (e.keyCode == `a`) {
|
|
||||||
me.selectAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
el.addEventListener("click", func(e) {
|
el.addEventListener("click", func(e) {
|
||||||
if (e.button == 2) {
|
if (e.button == 2) {
|
||||||
|
|
|
@ -357,10 +357,10 @@ var Shortcut = {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
var match = 1;
|
var match = 1;
|
||||||
match &= veccontains(me.modifiers, ModifierKeys["Shift"]) == shift;
|
match &= contains(me.modifiers, ModifierKeys["Shift"]) == shift;
|
||||||
match &= veccontains(me.modifiers, ModifierKeys["Ctrl"]) == ctrl;
|
match &= contains(me.modifiers, ModifierKeys["Ctrl"]) == ctrl;
|
||||||
match &= veccontains(me.modifiers, ModifierKeys["Alt"]) == alt;
|
match &= contains(me.modifiers, ModifierKeys["Alt"]) == alt;
|
||||||
match &= veccontains(me.modifiers, ModifierKeys["Meta"]) == meta;
|
match &= contains(me.modifiers, ModifierKeys["Meta"]) == meta;
|
||||||
match &= size(keys) == size(me.keys);
|
match &= size(keys) == size(me.keys);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -376,7 +376,6 @@ var Shortcut = {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
var names = [];
|
var names = [];
|
||||||
debug.dump(me.modifiers);
|
|
||||||
foreach (var mod; me.modifiers) {
|
foreach (var mod; me.modifiers) {
|
||||||
append(names, findKeyName(mod));
|
append(names, findKeyName(mod));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue