add text input and setContent.

This commit is contained in:
Christopher Jeffrey 2013-06-09 13:14:42 -05:00
parent 812aa7fa42
commit 41c4560a6f
3 changed files with 255 additions and 3 deletions

View File

@ -1239,6 +1239,7 @@ Program.prototype.text = function(text, attr) {
Program.prototype._attr = function(param, val) {
var self = this
, param = param || 'normal'
, parts = param.split(/\s*[,;]\s*/);
if (parts.length > 1) {
@ -2041,6 +2042,7 @@ Program.prototype.setScrollRegion = function(top, bottom) {
// CSI s
// Save cursor (ANSI.SYS).
Program.prototype.sc =
Program.prototype.saveCursor = function() {
this.savedX = this.x;
this.savedY = this.y;
@ -2050,6 +2052,7 @@ Program.prototype.saveCursor = function() {
// CSI u
// Restore cursor (ANSI.SYS).
Program.prototype.rc =
Program.prototype.restoreCursor = function() {
this.x = this.savedX || 1;
this.y = this.savedY || 1;
@ -2638,7 +2641,8 @@ exports = Program;
exports.Program = Program;
exports.Tput = Tput;
['Screen', 'Box', 'Text', 'List', 'Line', 'ProgressBar', 'ScrollableBox', 'ScrollableText'].forEach(function(key) {
['Screen', 'Box', 'Text', 'List', 'Line', 'ProgressBar',
'ScrollableBox', 'ScrollableText', 'Textbox'].forEach(function(key) {
exports.__defineGetter__(key, function() {
return (exports._widget || (exports._widget = require('./widget')))[key];
});

View File

@ -227,7 +227,9 @@ Screen.prototype._listenKeys = function(el) {
if (~self.input.indexOf(self.focused)) {
self.focused.emit('keypress', ch, key);
}
self.emit('keypress', ch, key);
if (!self._grabKeys) {
self.emit('keypress', ch, key);
}
});
};
@ -548,6 +550,16 @@ Element.prototype.focus = function() {
this.screen.emit('element focus', old, this);
};
Element.prototype.setContent = function(content) {
var ret = this.render(true);
this.content = 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));
};
Element.prototype.__defineGetter__('left', function() {
var left = this.position.left;
@ -1319,10 +1331,170 @@ Input.prototype.__proto__ = Box.prototype;
function Textbox(options) {
Input.call(this, options);
this.value = options.value || '';
this.content = options.content || '';
if (options.label) {
// TODO: Make sure negative relative coords work.
this.append(new Text({
content: options.label,
top: -1 - (this.border ? 1 : 0)
}));
}
}
Textbox.prototype.__proto__ = Input.prototype;
Textbox.prototype.setInput = function(callback) {
var self = this;
this.screen._grabKeys = true;
this.focus();
//this.screen.program.saveCursor();
this.screen.program.cup(this.top + 1 + (this.border ? 1 : 0), this.left + 1 + (this.border ? 1 : 0));
this.screen.program.showCursor();
this.screen.program.sgr('normal');
this._callback = function(err, value) {
//self.screen.program.restoreCursor();
self.screen.program.hideCursor();
// Wait for global keypress event to fire.
process.nextTick(function() {
self.screen._grabKeys = false;
});
return err
? callback(err)
: callback(null, value);
};
this.__listener = this._listener.bind(this);
this.on('keypress', this.__listener);
};
Textbox.prototype._listenerFast = function(ch, key) {
var y = this.top + 1 + (this.border ? 1 : 0)
, x = this.left + 1 + (this.border ? 1 : 0)
, line = this.screen.lines[y]
, callback = this._callback
, value = this.value;
if (key.name === 'escape' || key.name === 'enter') {
delete this._callback;
this.value = '';
this.removeListener('keypress', this.__listener);
delete this.__listener;
this.screen.program.cup(y, x);
this.screen.program.write(Array(value.length + 1).join(' '));
callback(null, key.name === 'enter' ? value : null);
} else if (key.name === 'backspace') {
if (this.value.length) {
this.value = this.value.slice(0, -1);
this.screen.program.cub();
this.screen.program.write(' ');
this.screen.program.cub();
}
} else {
if (ch) {
this.value += ch;
this.screen.program.write(ch);
}
}
};
Textbox.prototype._listenerStupid = function(ch, key) {
var y = this.top + 1 + (this.border ? 1 : 0)
, x = this.left + 1 + (this.border ? 1 : 0)
, line = this.screen.lines[y]
, callback = this._callback
, value = this.value;
if (key.name === 'escape' || key.name === 'enter') {
delete this._callback;
this.value = '';
this.removeListener('keypress', this.__listener);
delete this.__listener;
this.screen.clearRegion(x, x + value.length, y, y);
callback(null, key.name === 'enter' ? value : null);
} else if (key.name === 'backspace') {
if (this.value.length) {
line[x + this.value.length][1] = ' ';
line.dirty = true;
this.value = this.value.slice(0, -1);
}
} else {
if (ch) {
line[x + this.value.length][0] = this.screen.dattr;
line[x + this.value.length][1] = ch;
line.dirty = true;
this.value += ch;
}
}
this.screen.render();
};
Textbox.prototype._listener = function(ch, key) {
var callback = this._callback
, value = this.content;
//var y = this.top + 1 + (this.border ? 1 : 0)
// , line = this.screen.lines[y];
if (key.name === 'escape' || key.name === 'enter') {
delete this._callback;
//this.content = '';
this.setContent('');
this.removeListener('keypress', this.__listener);
delete this.__listener;
callback(null, key.name === 'enter' ? value : null);
} else if (key.name === 'backspace') {
if (this.content.length) {
//this.content = this.content.slice(0, -1);
this.setContent(this.content.slice(0, -1));
this.screen.program.cub();
}
} else {
if (ch) {
//this.content += ch;
this.setContent(this.content + ch);
this.screen.program.cuf();
}
}
//line.dirty = true;
this.screen.render();
};
Textbox.prototype.setEditor = function(callback) {
var self = this;
this.focus();
self.screen.program.normalBuffer();
self.screen.program.showCursor();
return readEditor(function(err, value) {
self.screen.program.alternateBuffer();
self.screen.program.hideCursor();
self.screen.alloc();
self.screen.render();
if (err) return callback(err);
self.setContent(value);
return callback(null, value);
});
};
/**
* Textarea
*/
function Textarea(options) {
Input.call(this, options);
}
Textarea.prototype.__proto__ = Input.prototype;
/**
* Button
*/
@ -1469,6 +1641,52 @@ function attrCode(code, cur) {
return (flags << 18) | (fg << 9) | bg;
}
function readEditor(callback) {
var spawn = require('child_process').spawn
, fs = require('fs')
, editor = process.env.EDITOR || 'vi'
, file = '/tmp/blessed.' + Math.random().toString(36);
var write = process.stdout.write;
process.stdout.write = function() {};
try {
process.stdin.pause();
} catch (e) {
;
}
var resume = function() {
try {
process.stdin.resume();
} catch (e) {
;
}
process.stdout.write = write;
};
var ps = spawn(editor, [file], {
stdio: 'inherit',
env: process.env,
cwd: process.env.HOME
});
ps.on('error', function(err) {
resume();
return callback(err);
});
ps.on('exit', function(code) {
resume();
return fs.readFile(file, 'utf8', function(err, data) {
return fs.unlink(file, function() {
if (err) return callback(err);
return callback(null, data);
});
});
});
}
/**
* Constants
*/

View File

@ -175,12 +175,42 @@ screen.on('element focus', function(old, cur) {
screen.render();
});
program.on('keypress', function(ch, key) {
var input = new blessed.Textbox({
mouse: true,
content: '',
fg: 4,
bg: -1,
barBg: -1,
barFg: 4,
border: {
type: 'ascii',
fg: -1,
bg: -1
},
width: '30%',
height: 3,
right: 0,
top: 0
});
screen.append(input);
screen.on('keypress', function(ch, key) {
if (key.name === 'tab') {
return key.shift
? screen.focusPrev()
: screen.focusNext();
}
if (key.name === 'i') {
return input.setInput(function(err, value) {
screen.children[0].setContent(value);
});
}
if (key.name === 'e') {
return input.setEditor(function(err, value) {
screen.children[0].setContent(value);
});
}
if (key.name === 'escape' || key.name === 'q') {
return process.exit(0);
}