Added menu bar widget and global menu bar, menu item improvements
This commit is contained in:
parent
2cf388e674
commit
a5e30023bd
9 changed files with 370 additions and 36 deletions
|
@ -91,5 +91,6 @@ var unload = func
|
||||||
{
|
{
|
||||||
unloadTooltips();
|
unloadTooltips();
|
||||||
unloadErrorNotification();
|
unloadErrorNotification();
|
||||||
|
unloadGUI();
|
||||||
logprint(LOG_INFO, "Unloaded canvas Nasal module");
|
logprint(LOG_INFO, "Unloaded canvas Nasal module");
|
||||||
};
|
};
|
|
@ -33,7 +33,7 @@ var Element = {
|
||||||
}
|
}
|
||||||
append(me._bindings, keyboard.Binding.new(s, f));
|
append(me._bindings, keyboard.Binding.new(s, f));
|
||||||
if (size(me._bindings) == 1) {
|
if (size(me._bindings) == 1) {
|
||||||
obj.addEventListener("keydown", func(e) obj.onKeyPressed(e));
|
me.addEventListener("keydown", func(e) me.onKeyPressed(e));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ var loadDialog = func(name) loadGUIFile("dialogs/" ~ name ~ ".nas");
|
||||||
|
|
||||||
loadGUIFile("Config.nas");
|
loadGUIFile("Config.nas");
|
||||||
loadGUIFile("Menu.nas");
|
loadGUIFile("Menu.nas");
|
||||||
|
loadGUIFile("MenuBar.nas");
|
||||||
loadGUIFile("Popup.nas");
|
loadGUIFile("Popup.nas");
|
||||||
loadGUIFile("Style.nas");
|
loadGUIFile("Style.nas");
|
||||||
loadGUIFile("Widget.nas");
|
loadGUIFile("Widget.nas");
|
||||||
|
@ -40,6 +41,7 @@ loadWidget("Button");
|
||||||
loadWidget("CheckBox");
|
loadWidget("CheckBox");
|
||||||
loadWidget("Label");
|
loadWidget("Label");
|
||||||
loadWidget("LineEdit");
|
loadWidget("LineEdit");
|
||||||
|
loadWidget("MenuBar");
|
||||||
loadWidget("PropertyWidgets");
|
loadWidget("PropertyWidgets");
|
||||||
loadWidget("ScrollArea");
|
loadWidget("ScrollArea");
|
||||||
loadWidget("Rule");
|
loadWidget("Rule");
|
||||||
|
@ -584,16 +586,17 @@ var Window = {
|
||||||
|
|
||||||
# Clear focus on click outside any window
|
# Clear focus on click outside any window
|
||||||
getDesktop().addEventListener("mousedown", func {
|
getDesktop().addEventListener("mousedown", func {
|
||||||
if( gui.focused_window != nil )
|
if (gui.focused_window != nil) {
|
||||||
gui.focused_window.clearFocus();
|
gui.focused_window.clearFocus();
|
||||||
|
}
|
||||||
|
|
||||||
if (size(gui.open_popups)) {
|
|
||||||
foreach (var p; gui.open_popups) {
|
foreach (var p; gui.open_popups) {
|
||||||
p.hide();
|
p.hide();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gui.menubar = gui.MenuBar.new();
|
||||||
|
|
||||||
# Provide old 'Dialog' for backwards compatiblity (should be removed for 3.0)
|
# Provide old 'Dialog' for backwards compatiblity (should be removed for 3.0)
|
||||||
var Dialog = {
|
var Dialog = {
|
||||||
new: func(size, type = nil, id = nil)
|
new: func(size, type = nil, id = nil)
|
||||||
|
@ -602,3 +605,7 @@ var Dialog = {
|
||||||
return Window.new(size, type, id);
|
return Window.new(size, type, id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var unloadGUI = func() {
|
||||||
|
gui.menubar.del();
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
# m.show();
|
# m.show();
|
||||||
|
|
||||||
gui.MenuItem = {
|
gui.MenuItem = {
|
||||||
|
MenuPosition: {
|
||||||
|
Above: 0x0,
|
||||||
|
Right: 0x1,
|
||||||
|
Below: 0x2,
|
||||||
|
Left: 0x4
|
||||||
|
},
|
||||||
# @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
|
||||||
|
@ -28,9 +34,11 @@ gui.MenuItem = {
|
||||||
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);
|
||||||
|
m._menu_position = cfg.get("menu_position", gui.MenuItem.MenuPosition.Right);
|
||||||
m._hovered = 0;
|
m._hovered = 0;
|
||||||
m._menu = nil;
|
m._menu = nil;
|
||||||
m._parent_menu = nil;
|
m._parent_menu = nil;
|
||||||
|
m._is_menubar_item = 0;
|
||||||
|
|
||||||
m._setView(style.createWidget(parent, cfg.get("type", "menu-item"), cfg));
|
m._setView(style.createWidget(parent, cfg.get("type", "menu-item"), cfg));
|
||||||
|
|
||||||
|
@ -45,32 +53,34 @@ gui.MenuItem = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setMenu: func(menu) {
|
setMenu: func(menu) {
|
||||||
|
menu._parent_item = me;
|
||||||
|
menu._canvas_item = me._parent_menu._canvas_item;
|
||||||
me._menu = menu;
|
me._menu = menu;
|
||||||
|
|
||||||
return me.update();
|
return me.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
onClicked: func(e) {
|
onClicked: func(e) {
|
||||||
print("clicked", me._menu == nil, me._cb != nil);
|
|
||||||
if (!me._menu and me._cb) {
|
if (!me._menu and me._cb) {
|
||||||
me._cb(e);
|
me._cb(e);
|
||||||
}
|
}
|
||||||
|
if (me._parent_menu != nil) {
|
||||||
me._parent_menu.hide();
|
me._parent_menu.hide();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseEnter: func(e) {
|
onMouseEnter: func(e) {
|
||||||
print("entered item ", me._enabled);
|
|
||||||
for (var i = 0; i < me._parent_menu._layout.count(); i += 1) {
|
for (var i = 0; i < me._parent_menu._layout.count(); i += 1) {
|
||||||
var item = me._parent_menu._layout.itemAt(i);
|
var item = me._parent_menu._layout.itemAt(i);
|
||||||
item._hovered = 0;
|
item._hovered = 0;
|
||||||
if (item._menu) {
|
if (item._menu != nil) {
|
||||||
item._menu.hide();
|
item._menu.hide();
|
||||||
}
|
}
|
||||||
item.update();
|
item.update();
|
||||||
}
|
}
|
||||||
if (me._enabled) {
|
if (me._enabled) {
|
||||||
me._hovered = 1;
|
me._hovered = 1;
|
||||||
var x = e.screenX - e.localX + me.geometry()[2];
|
var x = e.screenX - e.localX;
|
||||||
var y = e.screenY - e.localY;
|
var y = e.screenY - e.localY;
|
||||||
me._showMenu(x, y);
|
me._showMenu(x, y);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +88,6 @@ gui.MenuItem = {
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseLeave: func(e) {
|
onMouseLeave: func(e) {
|
||||||
print("left item");
|
|
||||||
if (me._menu == nil) {
|
if (me._menu == nil) {
|
||||||
me._hovered = 0;
|
me._hovered = 0;
|
||||||
}
|
}
|
||||||
|
@ -92,10 +101,29 @@ gui.MenuItem = {
|
||||||
|
|
||||||
_showMenu: func(x, y) {
|
_showMenu: func(x, y) {
|
||||||
if (me._menu) {
|
if (me._menu) {
|
||||||
me._menu.setPosition(x, y);
|
var pos = [0, 0];
|
||||||
|
if (me._menu_position == gui.MenuItem.MenuPosition.Right) {
|
||||||
|
pos = [x + me.geometry()[2], y];
|
||||||
|
} elsif (me._menu_position == gui.MenuItem.MenuPosition.Below) {
|
||||||
|
pos = [x, me.geometry()[3] + y];
|
||||||
|
} elsif (me._menu_position == gui.MenuItem.MenuPosition.Above) {
|
||||||
|
pos = [x, y - me._menu.getSize()[1]];
|
||||||
|
} elsif (me._menu_position == gui.MenuItem.MenuPosition.Left) {
|
||||||
|
pos = [x - me._menu.getSize()[0], y];
|
||||||
|
}
|
||||||
|
me._menu.setPosition(pos[0], pos[1]);
|
||||||
me._menu.show();
|
me._menu.show();
|
||||||
me._menu.setFocus();
|
me._menu.setFocus();
|
||||||
}
|
}
|
||||||
|
me._hovered = 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideMenu: func {
|
||||||
|
if (me._menu) {
|
||||||
|
me._menu.clearFocus();
|
||||||
|
me._menu.hide();
|
||||||
|
}
|
||||||
|
me._hovered = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
setEnabled: func(enabled = 1) {
|
setEnabled: func(enabled = 1) {
|
||||||
|
@ -121,8 +149,15 @@ gui.MenuItem = {
|
||||||
_setParentMenu: func(m) {
|
_setParentMenu: func(m) {
|
||||||
me._parent_menu = m;
|
me._parent_menu = m;
|
||||||
if (me._parent_menu != nil and me._parent_menu._canvas_item != nil and me._cb != nil) {
|
if (me._parent_menu != nil and me._parent_menu._canvas_item != nil and me._cb != nil) {
|
||||||
|
if (me._shortcut != nil) {
|
||||||
me._parent_menu._canvas_item.bindShortcut(me._shortcut, me._cb);
|
me._parent_menu._canvas_item.bindShortcut(me._shortcut, me._cb);
|
||||||
}
|
}
|
||||||
|
if (me._menu != nil) {
|
||||||
|
for (var i = 0; i < me._menu.count(); i += 1) {
|
||||||
|
me._menu.getItem(i).setCanvasItem(me._parent_menu._canvas_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: func(icon) {
|
setIcon: func(icon) {
|
||||||
|
@ -137,7 +172,9 @@ gui.MenuItem = {
|
||||||
},
|
},
|
||||||
|
|
||||||
update: func {
|
update: func {
|
||||||
|
if (me._view != nil) {
|
||||||
me._view.update(me);
|
me._view.update(me);
|
||||||
|
}
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -158,6 +195,7 @@ gui.Menu = {
|
||||||
var m = gui.Popup.new([100, 60], id);
|
var m = gui.Popup.new([100, 60], id);
|
||||||
m.parents = [gui.Menu] ~ m.parents;
|
m.parents = [gui.Menu] ~ m.parents;
|
||||||
m.style = style;
|
m.style = style;
|
||||||
|
m._parent_item = nil;
|
||||||
|
|
||||||
m._canvas = m.createCanvas().setColorBackground(style.getColor("bg_color"));
|
m._canvas = m.createCanvas().setColorBackground(style.getColor("bg_color"));
|
||||||
m._root = m._canvas.createGroup();
|
m._root = m._canvas.createGroup();
|
||||||
|
@ -182,7 +220,7 @@ gui.Menu = {
|
||||||
addItem: func(item) {
|
addItem: func(item) {
|
||||||
item._setParentMenu(me);
|
item._setParentMenu(me);
|
||||||
me._layout.addItem(item);
|
me._layout.addItem(item);
|
||||||
me.setSize(me._layout.minimumSize()[0], me._layout.minimumSize()[1]);
|
me.setSize(math.max(me._layout.minimumSize()[0], 64), math.max(me._layout.minimumSize()[1], 24));
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -199,27 +237,39 @@ gui.Menu = {
|
||||||
}
|
}
|
||||||
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: cb, shortcut: shortcut, icon: icon, enabled: enabled});
|
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: cb, shortcut: shortcut, icon: icon, enabled: enabled});
|
||||||
me.addItem(item);
|
me.addItem(item);
|
||||||
return item;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
# @description Create, insert and return a `canvas.gui.MenuItem with the given text and assign the given submenu to it,
|
# @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
|
# optionally add the given icon and set the given enabled state
|
||||||
# @param text: str required 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 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)
|
# @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
|
||||||
addMenu: func(text = nil, menu = nil, icon = nil, enabled = 1) {
|
addMenu: func(text = nil, menu = 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");
|
||||||
}
|
}
|
||||||
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: nil, icon: icon, enabled: enabled});
|
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: nil, shortcut: nil, icon: nil, enabled: enabled});
|
||||||
|
menu._parent_item = item;
|
||||||
item.setMenu(menu);
|
item.setMenu(menu);
|
||||||
me.addItem(item);
|
me.addItem(item);
|
||||||
return item;
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
createMenu: func(text = nil, enabled = 1) {
|
||||||
|
if (text == nil) {
|
||||||
|
die("cannot create a submenu item without text");
|
||||||
|
}
|
||||||
|
var menu = gui.Menu.new();
|
||||||
|
var item = gui.MenuItem.new(me._root, me.style, {text: text, cb: nil, shortcut: nil, icon: nil, enabled: enabled});
|
||||||
|
menu._parent_item = item;
|
||||||
|
item.setMenu(menu);
|
||||||
|
me.addItem(item);
|
||||||
|
return menu;
|
||||||
},
|
},
|
||||||
|
|
||||||
# @description Remove all items from the menu
|
# @description Remove all items from the menu
|
||||||
|
@ -297,6 +347,14 @@ gui.Menu = {
|
||||||
call(me.parents[1].show, [], me);
|
call(me.parents[1].show, [], me);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hide: func {
|
||||||
|
if (me._parent_item != nil) {
|
||||||
|
me._parent_item._hovered = 0;
|
||||||
|
me._parent_item.update();
|
||||||
|
}
|
||||||
|
call(me.parents[1].hide, [], me);
|
||||||
|
},
|
||||||
|
|
||||||
# @description Destructor
|
# @description Destructor
|
||||||
del: func() {
|
del: func() {
|
||||||
me.hide();
|
me.hide();
|
||||||
|
|
73
Nasal/canvas/gui/MenuBar.nas
Normal file
73
Nasal/canvas/gui/MenuBar.nas
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
gui.MenuBar = {
|
||||||
|
new: func(id = nil) {
|
||||||
|
var m = canvas.Window.new([64, 24]);
|
||||||
|
m.parents = [gui.MenuBar] ~ m.parents;
|
||||||
|
|
||||||
|
m._canvas = m.createCanvas().setColorBackground(style.getColor("bg_color"));
|
||||||
|
m._root = m._canvas.createGroup();
|
||||||
|
m._layout = VBoxLayout.new();
|
||||||
|
m.setLayout(m._layout);
|
||||||
|
m._menubar = gui.widgets.MenuBar.new(m._root, style, {});
|
||||||
|
m._menubar.setCanvasItem(getDesktop());
|
||||||
|
m._layout.addItem(m._menubar);
|
||||||
|
m.setPosition(0, 0);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
},
|
||||||
|
|
||||||
|
addMenu: func(text = nil, menu = nil, enabled = 1) {
|
||||||
|
var item = me._menubar.addMenu(text, menu, enabled);
|
||||||
|
me.setSize(math.max(me._layout.sizeHint()[0], 64), math.max(me._layout.sizeHint()[1], 24));
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
createMenu: func(text = nil, enabled = 1) {
|
||||||
|
var menu = me._menubar.createMenu(text, enabled);
|
||||||
|
me.setSize(math.max(me._layout.sizeHint()[0], 64), math.max(me._layout.sizeHint()[1], 24));
|
||||||
|
return menu;
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: func {
|
||||||
|
me._menubar.clear();
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMenu: func(item) {
|
||||||
|
me._menubar.removeMenu(item);
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
takeAt: func(index) {
|
||||||
|
return me._menubar.takeAt(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
count: func() {
|
||||||
|
return me._menubar.count();
|
||||||
|
},
|
||||||
|
|
||||||
|
getItem: func(index) {
|
||||||
|
return me._menubar.getItem(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMenu: func(index) {
|
||||||
|
return me._menubar.getMenu(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
show: func(x = nil, y = nil) {
|
||||||
|
if (x != nil and y != nil) {
|
||||||
|
me.setPosition(x, y);
|
||||||
|
}
|
||||||
|
me._ghost.show();
|
||||||
|
me.raise();
|
||||||
|
if (me._canvas != nil) {
|
||||||
|
me._canvas.update();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
del: func() {
|
||||||
|
me.hide();
|
||||||
|
me._menubar.clear();
|
||||||
|
me._canvas.del();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -7,10 +7,6 @@ gui.Popup = {
|
||||||
#
|
#
|
||||||
# @param size ([width, height])
|
# @param size ([width, height])
|
||||||
new: func(size_, id = nil, parent = nil) {
|
new: func(size_, id = nil, parent = nil) {
|
||||||
if (id == nil or contains(gui.Popup.__used_ids, id)) {
|
|
||||||
id = "popup" ~ size(gui.Popup.__used_ids);
|
|
||||||
}
|
|
||||||
append(gui.Popup.__used_ids, id);
|
|
||||||
var ghost = _newWindowGhost(id);
|
var ghost = _newWindowGhost(id);
|
||||||
var m = {
|
var m = {
|
||||||
parents: [gui.Popup, PropertyElement, ghost],
|
parents: [gui.Popup, PropertyElement, ghost],
|
||||||
|
@ -127,7 +123,6 @@ gui.Popup = {
|
||||||
me._focused = 1;
|
me._focused = 1;
|
||||||
me._onStateChange();
|
me._onStateChange();
|
||||||
gui.focused_window = me;
|
gui.focused_window = me;
|
||||||
setInputFocus(me);
|
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
#
|
#
|
||||||
|
@ -137,7 +132,6 @@ gui.Popup = {
|
||||||
me._onStateChange();
|
me._onStateChange();
|
||||||
if (gui.focused_window == me) {
|
if (gui.focused_window == me) {
|
||||||
gui.focused_window = nil;
|
gui.focused_window = nil;
|
||||||
setInputFocus(nil);
|
|
||||||
}
|
}
|
||||||
if (me._parent != nil and contains(gui.open_popups, me._parent)) {
|
if (me._parent != nil and contains(gui.open_popups, me._parent)) {
|
||||||
me._parent.setFocus();
|
me._parent.setFocus();
|
||||||
|
|
|
@ -866,12 +866,12 @@ DefaultStyle.widgets["menu-item"] = {
|
||||||
me._label = me._root.createChild("text")
|
me._label = me._root.createChild("text")
|
||||||
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
|
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
|
||||||
.set("character-size", 14)
|
.set("character-size", 14)
|
||||||
.set("alignment", "left-center");
|
.set("alignment", "left-baseline");
|
||||||
|
|
||||||
me._shortcut = me._root.createChild("text")
|
me._shortcut = me._root.createChild("text")
|
||||||
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
|
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
|
||||||
.set("character-size", 14)
|
.set("character-size", 14)
|
||||||
.set("alignment", "right-center");
|
.set("alignment", "right-baseline");
|
||||||
|
|
||||||
me._submenu_indicator = me._root.createChild("path")
|
me._submenu_indicator = me._root.createChild("path")
|
||||||
.vert(12).line(6, -7).close();
|
.vert(12).line(6, -7).close();
|
||||||
|
@ -879,15 +879,29 @@ DefaultStyle.widgets["menu-item"] = {
|
||||||
|
|
||||||
setSize: func(model, w, h) {
|
setSize: func(model, w, h) {
|
||||||
me._bg.reset().rect(0, 0, w, h);
|
me._bg.reset().rect(0, 0, w, h);
|
||||||
me._icon.setTranslation(3, int((h - 12) / 2));
|
var offset = 0;
|
||||||
me._label.setTranslation(24, int(h / 2) + 1);
|
if (!model._is_menubar_item) {
|
||||||
me._shortcut.setTranslation(w - 3, int(h / 2) + 1);
|
offset += 5 + 18;
|
||||||
me._submenu_indicator.setTranslation(w - 15, int((h - 12) / 2));
|
}
|
||||||
|
me._icon.setTranslation(5, int((h - 12) / 2));
|
||||||
|
me._label.setTranslation(offset + 5, int(h / 2) + 4);
|
||||||
|
me._shortcut.setTranslation(w - 5, int(h / 2) + 4);
|
||||||
|
me._submenu_indicator.setTranslation(w - 12, int((h - 12) / 2));
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLayoutSizes: func(model) {
|
_updateLayoutSizes: func(model) {
|
||||||
var min_width = 3 + 18 + 3 + me._label.maxWidth() + 3 + me._shortcut.maxWidth() + 3 + 12 + 3;
|
var min_width = 5 + me._label.maxWidth() + 5;
|
||||||
|
if (!model._is_menubar_item) {
|
||||||
|
# add icon space
|
||||||
|
min_width += 5 + 18;
|
||||||
|
# add shortcut space
|
||||||
|
min_width += me._shortcut.maxWidth() + 10;
|
||||||
|
if (model._menu != nil) {
|
||||||
|
# add submenu indicator space
|
||||||
|
min_width += 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
model.setLayoutMinimumSize([min_width, 24]);
|
model.setLayoutMinimumSize([min_width, 24]);
|
||||||
model.setLayoutSizeHint([min_width, 24]);
|
model.setLayoutSizeHint([min_width, 24]);
|
||||||
|
|
||||||
|
@ -927,13 +941,35 @@ DefaultStyle.widgets["menu-item"] = {
|
||||||
me._shortcut.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" : "")));
|
me._submenu_indicator.set("fill", me._style.getColor("menu_item_submenu_indicator" ~ (model._hovered ? "_hovered" : "")));
|
||||||
if (model._menu != nil) {
|
if (model._menu != nil) {
|
||||||
|
if (!model._is_menubar_item) {
|
||||||
me._submenu_indicator.show();
|
me._submenu_indicator.show();
|
||||||
|
}
|
||||||
me._shortcut.hide();
|
me._shortcut.hide();
|
||||||
} else {
|
} else {
|
||||||
me._submenu_indicator.hide();
|
me._submenu_indicator.hide();
|
||||||
me._shortcut.show();
|
me._shortcut.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultStyle.widgets["menu-bar"] = {
|
||||||
|
new: func(parent, cfg) {
|
||||||
|
me._root = parent.createChild("group", "menu-bar");
|
||||||
|
me._bg = me._root.createChild("path");
|
||||||
|
me._items = me._root.createChild("group", "tab-widget-content");
|
||||||
|
},
|
||||||
|
|
||||||
|
setSize: func(model, w, h) {
|
||||||
|
me._bg.reset().rect(0, 0, w, h);
|
||||||
|
me._items.setTranslation(0, 0);
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: func(model) {
|
||||||
|
me._bg.set("fill", me._style.getColor("bg_color"));
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
164
Nasal/canvas/gui/widgets/MenuBar.nas
Normal file
164
Nasal/canvas/gui/widgets/MenuBar.nas
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
# MenuBar.nas - a menu bar that can be added as a normal widget to a layout
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: (C) 2022 Frederic Croix <thefgfseagle@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
gui.widgets.MenuBar = {
|
||||||
|
new: func(parent, style, cfg) {
|
||||||
|
var m = gui.Widget.new(gui.widgets.MenuBar);
|
||||||
|
m._cfg = Config.new(cfg);
|
||||||
|
m._focus_policy = m.NoFocus;
|
||||||
|
|
||||||
|
m._setView(style.createWidget(parent, "menu-bar", m._cfg));
|
||||||
|
|
||||||
|
m._layout = HBoxLayout.new();
|
||||||
|
m._layout.setSpacing(0);
|
||||||
|
m._layout.setCanvas(m._view._root.getCanvas());
|
||||||
|
m._canvas_item = nil;
|
||||||
|
|
||||||
|
m.setLayoutMinimumSize([48, 24]);
|
||||||
|
m.setLayoutSizeHint([64, 24]);
|
||||||
|
|
||||||
|
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 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: 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 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 = nil, menu = 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._view._items, style,
|
||||||
|
{
|
||||||
|
text: text, cb: nil, shortcut: nil, icon: nil, enabled: enabled,
|
||||||
|
menu_position: gui.MenuItem.MenuPosition.Below,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
item._is_menubar_item = 1;
|
||||||
|
item._view._updateLayoutSizes(item);
|
||||||
|
item._setParentMenu(me);
|
||||||
|
item.setMenu(menu);
|
||||||
|
me._layout.addItem(item);
|
||||||
|
me.setSize(math.max(me._layout.minimumSize()[0], 64), math.max(me._layout.minimumSize()[1], 24));
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
createMenu: func(text = nil, enabled = 1) {
|
||||||
|
if (text == nil) {
|
||||||
|
die("cannot create a submenu item without text");
|
||||||
|
}
|
||||||
|
var menu = gui.Menu.new();
|
||||||
|
me.addMenu(text, menu, enabled);
|
||||||
|
return menu;
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description Remove all items from the menu
|
||||||
|
# @return canvas.gui.Menu Return me to enable method chaining
|
||||||
|
clear: func {
|
||||||
|
me._layout.clear();
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description If `item` is a `canvas.gui.Widget`, remove the given `canvas.gui.Widget` from the menu
|
||||||
|
# Else assume `item` to be a scalar and try to find an item of the menu that has a `getText` method
|
||||||
|
# and whose result of calling its `getText` method equals `item` and remove that item
|
||||||
|
# @param item: Union[str, canvas.gui.Widget] required The widget or the text of the menu item to remove
|
||||||
|
removeMenu: func(item) {
|
||||||
|
if (isa(item, gui.Widget)) {
|
||||||
|
me._layout.removeItem(item);
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < me._layout.count(); i += 1) {
|
||||||
|
if (me._layout.itemAt(i)["getText"] != nil and me._layout.itemAt(i).getText() == item) {
|
||||||
|
me._layout.takeAt(i);
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die("No menu with given text '" ~ item ~ "' found, could not remove !");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description If `index` is an integer, remove and return the item at the given `index`
|
||||||
|
# Else assume `item` to be a scalar and try to find an item of the menu that has a `getText` method
|
||||||
|
# and whose result of calling its `getText` method equals `item` and remove and return that item
|
||||||
|
# @param index: Union[int, str] required The index or text of the menu item to remove
|
||||||
|
# @return canvas.gui.Widget The item with given text `index` or at the given position `index`
|
||||||
|
takeAt: func(index) {
|
||||||
|
if (isint(index)) {
|
||||||
|
return me._layout.takeAt(index);
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < me._layout.count(); i += 1) {
|
||||||
|
if (me._layout.itemAt(i)["getText"] != nil and me._layout.itemAt(i).getText() == index) {
|
||||||
|
return me._layout.takeAt(i)._menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die("No menu with given text '" ~ index ~ "' found, could not remove !");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description Count the items of the menu
|
||||||
|
# @return int Number of items
|
||||||
|
count: func() {
|
||||||
|
return me._layout.count();
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description If `index` is an integer, eturn the item at the given `index`
|
||||||
|
# Else assume `item` to be a scalar and try to find an item of the menu that has a `getText` method
|
||||||
|
# and whose result of calling its `getText` method equals `item` and eturn that item
|
||||||
|
# @param index: Union[int, str] required The index or text of the menu item to return
|
||||||
|
# @return canvas.gui.Widget The item with given text `index` or at the given position `index`
|
||||||
|
getItem: func(index) {
|
||||||
|
if (isint(index)) {
|
||||||
|
return me._layout.itemAt(index);
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < me._layout.count(); i += 1) {
|
||||||
|
if (me._layout.itemAt(i)["getText"] != nil and me._layout.itemAt(i).getText() == index) {
|
||||||
|
return me._layout.itemAt(i)._menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die("No menu item with given text '" ~ index ~ "' found, could not remove !");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getMenu: func(index) {
|
||||||
|
return me.getItem(index)._menu;
|
||||||
|
},
|
||||||
|
|
||||||
|
setSize: func {
|
||||||
|
if (size(arg) == 1) {
|
||||||
|
var arg = arg[0];
|
||||||
|
}
|
||||||
|
var (x, y) = arg;
|
||||||
|
me._size = [x, y];
|
||||||
|
me.setLayoutMinimumSize([x, y]);
|
||||||
|
me.setLayoutSizeHint([x, y]);
|
||||||
|
return me.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
# @description Update the menu and its items
|
||||||
|
update: func() {
|
||||||
|
if(me._layout.getParent() == nil) {
|
||||||
|
me._layout.setParent(me);
|
||||||
|
}
|
||||||
|
|
||||||
|
me._layout.setGeometry([0, 0, me._size[0], me._size[1]]);
|
||||||
|
me._view.setSize(me, me._size[0], me._size[1]);
|
||||||
|
me._view.update(me);
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -433,6 +433,7 @@ var Binding = {
|
||||||
},
|
},
|
||||||
|
|
||||||
fire: func(e) {
|
fire: func(e) {
|
||||||
|
debug.dump(e);
|
||||||
if (isfunc(me.f)) {
|
if (isfunc(me.f)) {
|
||||||
me.f(e);
|
me.f(e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue