mirror of
https://github.com/chjj/blessed.git
synced 2026-02-06 14:11:51 +00:00
more scrolling improvements. scrolling form.
This commit is contained in:
parent
7af4dbaf1c
commit
a98bef4c90
127
lib/widget.js
127
lib/widget.js
@ -1614,6 +1614,32 @@ Element.prototype.toggle = function() {
|
||||
Element.prototype.focus = function() {
|
||||
var old = this.screen.focused;
|
||||
this.screen.focused = this;
|
||||
|
||||
// Find a scrollable ancestor if we have one.
|
||||
var el = this;
|
||||
while (el = el.parent) {
|
||||
if (el.childBase != null) break;
|
||||
}
|
||||
|
||||
// If we're in a scrollable element,
|
||||
// automatically scroll to the focused element.
|
||||
if (el) {
|
||||
var ryi = this.top - el.top - el.itop
|
||||
, ryl = this.top + this.height - el.top - el.ibottom
|
||||
, visible = el.height - el.iheight;
|
||||
|
||||
if (ryi < el.childBase) {
|
||||
el.scrollTo(ryi);
|
||||
this.screen.render();
|
||||
} else if (ryi >= el.childBase + visible) {
|
||||
el.scrollTo(ryi);
|
||||
this.screen.render();
|
||||
} else if (ryl >= el.childBase + visible) {
|
||||
el.scrollTo(ryi);
|
||||
this.screen.render();
|
||||
}
|
||||
}
|
||||
|
||||
old.emit('blur', this);
|
||||
this.emit('focus', old);
|
||||
this.screen.emit('element blur', old, this);
|
||||
@ -2374,35 +2400,39 @@ Box.prototype._getCoords = function(get) {
|
||||
, coords
|
||||
, v;
|
||||
|
||||
// Find a scrollable ancestor if we have one.
|
||||
var el = this;
|
||||
while (el = el.parent) {
|
||||
if (el.childBase != null) break;
|
||||
}
|
||||
|
||||
// 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))) {
|
||||
ryi = yi - this.parent._getTop(get) - this.parent.itop;
|
||||
ryl = yl - this.parent._getTop(get) - this.parent.ibottom;
|
||||
visible = this.parent._getHeight(get) - this.parent.iheight;
|
||||
if (el && (!el.items || ~el.items.indexOf(this))) {
|
||||
ryi = yi - el._getTop(get) - el.itop;
|
||||
ryl = yl - el._getTop(get) - el.ibottom;
|
||||
visible = el._getHeight(get) - el.iheight;
|
||||
|
||||
if (ryi < this.parent.childBase) {
|
||||
if (ryl > this.parent.childBase) {
|
||||
// Is partially covered above. TODO: Improve.
|
||||
v = ryl - this.parent.childBase;
|
||||
if (ryi < el.childBase) {
|
||||
if (ryl > el.childBase) {
|
||||
// Is partially covered above.
|
||||
v = ryl - el.childBase;
|
||||
yi += (ryl - ryi) - v;
|
||||
} else {
|
||||
// Is above.
|
||||
return;
|
||||
}
|
||||
} else if (ryi >= this.parent.childBase + visible) {
|
||||
} else if (ryi >= el.childBase + visible) {
|
||||
// Is below.
|
||||
return;
|
||||
} else if (ryl >= this.parent.childBase + visible) {
|
||||
// Is partially covered below. TODO: Improve.
|
||||
v = this.parent.childBase + visible + (yl - yi) - ryl;
|
||||
} else if (ryl >= el.childBase + visible) {
|
||||
// Is partially covered below.
|
||||
v = el.childBase + visible + (yl - yi) - ryl;
|
||||
yl = yi + v;
|
||||
}
|
||||
|
||||
yi -= this.parent.childBase;
|
||||
yl -= this.parent.childBase;
|
||||
yi -= el.childBase;
|
||||
yl -= el.childBase;
|
||||
}
|
||||
|
||||
// Attempt to shrink the element base on the
|
||||
@ -2455,11 +2485,12 @@ Box.prototype.render = function() {
|
||||
// If we're in a scrollable text box, check to
|
||||
// see which attributes this line starts with.
|
||||
if (this.contentIndex != null && this.childBase != null) {
|
||||
if (this._clines.length > this.childBase) {
|
||||
attr = this._clines.attr[this.childBase];
|
||||
} else {
|
||||
attr = this._clines.attr[this._clines.length - 1];
|
||||
}
|
||||
// if (this._clines.length > this.childBase) {
|
||||
// attr = this._clines.attr[this.childBase];
|
||||
// } else {
|
||||
// attr = this._clines.attr[this._clines.length - 1];
|
||||
// }
|
||||
attr = this._clines.attr[this.childBase];
|
||||
}
|
||||
|
||||
if (this.border) xi++, xl--, yi++, yl--;
|
||||
@ -3081,22 +3112,22 @@ function List(options) {
|
||||
return;
|
||||
}
|
||||
if (options.vi && key.name === 'u' && key.ctrl) {
|
||||
self.move(-((self.height - (self.border ? 2 : 0)) / 2) | 0);
|
||||
self.move(-((self.height - self.iheight) / 2) | 0);
|
||||
self.screen.render();
|
||||
return;
|
||||
}
|
||||
if (options.vi && key.name === 'd' && key.ctrl) {
|
||||
self.move((self.height - (self.border ? 2 : 0)) / 2 | 0);
|
||||
self.move((self.height - self.iheight) / 2 | 0);
|
||||
self.screen.render();
|
||||
return;
|
||||
}
|
||||
if (options.vi && key.name === 'b' && key.ctrl) {
|
||||
self.move(-(self.height - (self.border ? 2 : 0)));
|
||||
self.move(-(self.height - self.iheight));
|
||||
self.screen.render();
|
||||
return;
|
||||
}
|
||||
if (options.vi && key.name === 'f' && key.ctrl) {
|
||||
self.move(self.height - (self.border ? 2 : 0));
|
||||
self.move(self.height - self.iheight);
|
||||
self.screen.render();
|
||||
return;
|
||||
}
|
||||
@ -3109,7 +3140,7 @@ function List(options) {
|
||||
// TODO: Maybe use Math.min(this.items.length,
|
||||
// ... for calculating visible items elsewhere.
|
||||
var visible = Math.min(
|
||||
self.height - (self.border ? 2 : 0),
|
||||
self.height - self.iheight,
|
||||
self.items.length) / 2 | 0;
|
||||
self.move(self.childBase + visible - self.selected);
|
||||
self.screen.render();
|
||||
@ -3118,7 +3149,7 @@ function List(options) {
|
||||
if (options.vi && key.name === 'l' && key.shift) {
|
||||
// XXX This goes one too far on lists with an odd number of items.
|
||||
self.down(self.childBase
|
||||
+ Math.min(self.height - (self.border ? 2 : 0), self.items.length)
|
||||
+ Math.min(self.height - self.iheight, self.items.length)
|
||||
- self.selected);
|
||||
self.screen.render();
|
||||
return;
|
||||
@ -3438,7 +3469,7 @@ function Form(options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
Box.call(this, options);
|
||||
ScrollableBox.call(this, options);
|
||||
|
||||
if (options.keys) {
|
||||
this.screen._listenKeys(this);
|
||||
@ -3458,11 +3489,11 @@ function Form(options) {
|
||||
|| (options.vi && key.name === 'j')) {
|
||||
if (el.type === 'textbox' || el.type === 'textarea') {
|
||||
if (key.name === 'j') return;
|
||||
self.screen.grabKeys = false;
|
||||
if (key.name === 'tab') {
|
||||
// Workaround, since we can't stop the tab from being added.
|
||||
el.emit('keypress', null, { name: 'backspace' });
|
||||
}
|
||||
el.emit('keypress', '\x1b', { name: 'escape' });
|
||||
}
|
||||
self.focusNext();
|
||||
return;
|
||||
@ -3473,7 +3504,7 @@ function Form(options) {
|
||||
|| (options.vi && key.name === 'k')) {
|
||||
if (el.type === 'textbox' || el.type === 'textarea') {
|
||||
if (key.name === 'k') return;
|
||||
self.screen.grabKeys = false;
|
||||
el.emit('keypress', '\x1b', { name: 'escape' });
|
||||
}
|
||||
self.focusPrevious();
|
||||
return;
|
||||
@ -3487,7 +3518,7 @@ function Form(options) {
|
||||
}
|
||||
}
|
||||
|
||||
Form.prototype.__proto__ = Box.prototype;
|
||||
Form.prototype.__proto__ = ScrollableBox.prototype;
|
||||
|
||||
Form.prototype.type = 'form';
|
||||
|
||||
@ -3677,22 +3708,21 @@ function Textbox(options) {
|
||||
this.secret = options.secret;
|
||||
this.censor = options.censor;
|
||||
|
||||
this.on('resize', updateCursor);
|
||||
this.on('move', updateCursor);
|
||||
|
||||
function updateCursor() {
|
||||
if (self.screen.focused !== self) return;
|
||||
self.screen.program.cup(
|
||||
self.top + (self.border ? 1 : 0),
|
||||
self.left + (self.border ? 1 : 0)
|
||||
+ self.value.length);
|
||||
}
|
||||
this.__updateCursor = this.updateCursor.bind(this);
|
||||
this.on('resize', this.__updateCursor);
|
||||
this.on('move', this.__updateCursor);
|
||||
}
|
||||
|
||||
Textbox.prototype.__proto__ = Input.prototype;
|
||||
|
||||
Textbox.prototype.type = 'textbox';
|
||||
|
||||
Textbox.prototype.updateCursor = function() {
|
||||
if (this.screen.focused !== this) return;
|
||||
this.screen.program.cup(this.top + this.itop,
|
||||
this.left + this.ileft + this.value.length);
|
||||
};
|
||||
|
||||
Textbox.prototype.input =
|
||||
Textbox.prototype.readInput =
|
||||
Textbox.prototype.setInput = function(callback) {
|
||||
@ -3706,12 +3736,7 @@ Textbox.prototype.setInput = function(callback) {
|
||||
|
||||
this.screen.grabKeys = true;
|
||||
|
||||
// Could possibly save and restore cursor.
|
||||
|
||||
this.screen.program.cup(
|
||||
this.top + this.itop,
|
||||
this.left + this.ileft
|
||||
+ this.value.length);
|
||||
this.updateCursor();
|
||||
this.screen.program.showCursor();
|
||||
this.screen.program.sgr('normal');
|
||||
|
||||
@ -3801,6 +3826,7 @@ Textbox.prototype.render = function() {
|
||||
// setContent is necessary to clear the area in case
|
||||
// .shrink is being used and the new content is smaller.
|
||||
// Could technically optimize this.
|
||||
if (!this._getCoords(true)) return;
|
||||
if (this.secret) {
|
||||
this.setContent('');
|
||||
return this._render();
|
||||
@ -4134,11 +4160,8 @@ ProgressBar.prototype.type = 'progress-bar';
|
||||
|
||||
ProgressBar.prototype._render = ProgressBar.prototype.render;
|
||||
ProgressBar.prototype.render = function() {
|
||||
// NOTE: Maybe move this `hidden` check
|
||||
// down below `stop` check and return `ret`.
|
||||
if (this.hidden) return;
|
||||
|
||||
var ret = this._render();
|
||||
if (!ret) return;
|
||||
|
||||
var xi = ret.xi
|
||||
, xl = ret.xl
|
||||
@ -4412,6 +4435,7 @@ Checkbox.prototype.type = 'checkbox';
|
||||
|
||||
Checkbox.prototype._render = Checkbox.prototype.render;
|
||||
Checkbox.prototype.render = function() {
|
||||
if (!this._getCoords(true)) return;
|
||||
if (this.type === 'radio-button') {
|
||||
this.setContent('(' + (this.checked ? '*' : ' ') + ') ' + this.text);
|
||||
} else {
|
||||
@ -4981,6 +5005,7 @@ Listbar.prototype.setItems = function(commands) {
|
||||
|
||||
Listbar.prototype._render = Listbar.prototype.render;
|
||||
Listbar.prototype.render = function() {
|
||||
if (!this._getCoords(true)) return;
|
||||
var self = this
|
||||
, drawn = 0;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
var blessed = require('../')
|
||||
, screen = blessed.screen();
|
||||
, screen = blessed.screen({ dump: __dirname + '/form.log' });
|
||||
|
||||
var form = blessed.form({
|
||||
parent: screen,
|
||||
@ -84,6 +84,19 @@ var check = blessed.checkbox({
|
||||
content: 'check'
|
||||
});
|
||||
|
||||
var check2 = blessed.checkbox({
|
||||
parent: form,
|
||||
mouse: true,
|
||||
keys: true,
|
||||
shrink: true,
|
||||
bg: 'magenta',
|
||||
height: 1,
|
||||
left: 28,
|
||||
top: 10,
|
||||
name: 'foooooooo2',
|
||||
content: 'foooooooo2'
|
||||
});
|
||||
|
||||
var submit = blessed.button({
|
||||
parent: form,
|
||||
mouse: true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user