improve position, attribute parsing. misc.
This commit is contained in:
parent
3ae01237be
commit
df317bb472
|
@ -257,6 +257,7 @@ The base element.
|
|||
(`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`).
|
||||
`right` and `bottom` do not accept keywords.
|
||||
|
||||
##### Properties:
|
||||
|
||||
|
|
510
lib/widget.js
510
lib/widget.js
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
, assert = require('assert')
|
||||
, path = require('path')
|
||||
, fs = require('fs')
|
||||
, colors = require('./colors')
|
||||
|
@ -150,6 +151,39 @@ Node.prototype.detach = function() {
|
|||
if (this.parent) this.parent.remove(this);
|
||||
};
|
||||
|
||||
Node.prototype.forDescendants = function(iter, s) {
|
||||
if (s) iter(this);
|
||||
el.children.forEach(function emit(el) {
|
||||
iter(el);
|
||||
el.children.forEach(emit);
|
||||
});
|
||||
};
|
||||
|
||||
Node.prototype.forAncestors = function(iter, s) {
|
||||
var el = this;
|
||||
if (s) iter(this);
|
||||
while (el = el.parent) {
|
||||
iter(el);
|
||||
el.emit.apply(el, args);
|
||||
}
|
||||
};
|
||||
|
||||
Node.prototype.collectDescendants = function(s) {
|
||||
var out = [];
|
||||
this.forDescendants(function(el) {
|
||||
out.push(el);
|
||||
}, s);
|
||||
return out;
|
||||
};
|
||||
|
||||
Node.prototype.collectAncestors = function(s) {
|
||||
var out = [];
|
||||
this.forAncestors(function(el) {
|
||||
out.push(el);
|
||||
}, s);
|
||||
return out;
|
||||
};
|
||||
|
||||
Node.prototype.emitDescendants = function() {
|
||||
var args = Array.prototype.slice(arguments)
|
||||
, iter;
|
||||
|
@ -158,31 +192,28 @@ Node.prototype.emitDescendants = function() {
|
|||
iter = args.pop();
|
||||
}
|
||||
|
||||
(function emit(el) {
|
||||
return this.forDescendants(function(el) {
|
||||
if (iter) iter(el);
|
||||
el.emit.apply(el, args);
|
||||
if (el.children) {
|
||||
el.children.forEach(emit);
|
||||
}
|
||||
})(this);
|
||||
}, true);
|
||||
};
|
||||
|
||||
Node.prototype.emitAncestors = function() {
|
||||
var args = Array.prototype.slice(arguments)
|
||||
, el = this
|
||||
, iter;
|
||||
|
||||
if (typeof args[args.length-1] === 'function') {
|
||||
iter = args.pop();
|
||||
}
|
||||
|
||||
do {
|
||||
return this.forAncestors(function(el) {
|
||||
if (iter) iter(el);
|
||||
el.emit.apply(el, args);
|
||||
} while (el = el.parent);
|
||||
}, true);
|
||||
};
|
||||
|
||||
Node.prototype.hasDescendant = function(target) {
|
||||
// return this.collectDescendants().indexOf(target) !== -1;
|
||||
return (function find(el) {
|
||||
for (var i = 0; i < el.children.length; i++) {
|
||||
if (el.children[i] === target) {
|
||||
|
@ -197,6 +228,7 @@ Node.prototype.hasDescendant = function(target) {
|
|||
};
|
||||
|
||||
Node.prototype.hasAncestor = function(target) {
|
||||
// return this.collectAncestors().indexOf(target) !== -1;
|
||||
var el = this;
|
||||
while (el = el.parent) {
|
||||
if (el === target) return true;
|
||||
|
@ -1557,7 +1589,6 @@ Element.prototype.hide = function() {
|
|||
Element.prototype.show = function() {
|
||||
if (!this.hidden) return;
|
||||
this.hidden = false;
|
||||
// this.render();
|
||||
this.emit('show');
|
||||
};
|
||||
|
||||
|
@ -1602,11 +1633,14 @@ Element.prototype.parseContent = function() {
|
|||
this._clines = this._wrapContent(content, width);
|
||||
this._clines.width = width;
|
||||
this._clines.content = this.content;
|
||||
this._clines.attr = this._parseAttr(this._clines);
|
||||
this._pcontent = this._clines.join('\n');
|
||||
this.emit('parsed content');
|
||||
return true;
|
||||
}
|
||||
|
||||
this._clines.attr = this._parseAttr(this._clines) || this._clines.attr;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -1629,6 +1663,38 @@ Element.prototype._parseTags = function(text) {
|
|||
});
|
||||
};
|
||||
|
||||
Element.prototype._parseAttr = function(lines) {
|
||||
var attr = this.sattr(this.style, this.style.fg, this.style.bg)
|
||||
, attrs = []
|
||||
, line
|
||||
, i
|
||||
, j
|
||||
, c;
|
||||
|
||||
if (lines[0].attr === attr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.contentIndex == null || this.childBase == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (j = 0; j < lines.length; j++) {
|
||||
line = lines[j];
|
||||
attrs[j] = attr;
|
||||
for (i = 0; i < line.length; i++) {
|
||||
if (line[i] === '\x1b') {
|
||||
if (c = /^\x1b\[[\d;]*m/.exec(line.substring(i))) {
|
||||
attr = this.screen.attrCode(c[0], attr);
|
||||
i += c[0].length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attrs;
|
||||
};
|
||||
|
||||
Element.prototype._align = function(line, width, align) {
|
||||
if (!align) return line;
|
||||
|
||||
|
@ -1798,241 +1864,223 @@ Element.prototype.clearPos = function() {
|
|||
* Positioning
|
||||
*/
|
||||
|
||||
// Help center shrunken nested elements.
|
||||
Screen.prototype.spos =
|
||||
Element.prototype.spos = function() {
|
||||
// The below methods are a bit confusing: basically
|
||||
// whenever Box.render is called `lpos` gets set on
|
||||
// the element, an object containing the rendered
|
||||
// coordinates. Since these don't update if the
|
||||
// element is moved somehow, they're unreliable in
|
||||
// that situation. However, if we can guarantee that
|
||||
// lpos is good and up to date, it can be more
|
||||
// accurate than the calculated positions below.
|
||||
// In this case, if the element is being rendered,
|
||||
// it's guaranteed that the parent will have been
|
||||
// rendered first, in which case we can use the
|
||||
// parant's lpos instead of recalculating it's
|
||||
// position (since that might be wrong because
|
||||
// it doesn't handle content shrinkage).
|
||||
|
||||
Screen.prototype._getPos = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
Element.prototype._getPos = function() {
|
||||
var pos = this.lpos;
|
||||
if (!pos || !this.shrink) return this;
|
||||
pos.width = pos.xl - pos.xi;
|
||||
pos.height = pos.yl - pos.yi;
|
||||
|
||||
assert.ok(pos && !pos.changed);
|
||||
|
||||
if (pos.left != null) return pos;
|
||||
|
||||
pos.left = pos.xi;
|
||||
pos.top = pos.yi;
|
||||
pos.right = this.screen.cols - pos.xl;
|
||||
pos.bottom = this.screen.rows - pos.yl;
|
||||
pos.width = pos.xl - pos.xi;
|
||||
pos.height = pos.yl - pos.yi;
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
// NOTE: When coords are entered in the Element constructor, all of the coords
|
||||
// are *relative* to their parent, when retrieving them from `.left`, `.right`,
|
||||
// etc members, the coords are absolute. To see the *relative* coords again,
|
||||
// use `.rleft`, `.rright`, etc.
|
||||
|
||||
Element.prototype.__defineGetter__('left', function() {
|
||||
var left = this.position.left;
|
||||
|
||||
var parent = this.parent.spos();
|
||||
|
||||
if (typeof left === 'string') {
|
||||
if (left === 'center') left = '50%';
|
||||
left = +left.slice(0, -1) / 100;
|
||||
left = this.parent.width * left | 0;
|
||||
if (this.position.left === 'center') {
|
||||
left -= this.width / 2 | 0;
|
||||
}
|
||||
Element.prototype._bindPosChanged = function() {
|
||||
function changed() {
|
||||
self.forDescendants(function(el) {
|
||||
if (el.lpos) el.lpos.changed = true;
|
||||
}, true);
|
||||
}
|
||||
|
||||
if (this.options.left == null && this.options.right != null) {
|
||||
return this.screen.cols - this.width - this.right;
|
||||
}
|
||||
this.on('move', changed);
|
||||
// Resize might be tricky because it's
|
||||
// emitted recursively for a screen resize.
|
||||
this.on('resize', changed);
|
||||
this.on('reparent', changed);
|
||||
};
|
||||
|
||||
return (parent.left || 0) + left;
|
||||
});
|
||||
/**
|
||||
* Position Getters
|
||||
*/
|
||||
|
||||
Element.prototype.__defineGetter__('right', function() {
|
||||
if (this.options.right == null && this.options.left != null) {
|
||||
return this.screen.cols - (this.left + this.width);
|
||||
}
|
||||
return (this.parent.right || 0) + this.position.right;
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('top', function() {
|
||||
var top = this.position.top;
|
||||
|
||||
var parent = this.parent.spos();
|
||||
|
||||
if (typeof top === 'string') {
|
||||
if (top === 'center') top = '50%';
|
||||
top = +top.slice(0, -1) / 100;
|
||||
top = this.parent.height * top | 0;
|
||||
if (this.position.top === 'center') {
|
||||
top -= this.height / 2 | 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.top == null && this.options.bottom != null) {
|
||||
return this.screen.rows - this.height - this.bottom;
|
||||
}
|
||||
|
||||
return (parent.top || 0) + top;
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('bottom', function() {
|
||||
if (this.options.bottom == null && this.options.top != null) {
|
||||
return this.screen.rows - (this.top + this.height);
|
||||
}
|
||||
return (this.parent.bottom || 0) + this.position.bottom;
|
||||
});
|
||||
|
||||
// TODO: Move _getShrinkSize calculation here. This will in turn fix .left.
|
||||
Element.prototype.__defineGetter__('width', function() {
|
||||
Element.prototype._getWidth = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
var width = this.position.width;
|
||||
|
||||
if (typeof width === 'string') {
|
||||
if (width === 'half') width = '50%';
|
||||
width = +width.slice(0, -1) / 100;
|
||||
return this.parent.width * width | 0;
|
||||
return parent.width * width | 0;
|
||||
}
|
||||
|
||||
// This is for if the element is being streched or shrunken.
|
||||
// Although the width for shrunken elements is calculated
|
||||
// in the render function, it may be calculated based on
|
||||
// the content width, and the content width is initially
|
||||
// decided by the width the element, so it needs to be
|
||||
// calculated here.
|
||||
if (!width) {
|
||||
// Problem if .left is 'center', we can't calculate the width
|
||||
// NOTE: This assume `right` cannot be a string.
|
||||
var left = this.position.left;
|
||||
if (typeof left === 'string') {
|
||||
if (left === 'center') left = '50%';
|
||||
left = +left.slice(0, -1) / 100;
|
||||
left = this.parent.width * left | 0;
|
||||
left = parent.width * left | 0;
|
||||
}
|
||||
width = this.parent.width - this.position.right - left;
|
||||
width = parent.width - this.position.right - left;
|
||||
}
|
||||
|
||||
return width;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('width', function() {
|
||||
return this._getWidth(false);
|
||||
});
|
||||
|
||||
// TODO: Move _getShrinkSize calculation here. This will in turn fix .top.
|
||||
Element.prototype.__defineGetter__('height', function() {
|
||||
Element.prototype._getHeight = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
var height = this.position.height;
|
||||
|
||||
if (typeof height === 'string') {
|
||||
if (height === 'half') height = '50%';
|
||||
height = +height.slice(0, -1) / 100;
|
||||
return this.parent.height * height | 0;
|
||||
return parent.height * height | 0;
|
||||
}
|
||||
|
||||
// This is for if the element is being streched or shrunken.
|
||||
// Although the width for shrunken elements is calculated
|
||||
// in the render function, it may be calculated based on
|
||||
// the content width, and the content width is initially
|
||||
// decided by the width the element, so it needs to be
|
||||
// calculated here.
|
||||
if (!height) {
|
||||
// Problem if .top is 'center', we can't calculate the height
|
||||
// NOTE: This assume `bottom` cannot be a string.
|
||||
var top = this.position.top;
|
||||
if (typeof top === 'string') {
|
||||
if (top === 'center') top = '50%';
|
||||
top = +top.slice(0, -1) / 100;
|
||||
top = this.parent.height * top | 0;
|
||||
top = parent.height * top | 0;
|
||||
}
|
||||
height = this.parent.height - this.position.bottom - top;
|
||||
height = parent.height - this.position.bottom - top;
|
||||
}
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('height', function() {
|
||||
return this._getHeight(false);
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rleft', function() {
|
||||
Element.prototype._getLeft = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
var left = this.position.left;
|
||||
|
||||
if (typeof left === 'string') {
|
||||
if (left === 'center') left = '50%';
|
||||
left = +left.slice(0, -1) / 100;
|
||||
left = this.parent.width * left | 0;
|
||||
left = parent.width * left | 0;
|
||||
if (this.position.left === 'center') {
|
||||
left -= this.width / 2 | 0;
|
||||
left -= this._getWidth(get) / 2 | 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.left == null && this.options.right != null) {
|
||||
return this.parent.width - this.width - this.right;
|
||||
return this.screen.cols - this._getWidth(get) - this._getRight(get);
|
||||
}
|
||||
|
||||
return left;
|
||||
return (parent.left || 0) + left;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('left', function() {
|
||||
return this._getLeft(false);
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rright', function() {
|
||||
Element.prototype._getRight = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
if (this.options.right == null && this.options.left != null) {
|
||||
return this.parent.width - (this.rleft + this.width);
|
||||
return this.screen.cols - (this._getLeft(get) + this._getWidth(get));
|
||||
}
|
||||
return this.position.right;
|
||||
return (parent.right || 0) + this.position.right;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('right', function() {
|
||||
return this._getRight(false);
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rtop', function() {
|
||||
Element.prototype._getTop = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
var top = this.position.top;
|
||||
|
||||
if (typeof top === 'string') {
|
||||
if (top === 'center') top = '50%';
|
||||
top = +top.slice(0, -1) / 100;
|
||||
top = this.parent.height * top | 0;
|
||||
top = parent.height * top | 0;
|
||||
if (this.position.top === 'center') {
|
||||
top -= this.height / 2 | 0;
|
||||
top -= this._getHeight(get) / 2 | 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.top == null && this.options.bottom != null) {
|
||||
return this.parent.height - this.height - this.bottom;
|
||||
return this.screen.rows - this._getHeight(get) - this._getBottom(get);
|
||||
}
|
||||
|
||||
return top;
|
||||
return (parent.top || 0) + top;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('top', function() {
|
||||
return this._getTop(false);
|
||||
});
|
||||
|
||||
Element.prototype._getBottom = function(get) {
|
||||
var parent = get ? this.parent._getPos() : this.parent;
|
||||
if (this.options.bottom == null && this.options.top != null) {
|
||||
return this.screen.rows - (this._getTop(get) + this._getHeight(get));
|
||||
}
|
||||
return (parent.bottom || 0) + this.position.bottom;
|
||||
};
|
||||
|
||||
Element.prototype.__defineGetter__('bottom', function() {
|
||||
return this._getBottom(false);
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rleft', function() {
|
||||
return this.left - this.parent.left;
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rright', function() {
|
||||
return this.right - this.parent.right;
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rtop', function() {
|
||||
return this.top - this.parent.top;
|
||||
});
|
||||
|
||||
Element.prototype.__defineGetter__('rbottom', function() {
|
||||
if (this.options.bottom == null && this.options.top != null) {
|
||||
return this.parent.height - (this.rtop + this.height);
|
||||
}
|
||||
return this.position.bottom;
|
||||
return this.bottom - this.parent.bottom;
|
||||
});
|
||||
|
||||
// TODO: Reconcile the fact the `position.left` is actually `.rleft`. etc.
|
||||
// TODO: Allow string values for absolute coords below.
|
||||
// TODO: Optimize clearing to only clear what is necessary.
|
||||
|
||||
Element.prototype.__defineSetter__('left', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') val = '50%';
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.width * val | 0;
|
||||
}
|
||||
val -= this.parent.left;
|
||||
if (this.position.left === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.left = this.position.left = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('right', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') val = '50%';
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.width * val | 0;
|
||||
}
|
||||
val -= this.parent.right;
|
||||
if (this.position.right === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
//if (this.options.right == null) {
|
||||
// return this.options.left = this.position.left =
|
||||
// this.screen.width - 1 - val;
|
||||
//}
|
||||
return this.options.right = this.position.right = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('top', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') val = '50%';
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.height * val | 0;
|
||||
}
|
||||
val -= this.parent.top;
|
||||
if (this.position.top === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.top = this.position.top = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('bottom', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') val = '50%';
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.height * val | 0;
|
||||
}
|
||||
val -= this.parent.bottom;
|
||||
if (this.position.bottom === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
//if (this.options.bottom == null) {
|
||||
// return this.options.top = this.position.top =
|
||||
// this.screen.height - 1 - val;
|
||||
//}
|
||||
return this.options.bottom = this.position.bottom = val;
|
||||
});
|
||||
/**
|
||||
* Position Setters
|
||||
*/
|
||||
|
||||
// NOTE:
|
||||
// For right, bottom, rright, and rbottom:
|
||||
// If position.bottom is null, we could simply set top instead.
|
||||
// But it wouldn't replicate bottom behavior appropriately if
|
||||
// the parent was resized, etc.
|
||||
Element.prototype.__defineSetter__('width', function(val) {
|
||||
if (this.position.width === val) return;
|
||||
this.emit('resize');
|
||||
|
@ -2047,6 +2095,56 @@ Element.prototype.__defineSetter__('height', function(val) {
|
|||
return this.options.height = this.position.height = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('left', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') {
|
||||
val = this.screen.width / 2 | 0;
|
||||
val -= this.width / 2 | 0;
|
||||
} else {
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.width * val | 0;
|
||||
}
|
||||
}
|
||||
val -= this.parent.left;
|
||||
if (this.position.left === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.left = this.position.left = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('right', function(val) {
|
||||
val -= this.parent.right;
|
||||
if (this.position.right === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.right = this.position.right = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('top', function(val) {
|
||||
if (typeof val === 'string') {
|
||||
if (val === 'center') {
|
||||
val = this.screen.height / 2 | 0;
|
||||
val -= this.height / 2 | 0;
|
||||
} else {
|
||||
val = +val.slice(0, -1) / 100;
|
||||
val = this.screen.height * val | 0;
|
||||
}
|
||||
}
|
||||
val -= this.parent.top;
|
||||
if (this.position.top === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.top = this.position.top = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('bottom', function(val) {
|
||||
val -= this.parent.bottom;
|
||||
if (this.position.bottom === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
return this.options.bottom = this.position.bottom = val;
|
||||
});
|
||||
|
||||
Element.prototype.__defineSetter__('rleft', function(val) {
|
||||
if (this.position.left === val) return;
|
||||
this.emit('move');
|
||||
|
@ -2058,10 +2156,6 @@ Element.prototype.__defineSetter__('rright', function(val) {
|
|||
if (this.position.right === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
//if (this.options.right == null) {
|
||||
// return this.options.left = this.position.left =
|
||||
// this.parent.width - 1 - val;
|
||||
//}
|
||||
return this.options.right = this.position.right = val;
|
||||
});
|
||||
|
||||
|
@ -2076,10 +2170,6 @@ Element.prototype.__defineSetter__('rbottom', function(val) {
|
|||
if (this.position.bottom === val) return;
|
||||
this.emit('move');
|
||||
this.clearPos();
|
||||
//if (this.options.bottom == null) {
|
||||
// return this.options.top = this.position.top =
|
||||
// this.parent.height - 1 - val;
|
||||
//}
|
||||
return this.options.bottom = this.position.bottom = val;
|
||||
});
|
||||
|
||||
|
@ -2123,7 +2213,7 @@ Box.prototype.__proto__ = Element.prototype;
|
|||
|
||||
Box.prototype.type = 'box';
|
||||
|
||||
Box.prototype._getShrinkSize = function(content) {
|
||||
Box.prototype._getShrinkSize = function() {
|
||||
// TODO: Possibly move this to parseContent.
|
||||
return {
|
||||
height: this._clines.length,
|
||||
|
@ -2146,7 +2236,7 @@ Box.prototype._getShrinkBox = function(xi, xl, yi, yl) {
|
|||
for (i = 0; i < this.children.length; i++) {
|
||||
el = this.children[i];
|
||||
|
||||
ret = el.getCoords();
|
||||
ret = el._getCoords();
|
||||
if (!ret) continue;
|
||||
|
||||
if (ret.xi < mxi) mxi = ret.xi;
|
||||
|
@ -2183,8 +2273,8 @@ Box.prototype._getShrinkBox = function(xi, xl, yi, yl) {
|
|||
return { xi: xi, xl: xl, yi: yi, yl: yl };
|
||||
};
|
||||
|
||||
Box.prototype._getShrinkContent = function(xi, xl, yi, yl, content) {
|
||||
var hw = this._getShrinkSize(content)
|
||||
Box.prototype._getShrinkContent = function(xi, xl, yi, yl) {
|
||||
var hw = this._getShrinkSize()
|
||||
, h = hw.height
|
||||
, w = hw.width;
|
||||
|
||||
|
@ -2212,9 +2302,9 @@ Box.prototype._getShrinkContent = function(xi, xl, yi, yl, content) {
|
|||
return { xi: xi, xl: xl, yi: yi, yl: yl };
|
||||
};
|
||||
|
||||
Box.prototype._getShrink = function(xi, xl, yi, yl, content) {
|
||||
Box.prototype._getShrink = function(xi, xl, yi, yl) {
|
||||
var shrinkBox = this._getShrinkBox(xi, xl, yi, yl)
|
||||
, shrinkContent = this._getShrinkContent(xi, xl, yi, yl, content)
|
||||
, shrinkContent = this._getShrinkContent(xi, xl, yi, yl)
|
||||
, xll = xl
|
||||
, yll = yl;
|
||||
|
||||
|
@ -2251,48 +2341,30 @@ Box.prototype._getShrink = function(xi, xl, yi, yl, content) {
|
|||
return { xi: xi, xl: xl, yi: yi, yl: yl };
|
||||
};
|
||||
|
||||
Box.prototype.getCoords = function() {
|
||||
Box.prototype._getCoords = function(get) {
|
||||
if (this.hidden) return;
|
||||
|
||||
var lines = this.screen.lines
|
||||
, xi = this.left
|
||||
//, xl = this.screen.cols - this.right
|
||||
, xl = xi + this.width
|
||||
, yi = this.top
|
||||
//, yl = this.screen.rows - this.bottom
|
||||
, yl = yi + this.height
|
||||
var xi = this._getLeft(get)
|
||||
, xl = xi + this._getWidth(get)
|
||||
, yi = this._getTop(get)
|
||||
, yl = yi + this._getHeight(get)
|
||||
, rtop
|
||||
, visible
|
||||
, coords;
|
||||
|
||||
//if (this.position.width) {
|
||||
// xl = xi + this.width;
|
||||
//}
|
||||
|
||||
//if (this.position.height) {
|
||||
// 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
|
||||
rtop = yi - this.parent._getTop(get)
|
||||
- (this.parent.border ? 1 : 0)
|
||||
- this.parent.padding;
|
||||
|
||||
visible = this.parent.height
|
||||
visible = this.parent._getHeight(get)
|
||||
- (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)
|
||||
- this.parent.padding);
|
||||
|
||||
if (rtop - this.parent.childBase < 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -2300,6 +2372,9 @@ Box.prototype.getCoords = function() {
|
|||
if (rtop - this.parent.childBase >= visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
yi -= this.parent.childBase;
|
||||
yl -= this.parent.childBase;
|
||||
}
|
||||
|
||||
// Attempt to shrink the element base on the
|
||||
|
@ -2319,12 +2394,10 @@ Box.prototype.getCoords = function() {
|
|||
};
|
||||
|
||||
// Here be dragons.
|
||||
// TODO: Potentially move all calculations performed on
|
||||
// xi/xl/yi/yl here to Element offset and size getters.
|
||||
Box.prototype.render = function() {
|
||||
this.parseContent();
|
||||
|
||||
var coords = this.getCoords();
|
||||
var coords = this._getCoords(true);
|
||||
if (!coords) return;
|
||||
|
||||
var lines = this.screen.lines
|
||||
|
@ -2351,17 +2424,10 @@ Box.prototype.render = function() {
|
|||
dattr = this.sattr(this.style, this.style.fg, this.style.bg);
|
||||
attr = dattr;
|
||||
|
||||
// Check previous line for escape codes.
|
||||
if (this.contentIndex != null && this.childBase > 0 && this._clines) {
|
||||
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);
|
||||
i += c[0].length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.border) xi++, xl--, yi++, yl--;
|
||||
|
@ -2564,7 +2630,7 @@ Box.prototype.render = function() {
|
|||
// screen.render();
|
||||
// box.left++;
|
||||
// box.insertTop('foobar');
|
||||
// Things will break because we're using lpos instead of getCoords().
|
||||
// Things will break because we're using lpos instead of _getCoords().
|
||||
// Maybe lpos could be updated on .left, .right, etc setters?
|
||||
|
||||
Box.prototype.insertLine = function(i, line) {
|
||||
|
@ -4241,9 +4307,9 @@ function Checkbox(options) {
|
|||
}
|
||||
|
||||
this.on('focus', function(old) {
|
||||
if (!this.lpos) return;
|
||||
if (!self.lpos) return;
|
||||
self.screen.program.saveCursor();
|
||||
self.screen.program.cup(this.lpos.yi, this.lpos.xi + 1);
|
||||
self.screen.program.cup(self.lpos.yi, self.lpos.xi + 1);
|
||||
self.screen.program.showCursor();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue