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