« get me outta code hell

tui-lib - Pure Node.js library for making visual command-line programs (ala vim, ncdu)
about summary refs log tree commit diff
path: root/ui/form/ListScrollForm.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/form/ListScrollForm.js')
-rw-r--r--ui/form/ListScrollForm.js32
1 files changed, 30 insertions, 2 deletions
diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js
index 892f964..d748d40 100644
--- a/ui/form/ListScrollForm.js
+++ b/ui/form/ListScrollForm.js
@@ -312,12 +312,40 @@ class ScrollBar extends DisplayElement {
     const totalLength = this.h - 2
     const totalScroll = this.listScrollForm.getScrollItemsLength()
     const currentScroll = this.listScrollForm.scrollItems
-    const handlePosition = Math.floor(totalLength / (totalScroll + 1) * currentScroll)
-    const handleLength = totalLength / (totalScroll + 1)
+
+    // ..[-----]..
+    //   ^start|
+    //         ^end
+    //
+    // Start and end should correspond to how much of the scroll area
+    // is currently visible. So, if you can see 60% of the full scroll length
+    // at a time, and you are scrolled 10% down, the start position of the
+    // handle should be 10% down, and it should extend 60% of the scrollbar
+    // length, to the 70% mark.
+
+    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
+    // visible space indicating that you can scroll in that direction
+    // (in addition to the arrows we show at the ends).
+
+    if (canScrollBackwards && handlePosition === 0) {
+      handlePosition = 1
+    }
+
+    if (canScrollForwards && (handlePosition + handleLength) === edgeLength) {
+      handlePosition--
+    }
+
     if (this.listScrollForm.layoutType === 'vertical') {
       const start = this.absTop + handlePosition + 1
       for (let i = 0; i < handleLength; i++) {