diff --git a/js/term/widgets/keyboard.js b/js/term/widgets/keyboard.js new file mode 100644 index 0000000..dd164f3 --- /dev/null +++ b/js/term/widgets/keyboard.js @@ -0,0 +1,286 @@ +/** + ** ============================== + ** 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?i26) 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;