mirror of
https://github.com/embarklabs/neo-blessed.git
synced 2025-02-22 15:48:07 +00:00
textbox. progressbar. misc. readme.
This commit is contained in:
parent
2dfedf5e47
commit
6a03ad42ff
218
README.md
218
README.md
@ -258,7 +258,8 @@ The base element.
|
||||
- **valign** - vertical text alignment: `top`, `middle`, or `bottom`.
|
||||
- **shrink** - shrink/flex/grow to content and child elements. width/height
|
||||
during render.
|
||||
- **padding** - amount of padding on the inside of the element.
|
||||
- **padding** - amount of padding on the inside of the element. can be a number
|
||||
or an object containing the properties: `left`, `right`, `top`, and `bottom`.
|
||||
- **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
|
||||
@ -316,6 +317,8 @@ The base element.
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Node.
|
||||
- note: if the `scrollable` option is enabled, Element inherits all methods
|
||||
from ScrollableBox.
|
||||
- **render()** - write content and children to the screen buffer.
|
||||
- **hide()** - hide element.
|
||||
- **show()** - show element.
|
||||
@ -343,7 +346,7 @@ parameter must be a string.
|
||||
- **setContent(text)** - set the content. note: when text is input, it will be
|
||||
stripped of all non-SGR escape codes, tabs will be replaced with 8 spaces,
|
||||
and tags will be replaced with SGR codes (if enabled).
|
||||
- **getContent(text)** - return content, slightly different from `el.content`.
|
||||
- **getContent()** - return content, slightly different from `el.content`.
|
||||
assume the above formatting.
|
||||
- **insertLine(i, lines)** - insert a line into the box's content.
|
||||
- **deleteLine(i)** - delete a line from the box's content.
|
||||
@ -416,7 +419,8 @@ Inherits all options, properties, events, and methods from Box.
|
||||
|
||||
#### ScrollableBox (from Box)
|
||||
|
||||
**DEPRECATED** - Use box with the `scrollable` option instead.
|
||||
**DEPRECATED** - Use Box with the `scrollable` and `alwaysScroll` options
|
||||
instead.
|
||||
|
||||
A box with scrollable content.
|
||||
|
||||
@ -444,50 +448,7 @@ A box with scrollable content.
|
||||
##### Methods:
|
||||
|
||||
- **scroll(offset)** - scroll the content by an offset.
|
||||
|
||||
|
||||
#### List (from ScrollableBox)
|
||||
|
||||
A scrollable list which can display selectable items.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from ScrollableBox.
|
||||
- **selectedFg, selectedBg** - foreground and background for selected item,
|
||||
treated like fg and bg. (can be contained in style: e.g. `style.selected.fg`).
|
||||
- **selectedBold, selectedUnderline** - character attributes for selected item,
|
||||
treated like bold and underline. (can be contained in style: e.g.
|
||||
`style.selected.bold`).
|
||||
- **itemFg, itemBg** - foreground and background for unselected item,
|
||||
treated like fg and bg. (can be contained in style: e.g. `style.item.fg`).
|
||||
- **itemBold, itemUnderline** - character attributes for an unselected item,
|
||||
treated like bold and underline. (can be contained in style: e.g.
|
||||
`style.item.bold`).
|
||||
- **mouse** - whether to automatically enable mouse support for this list
|
||||
(allows clicking items).
|
||||
- **keys** - use predefined keys for navigating the list.
|
||||
- **vi** - use vi keys with the `keys` option.
|
||||
- **items** - an array of strings which become the list's items.
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from ScrollableBox.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from ScrollableBox.
|
||||
- **select** - received when an item is selected.
|
||||
- **cancel** - list was canceled (when `esc` is pressed with the `keys` option).
|
||||
- **action** - either a select or a cancel event was received.
|
||||
|
||||
##### 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.
|
||||
- **scrollTo(index)** - scroll the content to an absolute index.
|
||||
|
||||
|
||||
#### ScrollableText (from ScrollableBox)
|
||||
@ -517,6 +478,50 @@ pre-existing newlines and escape codes.
|
||||
- inherits all from ScrollableBox.
|
||||
|
||||
|
||||
#### List (from Box)
|
||||
|
||||
A scrollable list which can display selectable items.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from Box.
|
||||
- **selectedFg, selectedBg** - foreground and background for selected item,
|
||||
treated like fg and bg. (can be contained in style: e.g. `style.selected.fg`).
|
||||
- **selectedBold, selectedUnderline** - character attributes for selected item,
|
||||
treated like bold and underline. (can be contained in style: e.g.
|
||||
`style.selected.bold`).
|
||||
- **itemFg, itemBg** - foreground and background for unselected item,
|
||||
treated like fg and bg. (can be contained in style: e.g. `style.item.fg`).
|
||||
- **itemBold, itemUnderline** - character attributes for an unselected item,
|
||||
treated like bold and underline. (can be contained in style: e.g.
|
||||
`style.item.bold`).
|
||||
- **mouse** - whether to automatically enable mouse support for this list
|
||||
(allows clicking items).
|
||||
- **keys** - use predefined keys for navigating the list.
|
||||
- **vi** - use vi keys with the `keys` option.
|
||||
- **items** - an array of strings which become the list's items.
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Box.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from Box.
|
||||
- **select** - received when an item is selected.
|
||||
- **cancel** - list was canceled (when `esc` is pressed with the `keys` option).
|
||||
- **action** - either a select or a cancel event was received.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Box.
|
||||
- **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.
|
||||
|
||||
|
||||
#### Form (from Box)
|
||||
|
||||
A form which can contain form elements.
|
||||
@ -554,62 +559,63 @@ A form which can contain form elements.
|
||||
A form input.
|
||||
|
||||
|
||||
#### Textbox (from Input)
|
||||
|
||||
A box which allows text input.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from Input.
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Input.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from Input.
|
||||
- **submit** - value is submitted (enter).
|
||||
- **cancel** - value is discared (escape).
|
||||
- **action** - either submit or cancel.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Input.
|
||||
- **readInput(callback)** - grab key events and start reading text from the
|
||||
keyboard. takes a callback which receives the final value.
|
||||
- **readEditor(callback)** - open text editor in `$EDITOR`, read the output from
|
||||
the resulting file. takes a callback which receives the final value.
|
||||
- **clearInput** - clear input.
|
||||
|
||||
|
||||
#### Textarea (from Input/ScrollableText)
|
||||
#### Textarea (from Input)
|
||||
|
||||
A box which allows multiline text input.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
- inherits all from Input.
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
- inherits all from Input.
|
||||
- **value** - the input text. **read-only**.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
- inherits all from Input.
|
||||
- **submit** - value is submitted (enter).
|
||||
- **cancel** - value is discared (escape).
|
||||
- **action** - either submit or cancel.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
- inherits all from Input.
|
||||
- **submit** - submit the textarea (emits `submit`).
|
||||
- **cancel** - cancel the textarea (emits `cancel`).
|
||||
- **readInput(callback)** - grab key events and start reading text from the
|
||||
keyboard. takes a callback which receives the final value.
|
||||
- **readEditor(callback)** - open text editor in `$EDITOR`, read the output from
|
||||
the resulting file. takes a callback which receives the final value.
|
||||
- **clearInput** - clear input.
|
||||
- **getValue()** - the same as `this.value`, for now.
|
||||
- **clearValue()** - clear input.
|
||||
- **setValue(text)** - set value.
|
||||
|
||||
|
||||
#### Textbox (from Textarea)
|
||||
|
||||
A box which allows text input.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from Textarea.
|
||||
- **secret** - completely hide text.
|
||||
- **censor** - replace text with asterisks (`*`).
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Textarea.
|
||||
- **secret** - completely hide text.
|
||||
- **censor** - replace text with asterisks (`*`).
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from Textarea.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Textarea.
|
||||
|
||||
|
||||
#### Button (from Input)
|
||||
@ -626,12 +632,12 @@ A button which can be focused and allows key and mouse input.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from ScrollableBox.
|
||||
- inherits all from Input.
|
||||
- **press** - received when the button is clicked/pressed.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from ScrollableBox.
|
||||
- inherits all from Input.
|
||||
- **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.
|
||||
@ -646,6 +652,7 @@ A progress bar allowing various styles. This can also be used as a form input.
|
||||
##### Options:
|
||||
|
||||
- inherits all from Input.
|
||||
- **orientation** - can be `horizontal` or `vertical`.
|
||||
- **barFg, barBg** - (completed) bar foreground and background.
|
||||
(can be contained in `style`: e.g. `style.bar.fg`).
|
||||
- **ch** - the character to fill the bar with (default is space).
|
||||
@ -873,49 +880,6 @@ painted first. In terms of the painter's algorithm, the lowest indicies in the
|
||||
array are the furthest away, just like in the DOM.
|
||||
|
||||
|
||||
### Optimization and CSR
|
||||
|
||||
**NOTE:** This is now automatically optimized for full-width scrollable elements.
|
||||
|
||||
**TODO:** Detect to see if there are any elements under/to the sides of
|
||||
non-full-width elements.
|
||||
|
||||
You may notice a lot of terminal apps (e.g. mutt, irssi, vim, ncmpcpp) don't
|
||||
have sidebars, and only have "elements" that take up the entire width of the
|
||||
screen. The reason for this is speed (and general cleanliness). VT-like
|
||||
terminals have something called a CSR (change_scroll_region) code, as well as
|
||||
IL (insert_line), and DL (delete_code) codes. Using these three codes, it is
|
||||
possible to create a very efficient rendering by avoiding redrawing the entire
|
||||
screen when a line is inserted or removed. Since blessed is extremely dynamic,
|
||||
it is hard to do this optimization automatically (blessed assumes you may
|
||||
create any element of any width in any position). So, there is a solution:
|
||||
|
||||
``` js
|
||||
var box = blessed.box(...);
|
||||
box.setContent('line 1\nline 2');
|
||||
box.insertBottom('line 3');
|
||||
box.insertBottom('line 4');
|
||||
box.insertTop('line 0');
|
||||
box.insertLine(1, 'line 1.5');
|
||||
```
|
||||
|
||||
If your element has the same width as the screen, the line insertion will be
|
||||
optimized by using a combination CSR/IL/DL codes. These methods may be made
|
||||
smarter in the future to detect whether any elements are being overlapped to
|
||||
the sides.
|
||||
|
||||
Outputting:
|
||||
|
||||
```
|
||||
| line 0 |
|
||||
| line 1 |
|
||||
| line 1.5 |
|
||||
| line 2 |
|
||||
| line 3 |
|
||||
| line 4 |
|
||||
```
|
||||
|
||||
|
||||
### Testing
|
||||
|
||||
- For an interactive test, see `test/widget.js`.
|
||||
|
108
lib/widget.js
108
lib/widget.js
@ -3028,7 +3028,7 @@ Element.prototype.render = function() {
|
||||
el.render();
|
||||
});
|
||||
|
||||
this.emit('render');
|
||||
this.emit('render', coords);
|
||||
|
||||
return coords;
|
||||
};
|
||||
@ -3264,30 +3264,31 @@ function Line(options) {
|
||||
options.height = 1;
|
||||
}
|
||||
|
||||
Box.call(this, options);
|
||||
|
||||
this.ch = !options.type || options.type === 'line'
|
||||
? orientation === 'horizontal' ? '─' : '│'
|
||||
: options.ch || ' ';
|
||||
|
||||
options.border = {
|
||||
this.border = {
|
||||
type: 'bg',
|
||||
get ch() { return self.ch; },
|
||||
set ch(c) { self.ch = c; }
|
||||
__proto__: this
|
||||
// get ch() { return self.ch; },
|
||||
// set ch(c) { return self.ch = c; }
|
||||
};
|
||||
|
||||
options.style = {
|
||||
fg: this.style ? this.style.fg : this.fg,
|
||||
bg: this.style ? this.style.bg : this.bg,
|
||||
border: {
|
||||
get fg() { return self.style.fg; },
|
||||
get bg() { return self.style.bg; },
|
||||
set fg(c) { self.style.fg = c; },
|
||||
set bg(c) { self.style.bg = c; }
|
||||
}
|
||||
};
|
||||
this.style.border = this.style;
|
||||
|
||||
delete options.ch;
|
||||
|
||||
Box.call(this, options);
|
||||
// Maybe instead of the above:
|
||||
// this.on('prerender', function() {
|
||||
// self._style = self.style;
|
||||
// self.border = { type: 'bg', ch: self.ch };
|
||||
// self.style = { border: self.style };
|
||||
// });
|
||||
//
|
||||
// this.on('render', function(coords) {
|
||||
// self.style = self._style;
|
||||
// });
|
||||
}
|
||||
|
||||
Line.prototype.__proto__ = Box.prototype;
|
||||
@ -3435,7 +3436,6 @@ ScrollableBox.prototype._scrollBottom = function() {
|
||||
return Math.max(current, el.rtop + el.height);
|
||||
}, 0);
|
||||
|
||||
//bottom -= this.height;
|
||||
if (this.lpos) this.lpos._scrollBottom = bottom;
|
||||
|
||||
return bottom;
|
||||
@ -3561,6 +3561,24 @@ ScrollableBox.prototype.resetScroll = function() {
|
||||
return this.emit('scroll');
|
||||
};
|
||||
|
||||
/**
|
||||
* ScrollableText
|
||||
*/
|
||||
|
||||
function ScrollableText(options) {
|
||||
if (!(this instanceof Node)) {
|
||||
return new ScrollableText(options);
|
||||
}
|
||||
options = options || {};
|
||||
options.scrollable = true;
|
||||
options.alwaysScroll = true;
|
||||
Box.call(this, options);
|
||||
}
|
||||
|
||||
ScrollableText.prototype.__proto__ = Box.prototype;
|
||||
|
||||
ScrollableText.prototype.type = 'scrollable-text';
|
||||
|
||||
/**
|
||||
* List
|
||||
*/
|
||||
@ -3871,24 +3889,6 @@ List.prototype.down = function(offset) {
|
||||
this.move(offset || 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* ScrollableText
|
||||
*/
|
||||
|
||||
function ScrollableText(options) {
|
||||
if (!(this instanceof Node)) {
|
||||
return new ScrollableText(options);
|
||||
}
|
||||
options = options || {};
|
||||
options.scrollable = true;
|
||||
options.alwaysScroll = true;
|
||||
Box.call(this, options);
|
||||
}
|
||||
|
||||
ScrollableText.prototype.__proto__ = Box.prototype;
|
||||
|
||||
ScrollableText.prototype.type = 'scrollable-text';
|
||||
|
||||
/**
|
||||
* Form
|
||||
*/
|
||||
@ -4140,7 +4140,7 @@ function Textarea(options) {
|
||||
|
||||
this.value = options.value || '';
|
||||
|
||||
this.__updateCursor = this.updateCursor.bind(this);
|
||||
this.__updateCursor = this._updateCursor.bind(this);
|
||||
this.on('resize', this.__updateCursor);
|
||||
this.on('move', this.__updateCursor);
|
||||
this.on('focus', this.readInput.bind(this));
|
||||
@ -4151,8 +4151,7 @@ Textarea.prototype.__proto__ = Input.prototype;
|
||||
|
||||
Textarea.prototype.type = 'textarea';
|
||||
|
||||
Textbox.prototype.updateCursor =
|
||||
Textarea.prototype.updateCursor = function() {
|
||||
Textarea.prototype._updateCursor = function() {
|
||||
if (this.screen.focused !== this) {
|
||||
return;
|
||||
}
|
||||
@ -4203,8 +4202,8 @@ Textarea.prototype.updateCursor = function() {
|
||||
};
|
||||
|
||||
Textarea.prototype.input =
|
||||
Textarea.prototype.readInput =
|
||||
Textarea.prototype.setInput = function(callback) {
|
||||
Textarea.prototype.setInput =
|
||||
Textarea.prototype.readInput = function(callback) {
|
||||
var self = this
|
||||
, focused = this.screen.focused === this;
|
||||
|
||||
@ -4220,7 +4219,7 @@ Textarea.prototype.setInput = function(callback) {
|
||||
|
||||
this.screen.grabKeys = true;
|
||||
|
||||
this.updateCursor();
|
||||
this._updateCursor();
|
||||
this.screen.program.showCursor();
|
||||
this.screen.program.sgr('normal');
|
||||
|
||||
@ -4302,6 +4301,10 @@ Textarea.prototype._typeScroll = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Textarea.prototype.getValue = function() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
Textarea.prototype.setValue = function(value) {
|
||||
if (value == null) {
|
||||
value = this.value;
|
||||
@ -4311,12 +4314,12 @@ Textarea.prototype.setValue = function(value) {
|
||||
this._value = value;
|
||||
this.setContent(this.value);
|
||||
this._typeScroll();
|
||||
this.updateCursor();
|
||||
this._updateCursor();
|
||||
}
|
||||
};
|
||||
|
||||
Textarea.prototype.clearValue =
|
||||
Textarea.prototype.clearInput = function() {
|
||||
Textarea.prototype.clearInput =
|
||||
Textarea.prototype.clearValue = function() {
|
||||
return this.setValue('');
|
||||
};
|
||||
|
||||
@ -4335,8 +4338,8 @@ Textarea.prototype.render = function() {
|
||||
};
|
||||
|
||||
Textarea.prototype.editor =
|
||||
Textarea.prototype.readEditor =
|
||||
Textarea.prototype.setEditor = function(callback) {
|
||||
Textarea.prototype.setEditor =
|
||||
Textarea.prototype.readEditor = function(callback) {
|
||||
var self = this;
|
||||
return this.screen.readEditor({ value: this.value }, function(err, value) {
|
||||
if (err) return callback && callback(err);
|
||||
@ -4398,7 +4401,7 @@ Textbox.prototype.setValue = function(value) {
|
||||
val = this.value.replace(/\t/g, this.screen.tabc);
|
||||
this.setContent(val.slice(visible));
|
||||
}
|
||||
this.updateCursor();
|
||||
this._updateCursor();
|
||||
}
|
||||
};
|
||||
|
||||
@ -4498,13 +4501,14 @@ function ProgressBar(options) {
|
||||
if (options.mouse) {
|
||||
this.on('click', function(data) {
|
||||
var x, y, m, p;
|
||||
if (!self.lpos) return;
|
||||
if (self.orientation === 'horizontal') {
|
||||
x = data.x - self.left;
|
||||
m = self.width - self.iwidth;
|
||||
x = data.x - self.lpos.xi;
|
||||
m = (self.lpos.xl - self.lpos.xi) - self.iwidth;
|
||||
p = x / m * 100 | 0;
|
||||
} else if (self.orientation === 'vertical') {
|
||||
y = data.y - self.top;
|
||||
m = self.height - self.iheight;
|
||||
y = data.y - self.lpos.yi;
|
||||
m = (self.lpos.yl - self.lpos.yi) - self.iheight;
|
||||
p = y / m * 100 | 0;
|
||||
}
|
||||
self.setProgress(p);
|
||||
|
Loading…
x
Reference in New Issue
Block a user