From a25674337d5d9f873d079d442513c0faea0833dd Mon Sep 17 00:00:00 2001 From: TheFGFSEagle Date: Fri, 6 Jan 2023 12:19:32 +0100 Subject: [PATCH] Added shortcut option for menu items --- Nasal/canvas/gui/Menu.nas | 42 ++++++++++++++++++++---- Nasal/canvas/gui/styles/DefaultStyle.nas | 32 ++++++++++++++---- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/Nasal/canvas/gui/Menu.nas b/Nasal/canvas/gui/Menu.nas index 0db792599..e1abe7b9b 100644 --- a/Nasal/canvas/gui/Menu.nas +++ b/Nasal/canvas/gui/Menu.nas @@ -16,6 +16,7 @@ gui.MenuItem = { # @description Create a new menu item widget # @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 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 enabled: bool Initial state of the menu item: enabled (1) or disabled (0) @@ -23,6 +24,7 @@ gui.MenuItem = { var cfg = Config.new(cfg); var m = gui.Widget.new(gui.MenuItem); m._text = cfg.get("text", "Menu item"); + m._shortcut = cfg.get("shortcut", ""); m._cb = cfg.get("cb", nil); m._icon = cfg.get("icon", nil); m._enabled = cfg.get("enabled", 1); @@ -35,8 +37,10 @@ gui.MenuItem = { m.setLayoutMinimumSize([48, 24]); m.setLayoutSizeHint([64, 24]); m.setLayoutMaximumSize([1024, 24]); + m._view.setText(m, m._text); m._view.setIcon(m._icon); + m._view.setShortcut(m, m._shortcut); return m; }, @@ -47,9 +51,11 @@ gui.MenuItem = { }, onClicked: func(e) { + print("clicked", me._menu == nil, me._cb != nil); if (!me._menu and me._cb) { me._cb(e); } + me._parent_menu.hide(); }, onMouseEnter: func(e) { @@ -102,6 +108,12 @@ gui.MenuItem = { me._view.setText(me, text); return me.update(); }, + + setShortcut: func(shortcut) { + me._shortcut = shortcut; + me._view.setShortcut(me, shortcut); + return me.update(); + }, setIcon: func(icon) { me._icon = icon; @@ -157,26 +169,36 @@ gui.Menu = { }, # @description Create, insert and return a `canvas.gui.MenuItem` with given text and an optional callback, icon and enabled state. - # @param text: strrequired Text to display on the menu item + # @param text: str required Text to display on the menu item # @param cb: callable optional Function / method to call when the item is clicked - if no callback is wanted, nil can be used + # @param shortcut: str String representation of the keyboard shortcut for the item # @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) # @return canvas.gui.MenuItem The item that was created - createItem: func(text, cb = nil, icon = nil, enabled = 1) { - item = gui.MenuItem.new(me._root, me.style, {"text": text, "cb": cb, "icon": icon, "enabled": enabled}); + createItem: func(text = nil, cb = "TheEagle", shortcut = "", icon = nil, enabled = 1) { + if (text == nil) { + die("cannot create a menu item without text"); + } + var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: cb, shortcut: shortcut, icon: icon, enabled: enabled}); me.addItem(item); return item; }, # @description Create, insert and return a `canvas.gui.MenuItem with the given text and assign the given submenu to it, # optionally add the given icon and set the given enabled state - # @param text: strrequired Text to display on the menu item + # @param text: str required Text to display on the menu item # @param menu: canvas.gui.Menu Submenu that shall be assigned to the new menu item # @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) # @return canvas.gui.MenuItem The item that was created - addMenu: func(text, menu, icon = nil, enabled = 1) { - item = gui.MenuItem.new(me._root, me.style, {"text": text, cb: nil, "icon": icon, "enabled": enabled}); + addMenu: func(text = nil, menu = nil, icon = nil, enabled = 1) { + if (text == nil) { + die("cannot create a menu item without text"); + } + if (menu == nil) { + 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}); item.setMenu(menu); me.addItem(item); return item; @@ -249,6 +271,14 @@ gui.Menu = { } }, + # @description Show the menu, moving it to the position given by `x` and `y` if ´x` and `y` are not nil + show: func(x = nil, y = nil) { + if (x != nil and y != nil) { + me.setPosition(x, y); + } + call(me.parents[1].show, [], me); + }, + # @description Destructor del: func() { me.hide(); diff --git a/Nasal/canvas/gui/styles/DefaultStyle.nas b/Nasal/canvas/gui/styles/DefaultStyle.nas index befffa0ee..ebc1b0251 100644 --- a/Nasal/canvas/gui/styles/DefaultStyle.nas +++ b/Nasal/canvas/gui/styles/DefaultStyle.nas @@ -860,13 +860,19 @@ DefaultStyle.widgets["menu-item"] = { me._root = parent.createChild("group", "menu-item"); me._bg = me._root.createChild("path"); - me._icon = me._root.createChild("image"); + me._icon = me._root.createChild("image") + .set("slice", "18 18"); me._label = me._root.createChild("text") .set("font", "LiberationFonts/LiberationSans-Regular.ttf") .set("character-size", 14) .set("alignment", "left-center"); + me._shortcut = me._root.createChild("text") + .set("font", "LiberationFonts/LiberationSans-Regular.ttf") + .set("character-size", 14) + .set("alignment", "right-center"); + me._submenu_indicator = me._root.createChild("path") .vert(12).line(6, -7).close(); }, @@ -875,18 +881,27 @@ DefaultStyle.widgets["menu-item"] = { me._bg.reset().rect(0, 0, w, h); me._icon.setTranslation(3, int((h - 12) / 2)); me._label.setTranslation(24, int(h / 2) + 1); + me._shortcut.setTranslation(w - 3, int(h / 2) + 1); me._submenu_indicator.setTranslation(w - 15, int((h - 12) / 2)); return me; }, + _updateLayoutSizes: func(model) { + var min_width = 3 + 18 + 3 + me._label.maxWidth() + 3 + me._shortcut.maxWidth() + 3 + 12 + 3; + model.setLayoutMinimumSize([min_width, 24]); + model.setLayoutSizeHint([min_width, 24]); + + return me; + }, + setText: func(model, text) { me._label.setText(text); - - var min_width = me._label.maxWidth() + 6 + 48; - model.setLayoutMinimumSize([min_width, 24]); - model.setLayoutSizeHint([min_width, 24]); - - return me; + return me._updateLayoutSizes(model); + }, + + setShortcut: func(model, shortcut) { + me._shortcut.setText(shortcut); + return me._updateLayoutSizes(model); }, setIcon: func(icon) { @@ -909,11 +924,14 @@ DefaultStyle.widgets["menu-item"] = { text_color_name ~= "_disabled"; } me._label.set("fill", me._style.getColor(text_color_name)); + me._shortcut.set("fill", me._style.getColor(text_color_name)); me._submenu_indicator.set("fill", me._style.getColor("menu_item_submenu_indicator" ~ (model._hovered ? "_hovered" : ""))); if (model._menu != nil) { me._submenu_indicator.show(); + me._shortcut.hide(); } else { me._submenu_indicator.hide(); + me._shortcut.show(); } return me;