add auto-positioning which respects padding and borders.

This commit is contained in:
Christopher Jeffrey 2013-07-30 08:50:49 -05:00
parent ac88ceaebe
commit 78a3726f2f
3 changed files with 105 additions and 23 deletions

View File

@ -151,6 +151,8 @@ The screen on which every other node renders.
- **resizeTimeout** - amount of time (in ms) to redraw the screen after the
terminal is resized (default: 300).
- **tabSize** - the width of tabs within an element's content.
- **autoPadding** - automatically position child elements with border and
padding in mind.
##### Properties:

View File

@ -282,6 +282,8 @@ function Screen(options) {
this.tput = this.program.tput;
this.output = this.program.output;
this.autoPadding = options.autoPadding;
this.tabc = Array((options.tabSize || 4) + 1).join(' ');
this.dattr = ((0 << 18) | (0x1ff << 9)) | 0x1ff;
@ -292,6 +294,20 @@ function Screen(options) {
bottom: this.bottom = this.rbottom = 0
};
this.ileft = 0;
this.itop = 0;
this.iright = 0;
this.ibottom = 0;
this.iheight = 0;
this.iwidth = 0;
this.padding = {
left: 0,
top: 0,
right: 0,
bottom: 0
};
this.hover = null;
this.history = [];
this.clickable = [];
@ -1703,6 +1719,13 @@ function Element(options) {
height: options.height
};
// if (options.position.left == null && options.position.right == null) {
// options.position.left = 0;
// }
// if (options.position.top == null && options.position.bottom == null) {
// options.position.top = 0;
// }
if (options.position.width === 'shrink'
|| options.position.height === 'shrink') {
if (options.position.width === 'shrink') {
@ -1792,6 +1815,10 @@ function Element(options) {
style: this.style.label,
fixed: true
}));
if (this.screen.autoPadding) {
this.children[this.children.length-1].rleft = -this.ileft + 2;
this.children[this.children.length-1].rtop = -this.itop;
}
}
// TODO: Possibly move this to Node for screen.on('mouse', ...).
@ -2286,7 +2313,7 @@ Screen.prototype._getPos = function() {
Element.prototype._getPos = function() {
var pos = this.lpos;
assert.ok(pos && !pos.changed);
assert.ok(pos);
if (pos.left != null) return pos;
@ -2300,20 +2327,6 @@ Element.prototype._getPos = function() {
return pos;
};
Element.prototype._bindPosChanged = function() {
function changed() {
self.forDescendants(function(el) {
if (el.lpos) el.lpos.changed = true;
}, true);
}
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);
};
/**
* Position Getters
*/
@ -2342,6 +2355,11 @@ Element.prototype._getWidth = function(get) {
left = parent.width * left | 0;
}
width = parent.width - (this.position.right || 0) - left;
if (this.screen.autoPadding) {
width -= ((this.position.left != null || this.position.right == null)
&& this.position.left !== 'center' ? this.parent.ileft : 0);
width -= (this.position.right != null ? this.parent.iright : 0);
}
}
return width;
@ -2375,6 +2393,11 @@ Element.prototype._getHeight = function(get) {
top = parent.height * top | 0;
}
height = parent.height - (this.position.bottom || 0) - top;
if (this.screen.autoPadding) {
height -= ((this.position.top != null || this.position.bottom == null)
&& this.position.top !== 'center' ? this.parent.itop : 0);
height -= (this.position.bottom != null ? this.parent.ibottom : 0);
}
}
return height;
@ -2401,6 +2424,13 @@ Element.prototype._getLeft = function(get) {
return this.screen.cols - this._getWidth(get) - this._getRight(get);
}
if (this.screen.autoPadding) {
if ((this.position.left != null || this.position.right == null)
&& this.position.left !== 'center') {
left += this.parent.ileft;
}
}
return (parent.left || 0) + left;
};
@ -2411,9 +2441,17 @@ Element.prototype.__defineGetter__('left', function() {
Element.prototype._getRight = function(get) {
var parent = get ? this.parent._getPos() : this.parent;
if (this.position.right == null && this.position.left != null) {
return this.screen.cols - (this._getLeft(get) + this._getWidth(get));
var right = this.screen.cols - (this._getLeft(get) + this._getWidth(get));
if (this.screen.autoPadding) {
right += (this.position.right != null ? this.parent.iright : 0);
}
return right;
}
return (parent.right || 0) + (this.position.right || 0);
var right = (parent.right || 0) + (this.position.right || 0);
if (this.screen.autoPadding) {
right += (this.position.right != null ? this.parent.iright : 0);
}
return right;
};
Element.prototype.__defineGetter__('right', function() {
@ -2437,6 +2475,13 @@ Element.prototype._getTop = function(get) {
return this.screen.rows - this._getHeight(get) - this._getBottom(get);
}
if (this.screen.autoPadding) {
if ((this.position.top != null || this.position.bottom == null)
&& this.position.top !== 'center') {
top += this.parent.itop;
}
}
return (parent.top || 0) + top;
};
@ -2447,9 +2492,17 @@ Element.prototype.__defineGetter__('top', function() {
Element.prototype._getBottom = function(get) {
var parent = get ? this.parent._getPos() : this.parent;
if (this.position.bottom == null && this.position.top != null) {
return this.screen.rows - (this._getTop(get) + this._getHeight(get));
var bottom = this.screen.rows - (this._getTop(get) + this._getHeight(get));
if (this.screen.autoPadding) {
bottom += (this.position.bottom != null ? this.parent.ibottom : 0);
}
return bottom;
}
return (parent.bottom || 0) + (this.position.bottom || 0);
var bottom = (parent.bottom || 0) + (this.position.bottom || 0);
if (this.screen.autoPadding) {
bottom += (this.position.bottom != null ? this.parent.ibottom : 0);
}
return bottom;
};
Element.prototype.__defineGetter__('bottom', function() {
@ -2630,10 +2683,18 @@ Element.prototype._getShrinkBox = function(xi, xl, yi, yl) {
|| this.position.right == null)) {
if (this.position.left == null && this.position.right != null) {
xi = xl - (mxl - mxi);
xi -= this.padding.left + this.padding.right;
if (!this.screen.autoPadding) {
xi -= this.padding.left + this.padding.right;
} else {
xi -= this.padding.left;
}
} else {
xl = mxl;
xl += this.padding.left + this.padding.right;
if (!this.screen.autoPadding) {
xl += this.padding.left + this.padding.right;
} else {
xl += this.padding.right;
}
}
}
@ -2643,10 +2704,18 @@ Element.prototype._getShrinkBox = function(xi, xl, yi, yl) {
&& !this.scrollable) {
if (this.position.top == null && this.position.bottom != null) {
yi = yl - (myl - myi);
yi -= this.padding.top + this.padding.bottom;
if (!this.screen.autoPadding) {
yi -= this.padding.top + this.padding.bottom;
} else {
yi -= this.padding.top;
}
} else {
yl = myl;
yl += this.padding.top + this.padding.bottom;
if (!this.screen.autoPadding) {
yl += this.padding.top + this.padding.bottom;
} else {
yl += this.padding.bottom;
}
}
}
@ -3822,6 +3891,12 @@ List.prototype.add = function(item) {
focusEffects: this.mouse ? this.style.item.focus : null
};
if (this.screen.autoPadding) {
options.top = this.items.length;
options.left = 1;
options.right = 1;
}
['bg', 'fg', 'bold', 'underline',
'blink', 'inverse', 'invisible'].forEach(function(name) {
options[name] = function() {

View File

@ -103,6 +103,11 @@ list.prepend(blessed.text({
content: ' My list '
}));
if (screen.autoPadding) {
list.children[0].rleft = -list.ileft + 2;
list.children[0].rtop = -list.itop;
}
list.on('keypress', function(ch, key) {
if (key.name === 'up' || key.name === 'k') {
list.up();