« 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/Root.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/Root.js')
-rw-r--r--ui/Root.js65
1 files changed, 61 insertions, 4 deletions
diff --git a/ui/Root.js b/ui/Root.js
index 8242f7a..fd81fed 100644
--- a/ui/Root.js
+++ b/ui/Root.js
@@ -9,10 +9,11 @@ module.exports = class Root extends DisplayElement {
   // An element to be used as the root of a UI. Handles lots of UI and
   // socket stuff.
 
-  constructor(interfacer) {
+  constructor(interfacer, writable = null) {
     super()
 
     this.interfacer = interfacer
+    this.writable = writable || interfacer
 
     this.selectedElement = null
 
@@ -21,10 +22,8 @@ module.exports = class Root extends DisplayElement {
     this.oldSelectionStates = []
 
     interfacer.on('inputData', buf => this.handleData(buf))
-  }
 
-  render() {
-    this.renderTo(this.interfacer)
+    this.renderCount = 0
   }
 
   handleData(buffer) {
@@ -74,7 +73,60 @@ module.exports = class Root extends DisplayElement {
     writable.write(' '.repeat(this.w * this.h))
   }
 
+  scheduleRender() {
+    if (!this.scheduledRender) {
+      setTimeout(() => {
+        this.scheduledRender = false
+        this.render()
+      })
+      this.scheduledRender = true
+    }
+  }
+
+  render() {
+    this.renderTo(this.writable)
+  }
+
+  renderNow() {
+    this.renderNowTo(this.writable)
+  }
+
+  renderTo(writable) {
+    if (this.shouldRenderTo(writable)) {
+      this.renderNowTo(writable)
+    }
+  }
+
+  renderNowTo(writable) {
+    if (writable) {
+      this.renderCount++
+      super.renderTo(writable)
+    }
+  }
+
+  shouldRenderTo(writable) {
+    let render = false
+    this.eachDescendant(el => {
+      // If we already know we're going to render, checking the element's
+      // scheduled-draw status (which involves iterating over each of its draw
+      // dependency properties) is redundant.
+      if (render) {
+        el.unscheduleDraw()
+      } else if (el.hasScheduledDraw()) {
+        render = true
+        el.unscheduleDraw()
+      }
+      el.updateLastDrawValues()
+    })
+    return render
+  }
+
   didRenderTo(writable) {
+    /*
+    writable.write(ansi.moveCursorRaw(1, 1))
+    writable.write('Renders: ' + this.renderCount)
+    */
+
     // Render the cursor, based on the cursorX and cursorY of the currently
     // selected element.
     if (this.selectedElement && this.selectedElement.cursorVisible) {
@@ -94,6 +146,8 @@ module.exports = class Root extends DisplayElement {
     } else {
       writable.write(ansi.hideCursor())
     }
+
+    this.emit('rendered')
   }
 
   cursorMoved() {
@@ -209,4 +263,7 @@ module.exports = class Root extends DisplayElement {
     if (this.selectedElement.directAncestors.includes(el)) return true
     return false
   }
+
+  get selectedElement() { return this.getDep('selectedElement') }
+  set selectedElement(v) { return this.setDep('selectedElement', v) }
 }