diff --git a/core/menu_view.js b/core/menu_view.js index db6c641a..e585d141 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -34,12 +34,12 @@ function MenuView(options) { this.itemSpacing = _.isNumber(options.itemSpacing) ? options.itemSpacing : 0; + // :TODO: probably just replace this with owner draw / pipe codes / etc. more control, less specialization this.focusPrefix = options.focusPrefix || ''; this.focusSuffix = options.focusSuffix || ''; this.fillChar = miscUtil.valueWithDefault(options.fillChar, ' ').substr(0, 1); this.justify = options.justify || 'none'; - /* this.moveSelection = function(fromIndex, toIndex) { assert(!self.positionCacheExpired); @@ -122,5 +122,5 @@ MenuView.prototype.setHotKeys = function(hotKeys) { this.hotKeys = hotKeys; } } -} +}; diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index 85cff4df..c04c4350 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -23,25 +23,34 @@ function VerticalMenuView(options) { // :TODO: view.setDimens() would set autoSize to false. Otherwise, we cna scale @ setItems() // topViewIndex = top visibile item // itemsInView = height * (1 + itemSpacing) - this.calculateDimens2 = function() { - if(this.autoSize) { - self.dimens = self.dimens || {}; - if(!_.isNumber(this.dimens.height) || this.dimens.height < 1) { - this.dimens.height = 1; - } + this.updateViewable = function() { + var viewableItems = self.dimens.height / ((self.itemSpacing + 1) - self.itemSpacing); +console.log(viewableItems) + this.viewableRange = { + top : self.focusedItemIndex, + bottom : viewableItems - self.focusedItemIndex, + }; + + console.log(this.viewableRange) + }; + + this.scaleDimension = function() { + if(this.autoScale) { + this.dimens.height = (self.items.length * (self.itemSpacing + 1)) - (self.itemSpacing); + this.dimens.height = Math.min(this.dimens.height, self.client.term.termHeight - self.position.x); var l = 0; self.items.forEach(function item(i) { if(i.text.length > l) { - l = Math.min(l.text.length, self.client.term.termWidth - self.position.y); + l = Math.min(i.text.length, self.client.term.termWidth - self.position.y); } }); self.dimens.width = l; } }; - + /* this.calculateDimens = function() { if(!self.dimens || !self.dimens.width) { var l = 0; @@ -60,8 +69,29 @@ function VerticalMenuView(options) { this.dimens.height = 0; } }; + */ - this.calculateDimens(); + this.scaleDimension(); + + this.cacheVisiblePositions = function() { + if(self.positionCacheExpired) { + var x = self.position.x; + for(var i = this.viewableRange.top; i < this.viewableRange.bottom; ++i) { + if(i > 0) { + x += self.itemSpacing + 1; + } + self.items[i].xPosition = x; + } + + self.positionCacheExpired = false; + } + }; + + this.scrollToVisible = function() { + + }; + + this.cachePositions = function() { if(self.positionCacheExpired) { @@ -92,7 +122,7 @@ function VerticalMenuView(options) { }; this.drawItem = function(index) { - assert(!this.positionCacheExpired); + assert(self.positionCacheExpired === false); var item = self.items[index]; if(!item) { @@ -100,7 +130,7 @@ function VerticalMenuView(options) { } self.client.term.write(ansi.goto(item.xPosition, self.position.y)); - this.client.term.write(index === self.focusedItemIndex ? this.getFocusSGR() : this.getSGR()); + self.client.term.write(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR()); var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle); @@ -112,7 +142,13 @@ function VerticalMenuView(options) { util.inherits(VerticalMenuView, MenuView); VerticalMenuView.prototype.redraw = function() { - VerticalMenuView.super_.prototype.redrawAllItems.call(this); + //VerticalMenuView.super_.prototype.redrawAllItems.call(this); + VerticalMenuView.super_.prototype.redraw.call(this); + + for(var i = this.viewableRange.top; i < this.viewableRange.bottom; ++i) { + this.items[i].focused = this.focusedItemIndex === i; + this.drawItem(i); + } }; VerticalMenuView.prototype.setPosition = function(pos) { @@ -162,5 +198,7 @@ VerticalMenuView.prototype.setItems = function(items) { this.positionCacheExpired = true; this.cachePositions(); - this.calculateDimens(); + this.scaleDimension(); + + this.updateViewable(); }; \ No newline at end of file diff --git a/core/view.js b/core/view.js index d404f060..7a8221b7 100644 --- a/core/view.js +++ b/core/view.js @@ -55,22 +55,15 @@ function View(options) { this.setPosition(options.position); } - // :TODO: Don't allow width/height > client.term - if(_.isObject(options.dimens)) { - if(_.isNumber(options.dimens.height)) { - this.dimens.height = options.dimens.height; - } + this.autoScale = _.isBoolean(options.autoScale) ? options.autoScale : true; - if(_.isNumber(options.dimens.width)) { - this.dimens.width = options.dimens.width; - } + if(options.dimens) { + this.setDimension(options.dimens); + this.autoScale = false; // no auto scaling dimens supplied } else { - options.dimens = { width : 1, height : 1 }; + this.dimens = { width : 0, height : 0 }; } - //options.dimens.width = options.dimens.width || 1; - //options.dimens.height = options.dimens.height || 1; - this.ansiSGR = options.ansiSGR || ansi.getSGRFromGraphicRendition( { fg : 39, bg : 49 }, true); this.ansiFocusSGR = options.ansiFocusSGR || this.ansiSGR; @@ -140,6 +133,21 @@ View.prototype.setPosition = function(pos) { 'Y position ' + this.position.y + ' out of terminal range ' + this.client.term.termWidth); }; +View.prototype.setDimension = function(dimens) { + assert(_.isObject(dimens) && _.isNumber(dimens.height) && _.isNumber(dimens.width)); + + this.dimens = dimens; + this.autoScale = false; +}; + +View.prototype.setHeight = function(height) { + this.setDimension( { height : height, width : this.dimens.width } ); +}; + +View.prototype.setWidth = function(width) { + this.setDimension( { height : this.dimens.height, width : width } ); +}; + /* View.prototype.setColor = function(color, bgColor, flags) { if(_.isObject(color)) { @@ -175,11 +183,11 @@ View.prototype.setColor = function(color, bgColor, flags) { View.prototype.getSGR = function() { return this.ansiSGR; -} +}; View.prototype.getFocusSGR = function() { return this.ansiFocusSGR; -} +}; View.prototype.redraw = function() { this.client.term.write(ansi.goto(this.position.x, this.position.y)); diff --git a/core/view_controller.js b/core/view_controller.js index 9b44a8c6..61fa03af 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -177,16 +177,19 @@ function ViewController(options) { } } - setViewProp('items', function(v) { view.setItems(v); }); + setViewProp('width', function(v) { view.setWidth(parseInt(v, 10)); }); + setViewProp('height', function(v) { view.setHeight(parseInt(v, 10)); }); + setViewProp('itemSpacing', function(v) { view.setItemSpacing(v); }); - + setViewProp('items', function(v) { view.setItems(v); }); + setViewProp('text', function(v) { view.setText(v); }); setViewProp('textStyle'); setViewProp('focusTextStyle'); setViewProp('textMaskChar', function(v) { view.textMaskChar = v.substr(0, 1); }); setViewProp('maxLength'); - setViewProp('width', function(v) { view.dimens.width = parseInt(v, 10); }); + ['styleSGR1', 'styleSGR2'].forEach(function styleSgr(style) { setViewProp(style, function(v) { diff --git a/mods/menu.json b/mods/menu.json index 517f1cee..fd64f8cd 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -227,9 +227,13 @@ "items" : [ "Single Line Text Editing Views", "Spinner & Toggle Views", + "Vertical Menu Views", + "Horizontal Menu Views", "Art Display", + "Some More Stuff", "Other" ], + "height" : 4, "itemSpacing" : 1, // :TODO: justify not working?? "focusTextStyle" : "small i"