1 jls.loader.provide('jls.gui.FlowLayout');
  2 
  3 jls.loader.require('jls.gui.Layout');
  4 
  5 /**
  6  * @augments jls.gui.Layout
  7  * @class This class represents a flow layout. The children can have an absolute or a relative position,
  8  * these two layouts does not interfer, overlapping must be fix using z-index.
  9  * <p>Child style position: <b>absolute</b>.
 10  * The absolute position is defined using a combination of the following style options: left, right, top, bottom, width, height.
 11  * If some options are conflicting each other then the last ones are ignored,
 12  * the conflicting options and their priorities are: width, left, right and height, top, bottom.</p>
 13  * <p>Child style position: <b>relative</b>.
 14  * Children are positioned in a flow depending on the following style options:
 15  * direction (ltr, rtl), textAlign (left, right, center, justify), verticalAlign (top, middle, bottom).</p>
 16  */
 17 jls.gui.FlowLayout = jls.lang.Class.create(jls.gui.Layout,
 18 {
 19     onUpdate : function() {
 20     	/*
 21     	 * update relative children then absolute
 22     	 */
 23     	// TODO use several width: px, %, weight
 24         var cSize = this._element.getClientSize();
 25         var cWidth = cSize[0];
 26         var cHeight = cSize[1];
 27     	//jls.lang.System.out.println('update(): [' + cWidth + ', ' + cHeight + ']');
 28         var cStyle = this._element.getStyle();
 29         var hGap = cStyle.getPropertyValue('hGap') || 0;
 30         var vGap = cStyle.getPropertyValue('vGap') || 0;
 31         var lines = [];
 32         var lineWeight = 0;
 33         var lineHeight = 0;
 34         var lineWidth = 0;
 35         var lineElements = [];
 36         var globalHeight = 0;
 37         var globalWidth = 0;
 38         var childCount = this._element.getChildCount();
 39         // Special case for only one child without layout styles (left, top, width, height)
 40         if (childCount == 1) {
 41             var child = this._element.getChild(0);
 42             var style = child.getStyle();
 43             if ((style.getPropertyValue('width') == null) && (style.getPropertyValue('height') == null) &&
 44                 (style.getPropertyValue('left') == null) && (style.getPropertyValue('top') == null))
 45             {
 46                 jls.gui.FlowLayout.place(child, hGap, vGap, cWidth - hGap * 2, cHeight - vGap * 2);
 47                 return;
 48             }
 49         }
 50         for (var i = 0; i < childCount; i++) {
 51             var child = this._element.getChild(i);
 52             var style = child.getStyle();
 53             var position = style.getPropertyValue('position');
 54             var rawWidth = style.getPropertyValue('width');
 55             var rawHeight = style.getPropertyValue('height');
 56             if (position == 'relative') {
 57                 var weight = jls.gui.FlowLayout.getWeight(rawWidth);
 58                 var width = weight > 0 ? 0 : jls.gui.FlowLayout.computeSize(rawWidth, cWidth);
 59                 var height = jls.gui.FlowLayout.computeSize(rawHeight, cHeight, childCount);
 60             	/*
 61             	 * TODO Manage display:block styles
 62             	 */
 63                 if ((style.getPropertyValue('clear') == 'left') ||
 64                     ((lineElements.length > 0) && (lineElements[lineElements.length - 1].element.getStyle().getPropertyValue('clear') == 'right')) ||
 65                     (lineWidth + (lineElements.length > 0 ? hGap : 0) + width > cWidth))
 66                 {
 67                     globalHeight += vGap;
 68                 	// new line
 69                 	lines.push({
 70                 		weight: lineWeight,
 71                 		width: lineWidth,
 72                 		height: lineHeight,
 73                 		elements: lineElements
 74                 	});
 75                 	// compute global
 76                     if (lineWidth > globalWidth) {
 77                     	globalWidth = lineWidth;
 78                     }
 79                     globalHeight += lineHeight;
 80                 	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
 81                     // reset
 82                     lineElements = [];
 83                     lineWeight = 0;
 84                 	lineWidth = 0;
 85                     lineHeight = 0;
 86                 }
 87                 lineWidth += hGap;
 88                 lineElements.push({
 89             		width: width,
 90             		height: height,
 91             		rawWidth: rawWidth,
 92             		rawHeight: rawHeight,
 93             		element: child
 94                 });
 95                 lineWeight += weight;
 96                 lineWidth += width;
 97                 if (height > lineHeight) {
 98                 	lineHeight = height;
 99                 }
100             	//jls.lang.System.out.println('child[' + i + ']: ' + width + 'x' + height + ', ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
101             } else if (position == 'absolute') {
102                 var width = jls.gui.FlowLayout.computeSize(rawWidth, cWidth);
103                 var height = jls.gui.FlowLayout.computeSize(rawHeight, cHeight);
104                 var x = 0;
105                 var y = 0;
106                 var w = 0;
107                 var h = 0;
108                 var left = jls.gui.FlowLayout.computeSize(style.getPropertyValue('left'), cWidth);
109                 var top = jls.gui.FlowLayout.computeSize(style.getPropertyValue('top'), cHeight);
110                 var right = jls.gui.FlowLayout.computeSize(style.getPropertyValue('right'), cWidth);
111                 var bottom = jls.gui.FlowLayout.computeSize(style.getPropertyValue('bottom'), cHeight);
112                 // compute horizontal
113             	if (width != null) {
114             		w = width;
115             	} else if ((left != null) && (right != null)) {
116             		w = cWidth - right - left;
117             	} else {
118             		w = 10; // TODO auto
119             	}
120             	if (left != null) {
121             		x = left;
122             	} else if (right != null) {
123             		x = cWidth - right - w;
124             	} else {
125             		x = 0; // default
126             	}
127                 // compute vertical
128             	if (height != null) {
129             		h = height;
130             	} else if ((top != null) && (bottom != null)) {
131             		h = cHeight - bottom - top;
132             	} else {
133             		h = 10; // TODO auto
134             	}
135             	if (top != null) {
136             		y = top;
137             	} else if (right != null) {
138             		y = cHeight - bottom - h;
139             	} else {
140             		y = 0; // default
141             	}
142             	jls.gui.FlowLayout.place(child, x, y, w, h);
143             } else {
144             	throw new jls.lang.Exception('Invalid position: "' + position + '"');
145             }
146         }
147         if (lineElements.length > 0) {
148             if (lines.length > 0) {
149                 globalHeight += vGap;
150             }
151         	// new line
152         	lines.push({
153                 weight: lineWeight,
154                 width: lineWidth,
155         		height: lineHeight,
156         		elements: lineElements
157         	});
158         	// compute global
159             if (lineWidth > globalWidth) {
160             	globalWidth = lineWidth;
161             }
162             globalHeight += lineHeight;
163         	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
164         }
165     	//jls.lang.System.out.println('update(): ' + cWidth + 'x' + cHeight + ', ' + globalWidth + 'x' + globalHeight);
166         var lineCount = lines.length;
167         if (lineCount > 0) {
168             var direction = cStyle.getPropertyValue('direction');
169             var verticalPosition = cStyle.getPropertyValue('verticalPosition');
170             var textAlign = cStyle.getPropertyValue('textAlign');
171             var verticalAlign = cStyle.getPropertyValue('verticalAlign');
172             var y = vGap;
173             if (verticalPosition == 'middle') {
174             	y = Math.floor((cHeight - globalHeight) / 2);
175             } else if (verticalPosition == 'bottom') {
176             	y = cHeight - globalHeight;
177             }
178             for (var i = 0; i < lineCount; i++) {
179             	var line = lines[i];
180                 var x = hGap;
181                 var lineWidth = line.weight > 0 ? (cWidth - hGap * 2) : line.width;
182                 if (textAlign == 'center') {
183                 	x = Math.floor((cWidth - lineWidth) / 2);
184                 } else if (textAlign == 'right') {
185                 	x = cWidth - lineWidth;
186                 }
187             	lineElements = line.elements;
188                 if (direction == 'rtl') {
189                     for (var j = lineElements.length - 1; j >= 0; j--) {
190                     	var e = lineElements[j];
191                         var w;
192                         var h = e.height;
193                         if (line.weight > 0) {
194                             w = jls.gui.FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
195                         } else {
196                             w = e.width;
197                         }
198                     	jls.gui.FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
199                     	x += w + hGap;
200                     }
201                 } else {
202                     for (var j = 0; j < lineElements.length; j++) {
203                     	var e = lineElements[j];
204                         var w;
205                         var h = e.height;
206                         if ((line.weight > 0) && (e.width == 0)) {
207                             w = jls.gui.FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
208                             //jls.lang.System.out.println('computeSize(' + e.rawWidth + ', ' + cWidth + ', ' + line.weight + ') => ' + w);
209                         } else {
210                             w = e.width;
211                         }
212                     	jls.gui.FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
213                     	x += w + hGap;
214                     }
215                 }
216                 y += line.height + vGap;
217             }
218         }
219     }
220 });
221 
222 Object.extend(jls.gui.FlowLayout,
223 {
224     isWeight : function(value) {
225         return value.charAt(value.length - 1) == 'w';
226     },
227     getWeight : function(value) {
228         if ((typeof value != 'string') || (value.length < 2)) {
229             return 0;
230         }
231         value = value.match(/([0-9]+)(.*)/);
232         return value[2] == 'w' ? parseInt(value[1]) : 0;
233         /*var w = value[2] == 'w' ? parseInt(value[1]) : 0;
234         jls.lang.System.out.println('getWeight(' + value + ') => ' + w);
235         return w;*/
236     },
237     computeSize : function(value, size, totalWeight) {
238         if (value == null) {
239             return null;
240         }
241         if (typeof value == 'number') {
242             return value;
243         }
244         if ((typeof value != 'string') || (value.length == 0)) {
245             throw new jls.lang.Exception('Illegal type of value "' + (typeof value) + '"');
246         }
247         value = value.match(/([0-9]+)(.*)/);
248         var numberValue = value[1];
249         var typeValue = value[2] || 'px';
250         switch (typeValue) {
251         case 'px':
252             return Math.round(numberValue);
253         case '%':
254             return Math.round(numberValue * size / 100);
255         case 'w':
256             if (typeof totalWeight == 'undefined') {
257                 throw new jls.lang.Exception('The total weight is missing');
258             }
259             //jls.lang.System.out.println('computeSize(' + value + ', ' + size + ', ' + totalWeight + ') => ' + Math.round(numberValue * size / totalWeight));
260             return Math.round(numberValue * size / totalWeight);
261         default:
262             throw new jls.lang.Exception('Illegal size type "' + typeValue + '"');
263         }
264     },
265     placeElement : function(verticalAlign, lineHeight, child, x, y, w, h) {
266     	if (verticalAlign == 'middle') {
267     		y = y + Math.floor((lineHeight - h) / 2);
268     	} else if (verticalAlign == 'bottom') {
269     		y = y + lineHeight - h;
270     	}
271     	jls.gui.FlowLayout.place(child, x, y, w, h);
272     },
273     place : function(child, x, y, w, h) {
274         //jls.lang.System.out.println('[' + x + ', ' + y + ', ' + w + ', ' + h + ']');
275         //child.setLocation([x, y]);
276         child.setBounds([x, y, w, h]);
277         child.update();
278     }
279 });
280