diff options
author | Florrie <towerofnix@gmail.com> | 2019-09-15 16:55:53 -0300 |
---|---|---|
committer | Florrie <towerofnix@gmail.com> | 2019-09-15 17:09:31 -0300 |
commit | 3f76094c554c23ee3519f41458a04d348f4f75a3 (patch) | |
tree | 5b87c588651b52aec6136e651e73d9f1d747c638 /ui/DisplayElement.js | |
parent | 878e55e7c2a203d89fb1dad83ba6d6d8751b521a (diff) |
(!!) Only render when draw-dependency props change
This is a very large change and probably breaks most applications not built to work with it. (Obviously, I'm not really being that responsible with this sort of thing.) I've tested with mtui and it works fine, but some elements may need tweaks before being 100% adjusted to the new scheduled-render system we're using with this commit. Also, any elements which have custom draw behavior will likely need updating so that they appropriately schedule renders.
Diffstat (limited to 'ui/DisplayElement.js')
-rw-r--r-- | ui/DisplayElement.js | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/ui/DisplayElement.js b/ui/DisplayElement.js index b7e07b9..87a9cb5 100644 --- a/ui/DisplayElement.js +++ b/ui/DisplayElement.js @@ -14,10 +14,14 @@ module.exports = class DisplayElement extends EventEmitter { constructor() { super() - this.visible = true + this[DisplayElement.drawValues] = {} + this[DisplayElement.lastDrawValues] = {} + this[DisplayElement.scheduledDraw] = false - this.parent = null this.children = [] + this.parent = null + + this.visible = true this.x = 0 this.y = 0 @@ -82,6 +86,68 @@ module.exports = class DisplayElement extends EventEmitter { } } + getDep(key) { + return this[DisplayElement.drawValues][key] + } + + setDep(key, value) { + const oldValue = this[DisplayElement.drawValues][key] + // TODO: new map for old values. we only compare value !== oldValue LATER, at render time, not when choosing to schedule - otherwise intermediate sets e.g. f.y = 1; f.y++, which always has a net effect of f.y = 2, will count as a redraw even though the final value isn't changing between frames + 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]) + } + + eachDescendant(fn) { + // Run a function on this element, all of its children, all of their + // children, etc. + fn(this) + for (const child of this.children) { + child.eachDescendant(fn) + } + } + addChild(child, afterIndex = this.children.length, {fixLayout = true} = {}) { // TODO Don't let a direct ancestor of this be added as a child. Don't // let itself be one of its childs either! @@ -230,6 +296,17 @@ module.exports = class DisplayElement extends EventEmitter { 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) } + get absX() { if (this.parent) { return this.parent.contentX + this.x @@ -262,3 +339,7 @@ module.exports = class DisplayElement extends EventEmitter { 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') |