« get me outta code hell

Make ScrollBar an independent and published class - 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:
authorFlorrie <towerofnix@gmail.com>2019-10-17 12:57:24 -0300
committerFlorrie <towerofnix@gmail.com>2019-10-17 12:57:24 -0300
commit742d2543b88ad4cbb2fc9a859f093a57f32c1967 (patch)
tree9db69ace2691ee3fe8880800f7049ce4c22fb70c /ui/form/ListScrollForm.js
parentf1cc65d376141fa5e76878ffd3da4392f8a7c747 (diff)
Make ScrollBar an independent and published class
It's no longer strictly connected to a ListScrollForm, and is published,
so it's much easier to use as an element from the tui-lib API in any
project now.
Diffstat (limited to 'ui/form/ListScrollForm.js')
-rw-r--r--ui/form/ListScrollForm.js115
1 files changed, 7 insertions, 108 deletions
diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js
index 78c376f..72e79df 100644
--- a/ui/form/ListScrollForm.js
+++ b/ui/form/ListScrollForm.js
@@ -1,9 +1,8 @@
 const ansi = require('../../util/ansi')
 const telc = require('../../util/telchars')
-const unic = require('../../util/unichars')
 
-const DisplayElement = require('../DisplayElement')
 const Form = require('./Form')
+const ScrollBar = require('./ScrollBar')
 
 module.exports = class ListScrollForm extends Form {
   // A form that lets the user scroll through a list of items. It
@@ -21,7 +20,12 @@ module.exports = class ListScrollForm extends Form {
 
     this.scrollBarEnabled = enableScrollBar
 
-    this.scrollBar = new ScrollBar(this)
+    this.scrollBar = new ScrollBar({
+      getLayoutType: () => this.layoutType,
+      getCurrentScroll: () => this.scrollItems,
+      getMaximumScroll: () => this.getScrollItemsLength(),
+      getTotalItems: () => this.inputs.length
+    })
     this.scrollBarShown = false
   }
 
@@ -297,108 +301,3 @@ module.exports = class ListScrollForm extends Form {
     }
   }
 }
-
-class ScrollBar extends DisplayElement {
-  constructor(listScrollForm) {
-    super()
-
-    this.listScrollForm = listScrollForm
-  }
-
-  fixLayout() {
-    // Normally we'd subtract one from contentW/contentH when setting the x/y
-    // position, but the scrollbar is actually displayed OUTSIDE of (adjacent
-    // to) the parent's content area.
-    if (this.listScrollForm.layoutType === 'vertical') {
-      this.h = this.listScrollForm.contentH
-      this.w = 1
-      this.x = this.listScrollForm.contentW
-      this.y = 0
-    } else {
-      this.h = 1
-      this.w = this.listScrollForm.contentW
-      this.x = 0
-      this.y = this.listScrollForm.contentH
-    }
-  }
-
-  drawTo(writable) {
-    // Uuuurgh
-    this.fixLayout()
-
-    // 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
-
-    // ..[-----]..
-    //   ^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 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)
-
-    // 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++) {
-        writable.write(ansi.moveCursor(start + i, this.absLeft))
-        writable.write(unic.BOX_V_DOUBLE)
-      }
-
-      if (canScrollBackwards) {
-        writable.write(ansi.moveCursor(this.absTop, this.absLeft))
-        writable.write(unic.ARROW_UP_DOUBLE)
-      }
-
-      if (canScrollForwards) {
-        writable.write(ansi.moveCursor(this.absBottom, this.absLeft))
-        writable.write(unic.ARROW_DOWN_DOUBLE)
-      }
-    }
-  }
-
-  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
-  }
-}