3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.layout.container.Box
17 * @extends Ext.layout.container.Container
18 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
21 Ext.define('Ext.layout.container.Box', {
23 /* Begin Definitions */
25 alias: ['layout.box'],
26 extend: 'Ext.layout.container.Container',
27 alternateClassName: 'Ext.layout.BoxLayout',
30 'Ext.layout.container.boxOverflow.None',
31 'Ext.layout.container.boxOverflow.Menu',
32 'Ext.layout.container.boxOverflow.Scroller',
34 'Ext.dd.DragDropManager'
40 * @cfg {Boolean/Number/Object} animate
41 * <p>If truthy, child Component are <i>animated</i> into position whenever the Container
42 * is layed out. If this option is numeric, it is used as the animation duration in milliseconds.</p>
43 * <p>May be set as a property at any time.</p>
47 * @cfg {Object} defaultMargins
48 * <p>If the individual contained items do not have a <tt>margins</tt>
49 * property specified or margin specified via CSS, the default margins from this property will be
50 * applied to each item.</p>
51 * <br><p>This property may be specified as an object containing margins
52 * to apply in the format:</p><pre><code>
55 right: (right margin),
56 bottom: (bottom margin),
59 * <p>This property may also be specified as a string containing
60 * space-separated, numeric margin values. The order of the sides associated
61 * with each value matches the way CSS processes margin values:</p>
62 * <div class="mdetail-params"><ul>
63 * <li>If there is only one value, it applies to all sides.</li>
64 * <li>If there are two values, the top and bottom borders are set to the
65 * first value and the right and left are set to the second.</li>
66 * <li>If there are three values, the top is set to the first value, the left
67 * and right are set to the second, and the bottom is set to the third.</li>
68 * <li>If there are four values, they apply to the top, right, bottom, and
69 * left, respectively.</li>
80 * @cfg {String} padding
81 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
82 * <p>This property must be specified as a string containing
83 * space-separated, numeric padding values. The order of the sides associated
84 * with each value matches the way CSS processes padding values:</p>
85 * <div class="mdetail-params"><ul>
86 * <li>If there is only one value, it applies to all sides.</li>
87 * <li>If there are two values, the top and bottom borders are set to the
88 * first value and the right and left are set to the second.</li>
89 * <li>If there are three values, the top is set to the first value, the left
90 * and right are set to the second, and the bottom is set to the third.</li>
91 * <li>If there are four values, they apply to the top, right, bottom, and
92 * left, respectively.</li>
96 // documented in subclasses
101 * Controls how the child items of the container are packed together. Acceptable configuration values
102 * for this property are:
103 * <div class="mdetail-params"><ul>
104 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
105 * <b>left</b> side of container</div></li>
106 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
107 * <b>mid-width</b> of container</div></li>
108 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
109 * side of container</div></li>
114 * This configuration option is to be applied to <b>child <tt>items</tt></b> of the container managed
115 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
116 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
117 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
118 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
123 itemCls: Ext.baseCSSPrefix + 'box-item',
124 targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
125 innerCls: Ext.baseCSSPrefix + 'box-inner',
127 bindToOwnerCtContainer: true,
129 // availableSpaceOffset is used to adjust the availableWidth, typically used
130 // to reserve space for a scrollbar
131 availableSpaceOffset: 0,
133 // whether or not to reserve the availableSpaceOffset in layout calculations
137 * @cfg {Boolean} shrinkToFit
138 * True (the default) to allow fixed size components to shrink (limited to their
139 * minimum size) to avoid overflow. False to preserve fixed sizes even if they cause
145 * @cfg {Boolean} clearInnerCtOnLayout
147 clearInnerCtOnLayout: false,
149 flexSortFn: function (a, b) {
150 var maxParallelPrefix = 'max' + this.parallelPrefixCap,
151 infiniteValue = Infinity;
152 a = a.component[maxParallelPrefix] || infiniteValue;
153 b = b.component[maxParallelPrefix] || infiniteValue;
154 // IE 6/7 Don't like Infinity - Infinity...
155 if (!isFinite(a) && !isFinite(b)) {
161 // Sort into *descending* order.
162 minSizeSortFn: function(a, b) {
163 return b.available - a.available;
166 constructor: function(config) {
169 me.callParent(arguments);
171 // The sort function needs access to properties in this, so must be bound.
172 me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);
174 me.initOverflowHandler();
179 * Returns the current size and positioning of the passed child item.
180 * @param {Ext.Component} child The child Component to calculate the box for
181 * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
183 getChildBox: function(child) {
184 child = child.el || this.owner.getComponent(child).el;
185 var size = child.getBox(false, true);
196 * Calculates the size and positioning of the passed child item.
197 * @param {Ext.Component} child The child Component to calculate the box for
198 * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
200 calculateChildBox: function(child) {
202 boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
206 child = me.owner.getComponent(child);
207 for (; i < ln; i++) {
208 if (boxes[i].component === child) {
216 * Calculates the size and positioning of each item in the box. This iterates over all of the rendered,
217 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
218 * returns meta data such as maxSize which are useful when resizing layout wrappers such as this.innerCt.
219 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
220 * @param {Object} targetSize Object containing target size and height
221 * @return {Object} Object containing box measurements for each child, plus meta data
223 calculateChildBoxes: function(visibleItems, targetSize) {
227 infiniteValue = Infinity,
230 parallelPrefix = me.parallelPrefix,
231 parallelPrefixCap = me.parallelPrefixCap,
232 perpendicularPrefix = me.perpendicularPrefix,
233 perpendicularPrefixCap = me.perpendicularPrefixCap,
234 parallelMinString = 'min' + parallelPrefixCap,
235 perpendicularMinString = 'min' + perpendicularPrefixCap,
236 perpendicularMaxString = 'max' + perpendicularPrefixCap,
238 parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
239 perpendicularSize = targetSize[perpendicularPrefix],
240 padding = me.padding,
241 parallelOffset = padding[me.parallelBefore],
242 paddingParallel = parallelOffset + padding[me.parallelAfter],
243 perpendicularOffset = padding[me.perpendicularLeftTop],
244 paddingPerpendicular = perpendicularOffset + padding[me.perpendicularRightBottom],
245 availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
247 innerCtBorderWidth = me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB),
249 isStart = me.pack == 'start',
250 isCenter = me.pack == 'center',
251 isEnd = me.pack == 'end',
253 constrain = Ext.Number.constrain,
254 visibleCount = visibleItems.length,
264 i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
265 tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
266 flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
267 perpendicularMargins, stretchSize;
269 //gather the total flex of all flexed items and the width taken up by fixed width items
270 for (i = 0; i < visibleCount; i++) {
271 child = visibleItems[i];
272 childPerpendicular = child[perpendicularPrefix];
273 if (!child.flex || !(me.align == 'stretch' || me.align == 'stretchmax')) {
274 if (child.componentLayout.initialized !== true) {
275 me.layoutItem(child);
279 childMargins = child.margins;
280 parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
282 // Create the box description object for this child item.
285 margins: childMargins
288 // flex and not 'auto' width
290 totalFlex += child.flex;
291 childParallel = undefinedValue;
293 // Not flexed or 'auto' width or undefined width
295 if (!(child[parallelPrefix] && childPerpendicular)) {
296 childSize = child.getSize();
298 childParallel = child[parallelPrefix] || childSize[parallelPrefix];
299 childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
302 nonFlexSize += parallelMargins + (childParallel || 0);
303 desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
304 minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);
306 // Max height for align - force layout of non-laid out subcontainers without a numeric height
307 if (typeof childPerpendicular != 'number') {
308 // Clear any static sizing and revert to flow so we can get a proper measurement
309 // child['set' + perpendicularPrefixCap](null);
310 childPerpendicular = child['get' + perpendicularPrefixCap]();
313 // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
314 // Ensure that the tracked maximum perpendicular size takes into account child min[Width|Height] settings!
315 maxSize = mmax(maxSize, mmax(childPerpendicular, child[perpendicularMinString]||0) + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
317 tmpObj[parallelPrefix] = childParallel || undefinedValue;
318 tmpObj.dirtySize = child.componentLayout.lastComponentSize ? (tmpObj[parallelPrefix] !== child.componentLayout.lastComponentSize[parallelPrefix]) : false;
319 tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
323 // Only calculate parallel overflow indicators if we are not auto sizing
325 shortfall = desiredSize - parallelSize;
326 tooNarrow = minimumSize > parallelSize;
329 //the space available to the flexed items
330 availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
333 for (i = 0; i < visibleCount; i++) {
335 minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
336 box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
337 box[parallelPrefix] = minSize;
341 //all flexed items should be sized to their minimum size, other items should be shrunk down until
342 //the shortfall has been accounted for
345 * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
346 * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
347 * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
349 for (i = 0; i < visibleCount; i++) {
350 item = visibleItems[i];
351 minSize = item[parallelMinString] || 0;
353 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
354 //shrunk to their minSize because they're flexible and should be the first to lose size
357 box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
358 box[parallelPrefix] = minSize;
359 } else if (me.shrinkToFit) {
362 available: boxes[i][parallelPrefix] - minSize,
368 //sort by descending amount of width remaining before minWidth is reached
369 Ext.Array.sort(minSizes, me.minSizeSortFn);
372 * Distribute the shortfall (difference between total desired size of all items and actual size available)
373 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
374 * smallest difference between their size and minSize first, so that if reducing the size by the average
375 * amount would make that item less than its minSize, we carry the remainder over to the next item.
377 for (i = 0, length = minSizes.length; i < length; i++) {
378 itemIndex = minSizes[i].index;
380 if (itemIndex == undefinedValue) {
383 item = visibleItems[itemIndex];
384 minSize = minSizes[i].minSize;
386 box = boxes[itemIndex];
387 oldSize = box[parallelPrefix];
388 newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
389 reduction = oldSize - newSize;
391 box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
392 box[parallelPrefix] = newSize;
393 shortfall -= reduction;
395 tooNarrow = (shortfall > 0);
398 remainingSpace = availableSpace;
399 remainingFlex = totalFlex;
402 // Create an array containing *just the flexed boxes* for allocation of remainingSpace
403 for (i = 0; i < visibleCount; i++) {
404 child = visibleItems[i];
405 if (isStart && child.flex) {
406 flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
409 // The flexed boxes need to be sorted in ascending order of maxSize to work properly
410 // so that unallocated space caused by maxWidth being less than flexed width
411 // can be reallocated to subsequent flexed boxes.
412 Ext.Array.sort(flexedBoxes, me.flexSortFn);
414 // Calculate the size of each flexed item, and attempt to set it.
415 for (i = 0; i < flexedBoxes.length; i++) {
416 calcs = flexedBoxes[i];
417 child = calcs.component;
418 childMargins = calcs.margins;
420 flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);
422 // Implement maxSize and minSize check
423 flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));
425 // Remaining space has already had all parallel margins subtracted from it, so just subtract consumed size
426 remainingSpace -= flexedSize;
427 remainingFlex -= child.flex;
429 calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
430 calcs[parallelPrefix] = flexedSize;
436 parallelOffset += availableSpace / 2;
439 parallelOffset += availableSpace;
442 // Fix for left and right docked Components in a dock component layout. This is for docked Headers and docked Toolbars.
443 // Older Microsoft browsers do not size a position:absolute element's width to match its content.
444 // So in this case, in the updateInnerCtSize method we may need to adjust the size of the owning Container's element explicitly based upon
445 // the discovered max width. So here we put a calculatedWidth property in the metadata to facilitate this.
446 if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {
448 calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
449 if (me.owner.frameSize) {
450 calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
452 // If the owning element is not sized, calculate the available width to center or stretch in based upon maxSize
453 availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
456 //finally, calculate the left and top position of each item
457 for (i = 0; i < visibleCount; i++) {
458 child = visibleItems[i];
461 childMargins = calcs.margins;
463 perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];
465 // Advance past the "before" margin
466 parallelOffset += childMargins[me.parallelBefore];
468 calcs[me.parallelBefore] = parallelOffset;
469 calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];
471 if (me.align == 'stretch') {
472 stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
473 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
474 calcs[perpendicularPrefix] = stretchSize;
476 else if (me.align == 'stretchmax') {
477 stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
478 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
479 calcs[perpendicularPrefix] = stretchSize;
481 else if (me.align == me.alignCenteringString) {
482 // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
483 // the size to yield the space available to center within.
484 // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
485 diff = mmax(availPerpendicularSize, maxSize) - innerCtBorderWidth - calcs[perpendicularPrefix];
487 calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
491 // Advance past the box size and the "after" margin
492 parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
498 calculatedWidth: calculatedWidth,
500 nonFlexSize: nonFlexSize,
501 desiredSize: desiredSize,
502 minimumSize: minimumSize,
503 shortfall: shortfall,
509 onRemove: function(comp){
510 this.callParent(arguments);
511 if (this.overflowHandler) {
512 this.overflowHandler.onRemove(comp);
519 initOverflowHandler: function() {
520 var handler = this.overflowHandler;
522 if (typeof handler == 'string') {
528 var handlerType = 'None';
529 if (handler && handler.type !== undefined) {
530 handlerType = handler.type;
533 var constructor = Ext.layout.container.boxOverflow[handlerType];
534 if (constructor[this.type]) {
535 constructor = constructor[this.type];
538 this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
543 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
546 onLayout: function() {
548 // Clear the innerCt size so it doesn't influence the child items.
549 if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
550 this.innerCt.setSize(null, null);
554 targetSize = me.getLayoutTargetSize(),
555 items = me.getVisibleItems(),
556 calcs = me.calculateChildBoxes(items, targetSize),
559 handler, method, results;
561 if (me.autoSize && calcs.meta.desiredSize) {
562 targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
565 //invoke the overflow handler, if one is configured
566 if (meta.shortfall > 0) {
567 handler = me.overflowHandler;
568 method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';
570 results = handler[method](calcs, targetSize);
573 if (results.targetSize) {
574 targetSize = results.targetSize;
577 if (results.recalculate) {
578 items = me.getVisibleItems();
579 calcs = me.calculateChildBoxes(items, targetSize);
584 me.overflowHandler.clearOverflow();
589 * @property layoutTargetLastSize
591 * Private cache of the last measured size of the layout target. This should never be used except by
592 * BoxLayout subclasses during their onLayout run.
594 me.layoutTargetLastSize = targetSize;
598 * @property childBoxCache
600 * Array of the last calculated height, width, top and left positions of each visible rendered component
601 * within the Box layout.
603 me.childBoxCache = calcs;
605 me.updateInnerCtSize(targetSize, calcs);
606 me.updateChildBoxes(boxes);
607 me.handleTargetOverflow(targetSize);
610 animCallback: Ext.emptyFn,
613 * Resizes and repositions each child component
614 * @param {Object[]} boxes The box measurements
616 updateChildBoxes: function(boxes) {
619 length = boxes.length,
621 dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
622 oldBox, newBox, changed, comp, boxAnim, animCallback;
624 for (; i < length; i++) {
626 comp = newBox.component;
628 // If a Component is being drag/dropped, skip positioning it.
629 // Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
630 if (dd && (dd.getDragEl() === comp.el.dom)) {
636 oldBox = me.getChildBox(comp);
638 // If we are animating, we build up an array of Anim config objects, one for each
639 // child Component which has any changed box properties. Those with unchanged
640 // properties are not animated.
642 // Animate may be a config object containing callback.
643 animCallback = me.animate.callback || me.animate;
645 layoutAnimation: true, // Component Target handler must use set*Calculated*Size
651 // Only set from and to properties when there's a change.
652 // Perform as few Component setter methods as possible.
653 // Temporarily set the property values that we are not animating
654 // so that doComponentLayout does not auto-size them.
655 if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
657 // boxAnim.from.width = oldBox.width;
658 boxAnim.to.width = newBox.width;
660 if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
662 // boxAnim.from.height = oldBox.height;
663 boxAnim.to.height = newBox.height;
665 if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
667 // boxAnim.from.left = oldBox.left;
668 boxAnim.to.left = newBox.left;
670 if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
672 // boxAnim.from.top = oldBox.top;
673 boxAnim.to.top = newBox.top;
676 animQueue.push(boxAnim);
679 if (newBox.dirtySize) {
680 if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
681 me.setItemSize(comp, newBox.width, newBox.height);
684 // Don't set positions to NaN
685 if (isNaN(newBox.left) || isNaN(newBox.top)) {
688 comp.setPosition(newBox.left, newBox.top);
692 // Kick off any queued animations
693 length = animQueue.length;
696 // A function which cleans up when a Component's animation is done.
697 // The last one to finish calls the callback.
698 var afterAnimate = function(anim) {
699 // When we've animated all changed boxes into position, clear our busy flag and call the callback.
702 me.animCallback(anim);
703 me.layoutBusy = false;
704 if (Ext.isFunction(animCallback)) {
710 var beforeAnimate = function() {
711 me.layoutBusy = true;
714 // Start each box animation off
715 for (i = 0, length = animQueue.length; i < length; i++) {
716 boxAnim = animQueue[i];
718 // Clean up the Component after. Clean up the *layout* after the last animation finishes
719 boxAnim.listeners.afteranimate = afterAnimate;
721 // The layout is busy during animation, and may not be called, so set the flag when the first animation begins
723 boxAnim.listeners.beforeanimate = beforeAnimate;
725 if (me.animate.duration) {
726 boxAnim.duration = me.animate.duration;
728 comp = boxAnim.target;
729 delete boxAnim.target;
730 // Stop any currently running animation
731 comp.stopAnimation();
732 comp.animate(boxAnim);
739 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
740 * to make sure all child items fit within it. We call this before sizing the children because if our child
741 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
742 * again immediately afterwards, giving a performance hit.
743 * Subclasses should provide an implementation.
744 * @param {Object} currentSize The current height and width of the innerCt
745 * @param {Object} calculations The new box calculations of all items to be laid out
747 updateInnerCtSize: function(tSize, calcs) {
751 padding = me.padding,
753 height = tSize.height,
758 if (me.direction == 'horizontal') {
759 innerCtWidth = width;
760 innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');
762 if (align == 'stretch') {
763 innerCtHeight = height;
765 else if (align == 'middle') {
766 innerCtHeight = mmax(height, innerCtHeight);
769 innerCtHeight = height;
770 innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');
772 if (align == 'stretch') {
773 innerCtWidth = width;
775 else if (align == 'center') {
776 innerCtWidth = mmax(width, innerCtWidth);
779 me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);
781 // If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
782 // then, if the Component has not assumed the size of its content, set it to do so.
783 if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
784 me.owner.el.setWidth(meta.calculatedWidth);
787 if (me.innerCt.dom.scrollTop) {
788 me.innerCt.dom.scrollTop = 0;
794 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
795 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
796 * target. Having a Box layout inside such a target is therefore not recommended.
797 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
798 * @param {Ext.container.Container} container The container
799 * @param {Ext.Element} target The target element
800 * @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
802 handleTargetOverflow: function(previousTargetSize) {
803 var target = this.getTarget(),
804 overflow = target.getStyle('overflow'),
807 if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
808 newTargetSize = this.getLayoutTargetSize();
809 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
810 this.adjustmentPass = true;
816 delete this.adjustmentPass;
820 isValidParent : function(item, target, position) {
821 // Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
822 // We only care whether the item is a direct child of the innerCt element.
823 var itemEl = item.el ? item.el.dom : Ext.getDom(item);
824 return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
827 // Overridden method from AbstractContainer.
828 // Used in the base AbstractLayout.beforeLayout method to render all items into.
829 getRenderTarget: function() {
831 // the innerCt prevents wrapping and shuffling while the container is resizing
832 this.innerCt = this.getTarget().createChild({
836 this.padding = Ext.util.Format.parseBox(this.padding);
842 renderItem: function(item, target) {
843 this.callParent(arguments);
845 itemEl = item.getEl(),
846 style = itemEl.dom.style,
847 margins = item.margins || item.margin;
849 // Parse the item's margin/margins specification
851 if (Ext.isString(margins) || Ext.isNumber(margins)) {
852 margins = Ext.util.Format.parseBox(margins);
854 Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
857 margins = Ext.apply({}, me.defaultMargins);
860 // Add any before/after CSS margins to the configured margins, and zero the CSS margins
861 margins.top += itemEl.getMargin('t');
862 margins.right += itemEl.getMargin('r');
863 margins.bottom += itemEl.getMargin('b');
864 margins.left += itemEl.getMargin('l');
865 margins.height = margins.top + margins.bottom;
866 margins.width = margins.left + margins.right;
867 style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
869 // Item must reference calculated margins.
870 item.margins = margins;
876 destroy: function() {
877 Ext.destroy(this.innerCt, this.overflowHandler);
878 this.callParent(arguments);