more Box.render refactoring. docs. misc.
This commit is contained in:
parent
6f8ab54a4f
commit
29cd1a376f
10
README.md
10
README.md
|
@ -250,13 +250,18 @@ The base element.
|
|||
- **label** - a simple text label for the element.
|
||||
- **align** - text alignment: `left`, `center`, or `right`.
|
||||
- **valign** - vertical text alignment: `top`, `middle`, or `bottom`.
|
||||
- **shrink** - shrink/flex/grow to content width/height during render.
|
||||
- **shrinkBox** - shrink/flex/grow to combined coordinates of all child boxes.
|
||||
- **shrink** - shrink/flex/grow to content and child elements. width/height
|
||||
during render.
|
||||
- **padding** - amount of padding on the inside of the element.
|
||||
- **width, height** - width/height of the element, can be a number, percentage
|
||||
(`0-100%`), or keyword (`half` or `shrink`).
|
||||
- **left, right, top, bottom** - offsets of the element **relative to its
|
||||
parent**. can be a number, percentage (`0-100%`), or keyword (`center`).
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Node.
|
||||
- **name** - name of the element. useful for form submission.
|
||||
- **border** - border object.
|
||||
- **type** - type of border (`line` or `bg`). `bg` by default.
|
||||
- **ch** - character to use if `bg` type, default is space.
|
||||
|
@ -278,7 +283,6 @@ The base element.
|
|||
- **rright** - calculated relative right offset.
|
||||
- **rtop** - calculated relative top offset.
|
||||
- **rbottom** - calculated relative bottom offset.
|
||||
- **name** - name of the element. useful for form submission.
|
||||
|
||||
##### Events:
|
||||
|
||||
|
|
137
lib/widget.js
137
lib/widget.js
|
@ -1364,6 +1364,12 @@ function Element(options) {
|
|||
|
||||
this.name = options.name;
|
||||
|
||||
if (options.width === 'shrink' || options.height === 'shrink') {
|
||||
if (options.width === 'shrink') delete options.width;
|
||||
if (options.height === 'shrink') delete options.height;
|
||||
options.shrink = true;
|
||||
}
|
||||
|
||||
this.position = {
|
||||
left: options.left || 0,
|
||||
right: options.right || 0,
|
||||
|
@ -1393,6 +1399,7 @@ function Element(options) {
|
|||
this.hidden = options.hidden || false;
|
||||
this.fixed = options.fixed || false;
|
||||
this.align = options.align || 'left';
|
||||
this.valign = options.valign || 'top';
|
||||
this.shrink = options.shrink;
|
||||
this.padding = options.padding || 0;
|
||||
|
||||
|
@ -1942,6 +1949,7 @@ Box.prototype.__proto__ = Element.prototype;
|
|||
Box.prototype.type = 'box';
|
||||
|
||||
Box.prototype._getShrinkSize = function(content) {
|
||||
// TODO: Possibly move this to parseContent.
|
||||
return {
|
||||
height: this._clines.length,
|
||||
width: this._clines.reduce(function(current, line) {
|
||||
|
@ -1955,8 +1963,8 @@ Box.prototype._getShrinkSize = function(content) {
|
|||
|
||||
Box.prototype._getShrinkBox = function(xi, xl, yi, yl) {
|
||||
if (!this.children.length) {
|
||||
return { xi: xi, xl: xi, yi: yi, yl: yi };
|
||||
//return { xi: Infinity, xl: 0, yi: Infinity, yl: 0 };
|
||||
// return { xi: xi, xl: xi, yi: yi, yl: yi };
|
||||
return { xi: Infinity, xl: 0, yi: Infinity, yl: 0 };
|
||||
}
|
||||
|
||||
var i, el, mxi = 0, mxl = 0, myi = 0, myl = 0;
|
||||
|
@ -1965,6 +1973,7 @@ Box.prototype._getShrinkBox = function(xi, xl, yi, yl) {
|
|||
el = this.children[i];
|
||||
|
||||
var ret = el.render(true);
|
||||
if (!ret) continue;
|
||||
|
||||
if (ret.xi < mxi) mxi = ret.xi;
|
||||
if (ret.xl > mxl) mxl = ret.xl;
|
||||
|
@ -2083,7 +2092,6 @@ Box.prototype._getShrink = function(xi, xl, yi, yl, content) {
|
|||
// TODO: Potentially move all calculations performed on
|
||||
// xi/xl/yi/yl here to Element offset and size getters.
|
||||
Box.prototype.render = function(stop) {
|
||||
// NOTE: Maybe move this `hidden` check down below `stop` check and return `ret`.
|
||||
if (this.hidden) return;
|
||||
|
||||
this.parseContent();
|
||||
|
@ -2100,15 +2108,13 @@ Box.prototype.render = function(stop) {
|
|||
, ch
|
||||
, content = this._pcontent
|
||||
, ci = this.contentIndex || 0
|
||||
, cl = content.length
|
||||
, battr
|
||||
, dattr
|
||||
, c
|
||||
, rtop
|
||||
, visible
|
||||
, h
|
||||
, ret
|
||||
, cci;
|
||||
, i;
|
||||
|
||||
if (this.position.width) {
|
||||
xl = xi + this.width;
|
||||
|
@ -2118,13 +2124,25 @@ Box.prototype.render = function(stop) {
|
|||
yl = yi + this.height;
|
||||
}
|
||||
|
||||
// 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 = this.rtop - (this.parent.border ? 1 : 0);
|
||||
visible = this.parent.height - (this.parent.border ? 2 : 0);
|
||||
// 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 = this.rtop
|
||||
- (this.parent.border ? 1 : 0)
|
||||
- this.parent.padding;
|
||||
|
||||
visible = this.parent.height
|
||||
- (this.parent.border ? 2 : 0)
|
||||
- this.parent.padding * 2;
|
||||
|
||||
yi -= this.parent.childBase;
|
||||
yl = Math.min(yl, this.screen.rows - this.parent.bottom - (this.parent.border ? 1 : 0));
|
||||
|
||||
yl = Math.min(yl, this.screen.rows
|
||||
- this.parent.bottom
|
||||
- (this.parent.border ? 1 : 0)
|
||||
- this.parent.padding);
|
||||
|
||||
if (rtop - this.parent.childBase < 0) {
|
||||
return;
|
||||
|
@ -2135,18 +2153,13 @@ Box.prototype.render = function(stop) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Possibly do both shrinkBox and shrink
|
||||
// and use whichever values are higher.
|
||||
// TODO: Check for 'center', recalculate yi, and xi. Better
|
||||
// yet, simply move this check into this.left/width/etc.
|
||||
// Attempt to shrink the element base on the
|
||||
// size of the content and child elements.
|
||||
if (this.shrink) {
|
||||
ret = this._getShrink(xi, xl, yi, yl, content);
|
||||
xi = ret.xi, xl = ret.xl, yi = ret.yi, yl = ret.yl;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// Calculate whether we moved/resized by checking the previous _lastPos.
|
||||
// Maybe clear based on that. Possibly emit events here.
|
||||
ret = {
|
||||
xi: xi,
|
||||
xl: xl,
|
||||
|
@ -2154,6 +2167,9 @@ Box.prototype.render = function(stop) {
|
|||
yl: yl
|
||||
};
|
||||
|
||||
// If we just wanted to calculate the coords, return.
|
||||
// Possibly move the coord calculation into its own
|
||||
// method.
|
||||
if (stop) return ret;
|
||||
|
||||
this._lastPos = ret;
|
||||
|
@ -2167,43 +2183,47 @@ Box.prototype.render = function(stop) {
|
|||
|
||||
// Check previous line for escape codes.
|
||||
if (this.contentIndex != null && this.childBase > 0 && this._clines) {
|
||||
cci = ci - (this._clines[this.childBase - 1].length + 1);
|
||||
for (; cci < ci; cci++) {
|
||||
if (content[cci] === '\x1b') {
|
||||
if (c = /^\x1b\[[\d;]*m/.exec(content.substring(cci))) {
|
||||
i = ci - (this._clines[this.childBase - 1].length + 1);
|
||||
for (; i < ci; i++) {
|
||||
if (content[i] === '\x1b') {
|
||||
if (c = /^\x1b\[[\d;]*m/.exec(content.substring(i))) {
|
||||
attr = this.screen.attrCode(c[0], attr);
|
||||
cci += c[0].length - 1;
|
||||
i += c[0].length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.border) yi++, yl--, xi++, xl--;
|
||||
if (this.border) xi++, xl--, yi++, yl--;
|
||||
|
||||
if (this.padding || this.options.valign) {
|
||||
// If we have padding/valign, that means the
|
||||
// content-drawing loop will skip a few cells/lines.
|
||||
// To deal with this, we can just fill the whole thing
|
||||
// ahead of time. This could be optimized.
|
||||
if (this.padding || (this.valign && this.valign !== 'top')) {
|
||||
this.screen.fillRegion(dattr, ' ', xi, xl, yi, yl);
|
||||
}
|
||||
|
||||
if (this.padding) {
|
||||
yi += this.padding, yl -= this.padding;
|
||||
xi += this.padding, xl -= this.padding;
|
||||
yi += this.padding, yl -= this.padding;
|
||||
}
|
||||
|
||||
if (this.options.valign === 'middle' || this.options.valign === 'bottom') {
|
||||
//visible = (yl - yi) - (this.border ? 2 : 0) - this.padding;
|
||||
// Determine where to place the text if it's vertically aligned.
|
||||
if (this.valign === 'middle' || this.valign === 'bottom') {
|
||||
visible = yl - yi;
|
||||
if (this._clines.length < visible) {
|
||||
if (this.options.valign === 'middle') {
|
||||
if (this.valign === 'middle') {
|
||||
visible = visible / 2 | 0;
|
||||
visible -= this._clines.length / 2 | 0;
|
||||
} else if (this.options.valign === 'bottom') {
|
||||
} else if (this.valign === 'bottom') {
|
||||
visible -= this._clines.length;
|
||||
}
|
||||
yi += visible;
|
||||
}
|
||||
}
|
||||
|
||||
outer:
|
||||
// Draw the content and background.
|
||||
for (y = yi; y < yl; y++) {
|
||||
if (!lines[y]) break;
|
||||
for (x = xi; x < xl; x++) {
|
||||
|
@ -2234,8 +2254,8 @@ outer:
|
|||
x--;
|
||||
continue;
|
||||
}
|
||||
// this.screen.fillRegion(attr, ' ', x, xl, y, y + 1);
|
||||
// continue outer;
|
||||
// We could use fillRegion here, name the
|
||||
// outer loop, and continue to it instead.
|
||||
ch = ' ';
|
||||
for (; x < xl; x++) {
|
||||
cell = lines[y][x];
|
||||
|
@ -2248,7 +2268,6 @@ outer:
|
|||
}
|
||||
continue;
|
||||
}
|
||||
// if (ch < ' ') ch = ' ';
|
||||
|
||||
if (attr !== cell[0] || ch !== cell[1]) {
|
||||
lines[y][x][0] = attr;
|
||||
|
@ -2258,24 +2277,22 @@ outer:
|
|||
}
|
||||
}
|
||||
|
||||
h = this.items ? this.items.length : this._clines.length;
|
||||
if (this.scrollbar && (yl - yi) < h) {
|
||||
// Draw the scrollbar.
|
||||
i = this.items ? this.items.length : this._clines.length;
|
||||
if (this.scrollbar && (yl - yi) < i) {
|
||||
x = xl - 1;
|
||||
if (this.scrollbar.ignoreBorder && this.border) x++;
|
||||
if (this.selected == null) {
|
||||
// TODO: Fix this - doesn't work with lists (and possibly scrollabletext).
|
||||
y = h - (yl - yi) - (this.border ? 2 : 0) - this.padding * 2;
|
||||
y = i - (yl - yi) - (this.border ? 2 : 0) - this.padding * 2;
|
||||
y = yi + (((yl - yi) * (this.childBase / y)) | 0);
|
||||
} else {
|
||||
y = this.selected / h;
|
||||
y = this.selected / i;
|
||||
y = yi + ((yl - yi) * y | 0);
|
||||
}
|
||||
cell = lines[y] && lines[y][x];
|
||||
if (cell) {
|
||||
ch = this.scrollbar.ch || ' ';
|
||||
//attr = this.sattr(this.style,
|
||||
// this.scrollbar.style.fg || this.style.fg,
|
||||
// this.scrollbar.style.bg || this.style.bg);
|
||||
attr = this.sattr(this.style,
|
||||
this.style.scrollbar.fg || this.style.fg,
|
||||
this.style.scrollbar.bg || this.style.bg);
|
||||
|
@ -2287,46 +2304,14 @@ outer:
|
|||
}
|
||||
}
|
||||
|
||||
// This seems redundant, but we need to draw the
|
||||
// border second because of the `shrink` option.
|
||||
if (this.border) yi--, yl++, xi--, xl++;
|
||||
if (this.border) xi--, xl++, yi--, yl++;
|
||||
|
||||
if (this.padding) {
|
||||
yi -= this.padding, yl += this.padding;
|
||||
xi -= this.padding, xl += this.padding;
|
||||
yi -= this.padding, yl += this.padding;
|
||||
}
|
||||
|
||||
/*
|
||||
if (this.padding) {
|
||||
// Set padding to green for debugging:
|
||||
// dattr = (dattr & ~0x1ff) | colors.convert('green');
|
||||
// top
|
||||
this.screen.fillRegion(dattr, ' ',
|
||||
xi + (this.border ? 1 : 0),
|
||||
xl - (this.border ? 1 : 0),
|
||||
yi + (this.border ? 1 : 0),
|
||||
yi + 0 + (this.border ? 1 : 0) + this.padding);
|
||||
// bottom
|
||||
this.screen.fillRegion(dattr, ' ',
|
||||
xi + (this.border ? 1 : 0),
|
||||
xl - (this.border ? 1 : 0),
|
||||
yl - 0 - (this.border ? 1 : 0) - this.padding,
|
||||
yl - (this.border ? 1 : 0));
|
||||
// left
|
||||
this.screen.fillRegion(dattr, ' ',
|
||||
xi + (this.border ? 1 : 0),
|
||||
xi + 0 + (this.border ? 1 : 0) + this.padding,
|
||||
yi + (this.border ? 1 : 0),
|
||||
yl - (this.border ? 1 : 0));
|
||||
// right
|
||||
this.screen.fillRegion(dattr, ' ',
|
||||
xl - 0 - (this.border ? 1 : 0) - this.padding,
|
||||
xl - (this.border ? 1 : 0),
|
||||
yi + (this.border ? 1 : 0),
|
||||
yl - (this.border ? 1 : 0));
|
||||
}
|
||||
*/
|
||||
|
||||
// Draw the border.
|
||||
if (this.border) {
|
||||
y = yi;
|
||||
for (x = xi; x < xl; x++) {
|
||||
|
|
Loading…
Reference in New Issue