1
0
Fork 0

Added real keyboard shortcut support for menu items

This commit is contained in:
TheFGFSEagle 2023-01-08 15:35:46 +01:00 committed by James Turner
parent 66fcfce8af
commit 2cf388e674
6 changed files with 77 additions and 35 deletions

View file

@ -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();
}, },

View file

@ -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;

View file

@ -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)
{ {

View file

@ -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);
}, },

View file

@ -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) {

View file

@ -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));
} }