Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / HBoxLayout.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 <div id="cls-Ext.layout.HBoxLayout"></div>/**
16  * @class Ext.layout.HBoxLayout
17  * @extends Ext.layout.BoxLayout
18  * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
19  * space between child items containing a numeric <code>flex</code> configuration.</p>
20  * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
21  */
22 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
23     <div id="cfg-Ext.layout.HBoxLayout-align"></div>/**
24      * @cfg {String} align
25      * Controls how the child items of the container are aligned. Acceptable configuration values for this
26      * property are:
27      * <div class="mdetail-params"><ul>
28      * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
29      * at the <b>top</b> of the container</div></li>
30      * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
31      * <b>middle</b> of the container</div></li>
32      * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
33      * the height of the container</div></li>
34      * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
35      * the height of the largest item.</div></li>
36      */
37     align: 'top', // top, middle, stretch, strechmax
38
39     type : 'hbox',
40
41     <div id="cfg-Ext.layout.HBoxLayout-pack"></div>/**
42      * @cfg {String} pack
43      * Controls how the child items of the container are packed together. Acceptable configuration values
44      * for this property are:
45      * <div class="mdetail-params"><ul>
46      * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
47      * <b>left</b> side of container</div></li>
48      * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
49      * <b>mid-width</b> of container</div></li>
50      * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
51      * side of container</div></li>
52      * </ul></div>
53      */
54     <div id="cfg-Ext.layout.HBoxLayout-flex"></div>/**
55      * @cfg {Number} flex
56      * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
57      * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
58      * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
59      * a <tt>flex</tt> value specified.  Any child items that have either a <tt>flex = 0</tt> or
60      * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
61      */
62
63     /**
64      * @private
65      * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
66      * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
67      * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
68      * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
69      * @param {Object} targetSize Object containing target size and height
70      * @return {Object} Object containing box measurements for each child, plus meta data
71      */
72     calculateChildBoxes: function(visibleItems, targetSize) {
73         var visibleCount = visibleItems.length,
74
75             padding      = this.padding,
76             topOffset    = padding.top,
77             leftOffset   = padding.left,
78             paddingVert  = topOffset  + padding.bottom,
79             paddingHoriz = leftOffset + padding.right,
80
81             width        = targetSize.width - this.scrollOffset,
82             height       = targetSize.height,
83             availHeight  = Math.max(0, height - paddingVert),
84
85             isStart      = this.pack == 'start',
86             isCenter     = this.pack == 'center',
87             isEnd        = this.pack == 'end',
88
89             nonFlexWidth = 0,
90             maxHeight    = 0,
91             totalFlex    = 0,
92             desiredWidth = 0,
93             minimumWidth = 0,
94
95             //used to cache the calculated size and position values for each child item
96             boxes        = [],
97
98             //used in the for loops below, just declared here for brevity
99             child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth, 
100             horizMargins, vertMargins, stretchHeight;
101
102         //gather the total flex of all flexed items and the width taken up by fixed width items
103         for (i = 0; i < visibleCount; i++) {
104             child       = visibleItems[i];
105             childHeight = child.height;
106             childWidth  = child.width;
107             canLayout   = !child.hasLayout && typeof child.doLayout == 'function';
108
109             // Static width (numeric) requires no calcs
110             if (typeof childWidth != 'number') {
111
112                 // flex and not 'auto' width
113                 if (child.flex && !childWidth) {
114                     totalFlex += child.flex;
115
116                 // Not flexed or 'auto' width or undefined width
117                 } else {
118                     //Render and layout sub-containers without a flex or width defined, as otherwise we
119                     //don't know how wide the sub-container should be and cannot calculate flexed widths
120                     if (!childWidth && canLayout) {
121                         child.doLayout();
122                     }
123
124                     childSize   = child.getSize();
125                     childWidth  = childSize.width;
126                     childHeight = childSize.height;
127                 }
128             }
129
130             childMargins = child.margins;
131             horizMargins = childMargins.left + childMargins.right;
132
133             nonFlexWidth += horizMargins + (childWidth || 0);
134             desiredWidth += horizMargins + (child.flex ? child.minWidth || 0 : childWidth);
135             minimumWidth += horizMargins + (child.minWidth || childWidth || 0);
136
137             // Max height for align - force layout of non-laid out subcontainers without a numeric height
138             if (typeof childHeight != 'number') {
139                 if (canLayout) {
140                     child.doLayout();
141                 }
142                 childHeight = child.getHeight();
143             }
144
145             maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
146
147             //cache the size of each child component. Don't set height or width to 0, keep undefined instead
148             boxes.push({
149                 component: child,
150                 height   : childHeight || undefined,
151                 width    : childWidth  || undefined
152             });
153         }
154                 
155         var shortfall = desiredWidth - width,
156             tooNarrow = minimumWidth > width;
157             
158         //the width available to the flexed items
159         var availableWidth = Math.max(0, width - nonFlexWidth - paddingHoriz);
160         
161         if (tooNarrow) {
162             for (i = 0; i < visibleCount; i++) {
163                 boxes[i].width = visibleItems[i].minWidth || visibleItems[i].width || boxes[i].width;
164             }
165         } else {
166             //all flexed items should be sized to their minimum width, other items should be shrunk down until
167             //the shortfall has been accounted for
168             if (shortfall > 0) {
169                 var minWidths = [];
170                 
171                 <div id="prop-Ext.layout.HBoxLayout-for"></div>/**
172                  * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
173                  * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
174                  * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
175                  */
176                 for (var index = 0, length = visibleCount; index < length; index++) {
177                     var item     = visibleItems[index],
178                         minWidth = item.minWidth || 0;
179
180                     //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
181                     //shrunk to their minWidth because they're flexible and should be the first to lose width
182                     if (item.flex) {
183                         boxes[index].width = minWidth;
184                     } else {
185                         minWidths.push({
186                             minWidth : minWidth,
187                             available: boxes[index].width - minWidth,
188                             index    : index
189                         });
190                     }
191                 }
192                 
193                 //sort by descending amount of width remaining before minWidth is reached
194                 minWidths.sort(function(a, b) {
195                     return a.available > b.available ? 1 : -1;
196                 });
197                 
198                 /*
199                  * Distribute the shortfall (difference between total desired with of all items and actual width available)
200                  * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
201                  * smallest difference between their width and minWidth first, so that if reducing the width by the average
202                  * amount would make that item less than its minWidth, we carry the remainder over to the next item.
203                  */
204                 for (var i = 0, length = minWidths.length; i < length; i++) {
205                     var itemIndex = minWidths[i].index;
206                     
207                     if (itemIndex == undefined) {
208                         continue;
209                     }
210                         
211                     var item      = visibleItems[itemIndex],
212                         box       = boxes[itemIndex],
213                         oldWidth  = box.width,
214                         minWidth  = item.minWidth,
215                         newWidth  = Math.max(minWidth, oldWidth - Math.ceil(shortfall / (length - i))),
216                         reduction = oldWidth - newWidth;
217                     
218                     boxes[itemIndex].width = newWidth;
219                     shortfall -= reduction;                    
220                 }
221             } else {
222                 //temporary variables used in the flex width calculations below
223                 var remainingWidth = availableWidth,
224                     remainingFlex  = totalFlex;
225
226                 //calculate the widths of each flexed item
227                 for (i = 0; i < visibleCount; i++) {
228                     child = visibleItems[i];
229                     calcs = boxes[i];
230
231                     childMargins = child.margins;
232                     vertMargins  = childMargins.top + childMargins.bottom;
233
234                     if (isStart && child.flex && !child.width) {
235                         flexedWidth     = Math.ceil((child.flex / remainingFlex) * remainingWidth);
236                         remainingWidth -= flexedWidth;
237                         remainingFlex  -= child.flex;
238
239                         calcs.width = flexedWidth;
240                         calcs.dirtySize = true;
241                     }
242                 }
243             }
244         }
245         
246         if (isCenter) {
247             leftOffset += availableWidth / 2;
248         } else if (isEnd) {
249             leftOffset += availableWidth;
250         }
251         
252         //finally, calculate the left and top position of each item
253         for (i = 0; i < visibleCount; i++) {
254             child = visibleItems[i];
255             calcs = boxes[i];
256             
257             childMargins = child.margins;
258             leftOffset  += childMargins.left;
259             vertMargins  = childMargins.top + childMargins.bottom;
260             
261             calcs.left = leftOffset;
262             calcs.top  = topOffset + childMargins.top;
263
264             switch (this.align) {
265                 case 'stretch':
266                     stretchHeight = availHeight - vertMargins;
267                     calcs.height  = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
268                     calcs.dirtySize = true;
269                     break;
270                 case 'stretchmax':
271                     stretchHeight = maxHeight - vertMargins;
272                     calcs.height  = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
273                     calcs.dirtySize = true;
274                     break;
275                 case 'middle':
276                     var diff = availHeight - calcs.height - vertMargins;
277                     if (diff > 0) {
278                         calcs.top = topOffset + vertMargins + (diff / 2);
279                     }
280             }
281             
282             leftOffset += calcs.width + childMargins.right;
283         }
284
285         return {
286             boxes: boxes,
287             meta : {
288                 maxHeight   : maxHeight,
289                 nonFlexWidth: nonFlexWidth,
290                 desiredWidth: desiredWidth,
291                 minimumWidth: minimumWidth,
292                 shortfall   : desiredWidth - width,
293                 tooNarrow   : tooNarrow
294             }
295         };
296     }
297 });
298
299 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;</pre>    
300 </body>
301 </html>