diff --git a/README.md b/README.md index 317868a..4d95964 100644 --- a/README.md +++ b/README.md @@ -1337,6 +1337,10 @@ By default, the Layout element automatically positions children as if they were - __renderer__ - a callback which is called right before the children are iterated over to be rendered. should return an iterator callback which is called on each child element: __iterator(el, i)__. +- __layout__ - using the default renderer, it provides two layouts: inline, and + grid. `inline` is the default and will render akin to `inline-block`. `grid` + will create an automatic grid based on element dimensions. the grid cells' + width and height are always determined by the largest children in the layout. ##### Properties: diff --git a/lib/widgets/layout.js b/lib/widgets/layout.js index efb929d..4dc52db 100644 --- a/lib/widgets/layout.js +++ b/lib/widgets/layout.js @@ -33,6 +33,8 @@ function Layout(options) { throw new Error('`Layout` must have a width and height!'); } + options.layout = options.layout || 'inline'; + Element.call(this, options); if (options.renderer) { @@ -87,6 +89,15 @@ Layout.prototype.renderer = function(coords) { // The index of the first child in the row var rowIndex = 0; + var lastRowIndex = 0; + + // Figure out the highest width child + if (this.options.layout === 'grid') { + var highWidth = this.children.reduce(function(out, el) { + out = Math.max(out, el.width); + return out; + }, 0); + } return function iterator(el, i) { // Make our children shrinkable. If they don't have a height, for @@ -106,6 +117,14 @@ Layout.prototype.renderer = function(coords) { // rendered element. This child will end up directly to the right of it. el.position.left = last.lpos.xl - xi; + // Make sure the position matches the highest width element + if (self.options.layout === 'grid') { + // Compensate with width: + // el.position.width = el.width + (highWidth - el.width); + // Compensate with position: + el.position.left += highWidth - (last.lpos.xl - last.lpos.xi); + } + // If our child does not overlap the right side of the Layout, set it's // `top`/`y` to the current `rowOffset` (the coordinate for the current // row). @@ -120,12 +139,32 @@ Layout.prototype.renderer = function(coords) { out = Math.max(out, el.lpos.yl - el.lpos.yi); return out; }, 0); + lastRowIndex = rowIndex; rowIndex = i; el.position.left = 0; el.position.top = rowOffset; } } + // Make sure the elements on lower rows graviatate up as much as possible + if (self.options.layout === 'inline') { + var above = null; + var abovea = Infinity; + for (var j = lastRowIndex; j < rowIndex; j++) { + var l = self.children[j]; + if (!self.isRendered(l)) continue; + var abs = Math.abs(el.position.left - (l.lpos.xi - xi)); + // if (abs < abovea && (l.lpos.xl - l.lpos.xi) <= el.width) { + if (abs < abovea) { + above = l; + abovea = abs; + } + } + if (above) { + el.position.top = above.lpos.yl - yi; + } + } + // If our child overflows the Layout, do not render it! // Disable this feature for now. if (el.position.top + el.height > height) { diff --git a/test/widget-layout.js b/test/widget-layout.js index a92d249..47f2421 100644 --- a/test/widget-layout.js +++ b/test/widget-layout.js @@ -14,6 +14,7 @@ var layout = blessed.layout({ width: '50%', height: '50%', border: 'line', + layout: 'inline', style: { bg: 'red', border: { @@ -28,7 +29,8 @@ var box1 = blessed.box({ left: 'center', width: 20, height: 10, - border: 'line' + border: 'line', + content: '1' }); var box2 = blessed.box({ @@ -37,79 +39,108 @@ var box2 = blessed.box({ left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '2' }); -var box2 = blessed.box({ +var box3 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '3' }); -var box2 = blessed.box({ +var box4 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '4' }); -var box2 = blessed.box({ +var box5 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '5' }); -var box2 = blessed.box({ +var box6 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '6' }); -var box2 = blessed.box({ +var box7 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '7' }); -var box1 = blessed.box({ +var box8 = blessed.box({ parent: layout, top: 'center', left: 'center', width: 20, height: 10, - border: 'line' + border: 'line', + content: '8' }); -var box2 = blessed.box({ +var box9 = blessed.box({ parent: layout, top: 0, left: 0, width: 10, height: 5, - border: 'line' + border: 'line', + content: '9' }); -var box1 = blessed.box({ +var box10 = blessed.box({ parent: layout, top: 'center', left: 'center', width: 20, height: 10, - border: 'line' + border: 'line', + content: '10' +}); + +var box11 = blessed.box({ + parent: layout, + top: 0, + left: 0, + width: 10, + height: 5, + border: 'line', + content: '11' +}); + +var box12 = blessed.box({ + parent: layout, + top: 'center', + left: 'center', + width: 20, + height: 10, + border: 'line', + content: '12' }); /* @@ -118,7 +149,8 @@ for (var i = 0; i < 10; i++) { parent: layout, width: i % 2 === 0 ? 10 : 20, height: i % 2 === 0 ? 5 : 10, - border: 'line' + border: 'line', + content: (i + 1) + '' }); } */