diff --git a/core/art.js b/core/art.js index 5f4a4086..23cd19c2 100644 --- a/core/art.js +++ b/core/art.js @@ -433,6 +433,7 @@ function display(art, options, cb) { bg : parser.bgColor, flags : parser.flags, }; + mci[mapItem].focusArgs = args; } else { mci[mapItem] = { args : args, diff --git a/core/button_view.js b/core/button_view.js index 9596af8e..6c81496b 100644 --- a/core/button_view.js +++ b/core/button_view.js @@ -9,8 +9,10 @@ var assert = require('assert'); exports.ButtonView = ButtonView; function ButtonView(client, options) { - options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); - options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); + console.log(options); + options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); + options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); + options.justify = miscUtil.valueWithDefault(options.justify, 'center'); TextView.call(this, client, options); } @@ -21,6 +23,7 @@ ButtonView.prototype.onKeyPress = function(key, isSpecial) { ButtonView.super_.prototype.onKeyPress.call(this, key, isSpecial); // allow spacebar to 'click' buttons + // :TODO: need to check configurable mapping here if(' ' === key) { this.emit('action', 'accept'); } diff --git a/core/edit_text_view.js b/core/edit_text_view.js index 43440bd8..686ddfca 100644 --- a/core/edit_text_view.js +++ b/core/edit_text_view.js @@ -16,7 +16,8 @@ function EditTextView(client, options) { TextView.call(this, client, options); this.clientBackspace = function() { - this.client.term.write('\b \b'); + this.client.term.write( + '\b' + this.getANSIColor(this.getColor()) + this.fillChar + '\b' + this.getANSIColor(this.getFocusColor())); }; } @@ -29,7 +30,7 @@ EditTextView.prototype.onKeyPress = function(key, isSpecial) { assert(1 === key.length); - console.log('key: ' + key); + // :TODO: how to handle justify left/center? if(this.text.length < this.options.maxLength) { key = strUtil.stylizeString(key, this.textStyle); diff --git a/core/line_editor.js b/core/line_editor.js deleted file mode 100644 index b3cd1726..00000000 --- a/core/line_editor.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; - -var assert = require('assert'); -var miscUtil = require('./misc_util.js'); - -exports.LineEditor = LineEditor; - -var STANDARD_KEYSET = { - refresh : [ 12 ], - backspace : [ 8, 127 ], - backword : [ 23 ], - enter : [ 10 ], - exit : [ 27 ], -}; - -// :TODO: Rename to TextEdit -// :TODO: TextEdit should be single or multi line - - -function LineEditor(client, options) { - var self = this; - - self.client = client; - self.valueText = ''; - - if(typeof options !== 'undefined') { - self.options.keyset = miscUtil.valueWithDefault(options.keyset, STANDARD_KEYSET); - } else { - self.options = { - keyset : STANDARD_KEYSET, - }; - } - - - this.client.on('data', function onData(data) { - assert(1 === data.length); - self.onCh(data); - - }); -}; - -LineEditor.prototype.isKey = function(setName, ch) { - return this.options.keyset[setName].indexOf(ch) > -1; -} - -LineEditor.prototype.onCh = function(ch) { - if(this.isKey('refresh', ch)) { - - } else if(this.isKey('backspace', ch)) { - - } else if(this.isKey('backword', ch)) { - - } else if(this.isKey('enter', ch)) { - - } else if(this.isKey('exit', ch)) { - - } else { - - // :TODO: filter out chars - // :TODO: check max width - this.valueText += ch; - this.client.term.write(ch); - } -}; diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index 089dec2a..1b0f700d 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -26,13 +26,6 @@ MCIViewFactory.prototype.getPredefinedViewLabel = function(name) { return label; }; -// :TODO: probably do something like this and generalize all of this: -/* -var MCI_ARG_MAP = { - 'ET' : { 0 : 'maxLength', 1 : 'textStyle' } -}; -*/ - MCIViewFactory.prototype.createFromMCI = function(mci) { assert(mci.code); assert(mci.id > 0); @@ -46,7 +39,6 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { position : { x : mci.position[0], y : mci.position[1] }, }; - // :TODO: move this stuff out of the switch to their own methods/objects function setOption(pos, name) { if(mci.args.length > pos && mci.args[pos].length > 0) { options[name] = mci.args[pos]; @@ -55,19 +47,19 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { return false; } + function setFocusOption(pos, name) { + if(mci.focusArgs && mci.focusArgs.length > pos && mci.focusArgs[pos].length > 0) { + options[name] = mci.focusArgs[pos]; + } + return false; + } + switch(mci.code) { case 'TL' : - // :TODO: convert to setOption() - if(mci.args.length > 0) { - options.textStyle = mci.args[0]; - } - - if(mci.args.length > 1) { - options.justify = mci.args[1]; - } - - if(mci.args.length > 2) { - options.maxLength = mci.args[2]; + setOption(0, 'textStyle'); + setOption(1, 'justify'); + if(setOption(2, 'maxLength')) { + options.maxLength = parseInt(options.maxLength, 10); options.dimens = { width : options.maxLength }; } @@ -76,29 +68,26 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { case 'ET' : if(setOption(0, 'maxLength')) { - options.dimens = { width : options.maxLength }; + options.maxLength = parseInt(options.maxLength, 10); + options.dimens = { width : options.maxLength }; } setOption(1, 'textStyle'); + setFocusOption(0, 'focusTextStyle'); + view = new EditTextView(this.client, options); break; case 'PL' : - // :TODO: convert to setOption() if(mci.args.length > 0) { options.text = this.getPredefinedViewLabel(mci.args[0]); if(options.text) { - if(mci.args.length > 1) { - options.textStyle = mci.args[1]; - } + setOption(1, 'textStyle'); + setOption(2, 'justify'); - if(mci.args.length > 2) { - options.justify = mci.args[2]; - } - - if(mci.args.length > 3) { - options.maxLength = mci.args[3]; + if(setOption(3, 'maxLength')) { + options.maxLength = parseInt(options.maxLength, 10); options.dimens = { width : options.maxLength }; } @@ -107,20 +96,25 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { } break; - case 'BV' : - // :TODO: convert to setOption() + case 'BN' : if(mci.args.length > 0) { - options.text = mci.args[0]; - options.dimens = { width : options.text.length }; + options.dimens = { width : parseInt(mci.args[0], 10) }; } + setOption(1, 'textStyle'); + setOption(2, 'justify'); + + setFocusOption(0, 'focusTextStyle'); + view = new ButtonView(this.client, options); break; case 'VM' : - setOption(0, 'itemSpacing'); - setOption(1, 'justify'); - setOption(2, 'textStyle'); + setOption(0, 'itemSpacing'); + setOption(1, 'justify'); + setOption(2, 'textStyle'); + + setFocusOption(0, 'focusTextStyle'); view = new VerticalMenuView(this.client, options); break; diff --git a/core/menu_view.js b/core/menu_view.js index 0e83b4ac..0220b6e7 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -34,10 +34,43 @@ function MenuView(client, options) { this.fillChar = miscUtil.valueWithDefault(this.options.fillChar, ' ').substr(0, 1); this.justify = this.options.justify || 'none'; + + this.moveSelection = function(fromIndex, toIndex) { + assert(!self.xPositionCacheExpired); + assert(fromIndex >= 0 && fromIndex <= self.items.length); + assert(toIndex >= 0 && toIndex <= self.items.length); + + self.items[fromIndex].focused = false; + self.drawItem(fromIndex); + + self.items[toIndex].focused = true; + self.focusedItemIndex = toIndex; + self.drawItem(toIndex); + }; + + this.cachePositions = function() { + // :TODO: implement me! + }; + + this.drawItem = function(index) { + // :TODO: implement me! + }; } util.inherits(MenuView, View); +MenuView.prototype.redraw = function() { + MenuView.super_.prototype.redraw.call(this); + + this.cachePositions(); + + var count = this.items.length; + for(var i = 0; i < count; ++i) { + this.items[i].focused = this.focusedItemIndex === i; + this.drawItem(i); + } +}; + MenuView.prototype.setItems = function(items) { var self = this; if(items) { diff --git a/core/string_util.js b/core/string_util.js index 76a67ee3..8c550f87 100644 --- a/core/string_util.js +++ b/core/string_util.js @@ -112,17 +112,19 @@ function stylizeString(s, style) { } // Based on http://www.webtoolkit.info/ -function pad(s, len, padChar, dir) { - len = miscUtil.valueWithDefault(len, 0); - padChar = miscUtil.valueWithDefault(padChar, ' '); - dir = miscUtil.valueWithDefault(dir, 'right'); +function pad(s, len, padChar, dir, stringColor, padColor) { + len = miscUtil.valueWithDefault(len, 0); + padChar = miscUtil.valueWithDefault(padChar, ' '); + dir = miscUtil.valueWithDefault(dir, 'right'); + stringColor = miscUtil.valueWithDefault(stringColor, ''); + padColor = miscUtil.valueWithDefault(padColor, ''); var padlen = len - s.length; switch(dir) { case 'L' : case 'left' : - s = new Array(padlen).join(padChar) + s; + s = padColor + new Array(padlen).join(padChar) + stringColor + s; break; case 'C' : @@ -130,16 +132,16 @@ function pad(s, len, padChar, dir) { case 'both' : var right = Math.ceil(padlen / 2); var left = padlen - right; - s = new Array(left + 1).join(padChar) + s + new Array(right + 1).join(padChar); + s = padColor + new Array(left + 1).join(padChar) + stringColor + s + padColor + new Array(right + 1).join(padChar); break; case 'R' : case 'right' : - s = s + new Array(padlen).join(padChar); + s = stringColor + s + padColor + new Array(padlen).join(padChar); break; default : break; } - return s; + return stringColor + s; } \ No newline at end of file diff --git a/core/text_view.js b/core/text_view.js index a4b9cb43..0770d54b 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -20,7 +20,7 @@ function TextView(client, options) { this.multiLine = this.options.multiLine || false; this.fillChar = miscUtil.valueWithDefault(this.options.fillChar, ' ').substr(0, 1); - this.justify = this.options.justify || 'none'; + this.justify = this.options.justify || 'right'; assert(!this.multiLine); // :TODO: not yet supported @@ -40,15 +40,25 @@ util.inherits(TextView, View); TextView.prototype.redraw = function() { TextView.super_.prototype.redraw.call(this); - var color = this.hasFocus ? this.getFocusColor() : this.getColor(); - this.client.term.write(this.getANSIColor(color)); + var ansiColor = this.getANSIColor(this.hasFocus ? this.getFocusColor() : this.getColor()); - // :TODO: If using fillChar, don't just pad. switch to non-focus color & fill with |fillChar| - // :TODO: Apply justification if(this.isPasswordTextStyle) { - this.client.term.write(strUtil.pad(new Array(this.text.length + 1).join(this.textMaskChar), this.dimens.width)); + this.client.term.write(strUtil.pad( + new Array(this.text.length + 1).join(this.textMaskChar), + this.dimens.width, + this.fillChar, + this.justify, + ansiColor, + this.getANSIColor(this.getColor()))); } else { - this.client.term.write(strUtil.pad(this.text, this.dimens.width)); + var text = strUtil.stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); + this.client.term.write(strUtil.pad( + text, + this.dimens.width, + this.fillChar, + this.justify, + ansiColor, + this.getANSIColor(this.getColor()))); } }; @@ -57,6 +67,7 @@ TextView.prototype.setFocus = function(focused) { this.redraw(); this.client.term.write(ansi.goto(this.position.x, this.position.y + this.text.length)); + this.client.term.write(this.getANSIColor(this.getFocusColor())); }; TextView.prototype.setText = function(text) { @@ -66,7 +77,7 @@ TextView.prototype.setText = function(text) { this.text = this.text.substr(0, this.maxLength); } - this.text = strUtil.stylizeString(this.text, this.textStyle); + this.text = strUtil.stylizeString(this.text, this.hasFocus ? this.focusTextStyle : this.textStyle); if(!this.multiLine && !this.dimens.width) { this.dimens.width = this.text.length; diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index b224084f..a70e0262 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -14,6 +14,8 @@ function VerticalMenuView(client, options) { var self = this; + this.itemSpacing = 3; + this.calculateDimens = function() { if(!self.dimens || !self.dimens.width) { var l = 0; @@ -26,15 +28,17 @@ function VerticalMenuView(client, options) { self.dimens.width = l; } - if(!self.dimens.height) { - //this.dimens.height = self.items.length + if(this.items.length > 0) { + this.dimens.height = (self.items.length * self.itemSpacing) - (self.itemSpacing - 1); + } else { + this.dimens.height = 0; } }; this.calculateDimens(); - this.cacheXPositions = function() { - if(self.xPositionCacheExpired) { + this.cachePositions = function() { + if(self.positionCacheExpired) { var count = this.items.length; var x = self.position.x; for(var i = 0; i < count; ++i) { @@ -44,12 +48,12 @@ function VerticalMenuView(client, options) { self.items[i].xPosition = x; } - self.xPositionCacheExpired = false; + self.positionCacheExpired = false; } }; this.drawItem = function(index) { - assert(!this.xPositionCacheExpired); + assert(!this.positionCacheExpired); var item = self.items[index]; if(!item) { @@ -60,25 +64,11 @@ function VerticalMenuView(client, options) { this.client.term.write(self.getANSIColor( index === self.focusedItemIndex || item.selected ? self.getFocusColor() : self.getColor())); - var text = strUtil.stylizeString(item.text, item.hasFocus ? self.focusTextStyle : self.textStyle); + var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle); self.client.term.write( strUtil.pad(text, this.dimens.width, this.fillChar, this.justify)); }; - - // :TODO: move to MenuView - this.moveSelection = function(fromIndex, toIndex) { - assert(!self.xPositionCacheExpired); - assert(fromIndex >= 0 && fromIndex <= self.items.length); - assert(toIndex >= 0 && toIndex <= self.items.length); - - self.items[fromIndex].focused = false; - self.drawItem(fromIndex); - - self.items[toIndex].focused = true; - self.focusedItemIndex = toIndex; - self.drawItem(toIndex); - }; } util.inherits(VerticalMenuView, MenuView); @@ -86,19 +76,7 @@ util.inherits(VerticalMenuView, MenuView); VerticalMenuView.prototype.setPosition = function(pos) { VerticalMenuView.super_.prototype.setPosition.call(this, pos); - this.xPositionCacheExpired = true; -}; - -// :TODO: Could be moved to base with just this.cachePositions() ? -VerticalMenuView.prototype.redraw = function() { - VerticalMenuView.super_.prototype.redraw.call(this); - - this.cacheXPositions(); - - var count = this.items.length; - for(var i = 0; i < count; ++i) { - this.drawItem(i); - } + this.positionCacheExpired = true; }; VerticalMenuView.prototype.setFocus = function(focused) { @@ -139,7 +117,7 @@ VerticalMenuView.prototype.getViewData = function() { VerticalMenuView.prototype.setItems = function(items) { VerticalMenuView.super_.prototype.setItems.call(this, items); - this.xPositionCacheExpired = true; - this.cacheXPositions(); + this.positionCacheExpired = true; + this.cachePositions(); this.calculateDimens(); }; \ No newline at end of file diff --git a/core/view.js b/core/view.js index 48f994b7..f44ad716 100644 --- a/core/view.js +++ b/core/view.js @@ -32,7 +32,7 @@ function View(client, options) { this.acceptsFocus = options.acceptsFocus || false; this.acceptsInput = options.acceptsInput || false; - this.submit = this.acceptsInput ? options.acceptsInput || false : false; + //this.submit = this.acceptsInput ? options.acceptsInput || false : false; this.position = { x : 0, y : 0 }; this.dimens = { height : 1, width : 0 }; diff --git a/mods/matrix.js b/mods/matrix.js index 1764bc6e..81a7b9fc 100644 --- a/mods/matrix.js +++ b/mods/matrix.js @@ -3,7 +3,6 @@ //var art = require('../core/art.js'); var ansi = require('../core/ansi_term.js'); -var lineEditor = require('../core/line_editor.js'); var art = require('../core/art.js'); var user = require('../core/user.js'); var theme = require('../core/theme.js'); @@ -30,7 +29,7 @@ function entryPoint(client) { //art.getArt('SO-CC1.ANS'/* 'MATRIX'*/, { types: ['.ans'], random: true}, function onArt(err, theArt) { //client.user.properties.art_theme_id = ''; - theme.getThemeArt('MCI_VM1.ANS', client.user.properties.art_theme_id, function onArt(err, theArt) { + theme.getThemeArt('MCI_FORM1.ANS', client.user.properties.art_theme_id, function onArt(err, theArt) { //art.getArt('MATRIX_1.ANS', {}, function onArt(err, theArt) { if(!err) { @@ -60,12 +59,18 @@ function entryPoint(client) { }); var vc = new viewController.ViewController(client); + vc.on('submit', function onSubmit(formData) { + console.log(formData); + }); + vc.loadFromMCIMap(mci); //vc.getView(3).setText('New'); //vc.getView(4).setText('Login'); vc.setViewOrder(); - vc.getView(1).submit = true; - vc.getView(1).setItems(['System Login', 'Apply', 'GTFO!']); + //vc.getView(1).submit = true; + //vc.getView(1).setItems(['System Login', 'Apply', 'GTFO!']); + vc.getView(2).submit = true; + vc.getView(3).setText('Apply'); vc.switchFocus(1); }); } diff --git a/test/ansi/MCI_FORM1.ANS b/test/ansi/MCI_FORM1.ANS new file mode 100644 index 00000000..266c9156 Binary files /dev/null and b/test/ansi/MCI_FORM1.ANS differ diff --git a/test/ansi/MCI_VM1.ANS b/test/ansi/MCI_VM1.ANS index 54621804..ef264eb1 100644 Binary files a/test/ansi/MCI_VM1.ANS and b/test/ansi/MCI_VM1.ANS differ