From eebff4fbbac489f96954f05d6d0d838c62a8e6c7 Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 4 Jul 2018 22:50:39 -0300 Subject: An assortment of changes to how selected/unselected works --- ui/Root.js | 77 ++++++++++++++++++++++++++++++++++------------ ui/form/CancelDialog.js | 2 +- ui/form/ConfirmDialog.js | 2 +- ui/form/FocusElement.js | 8 ++--- ui/form/Form.js | 6 ++-- ui/tools/OpenFileDialog.js | 2 +- 6 files changed, 68 insertions(+), 29 deletions(-) diff --git a/ui/Root.js b/ui/Root.js index 16b2fc2..a6b3acf 100644 --- a/ui/Root.js +++ b/ui/Root.js @@ -13,7 +13,7 @@ module.exports = class Root extends DisplayElement { this.interfacer = interfacer - this.selected = null + this.selectedElement = null this.cursorBlinkOffset = Date.now() @@ -25,8 +25,9 @@ module.exports = class Root extends DisplayElement { } handleData(buffer) { - if (this.selected) { - const els = this.selected.directAncestors.concat([this.selected]) + if (this.selectedElement) { + const els = [ + ...this.selectedElement.directAncestors, this.selectedElement] for (const el of els) { if (el instanceof FocusElement) { const shouldBreak = (el.keyPressed(buffer) === false) @@ -47,25 +48,21 @@ module.exports = class Root extends DisplayElement { didRenderTo(writable) { // Render the cursor, based on the cursorX and cursorY of the currently // selected element. - if (this.selected && this.selected.cursorVisible) { + if (this.selectedElement && this.selectedElement.cursorVisible) { if ((Date.now() - this.cursorBlinkOffset) % 1000 < 500) { - writable.write( - ansi.moveCursor(this.selected.absCursorY, this.selected.absCursorX) - ) + writable.write(ansi.moveCursor( + this.selectedElement.absCursorY, this.selectedElement.absCursorX)) writable.write(ansi.invert()) writable.write('I') writable.write(ansi.resetAttributes()) } writable.write(ansi.showCursor()) - writable.write( - ansi.moveCursor(this.selected.absCursorY, this.selected.absCursorX) - ) + writable.write(ansi.moveCursor( + this.selectedElement.absCursorY, this.selectedElement.absCursorX)) } else { writable.write(ansi.hideCursor()) } - - if (this.selected && this.selected.cursorVisible) {} } cursorMoved() { @@ -79,20 +76,60 @@ module.exports = class Root extends DisplayElement { // Select an element. Calls the unfocus method on the already-selected // element, if there is one. - if (this.selected) { - this.selected.unfocused() - } + const oldSelected = this.selectedElement + const newSelected = el + + // Relevant elements that COULD have their "isSelected" state change. + // We ignore elements where isSelected is undefined, because they aren't + // build to handle being selected, and they break the compare-old-and-new- + // state code below. + const relevantElements = [ + ...(oldSelected ? [...oldSelected.directAncestors, oldSelected] : []), + ...(newSelected ? newSelected.directAncestors : []) + ].filter(el => typeof el.isSelected !== 'undefined') + + const oldStates = relevantElements.map(el => [el, el.isSelected]) + + this.selectedElement = el + + // Same stuff as in the for loop below. We always call selected() on the + // passed element, even if it was already selected before. + if (el.selected) el.selected() + if (typeof el.focused === 'function') el.focused() + if (this.selectedElement !== newSelected) return + + // Compare the old "isSelected" state of every relevant element with their + // current "isSelected" state, and call the respective selected/unselected + // functions. (Also call focused and unfocused for some sense of trying to + // not break old programs, but, like, old programs are going to be broken + // anyways.) + for (const [ el, wasSelected ] of oldStates) { + const { isSelected } = el + if (isSelected && !wasSelected) { + if (el.selected) el.selected() + if (typeof el.focused === 'function') el.focused() + } else if (wasSelected && !isSelected) { + if (el.unselected) el.unselected() + if (typeof el.unfocused === 'function') el.unfocused() + } - this.selected = el - this.selected.focused() + // If the (un)selected() handler actually selected a different element + // itself, then further processing of new selected states is irrelevant, + // so stop here. (We return instead of breaking the for loop because + // anything after this loop would have already been handled by the call + // to Root.select() from the (un)selected() handler.) + if (this.selectedElement !== newSelected) { + return + } + } this.cursorMoved() } isChildOrSelfSelected(el) { - if (!this.selected) return false - if (this.selected === el) return true - if (this.selected.directAncestors.includes(el)) return true + if (!this.selectedElement) return false + if (this.selectedElement === el) return true + if (this.selectedElement.directAncestors.includes(el)) return true return false } } diff --git a/ui/form/CancelDialog.js b/ui/form/CancelDialog.js index c5eb7d3..21ff6df 100644 --- a/ui/form/CancelDialog.js +++ b/ui/form/CancelDialog.js @@ -47,7 +47,7 @@ module.exports = class ConfirmDialog extends FocusElement { this.cancelBtn.y = this.pane.contentH - 2 } - focused() { + selected() { this.root.select(this.cancelBtn) } diff --git a/ui/form/ConfirmDialog.js b/ui/form/ConfirmDialog.js index 3614cf9..230230d 100644 --- a/ui/form/ConfirmDialog.js +++ b/ui/form/ConfirmDialog.js @@ -59,7 +59,7 @@ module.exports = class ConfirmDialog extends FocusElement { this.cancelBtn.y = this.form.contentH - 2 } - focused() { + selected() { this.root.select(this.form) } diff --git a/ui/form/FocusElement.js b/ui/form/FocusElement.js index 9061838..23c2e02 100644 --- a/ui/form/FocusElement.js +++ b/ui/form/FocusElement.js @@ -11,11 +11,11 @@ module.exports = class FocusElement extends DisplayElement { this.cursorY = 0 } - focused() { + selected() { // Should be overridden in subclasses. } - unfocused() { + unselected() { // Should be overridden in subclasses. } @@ -36,8 +36,8 @@ module.exports = class FocusElement extends DisplayElement { } get isSelected() { - const selected = this.root.selected - return selected && [selected, ...selected.directAncestors].includes(this) + const selected = this.root.selectedElement + return !!(selected && [selected, ...selected.directAncestors].includes(this)) } get absCursorX() { return this.absX + this.cursorX } diff --git a/ui/form/Form.js b/ui/form/Form.js index 87763bb..ac9f1e4 100644 --- a/ui/form/Form.js +++ b/ui/form/Form.js @@ -117,7 +117,9 @@ module.exports = class Form extends FocusElement { } } - focused() { - this.updateSelectedElement() + selected() { + if (this.root.selectedElement === this) { + this.updateSelectedElement() + } } } diff --git a/ui/tools/OpenFileDialog.js b/ui/tools/OpenFileDialog.js index 92bd4af..43f2638 100644 --- a/ui/tools/OpenFileDialog.js +++ b/ui/tools/OpenFileDialog.js @@ -90,7 +90,7 @@ module.exports = class OpenFileDialog extends Dialog { this.cancelButton.y = this.openButton.y } - focused() { + selected() { this.form.firstInput() } -- cgit 1.3.0-6-gf8a5