287 lines
7.8 KiB
JavaScript
287 lines
7.8 KiB
JavaScript
/**
|
|
** ==============================
|
|
** O O O OOOO
|
|
** O O O O O O
|
|
** O O O O O O
|
|
** OOOO OOOO O OOO OOOO
|
|
** O O O O O O O
|
|
** O O O O O O O
|
|
** OOOO OOOO O O OOOO
|
|
** ==============================
|
|
** Dr. Stefan Bosse http://www.bsslab.de
|
|
**
|
|
** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
|
|
** BY THE AUTHOR(S).
|
|
** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
|
|
** MODIFIED, OR OTHERWISE USED IN A CONTEXT
|
|
** OUTSIDE OF THE SOFTWARE SYSTEM.
|
|
**
|
|
** $AUTHORS: Stefan Bosse
|
|
** $INITIAL: sbosse (C) 2006-2018
|
|
** $REVESIO: 1.2.3
|
|
**
|
|
** $INFO:
|
|
**
|
|
** keyboard.js - software keyboard (overlay)
|
|
**
|
|
** Options:
|
|
** typeof options = {
|
|
** top,left,width,height,
|
|
** button?={width,height} is button size,
|
|
** margin?={x,y} is button margin,
|
|
** compact?:boolean,
|
|
** delButton?:string,
|
|
** nlButton?:string,
|
|
** okayButton?:string,
|
|
** cancelButton?:string,
|
|
** }
|
|
**
|
|
** $ENDOFINFO
|
|
*/
|
|
var options = {
|
|
version:'1.2.3'
|
|
}
|
|
/**
|
|
* Modules
|
|
*/
|
|
var Comp = Require('com/compat');
|
|
|
|
var Node = Require('term/widgets/node');
|
|
var Box = Require('term/widgets/box');
|
|
var Button = Require('term/widgets/button');
|
|
var TextBox = Require('term/widgets/textbox');
|
|
var Helpers = Require('term/helpers');
|
|
/**
|
|
* Keyboard
|
|
*/
|
|
|
|
function Keyboard(options) {
|
|
var self=this,
|
|
x,y,key,i=0,bbox;
|
|
|
|
if (!instanceOf(this,Node)) {
|
|
return new Keyboard(options);
|
|
}
|
|
|
|
options = options || {};
|
|
options.hidden = true;
|
|
if (!options.height || options.height<10) options.height=10;
|
|
|
|
Box.call(this, options);
|
|
|
|
// Collect clickable elements of this widget
|
|
this._clickable=this.screen.clickable;
|
|
this.screen.clickable=[];
|
|
|
|
if (!options.button) options.button={width:3,height:2};
|
|
if (!options.margin) options.margin={x:2,y:1};
|
|
|
|
this.shift=false;
|
|
this.group=0;
|
|
this._.buttons=[];
|
|
|
|
var Keys = [
|
|
[
|
|
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
|
|
'p','q','r','s','t','u','v','w','x','y','z'
|
|
],
|
|
[
|
|
'0','1','2','3','4','5','6','7','8','9','.','+','-','*',':',';'
|
|
],
|
|
[
|
|
'"','!','=','_','<','>','(',')','{','}','[',']','?','#','~',' '
|
|
]
|
|
];
|
|
|
|
|
|
var keys = Comp.array.flatten(Keys);
|
|
var complen=Keys[0].length+Keys[1].length;
|
|
|
|
// compute for button positions
|
|
bbox=Helpers.bbox(this.screen,options);
|
|
|
|
if (options.okayButton) {
|
|
this._.okay = new Button({
|
|
screen: this.screen,
|
|
parent: this,
|
|
top: bbox.height-3,
|
|
height: 1,
|
|
left: 1,
|
|
width: Math.max(6,options.okayButton.length+2),
|
|
content: options.okayButton,
|
|
align: 'center',
|
|
autoFocus: false,
|
|
mouse: true,
|
|
style: {
|
|
bold:true,
|
|
bg:'green',
|
|
fg:'white'
|
|
}
|
|
});
|
|
this._.okay.on('press',function () { self.hide(); if (self._.callback) self._.callback(self._.input.getValue())});
|
|
}
|
|
if (options.cancelButton) {
|
|
this._.cancel = new Button({
|
|
screen: this.screen,
|
|
parent: this,
|
|
top: bbox.height-3,
|
|
height: 1,
|
|
right: 1,
|
|
width: options.cancelButton.length+2,
|
|
content: options.cancelButton,
|
|
align: 'center',
|
|
autoFocus: false,
|
|
mouse: true,
|
|
style: {
|
|
bold:true,
|
|
bg:'red',
|
|
fg:'white'
|
|
}
|
|
});
|
|
this._.cancel.on('press',function () { self.hide(); });
|
|
}
|
|
this._.shift = new Button({
|
|
screen: this.screen,
|
|
parent: this,
|
|
top: bbox.height-3,
|
|
height: 1,
|
|
right: int(bbox.width/2)+(options.compact?1:int(options.margin.x)),
|
|
width: (options.shiftButton && options.shiftButton.length+2)||6,
|
|
content: options.shiftButton||'Shft',
|
|
align: 'center',
|
|
autoFocus: false,
|
|
mouse: true
|
|
});
|
|
this._.shift.on('press',function () {
|
|
self.shift=~self.shift;
|
|
for(var i=0;i<26;i++) {
|
|
self._.buttons[i].setContent(self.shift?Keys[0][i].toUpperCase():Keys[0][i]);
|
|
}
|
|
if (options.compact && self.shift) for(i in Keys[1]) self._.buttons[26+Number(i)].setContent(Keys[2][i]);
|
|
if (options.compact && !self.shift) for(i in Keys[1]) self._.buttons[26+Number(i)].setContent(Keys[1][i]);
|
|
if (self.shift && options.nlButton) self._.delete.setContent(options.nlButton);
|
|
else if (!self.shift && options.nlButton) self._.delete.setContent(options.delButton||'DEL');
|
|
self.screen.render();
|
|
});
|
|
this._.delete = new Button({
|
|
screen: this.screen,
|
|
parent: this,
|
|
top: bbox.height-3,
|
|
height: 1,
|
|
left: int(bbox.width/2)+(options.compact?0:int(options.margin.x)),
|
|
width: (options.delButton && options.delButton.length+2)||6,
|
|
content: options.delButton||'DEL',
|
|
align: 'center',
|
|
autoFocus: false,
|
|
mouse: true
|
|
});
|
|
this._.delete.on('press',function () {
|
|
var line=self._.input.getValue();
|
|
if (!self.shift || !options.nlButton) {
|
|
// Delete last character
|
|
self._.input.setValue(line.substring(0,line.length-1));
|
|
} else if (self.shift && options.nlButton) {
|
|
// Insert newline
|
|
self._.input.setValue(line+'\n');
|
|
}
|
|
//self.screen.render();
|
|
self._.input.update();
|
|
});
|
|
|
|
this._.input = new TextBox({
|
|
parent: this,
|
|
value: options.value||'content',
|
|
width: bbox.width-4,
|
|
height: 1,
|
|
left: 1,
|
|
top: 0,
|
|
style: {
|
|
fg:(options.style.input&&options.style.input.fg)||'black',
|
|
bg:(options.style.input&&options.style.input.bg)||'white',
|
|
bold:true
|
|
}
|
|
});
|
|
y=1+options.margin.y;
|
|
|
|
i=0;
|
|
while ((options.compact?i<complen:true) && keys[i] && y < (bbox.height-options.button.height-options.margin.y)-1) {
|
|
x=options.margin.x;
|
|
while ((options.compact?i<complen:true) && keys[i] && x < (bbox.width-options.button.width-options.margin.x)) {
|
|
function make(i) {
|
|
key = new Button ({
|
|
screen: self.screen,
|
|
parent: self,
|
|
top: y,
|
|
height: options.button.height,
|
|
left: x,
|
|
width: options.button.width,
|
|
content: keys[i],
|
|
align: 'center',
|
|
autoFocus: false,
|
|
mouse: true
|
|
});
|
|
self._.buttons.push(key);
|
|
key.on('press',function () {self.emit('key',i)});
|
|
}
|
|
make(i);
|
|
i++,x += (options.button.width+options.margin.x);
|
|
}
|
|
y += (options.button.height+options.margin.y);
|
|
}
|
|
// Save clickable elements of this widget; restore screen
|
|
this.clickable=this.screen.clickable;
|
|
this.screen.clickable=this._clickable;
|
|
|
|
this._hide=this.hide;
|
|
this.hide = function() {
|
|
self._hide();
|
|
self.screen.render();
|
|
// restore all clickable elements
|
|
self.screen.clickable=self._clickable;
|
|
}
|
|
this._show = this.show;
|
|
this.show = function() {
|
|
// save all screen clickable elements; enable only this clickables
|
|
self._clickable=self.screen.clickable;
|
|
self.screen.clickable=self.clickable;
|
|
self._show();
|
|
self.screen.render();
|
|
}
|
|
this.on('key',function (index) {
|
|
var line=self._.input.getValue(),ch;
|
|
if (options.compact) {
|
|
if (index<26) {
|
|
ch=self.shift?Keys[0][index].toUpperCase():Keys[0][index];
|
|
} else {
|
|
ch=self.shift?Keys[2][index-26]:Keys[1][index-26];
|
|
}
|
|
} else {
|
|
if (!self.shift || index>26) ch = keys[index];
|
|
else ch = keys[index].toUpperCase();
|
|
}
|
|
line += ch;
|
|
self._.input.setValue(line);
|
|
//self.screen.render();
|
|
self._.input.update();
|
|
});
|
|
}
|
|
|
|
//Question.prototype.__proto__ = Box.prototype;
|
|
inheritPrototype(Keyboard,Box);
|
|
|
|
Keyboard.prototype.setCallback = function (cb) {
|
|
this._.callback=cb
|
|
}
|
|
|
|
Keyboard.prototype.setValue = function (line) {
|
|
this._.input.setValue(line);
|
|
this._.input.update();
|
|
}
|
|
|
|
Keyboard.prototype.type = 'keyboard';
|
|
/**
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = Keyboard;
|