« 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/DisplayElement.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/DisplayElement.js')
-rw-r--r--ui/DisplayElement.js306
1 files changed, 0 insertions, 306 deletions
diff --git a/ui/DisplayElement.js b/ui/DisplayElement.js
deleted file mode 100644
index 8720142..0000000
--- a/ui/DisplayElement.js
+++ /dev/null
@@ -1,306 +0,0 @@
-const Element = require('./Element')
-const exception = require('../util/exception')
-
-module.exports = class DisplayElement extends Element {
-  // A general class that handles dealing with screen coordinates, the tree
-  // of elements, and other common stuff.
-  //
-  // This element doesn't handle any real rendering; just layouts. Placing
-  // characters at specific positions should be implemented in subclasses.
-  //
-  // It's a subclass of EventEmitter, so you can make your own events within
-  // the logic of your subclass.
-
-  constructor() {
-    super()
-
-    this[DisplayElement.drawValues] = {}
-    this[DisplayElement.lastDrawValues] = {}
-    this[DisplayElement.scheduledDraw] = false
-
-    this.visible = true
-
-    this.x = 0
-    this.y = 0
-    this.w = 0
-    this.h = 0
-
-    this.hPadding = 0
-    this.vPadding = 0
-
-    // Note! This only applies to the parent, not the children. Useful for
-    // when you want an element to cover the whole screen but allow mouse
-    // events to pass through.
-    this.clickThrough = false
-  }
-
-  drawTo(writable) {
-    // Writes text to a "writable" - an object that has a "write" method.
-    // Custom rendering should be handled as an override of this method in
-    // subclasses of DisplayElement.
-  }
-
-  renderTo(writable) {
-    // Like drawTo, but only calls drawTo if the element is visible. Use this
-    // with your root element, not drawTo.
-
-    if (!this.visible) {
-      return
-    }
-
-    const causeRenderEl = this.shouldRender()
-    if (causeRenderEl) {
-      this.drawTo(writable)
-      this.renderChildrenTo(writable)
-      this.didRenderTo(writable)
-    } else {
-      this.renderChildrenTo(writable)
-    }
-  }
-
-  shouldRender() {
-    // WIP! Until this implementation is finished, always return true (or else
-    // lots of rendering breaks).
-    /*
-    return (
-      this[DisplayElement.scheduledDraw] ||
-      [...this.directAncestors].find(el => el.shouldRender())
-    )
-    */
-    return true
-  }
-
-  renderChildrenTo(writable) {
-    // Renders all of the children to a writable.
-
-    for (const child of this.children) {
-      child.renderTo(writable)
-    }
-  }
-
-  didRenderTo(writable) {
-    // Called immediately after rendering this element AND all of its
-    // children. If you need to do something when that happens, override this
-    // method in your subclass.
-    //
-    // It's fine to draw more things to the writable here - just keep in mind
-    // that it'll be drawn over this element and its children, but not any
-    // elements drawn in the future.
-  }
-
-  fixLayout() {
-    // Adjusts the layout of children in this element. If your subclass has
-    // any children in it, you should override this method.
-  }
-
-  fixAllLayout() {
-    // Runs fixLayout on this as well as all children.
-
-    this.fixLayout()
-    for (const child of this.children) {
-      child.fixAllLayout()
-    }
-  }
-
-  confirmDrawValuesExists() {
-    if (!this[DisplayElement.drawValues]) {
-      this[DisplayElement.drawValues] = {}
-    }
-  }
-
-  getDep(key) {
-    this.confirmDrawValuesExists()
-    return this[DisplayElement.drawValues][key]
-  }
-
-  setDep(key, value) {
-    this.confirmDrawValuesExists()
-    const oldValue = this[DisplayElement.drawValues][key]
-    if (value !== this[DisplayElement.drawValues][key]) {
-      this[DisplayElement.drawValues][key] = value
-      this.scheduleDraw()
-      // Grumble: technically it's possible for a root element to not be an
-      // actual Root. While we don't check for this case most of the time (even
-      // though we ought to), we do here because it's not unlikely for draw
-      // dependency values to be changed before the element is actually added
-      // to a Root element.
-      if (this.root.scheduleRender) {
-        this.root.scheduleRender()
-      }
-    }
-    return value
-  }
-
-  scheduleDrawWithoutPropertyChange() {
-    // Utility function for when you need to schedule a draw without updating
-    // any particular draw-dependency property on the element. Works by setting
-    // an otherwise unused dep to a unique object. (We can't use a symbol here,
-    // because then Object.entries doesn't notice it.)
-    this.setDep('drawWithoutProperty', Math.random())
-  }
-
-  scheduleDraw() {
-    this[DisplayElement.scheduledDraw] = true
-  }
-
-  unscheduleDraw() {
-    this[DisplayElement.scheduledDraw] = false
-  }
-
-  hasScheduledDraw() {
-    if (this[DisplayElement.scheduledDraw]) {
-      for (const [ key, value ] of Object.entries(this[DisplayElement.drawValues])) {
-        if (value !== this[DisplayElement.lastDrawValues][key]) {
-          return true
-        }
-      }
-    }
-    return false
-  }
-
-  updateLastDrawValues() {
-    Object.assign(this[DisplayElement.lastDrawValues], this[DisplayElement.drawValues])
-  }
-
-  centerInParent() {
-    // Utility function to center this element in its parent. Must be called
-    // only when it has a parent. Set the width and height of the element
-    // before centering it!
-
-    if (this.parent === null) {
-      throw new Error('Cannot center in parent when parent is null')
-    }
-
-    this.x = Math.round((this.parent.contentW - this.w) / 2)
-    this.y = Math.round((this.parent.contentH - this.h) / 2)
-  }
-
-  fillParent() {
-    // Utility function to fill this element in its parent. Must be called
-    // only when it has a parent.
-
-    if (this.parent === null) {
-      throw new Error('Cannot fill parent when parent is null')
-    }
-
-    this.x = 0
-    this.y = 0
-    this.w = this.parent.contentW
-    this.h = this.parent.contentH
-  }
-
-  fitToParent() {
-    // Utility function to position this element so that it stays within its
-    // parent's bounds. Must be called only when it has a parent.
-    //
-    // This function is useful when (and only when) the right or bottom edge
-    // of this element may be past the right or bottom edge of its parent.
-    // In such a case, the element will first be moved left or up by the
-    // distance that its edge exceeds that of its parent, so that its edge is
-    // no longer past the parent's. Then, if the left or top edge of the
-    // element is less than zero, i.e. outside the parent, it is set to zero
-    // and the element's width or height is adjusted so that it does not go
-    // past the bounds of the parent.
-
-    if (this.x + this.w > this.parent.right) {
-      const offendExtent = (this.x + this.w) - this.parent.contentW
-      this.x -= offendExtent
-      if (this.x < 0) {
-        const offstartExtent = 0 - this.x
-        this.w -= offstartExtent
-        this.x = 0
-      }
-    }
-
-    if (this.y + this.h > this.parent.bottom) {
-      const offendExtent = (this.y + this.h) - this.parent.contentH
-      this.y -= offendExtent
-      if (this.y < 0) {
-        const offstartExtent = 0 - this.y
-        this.h -= offstartExtent
-        this.y = 0
-      }
-    }
-  }
-
-  getElementAt(x, y) {
-    // Gets the topmost element at the provided absolute coordinate.
-    // Note that elements which are not visible or have the clickThrough
-    // property set to true are not considered.
-
-    const children = this.children.slice()
-
-    // Start searching the last- (top-) rendered children first.
-    children.reverse()
-
-    for (const el of children) {
-      if (!el.visible || el.clickThrough) {
-        continue
-      }
-
-      const el2 = el.getElementAt(x, y)
-      if (el2) {
-        return el2
-      }
-
-      const { absX, absY, w, h } = el
-      if (absX <= x && absX + w > x) {
-        if (absY <= y && absY + h > y) {
-          return el
-        }
-      }
-    }
-    return null
-  }
-
-  get x() { return this.getDep('x') }
-  set x(v) { return this.setDep('x', v) }
-  get y() { return this.getDep('y') }
-  set y(v) { return this.setDep('y', v) }
-  get hPadding() { return this.getDep('hPadding') }
-  set hPadding(v) { return this.setDep('hPadding', v) }
-  get vPadding() { return this.getDep('vPadding') }
-  set vPadding(v) { return this.setDep('vPadding', v) }
-  get visible() { return this.getDep('visible') }
-  set visible(v) { return this.setDep('visible', v) }
-
-  // Commented out because this doesn't fix any problems (at least ATM).
-  // get parent() { return this.getDep('parent') }
-  // set parent(v) { return this.setDep('parent', v) }
-
-  get absX() {
-    if (this.parent) {
-      return this.parent.contentX + this.x
-    } else {
-      return this.x
-    }
-  }
-
-  get absY() {
-    if (this.parent) {
-      return this.parent.contentY + this.y
-    } else {
-      return this.y
-    }
-  }
-
-  // Where contents should be positioned.
-  get contentX() { return this.absX + this.hPadding }
-  get contentY() { return this.absY + this.vPadding }
-  get contentW() { return this.w - this.hPadding * 2 }
-  get contentH() { return this.h - this.vPadding * 2 }
-
-  get left()   { return this.x }
-  get right()  { return this.x + this.w }
-  get top()    { return this.y }
-  get bottom() { return this.y + this.h }
-
-  get absLeft()   { return this.absX }
-  get absRight()  { return this.absX + this.w - 1 }
-  get absTop()    { return this.absY }
-  get absBottom() { return this.absY + this.h - 1 }
-}
-
-module.exports.drawValues = Symbol('drawValues')
-module.exports.lastDrawValues = Symbol('lastDrawValues')
-module.exports.scheduledDraw = Symbol('scheduledDraw')