Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / grid / ColumnLayout.js
1 /**
2  * @class Ext.grid.ColumnLayout
3  * @extends Ext.layout.container.HBox
4  * @private
5  *
6  * <p>This class is used only by the grid's HeaderContainer docked child.</p>
7  *
8  * <p>This class adds the ability to shrink the vertical size of the inner container element back if a grouped
9  * column header has all its child columns dragged out, and the whole HeaderContainer needs to shrink back down.</p>
10  *
11  * <p>It also enforces the grid's HeaderContainer's forceFit config by, after every calaculateChildBoxes call, converting
12  * all pixel widths into flex values, so that propertions are maintained upon width change of the grid.</p>
13  *
14  * <p>Also, after every layout, after all headers have attained their 'stretchmax' height, it goes through and calls
15  * <code>setPadding</code> on the columns so that they lay out correctly. TODO: implement a ColumnHeader component
16  * layout which takes responsibility for this, and will run upon resize.</p>
17  */
18 Ext.define('Ext.grid.ColumnLayout', {
19     extend: 'Ext.layout.container.HBox',
20     alias: 'layout.gridcolumn',
21     type : 'column',
22
23     // Height-stretched innerCt must be able to revert back to unstretched height
24     clearInnerCtOnLayout: false,
25
26     constructor: function() {
27         var me = this;
28         me.callParent(arguments);
29         if (!Ext.isDefined(me.availableSpaceOffset)) {
30             me.availableSpaceOffset = (Ext.getScrollBarWidth() - 2);
31         }
32     },
33
34     beforeLayout: function() {
35         var me = this,
36             i = 0,
37             items = me.getLayoutItems(),
38             len = items.length,
39             item, returnValue;
40
41         returnValue = me.callParent(arguments);
42
43         // Size to a sane minimum height before possibly being stretched to accommodate grouped headers
44         me.innerCt.setHeight(23);
45
46         // Unstretch child items before the layout which stretches them.
47         if (me.align == 'stretchmax') {
48             for (; i < len; i++) {
49                 item = items[i];
50                 item.el.setStyle({
51                     height: 'auto'
52                 });
53                 item.titleContainer.setStyle({
54                     height: 'auto',
55                     paddingTop: '0'
56                 });
57                 if (item.componentLayout && item.componentLayout.lastComponentSize) {
58                     item.componentLayout.lastComponentSize.height = item.el.dom.offsetHeight;
59                 }
60             }
61         }
62         return returnValue;
63     },
64
65     // Override to enforce the forceFit config.
66     calculateChildBoxes: function(visibleItems, targetSize) {
67         var me = this,
68             calculations = me.callParent(arguments),
69             boxes = calculations.boxes,
70             metaData = calculations.meta,
71             len = boxes.length, i = 0, box, item;
72
73         if (targetSize.width && !me.isColumn) {
74             // If configured forceFit then all columns will be flexed
75             if (me.owner.forceFit) {
76
77                 for (; i < len; i++) {
78                     box = boxes[i];
79                     item = box.component;
80
81                     // Set a sane minWidth for the Box layout to be able to squeeze flexed Headers down to.
82                     item.minWidth = Ext.grid.plugin.HeaderResizer.prototype.minColWidth;
83
84                     // For forceFit, just use allocated width as the flex value, and the proportions
85                     // will end up the same whatever HeaderContainer width they are being forced into.
86                     item.flex = box.width;
87                 }
88
89                 // Recalculate based upon all columns now being flexed instead of sized.
90                 calculations = me.callParent(arguments);
91             }
92             else if (metaData.tooNarrow) {
93                 targetSize.width = metaData.desiredSize;
94             }
95         }
96
97         return calculations;
98     },
99
100     afterLayout: function() {
101         var me = this,
102             i = 0,
103             items = me.getLayoutItems(),
104             len = items.length;
105
106         me.callParent(arguments);
107
108         // Set up padding in items
109         if (me.align == 'stretchmax') {
110             for (; i < len; i++) {
111                 items[i].setPadding();
112             }
113         }
114     },
115
116     // FIX: when flexing we actually don't have enough space as we would
117     // typically because of the scrollOffset on the GridView, must reserve this
118     updateInnerCtSize: function(tSize, calcs) {
119         var me    = this,
120             extra = 0;
121
122         // Columns must not account for scroll offset
123         if (!me.isColumn && calcs.meta.tooNarrow) {
124             if (
125                 Ext.isWebKit ||
126                 Ext.isGecko ||
127                 (Ext.isIEQuirks && (Ext.isIE6 || Ext.isIE7 || Ext.isIE8))
128             ) {
129                 extra = 1;
130             // IE6-8 not quirks
131             } else if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
132                 extra = 2;
133             }
134             
135             // this is the 1px accounted for in the Scroller when subtracting 1px.
136             extra++;
137             tSize.width = calcs.meta.desiredSize + (me.reserveOffset ? me.availableSpaceOffset : 0) + extra;
138         }
139         return me.callParent(arguments);
140     },
141
142     doOwnerCtLayouts: function() {
143         var ownerCt = this.owner.ownerCt;
144         if (!ownerCt.componentLayout.layoutBusy) {
145             ownerCt.doComponentLayout();
146         }
147     }
148 });