button and shrink work.

This commit is contained in:
Christopher Jeffrey 2013-06-16 04:21:57 -05:00
parent 2c632522e7
commit f0b107978b
3 changed files with 184 additions and 18 deletions

View File

@ -143,6 +143,7 @@ screen.render();
Blessed comes with a number of high-level widgets so you can avoid all the
nasty low-level terminal stuff.
#### Node (from EventEmitter)
The base node which everything inherits from.
@ -173,6 +174,7 @@ The base node which everything inherits from.
- **remove(node)** - remove child node from node.
- **detach()** - remove node from its parent.
#### Screen (from Node)
The screen on which every other node renders.
@ -218,6 +220,7 @@ The screen on which every other node renders.
- **focusPush(element)** - push element on the focus stack (equivalent to `screen.focused = el`).
- **focusPop()/focusLast()** - pop element off the focus stack.
#### Element (from Node)
The base element.
@ -277,6 +280,7 @@ The base element.
- **toggle()** - toggle hidden/shown.
- **focus()** - focus element.
#### Box (from Element)
A box element which draws a simple box containing `content` or other elements.
@ -296,6 +300,7 @@ An element similar to Box, but geared towards rendering simple text elements.
Inherits all options, properties, events, and methods from Element.
#### Line (from Box)
A simple line which can be `ascii` or `bg` styled.
@ -308,6 +313,7 @@ A simple line which can be `ascii` or `bg` styled.
Inherits all options, properties, events, and methods from Box.
#### ScrollableBox (from Box)
A box with scrollable content.
@ -334,6 +340,7 @@ A box with scrollable content.
- **scroll(offset)** - scroll the content by an offset.
#### List (from ScrollableBox)
A scrollable list which can display selectable items.
@ -367,6 +374,7 @@ A scrollable list which can display selectable items.
- **up(amount)** - select item above selected.
- **down(amount)** - select item below selected.
#### ScrollableText (from ScrollableBox)
A scrollable text box which can display and scroll text, as well as handle pre-existing newlines and escape codes.
@ -392,6 +400,7 @@ A scrollable text box which can display and scroll text, as well as handle pre-e
A form input.
#### Textbox (from Input)
A box which allows text input.
@ -416,6 +425,34 @@ A box which allows text input.
- **setEditor(callback)** - open text editor in $EDITOR, read the output from the
resulting file. takes a callback which receives the final value.
#### Button (from Input)
A button which can be focused and allows key and mouse input.
##### Options:
- inherits all from Input.
##### Properties:
- inherits all from Input.
##### Events:
- inherits all from ScrollableBox.
- **press** - received when the button is clicked/pressed.
##### Methods:
- inherits all from ScrollableBox.
- **add(text)** - add an item based on a string.
- **select(index)** - select an index of an item.
- **move(offset)** - select item based on current offset.
- **up(amount)** - select item above selected.
- **down(amount)** - select item below selected.
#### ProgressBar (from Input)
A progress bar allowing various styles.
@ -443,6 +480,7 @@ A progress bar allowing various styles.
- **progress(amount)** - progress the bar by a fill amount.
- **reset()** - reset the bar.
### Positioning
Offsets may be a number, a percentage (e.g. `50%`), or a keyword (e.g.

View File

@ -438,7 +438,10 @@ Screen.prototype.draw = function(start, end) {
}
if (bgColor !== 0x1ff) {
if (bgColor < 16 || (this.tput && this.tput.colors <= 16)) {
if (this.tput) {
bgColor = this._reduceColor(bgColor);
}
if (bgColor < 16) {
if (bgColor < 8) {
bgColor += 40;
} else if (bgColor < 16) {
@ -452,7 +455,10 @@ Screen.prototype.draw = function(start, end) {
}
if (fgColor !== 0x1ff) {
if (fgColor < 16 || (this.tput && this.tput.colors <= 16)) {
if (this.tput) {
fgColor = this._reduceColor(fgColor);
}
if (fgColor < 16) {
if (fgColor < 8) {
fgColor += 30;
} else if (fgColor < 16) {
@ -489,6 +495,22 @@ Screen.prototype.draw = function(start, end) {
this.program.restoreCursor();
};
Screen.prototype._reduceColor = function(col) {
if (this.tput) {
if (col >= 16 && this.tput.colors <= 16) {
//col = Screen.ccolors[col];
if (col >= 244) col = colors.white;
else if (col >= 232) col = colors.black;
else col = colors.blue;
} else if (col >= 8 && this.tput.colors <= 8) {
col -= 8;
} else if (col >= 2 && this.tput.colors <= 2) {
col %= 2;
}
}
return col;
};
Screen.prototype.focus = function(offset) {
if (!this.input.length || !offset) return;
var i = this.input.indexOf(this.focused);
@ -632,6 +654,8 @@ function Element(options) {
if (type === 'mouse'
|| type === 'click'
|| type === 'hover'
|| type === 'mouseover'
|| type === 'mouseout'
|| type === 'mousedown'
|| type === 'mouseup'
|| type === 'mousewheel'
@ -697,11 +721,7 @@ Element.prototype.setContent = function(content) {
var ret = this.render(true);
// TODO: Maybe simply set _pcontent with _parseTags result.
this.content = this._parseTags(content || '');
this.screen.clearRegion(
ret.xi + (this.border ? 1 : 0),
ret.xl - (this.border ? 1 : 0),
ret.yi + (this.border ? 1 : 0),
ret.yl - (this.border ? 1 : 0));
this.screen.clearRegion(ret.xi, ret.xl, ret.yi, ret.yl);
};
// Convert `{red-fg}foo{/red-fg}` to `\x1b[31mfoo\x1b[39m`.
@ -1021,6 +1041,19 @@ function Box(options) {
Box.prototype.__proto__ = Element.prototype;
Box.prototype._getShrinkSize = function(content) {
var lines = content.replace(/\x1b\[[\d;]*m/g, '').split('\n');
return {
height: lines.length,
width: lines.reduce(function(current, line) {
return line.length > current
? line.length //+ (lines.length > 1 ? 1 : 0) // for newlines
: current;
}, 0)
};
};
// Here be dragons.
Box.prototype.render = function(stop) {
// NOTE: Maybe move this `hidden` check down below `stop` check and return `ret`.
if (this.hidden) return;
@ -1065,19 +1098,48 @@ Box.prototype.render = function(stop) {
}
}
// NOTE: Could simply change some offsets around and move this below the
// shrink block. Could also stop passing a string to _getShrinkSize.
if (this.align === 'center' || this.align === 'right') {
var ncontent = content.split('\n')[0].replace(/\x1b\[[\d;]*m/g, '')
, width = this.width;
var ncontent = content.replace(/\x1b\[[\d;]*m/g, '')
, width = this.width - (this.border ? 2 : 0) - this.padding * 2;
if (ncontent.length < width) {
var s = width - ncontent.length;
if (this.align === 'center') {
content = Array(((s / 2 | 0) - (this.border ? 1 : 0)) + 1).join(' ') + content;
s = Array(((s / 2 | 0) - (this.border ? 1 : 0)) + 1).join(' ');
content = s + content + (this.shrink ? s : '');
//s = (s / 2 | 0) - (this.border ? 1 : 0);
//ci -= s;
//xl += s * 2;
} else {
content = Array((s - (this.border ? 2 : 0)) + 1).join(' ') + content;
s -= this.left; // this shouldn't be necessary
s = Array((s - (this.border ? 2 : 0)) + 1).join(' ');
content = s + content;
//s = s - (this.border ? 2 : 0);
//ci -= s;
//xl += s;
}
}
}
if (this.shrink) {
var hw = this._getShrinkSize(content)
, h = hw.height
, w = hw.width;
if (this.options.left == null && this.options.right != null) {
xi_ = xl - w - (this.border ? 2 : 0) - this.padding;
//xi_--; // make it one cell wider for newlines
} else {
xl = xi_ + w + (this.border ? 2 : 0) + this.padding;
//xl++; // make it one cell wider for newlines
}
if (this.options.top == null && this.options.bottom != null) {
yi_ = yl - h - (this.border ? 2 : 0) - this.padding;
} else {
yl = yi_ + h + (this.border ? 2 : 0) + this.padding;
}
}
var ret = {
xi: xi_,
xl: xl,
@ -1109,6 +1171,7 @@ Box.prototype.render = function(stop) {
if (this.border) yi_++, yl--, xi_++, xl--;
// TODO: Fix padding.
if (this.padding) {
yi_ += this.padding, yl -= this.padding;
xi_ += this.padding, xl -= this.padding;
@ -1121,12 +1184,6 @@ outer:
cell = lines[yi][xi];
if (!cell) break;
if (this.shrink && !content[ci] && yi === yi_) {
// Need to subtract 1 and padding for below.
xl = xi + 1 - 1 - this.padding;
break outer;
}
ch = content[ci++] || ' ';
// Handle escape codes.
@ -1144,6 +1201,15 @@ outer:
// Handle newlines.
if (ch === '\t') ch = ' ';
if (ch === '\n' || ch === '\r') {
// If we're on the first cell and we find a newline and the last cell
// of the last line was not a newline, let's just treat this like the
// newline was already "counted".
if (xi === xi_ && yi !== yi_ && content[ci-2] !== '\n') {
xi--;
continue;
}
// this.screen.fillRegion(attr, ' ', xi, xl, yi, yi + 1);
// continue outer;
ch = ' ';
for (; xi < xl; xi++) {
cell = lines[yi][xi];
@ -1722,14 +1788,51 @@ Textarea.prototype.__proto__ = Input.prototype;
*/
function Button(options) {
var self = this;
if (!(this instanceof Button)) {
return new Button(options);
}
Input.call(this, options);
this.on('keypress', function(ch, key) {
if (key.name === 'enter' || key.name === 'space') {
self.press();
}
});
this.on('click', function() {
self.press();
});
this.on('mouseover', function() {
self.inverse = !self.options.inverse;
self.screen.render();
});
this.on('mouseout', function() {
self.inverse = self.options.inverse;
self.screen.render();
});
}
Button.prototype.__proto__ = Input.prototype;
Button.prototype.press = function() {
var self = this;
this.emit('press');
if (this.border) {
var color = this.border.color;
this.border.color = 2;
this.screen.render();
setTimeout(function() {
self.border.color = color;
self.screen.render();
}, 300);
}
};
/**
* ProgressBar
*/
@ -2002,6 +2105,7 @@ function convert(color) {
var val = colors[color];
if (val == null) val = color;
if (val == null) val = -1;
//if (typeof val === 'string') val = Screen._findColor(val);
if (val === -1) return 0x1ff;
return val;
}
@ -2029,5 +2133,6 @@ exports.List = List;
exports.ScrollableText = ScrollableText;
exports.Input = Input;
exports.Textbox = Textbox;
exports.Textarea = Textarea;
exports.Button = Button;
exports.ProgressBar = ProgressBar;

View File

@ -9,7 +9,8 @@ screen.append(new blessed.Text({
top: 0,
left: 2,
width: '100%',
content: '{green-fg}Welcome{/green-fg} to my {red-bg,ul}program{/}',
//bg: 'blue',
content: '{green-fg}Welcome{/green-fg} to my {red-fg,ul}program{/red-fg,ul}',
tags: true,
align: 'center'
}));
@ -196,6 +197,28 @@ var input = new blessed.Textbox({
screen.append(input);
var button = blessed.Button({
//content: 'Click me!',
content: 'Click\nme!',
shrink: true,
border: {
type: 'ascii'
},
fg: 'red',
bg: 'blue',
//height: 3,
right: 4,
//bottom: 6,
bottom: 2,
padding: 0
});
button.on('press', function() {
button.setContent('Clicked!');
});
screen.append(button);
screen.on('keypress', function(ch, key) {
if (key.name === 'tab') {
return key.shift