diff --git a/README.md b/README.md index 60741f0..f31786f 100644 --- a/README.md +++ b/README.md @@ -714,6 +714,11 @@ array are the furthest away, just like in the DOM. ### Optimization and CSR +**NOTE:** This is now automatically optimized for full-width scrollable elements. + +**TODO:** Detect to see if there are any elements under/to the sides of +non-full-width elements. + You may notice a lot of terminal apps (e.g. mutt, irssi, vim, ncmpcpp) don't have sidebars, and only have "elements" that take up the entire width of the screen. The reason for this is speed (and general cleanliness). VT-like diff --git a/lib/widget.js b/lib/widget.js index 6327d75..88cad7f 100644 --- a/lib/widget.js +++ b/lib/widget.js @@ -581,14 +581,21 @@ Screen.prototype.blankLine = function(ch, dirty) { }; Screen.prototype.insertLine = function(n, y, top, bottom) { - this.program.csr(top, bottom); - this.program.cup(y, 0); - this.program.il(1); - this.program.csr(0, this.height - 1); - this.program.cup(y, 0); + if (!this.tput + || !this.tput.strings.change_scroll_region + || !this.tput.strings.delete_line + || !this.tput.strings.insert_line) return; if (n < 1) n = 1; + this.program.saveCursor(); + this.program.csr(top, bottom); + this.program.cup(y, 0); + this.program.il(n); + this.program.csr(0, this.height - 1); + this.program.cup(y, 0); + this.program.restoreCursor(); + var j = this.rows - 1 - bottom; j = this.rows - 1 - j + 1; @@ -601,14 +608,21 @@ Screen.prototype.insertLine = function(n, y, top, bottom) { }; Screen.prototype.deleteLine = function(n, y, top, bottom) { - this.program.csr(top, bottom); - this.program.cup(y, 0); - this.program.dl(1); - this.program.csr(0, this.height - 1); - this.program.cup(y, 0); + if (!this.tput + || !this.tput.strings.change_scroll_region + || !this.tput.strings.delete_line + || !this.tput.strings.insert_line) return; if (n < 1) n = 1; + this.program.saveCursor(); + this.program.csr(top, bottom); + this.program.cup(y, 0); + this.program.dl(n); + this.program.csr(0, this.height - 1); + this.program.cup(y, 0); + this.program.restoreCursor(); + var j = this.rows - 1 - bottom; j = this.rows - 1 - j + 1; @@ -1953,7 +1967,7 @@ Box.prototype.insertLine = function(i, line) { this.screen.insertLine(1, this._lastPos.yi + (this.border ? 1 : 0) + this.padding + i, this._lastPos.yi, - this._lastPos.yl - 1); + this._lastPos.yl - (this.border ? 1 : 0) - this.padding - 1); } this._clines.splice((this.childBase || 0) + (this.border ? 1 : 0) + this.padding + i, 0, line); // OR: @@ -1973,7 +1987,7 @@ Box.prototype.deleteLine = function(i) { this.screen.deleteLine(1, this._lastPos.yi + (this.border ? 1 : 0) + this.padding + i, this._lastPos.yi, - this._lastPos.yl - 1); + this._lastPos.yl - (this.border ? 1 : 0) - this.padding - 1); reset = false; } this._clines.splice((this.childBase || 0) + (this.border ? 1 : 0) + this.padding + i, 1); @@ -2106,7 +2120,12 @@ ScrollableBox.prototype.__proto__ = Box.prototype; ScrollableBox.prototype.type = 'scrollable-box'; ScrollableBox.prototype.scroll = function(offset) { - var visible = this.height - (this.border ? 2 : 0) - this.padding * 2; + var visible = this.height - (this.border ? 2 : 0) - this.padding * 2 + , base = this.childBase + , d + , p + , t + , b; // Maybe do for lists: // if (this.items) visible = Math.min(this.items.length, visible); @@ -2120,11 +2139,11 @@ ScrollableBox.prototype.scroll = function(offset) { } if (this.childOffset > visible - 1) { - var d = this.childOffset - (visible - 1); + d = this.childOffset - (visible - 1); this.childOffset -= d; this.childBase += d; } else if (this.childOffset < 0) { - var d = this.childOffset; + d = this.childOffset; this.childOffset += -d; this.childBase += d; } @@ -2135,6 +2154,23 @@ ScrollableBox.prototype.scroll = function(offset) { this.childBase = this.baseLimit; } + // Optimize scrolling with CSR + IL/DL. + p = this._lastPos; + if (this.childBase !== base && p && (p.xl - p.xi) === this.screen.width) { + t = p.yi + (this.border ? 1 : 0) + this.padding; + b = p.yl - (this.border ? 1 : 0) - this.padding - 1; + d = this.childBase - base; + + if (d > 0 && d < visible) { + // scrolled down + this.screen.deleteLine(d, t, t, b); + } else if (d < 0 && -d < visible) { + // scrolled up + d = -d; + this.screen.insertLine(d, t, t, b); + } + } + this.emit('scroll'); }; @@ -2474,6 +2510,8 @@ function ScrollableText(options) { this.on('parsed content', function() { self._recalculateIndex(); }); + + self._recalculateIndex(); } ScrollableText.prototype.__proto__ = ScrollableBox.prototype;