From d569cc0db9994295860f48d254f630211c1806ad Mon Sep 17 00:00:00 2001 From: Florrie Date: Sun, 12 May 2019 17:17:53 -0300 Subject: Automatically show/hide ListScrollForm scrollbar ...depending on whether there is enough content that it cannot all be displayed in the form's space or not. --- ui/form/ListScrollForm.js | 53 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'ui') diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js index d748d40..64214ab 100644 --- a/ui/form/ListScrollForm.js +++ b/ui/form/ListScrollForm.js @@ -8,19 +8,21 @@ const Form = require('./Form') module.exports = class ListScrollForm extends Form { // A form that lets the user scroll through a list of items. It // automatically adjusts to always allow the selected item to be visible. + // Unless disabled in the constructor, a scrollbar is automatically displayed + // if there are more items than can be shown in the height of the form at a + // single time. - constructor(layoutType = 'vertical', scrollBarShown = true) { + constructor(layoutType = 'vertical', enableScrollBar = true) { super() this.layoutType = layoutType this.scrollItems = 0 + this.scrollBarEnabled = enableScrollBar + this.scrollBar = new ScrollBar(this) - this.scrollBarShown = scrollBarShown - if (scrollBarShown) { - this.addChild(this.scrollBar) - } + this.scrollBarShown = false } fixLayout() { @@ -79,6 +81,10 @@ module.exports = class ListScrollForm extends Form { } delete this._scrollItemsLength + + if (this.scrollBarEnabled) { + this.showScrollbarIfNecessary() + } } keyPressed(keyBuf) { @@ -245,6 +251,17 @@ module.exports = class ListScrollForm extends Form { return pos } + showScrollbarIfNecessary() { + this.scrollBarShown = this.scrollBar.canScrollAtAll() + + const isChild = this.children.includes(this.scrollBar) + if (this.scrollBarShown) { + if (!isChild) this.addChild(this.scrollBar) + } else { + if (isChild) this.removeChild(this.scrollBar) + } + } + get scrollSize() { // Gets the actual length made up by all of the items currently scrolled // past. @@ -308,10 +325,13 @@ class ScrollBar extends DisplayElement { // TODO: Horizontal layout! Not functionally a lot different, but I'm too // lazy to write a test UI for it right now. + const { + backwards: canScrollBackwards, + forwards: canScrollForwards + } = this.getScrollableDirections() + // - 2 for extra UI elements (arrows) const totalLength = this.h - 2 - const totalScroll = this.listScrollForm.getScrollItemsLength() - const currentScroll = this.listScrollForm.scrollItems // ..[-----].. // ^start| @@ -323,15 +343,13 @@ class ScrollBar extends DisplayElement { // handle should be 10% down, and it should extend 60% of the scrollbar // length, to the 70% mark. + const currentScroll = this.listScrollForm.scrollItems const edgeLength = this.listScrollForm.contentH const totalItems = this.listScrollForm.inputs.length const itemsVisibleAtOnce = Math.min(totalItems, edgeLength) const handleLength = itemsVisibleAtOnce / totalItems * totalLength let handlePosition = Math.floor(totalLength / totalItems * currentScroll) - const canScrollBackwards = (currentScroll > 0) - const canScrollForwards = (currentScroll < totalScroll) - // Silly peeve of mine: The handle should only be visibly touching the top // or bottom of the scrollbar area if you're actually scrolled all the way // to the start or end. Otherwise, it shouldn't be touching! There should @@ -364,4 +382,19 @@ class ScrollBar extends DisplayElement { } } } + + getScrollableDirections() { + const currentScroll = this.listScrollForm.scrollItems + const totalScroll = this.listScrollForm.getScrollItemsLength() + + return { + backwards: (currentScroll > 0), + forwards: (currentScroll < totalScroll) + } + } + + canScrollAtAll() { + const {backwards, forwards} = this.getScrollableDirections() + return backwards || forwards + } } -- cgit 1.3.0-6-gf8a5