/* Copyright © 2015-2016 David Valdman */
define(function(require, exports, module) {
var Transform = require('../core/Transform');
var Transitionable = require('../core/Transitionable');
var View = require('../core/View');
var Stream = require('../streams/Stream');
var LayoutNode = require('../core/LayoutNode');
var SizeNode = require('../core/SizeNode');
var CONSTANTS = {
DIRECTION : {
X : 0,
Y : 1
}
};
/**
* A layout which arranges items vertically or horizontally and
* with sizes prescribed by ratios of a containing size. These
* ratios can be animated.
*
* @class FlexibleLayout
* @constructor
* @namespace Layouts
* @extends Core.View
* @param [options] {Object} Options
* @param [options.direction]{Number} Direction to lay out items
* @param [options.ratios] {Transitionable|Array} The proportions
*/
var FlexibleLayout = View.extend({
defaults : {
direction : CONSTANTS.DIRECTION.X,
ratios : []
},
initialize : function initialize(options){
var ratios = (options.ratios instanceof Transitionable)
? options.ratios
: new Transitionable(options.ratios);
this.nodes = [];
var stateStream = Stream.lift(function(ratios, parentSize){
var direction = options.direction;
// calculate remaining size after true-sized nodes are accounted for
var flexLength = parentSize[direction];
var ratioSum = 0;
for (var i = 0; i < ratios.length; i++) {
var ratio = ratios[i];
var node = this.nodes[i];
(typeof ratio !== 'number')
? flexLength -= node.getSize()[direction] || 0
: ratioSum += ratio;
}
// calculate sizes and displacements of nodes
var displacement = 0;
var transforms = [];
var sizes = [];
for (var i = 0; i < ratios.length; i++) {
node = this.nodes[i];
ratio = ratios[i];
var nodeLength = (typeof ratio === 'number')
? flexLength * ratio / ratioSum
: node.getSize()[direction];
var transform = (direction == CONSTANTS.DIRECTION.X)
? Transform.translateX(displacement)
: Transform.translateY(displacement);
var size = (direction == CONSTANTS.DIRECTION.X)
? [nodeLength, undefined]
: [undefined, nodeLength];
sizes.push(size);
transforms.push(transform);
displacement += nodeLength;
}
return {
transforms : transforms,
sizes : sizes
};
}.bind(this), [ratios, this.size]);
this.transforms = stateStream.pluck('transforms');
this.sizes = stateStream.pluck('sizes');
},
/**
* Add content as an array of Views or Surfaces.
*
* @method addItems
* @param items {Array} An array of Views or Surfaces
*/
addItems : function addItems(items){
this.nodes = items;
for (var i = 0; i < this.nodes.length; i++){
var node = this.nodes[i];
var layoutNode = new LayoutNode({
transform : this.transforms.pluck(i)
});
var sizeNode = new SizeNode({
size : this.sizes.pluck(i)
});
this.add(layoutNode).add(sizeNode).add(node);
}
}
}, CONSTANTS);
module.exports = FlexibleLayout;
});