Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / layout / container / Box.js
index 319052e..e532c99 100644 (file)
@@ -1,3 +1,17 @@
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+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.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @class Ext.layout.container.Box
  * @extends Ext.layout.container.Container
@@ -11,7 +25,7 @@ Ext.define('Ext.layout.container.Box', {
     alias: ['layout.box'],
     extend: 'Ext.layout.container.Container',
     alternateClassName: 'Ext.layout.BoxLayout',
-    
+
     requires: [
         'Ext.layout.container.boxOverflow.None',
         'Ext.layout.container.boxOverflow.Menu',
@@ -23,7 +37,7 @@ Ext.define('Ext.layout.container.Box', {
     /* End Definitions */
 
     /**
-     * @cfg {Mixed} animate
+     * @cfg {Boolean/Number/Object} animate
      * <p>If truthy, child Component are <i>animated</i> into position whenever the Container
      * is layed out. If this option is numeric, it is used as the animation duration in milliseconds.</p>
      * <p>May be set as a property at any time.</p>
@@ -54,9 +68,6 @@ Ext.define('Ext.layout.container.Box', {
      * <li>If there are four values, they apply to the top, right, bottom, and
      * left, respectively.</li>
      * </ul></div>
-     * <p>Defaults to:</p><pre><code>
-     * {top:0, right:0, bottom:0, left:0}
-     * </code></pre>
      */
     defaultMargins: {
         top: 0,
@@ -80,7 +91,6 @@ Ext.define('Ext.layout.container.Box', {
      * <li>If there are four values, they apply to the top, right, bottom, and
      * left, respectively.</li>
      * </ul></div>
-     * <p>Defaults to: <code>"0"</code></p>
      */
     padding: '0',
     // documented in subclasses
@@ -116,15 +126,21 @@ Ext.define('Ext.layout.container.Box', {
 
     bindToOwnerCtContainer: true,
 
-    fixedLayout: false,
-    
     // availableSpaceOffset is used to adjust the availableWidth, typically used
     // to reserve space for a scrollbar
     availableSpaceOffset: 0,
-    
+
     // whether or not to reserve the availableSpaceOffset in layout calculations
     reserveOffset: true,
-    
+
+    /**
+     * @cfg {Boolean} shrinkToFit
+     * True (the default) to allow fixed size components to shrink (limited to their
+     * minimum size) to avoid overflow. False to preserve fixed sizes even if they cause
+     * overflow.
+     */
+    shrinkToFit: true,
+
     /**
      * @cfg {Boolean} clearInnerCtOnLayout
      */
@@ -161,23 +177,24 @@ Ext.define('Ext.layout.container.Box', {
     /**
      * @private
      * Returns the current size and positioning of the passed child item.
-     * @param {Component} child The child Component to calculate the box for
+     * @param {Ext.Component} child The child Component to calculate the box for
      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
      */
     getChildBox: function(child) {
         child = child.el || this.owner.getComponent(child).el;
+        var size = child.getBox(false, true);
         return {
-            left: child.getLeft(true),
-            top: child.getTop(true),
-            width: child.getWidth(),
-            height: child.getHeight()
+            left: size.left,
+            top: size.top,
+            width: size.width,
+            height: size.height
         };
     },
 
     /**
      * @private
      * Calculates the size and positioning of the passed child item.
-     * @param {Component} child The child Component to calculate the box for
+     * @param {Ext.Component} child The child Component to calculate the box for
      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
      */
     calculateChildBox: function(child) {
@@ -227,6 +244,8 @@ Ext.define('Ext.layout.container.Box', {
             paddingPerpendicular =  perpendicularOffset + padding[me.perpendicularRightBottom],
             availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
 
+            innerCtBorderWidth = me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB),
+
             isStart = me.pack == 'start',
             isCenter = me.pack == 'center',
             isEnd = me.pack == 'end',
@@ -242,16 +261,21 @@ Ext.define('Ext.layout.container.Box', {
             minSizes = [],
             calculatedWidth,
 
-            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall, 
-            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff, 
-            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset, 
+            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
+            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
+            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
             perpendicularMargins, stretchSize;
 
         //gather the total flex of all flexed items and the width taken up by fixed width items
         for (i = 0; i < visibleCount; i++) {
             child = visibleItems[i];
             childPerpendicular = child[perpendicularPrefix];
-            me.layoutItem(child);
+            if (!child.flex || !(me.align == 'stretch' || me.align == 'stretchmax')) {
+                if (child.componentLayout.initialized !== true) {
+                    me.layoutItem(child);
+                }
+            }
+
             childMargins = child.margins;
             parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
 
@@ -287,14 +311,20 @@ Ext.define('Ext.layout.container.Box', {
             }
 
             // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
-            maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
+            // Ensure that the tracked maximum perpendicular size takes into account child min[Width|Height] settings!
+            maxSize = mmax(maxSize, mmax(childPerpendicular, child[perpendicularMinString]||0) + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
 
             tmpObj[parallelPrefix] = childParallel || undefinedValue;
+            tmpObj.dirtySize = child.componentLayout.lastComponentSize ? (tmpObj[parallelPrefix] !== child.componentLayout.lastComponentSize[parallelPrefix]) : false;
             tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
             boxes.push(tmpObj);
         }
-        shortfall = desiredSize - parallelSize;
-        tooNarrow = minimumSize > parallelSize;
+
+        // Only calculate parallel overflow indicators if we are not auto sizing
+        if (!me.autoSize) {
+            shortfall = desiredSize - parallelSize;
+            tooNarrow = minimumSize > parallelSize;
+        }
 
         //the space available to the flexed items
         availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
@@ -326,8 +356,7 @@ Ext.define('Ext.layout.container.Box', {
                         box = boxes[i];
                         box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                         box[parallelPrefix] = minSize;
-                    }
-                    else {
+                    } else if (me.shrinkToFit) {
                         minSizes.push({
                             minSize: minSize,
                             available: boxes[i][parallelPrefix] - minSize,
@@ -363,6 +392,7 @@ Ext.define('Ext.layout.container.Box', {
                     box[parallelPrefix] = newSize;
                     shortfall -= reduction;
                 }
+                tooNarrow = (shortfall > 0);
             }
             else {
                 remainingSpace = availableSpace;
@@ -452,7 +482,7 @@ Ext.define('Ext.layout.container.Box', {
                 // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
                 // the size to yield the space available to center within.
                 // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
-                diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
+                diff = mmax(availPerpendicularSize, maxSize) - innerCtBorderWidth - calcs[perpendicularPrefix];
                 if (diff > 0) {
                     calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
                 }
@@ -476,6 +506,13 @@ Ext.define('Ext.layout.container.Box', {
         };
     },
 
+    onRemove: function(comp){
+        this.callParent(arguments);
+        if (this.overflowHandler) {
+            this.overflowHandler.onRemove(comp);
+        }
+    },
+
     /**
      * @private
      */
@@ -489,7 +526,7 @@ Ext.define('Ext.layout.container.Box', {
         }
 
         var handlerType = 'None';
-        if (handler && handler.type != undefined) {
+        if (handler && handler.type !== undefined) {
             handlerType = handler.type;
         }
 
@@ -538,7 +575,7 @@ Ext.define('Ext.layout.container.Box', {
                 }
 
                 if (results.recalculate) {
-                    items = me.getVisibleItems(owner);
+                    items = me.getVisibleItems();
                     calcs = me.calculateChildBoxes(items, targetSize);
                     boxes = calcs.boxes;
                 }
@@ -569,10 +606,12 @@ Ext.define('Ext.layout.container.Box', {
         me.updateChildBoxes(boxes);
         me.handleTargetOverflow(targetSize);
     },
+    
+    animCallback: Ext.emptyFn,
 
     /**
      * Resizes and repositions each child component
-     * @param {Array} boxes The box measurements
+     * @param {Object[]} boxes The box measurements
      */
     updateChildBoxes: function(boxes) {
         var me = this,
@@ -660,6 +699,7 @@ Ext.define('Ext.layout.container.Box', {
                 // When we've animated all changed boxes into position, clear our busy flag and call the callback.
                 length -= 1;
                 if (!length) {
+                    me.animCallback(anim);
                     me.layoutBusy = false;
                     if (Ext.isFunction(animCallback)) {
                         animCallback();
@@ -702,7 +742,7 @@ Ext.define('Ext.layout.container.Box', {
      * again immediately afterwards, giving a performance hit.
      * Subclasses should provide an implementation.
      * @param {Object} currentSize The current height and width of the innerCt
-     * @param {Array} calculations The new box calculations of all items to be laid out
+     * @param {Object} calculations The new box calculations of all items to be laid out
      */
     updateInnerCtSize: function(tSize, calcs) {
         var me = this,
@@ -756,7 +796,7 @@ Ext.define('Ext.layout.container.Box', {
      * target. Having a Box layout inside such a target is therefore not recommended.
      * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
      * @param {Ext.container.Container} container The container
-     * @param {Ext.core.Element} target The target element
+     * @param {Ext.Element} target The target element
      * @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
      */
     handleTargetOverflow: function(previousTargetSize) {
@@ -822,6 +862,8 @@ Ext.define('Ext.layout.container.Box', {
         margins.right  += itemEl.getMargin('r');
         margins.bottom += itemEl.getMargin('b');
         margins.left   += itemEl.getMargin('l');
+        margins.height  = margins.top  + margins.bottom;
+        margins.width   = margins.left + margins.right;
         style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
 
         // Item must reference calculated margins.
@@ -832,7 +874,7 @@ Ext.define('Ext.layout.container.Box', {
      * @private
      */
     destroy: function() {
-        Ext.destroy(this.overflowHandler);
+        Ext.destroy(this.innerCt, this.overflowHandler);
         this.callParent(arguments);
     }
-});
\ No newline at end of file
+});