From c814d5d140ea2383b7b1719a31abf731753c3fd6 Mon Sep 17 00:00:00 2001 From: Florrie Date: Sun, 25 Aug 2019 19:33:57 -0300 Subject: Submenu support, add inline list picker dropdown --- ui.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/ui.js b/ui.js index 5371b56..840c7ee 100644 --- a/ui.js +++ b/ui.js @@ -256,7 +256,7 @@ class AppElement extends FocusElement { {value: 'end', label: 'At end of queue'}, {value: 'distribute-evenly', label: 'Distributed across queue evenly'}, {value: 'distribute-randomly', label: 'Distributed across queue randomly'} - ]) + ], this.showContextMenu) this.orderControl = new InlineListPickerElement('Order?', [ {value: 'shuffle', label: 'Shuffle all'}, @@ -264,7 +264,7 @@ class AppElement extends FocusElement { {value: 'reverse', label: 'Reverse all'}, {value: 'reverse-groups', label: 'Reverse order of groups'}, {value: 'normal', label: 'In order'} - ]) + ], this.showContextMenu) this.menubar.buildItems([ {text: 'mtui', menuItems: [ @@ -494,8 +494,11 @@ class AppElement extends FocusElement { } showContextMenu(opts) { - const menu = new ContextMenu() + const menu = new ContextMenu(this.showContextMenu) this.menuLayer.addChild(menu) + if (opts.beforeShowing) { + opts.beforeShowing(menu) + } menu.show(opts) return menu } @@ -1754,10 +1757,11 @@ class InlineListPickerElement extends FocusElement { // next or previous. (That's the point, it's inline.) This element is mainly // useful in forms or ContextMenus. - constructor(labelText, options) { + constructor(labelText, options, showContextMenu = null) { super() this.labelText = labelText this.options = options + this.showContextMenu = showContextMenu this.curIndex = 0 this.keyboardIdentifier = this.labelText } @@ -1809,6 +1813,17 @@ class InlineListPickerElement extends FocusElement { this.nextOption() } else if (telc.isLeft(keyBuf)) { this.previousOption() + } else if (input.isMenu(keyBuf) && this.showContextMenu) { + this.showContextMenu({ + x: this.absLeft + ansi.measureColumns(this.labelText) + 1, + y: this.absTop + 1, + items: this.options.map(({ value, label }, index) => ({ + label: label, + action: () => { + this.curIndex = index + } + })) + }) } else { return true } @@ -2886,7 +2901,7 @@ class TabberListItem extends FocusElement { } class ContextMenu extends FocusElement { - constructor() { + constructor(showContextMenu) { super() this.pane = new Pane() @@ -2898,6 +2913,10 @@ class ContextMenu extends FocusElement { this.keyboardSelector = new KeyboardSelector(this.form) this.visible = false + + this.showContextMenu = showContextMenu + this.showSubmenu = this.showSubmenu.bind(this) + this.submenu = null } show({x = 0, y = 0, items}) { @@ -2906,10 +2925,9 @@ class ContextMenu extends FocusElement { return } - // This *should* work with a menu action which opens the menu again, - // because the selected element will be restored before the menu is - // opened the second time. - this.selectedBefore = this.root.selectedElement + if (!this.root.selectedElement.directAncestors.includes(this)) { + this.selectedBefore = this.root.selectedElement + } this.clearItems() @@ -2932,6 +2950,7 @@ class ContextMenu extends FocusElement { if (item.element) { addDividerIfWanted() this.form.addInput(item.element) + item.element.showContextMenu = this.showSubmenu } else if (item.divider) { wantDivider = true } else { @@ -2955,6 +2974,21 @@ class ContextMenu extends FocusElement { this.keyboardSelector.reset() } + showSubmenu(opts) { + this.showContextMenu(Object.assign({}, opts, { + // We need to get a reference to the submenu before it is shown, or else + // the parent menu will be closed (from being unselected and not knowing + // that a submenu was just opened). + beforeShowing: menu => { + this.submenu = menu + } + })) + + this.submenu.on('close', () => { + this.submenu = null + }) + } + keyPressed(keyBuf) { if (telc.isEscape(keyBuf) || telc.isBackspace(keyBuf)) { this.close() @@ -2966,7 +3000,12 @@ class ContextMenu extends FocusElement { } unselected() { - this.selectedBefore = this.root.selectedElement + // Don't close if we just opened a submenu! + const newEl = this.root.selectedElement + if (this.submenu && newEl.directAncestors.includes(this.submenu)) { + return + } + if (this.visible) { this.close() } -- cgit 1.3.0-6-gf8a5