scrollable elements.

This commit is contained in:
Christopher Jeffrey 2013-07-19 01:57:17 -05:00
parent 0f4b60314b
commit e33838804b
3 changed files with 169 additions and 29 deletions

View File

@ -2348,29 +2348,43 @@ Box.prototype._getCoords = function(get) {
, xl = xi + this._getWidth(get)
, yi = this._getTop(get)
, yl = yi + this._getHeight(get)
, rtop
, ryi
, ryl
, visible
, coords;
, coords
, v;
// Check to make sure we're visible and
// inside of the visible scroll area.
if (this.parent.childBase != null
&& (!this.parent.items
|| ~this.parent.items.indexOf(this))) {
rtop = yi - this.parent._getTop(get)
ryi = yi - this.parent._getTop(get)
- (this.parent.border ? 1 : 0)
- this.parent.padding;
ryl = yl - this.parent._getTop(get)
- (this.parent.border ? 1 : 0)
- this.parent.padding;
visible = this.parent._getHeight(get)
- (this.parent.border ? 2 : 0)
- this.parent.padding * 2;
if (rtop - this.parent.childBase < 0) {
return;
}
if (rtop - this.parent.childBase >= visible) {
if (ryi < this.parent.childBase) {
if (ryl > this.parent.childBase) {
// Is partially covered above. TODO: Improve.
v = ryl - this.parent.childBase;
yi += (ryl - ryi) - v;
} else {
// Is above.
return;
}
} else if (ryi >= this.parent.childBase + visible) {
// Is below.
return;
} else if (ryl >= this.parent.childBase + visible) {
// Is partially covered below. TODO: Improve.
v = this.parent.childBase + visible + (yl - yi) - ryl;
yl = yi + v;
}
yi -= this.parent.childBase;
@ -2427,7 +2441,11 @@ Box.prototype.render = function() {
// If we're in a scrollable text box, check to
// see which attributes this line starts with.
if (this.contentIndex != null && this.childBase != null) {
attr = this._clines.attr[this.childBase];
if (this._clines.length > this.childBase) {
attr = this._clines.attr[this.childBase];
} else {
attr = this._clines.attr[this._clines.length - 1];
}
}
if (this.border) xi++, xl--, yi++, yl--;
@ -2514,19 +2532,21 @@ Box.prototype.render = function() {
}
// Draw the scrollbar.
i = this.items ? this.items.length : this._clines.length;
if (this.scrollbar) {
i = this.type === 'scrollable-text'
? this._clines.length + 1
: this._scrollBottom() + (yl - yi) + 1;
//i = Math.max(this._clines.length + 1, this._scrollBottom() + (yl - yi) + 1);
}
if (this.scrollbar && (yl - yi) < i) {
i -= yl - yi;
x = xl - 1;
if (this.scrollbar.ignoreBorder && this.border) x++;
if (this.selected == null) {
// TODO: The scrollbar seems to disappear at
// the bottom of a scrollable text box. Fix.
i = i - (yl - yi);
y = yi + (yl - yi) * (this.childBase / i) | 0;
} else {
y = this.selected / i;
y = yi + ((yl - yi) * y | 0);
}
y = this.selected == null
? this.childBase
: this.selected;
y = y / i;
y = yi + ((yl - yi) * y | 0);
cell = lines[y] && lines[y][x];
if (cell) {
ch = this.scrollbar.ch || ' ';
@ -2819,12 +2839,17 @@ function ScrollableBox(options) {
this.scrollbar = options.scrollbar;
if (this.scrollbar) {
this.scrollbar.ch = this.scrollbar.ch || ' ';
if (!this.scrollbar.style) {
this.scrollbar.style = this.style.scrollbar || {};
this.scrollbar.style.fg = this.scrollbar.fg;
this.scrollbar.style.bg = this.scrollbar.bg;
this.style.scrollbar = this.style.scrollbar || this.scrollbar.style;
if (!this.style.scrollbar) {
this.style.scrollbar = {};
this.style.scrollbar.fg = this.scrollbar.fg;
this.style.scrollbar.bg = this.scrollbar.bg;
this.style.scrollbar.bold = this.scrollbar.bold;
this.style.scrollbar.underline = this.scrollbar.underline;
this.style.scrollbar.inverse = this.scrollbar.inverse;
this.style.scrollbar.invisible = this.scrollbar.invisible;
}
this.style.scrollbar = this.scrollbar.style;
this.scrollbar.style = this.style.scrollbar;
}
}
@ -2832,6 +2857,30 @@ ScrollableBox.prototype.__proto__ = Box.prototype;
ScrollableBox.prototype.type = 'scrollable-box';
ScrollableBox.prototype._scrollBottom = function() {
// We could just calculate the children, but we can
// optimize for lists by just returning the items.length.
if (this.type === 'list') {
return this.items.length;
}
if (this.lpos && this.lpos._scrollBottom) {
return this.lpos._scrollBottom;
}
var bottom = this.children.reduce(function(current, el) {
return Math.max(current, el.rtop + el.height);
}, 0);
if (this.lpos) this.lpos._scrollBottom = bottom;
return bottom;
};
ScrollableBox.prototype.scrollTo = function(offset) {
return this.scroll(offset - (this.childBase + this.childOffset));
};
ScrollableBox.prototype.scroll = function(offset) {
var visible = this.height - (this.border ? 2 : 0) - this.padding * 2
, base = this.childBase
@ -2867,6 +2916,15 @@ ScrollableBox.prototype.scroll = function(offset) {
this.childBase = this.baseLimit;
}
// This code works for scrollable box and list, but it
// makes scrollable text choke because it can't diff properly.
if (this.type !== 'scrollable-text') {
var bottom = this._scrollBottom();
if (this.childBase > bottom) {
this.childBase = bottom;
}
}
// Optimize scrolling with CSR + IL/DL.
p = this.lpos;
if (this.childBase !== base && this.screen.cleanSides(this)) {
@ -3065,7 +3123,7 @@ function List(options) {
}
this.on('resize', function() {
var visible = self.height - (self.border ? 2 : 0);
var visible = self.height - (self.border ? 2 : 0) - self.padding * 2;
if (visible >= self.selected + 1) {
//if (self.selected < visible - 1) {
self.childBase = 0;
@ -3182,10 +3240,11 @@ List.prototype.select = function(index) {
if (this.selected === index && this._listInitialized) return;
this._listInitialized = true;
var diff = index - this.selected;
//var diff = index - this.selected;
this.selected = index;
this.value = this.ritems[this.selected];
this.scroll(diff);
//this.scroll(diff);
this.scrollTo(this.selected);
};
List.prototype.move = function(offset) {
@ -3313,12 +3372,18 @@ ScrollableText.prototype.scroll = function(offset) {
diff = cb - base;
}
// this.childBase = Math.max(this.childBase, max);
// cb = this.childBase;
// diff = cb - base;
if (diff > 0) {
for (i = base; i < cb; i++) {
// if (!this._clines[i]) continue;
this.contentIndex += this._clines[i].length + 1;
}
} else {
for (i = base - 1; i >= cb; i--) {
// if (!this._clines[i]) continue;
this.contentIndex -= this._clines[i].length + 1;
}
}
@ -3338,7 +3403,10 @@ ScrollableText.prototype._recalculateIndex = function() {
this.childBase = max;
}
//this.childBase = Math.max(this.childBase, max);
for (var i = 0, t = 0; i < this.childBase; i++) {
// if (!this._clines[i]) continue;
t += this._clines[i].length + 1;
}

View File

@ -0,0 +1,68 @@
var blessed = require('../')
, screen = blessed.screen();
var box = blessed.scrollablebox({
//var box = blessed.scrollabletext({
parent: screen,
left: 'center',
top: 'center',
width: '80%',
height: '80%',
bg: 'green',
border: {
type: 'ascii'
},
content: 'foobar',
keys: true,
vi: true,
alwaysScroll: true,
scrollbar: {
ch: ' ',
inverse: true
}
});
var text = blessed.box({
parent: box,
content: 'hello',
style: {
bg: 'red'
},
left: 2,
top: 30,
width: '50%',
height: 4
});
var text2 = blessed.box({
parent: box,
content: 'world',
style: {
bg: 'red'
},
left: 2,
top: 50,
width: '50%',
height: 3
});
screen.key('q', function() {
return process.exit(0);
});
box.on('keypress', function(ch, key) {
if (key.name === 'up' || key.name === 'k') {
box.scroll(-1);
screen.render();
return;
}
if (key.name === 'down' || key.name === 'j') {
box.scroll(1);
screen.render();
return;
}
});
box.focus();
screen.render();

View File

@ -79,7 +79,11 @@ var list = blessed.list({
'eight',
'nine',
'ten'
]
],
scrollbar: {
ch: ' ',
inverse: true
}
});
screen.append(list);