PDA

View Full Version : collapsibles in a vbox



lsaffre
12 Sep 2010, 7:04 AM
Hello,

below is a showcase that opens a window with 3 collapsible grids in a vbox. When one of these grids is collapsed, I'd like the other two grids to fill up the space that got free.
This is not a case for AccordionLayout since more than one Panel can be expanded.
I guess that with BorderLayout it would work out of the box, but I'd like this to work also with 2 or 4 grids.


<html><head>
<!-- -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id="title">2010-09-12</title>
<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<!-- overrides to base library -->
<!-- ** Javascript ** -->
<!-- ExtJS library: base/adapter -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<!-- ExtJS library: all widgets -->
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript">

// taken from http://examples.extjs.eu/
ExampleGrid = Ext.extend(Ext.grid.GridPanel, {
initComponent:function() {
// hard coded - cannot be changed from outside
var config = {
store: new Ext.data.SimpleStore({
id:0
,fields:[
{name: 'company'}
,{name: 'price', type: 'float'}
,{name: 'change', type: 'float'}
,{name: 'pctChange', type: 'float'}
,{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
,{name: 'industry'}
,{name: 'desc'}
]
,data:[
['3m Co',71.72,0.02,0.03,'8/1 12:00am', 'Manufacturing'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['Altria Group Inc',83.81,0.28,0.34,'10/1 12:00am', 'Manufacturing'],
['American Express Company',52.55,0.01,0.02,'9/1 10:00am', 'Finance'],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 11:00am', 'Services'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am', 'Manufacturing'],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am', 'Services'],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am', 'Finance'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am', 'Manufacturing'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am', 'Manufacturing'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am', 'Automotive'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am', 'Computer'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am', 'Manufacturing'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am', 'Computer'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am', 'Computer'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am', 'Medical'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am', 'Finance'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am', 'Food'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am', 'Medical'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am', 'Computer'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am', 'Services', 'Medical'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am', 'Food'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am', 'Retail'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am', 'Manufacturing'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am', 'Computer'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am', 'Services'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am', 'Retail'],
['Walt Disney Company (The) (Holding Company)',29.89,0.24,0.81,'9/1 12:00am', 'Services']
]
}
)
,columns:[
{id:'company',header: "Company", width: 80, sortable: true, dataIndex: 'company'}
,{header: "Price", width: 40, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'}
,{header: "Change", width: 40, sortable: true, dataIndex: 'change'}
,{header: "% Change", width: 40, sortable: true, dataIndex: 'pctChange'}
,{header: "Last Updated", width: 40, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]
,viewConfig:{forceFit:true}
}; // eo config object

// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));

// call parent
ExampleGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent

});

//~ Ext.reg('examplegrid', ExampleGrid);



Ext.onReady(function() {
var leftPanel = {
layout: 'form',
flex:1,
autoScroll:true,
items: [
{xtype: 'textfield', fieldLabel: 'A', value:'A'},
{xtype: 'textfield', fieldLabel: 'B', value:'B'},
{xtype: 'textfield', fieldLabel: 'C', value:'C'},
{xtype: 'textfield', fieldLabel: 'D', value:'D'},
{xtype: 'textfield', fieldLabel: 'E', value:'E'},
{xtype: 'textfield', fieldLabel: 'F', value:'F'},
{xtype: 'textfield', fieldLabel: 'G', value:'G'}
]
};

var grid1 = new ExampleGrid({title:"First Grid",collapsible:true});
var gridbox1 = {flex:1,autoScroll:true,items:grid1,xtype:'container',layout:'fit'}
var grid2 = new ExampleGrid({title:"Second Grid",collapsible:true});
var gridbox2 = {flex:1,autoScroll:true,items:grid2,xtype:'container',layout:'fit'}
var grid3 = new ExampleGrid({title:"Third Grid",collapsible:true});
var gridbox3 = {flex:1,autoScroll:true,items:grid3,xtype:'container',layout:'fit'}

var rightPanel = {
//~ layout: 'form',
layout: 'vbox', layoutConfig: {align:'stretch'},
flex:1,
autoScroll:true,
items: [ gridbox1, gridbox2, gridbox3 ]
};

var win = new Ext.Window({
width: 600, height:400,
layout:'fit',
maximizable: true,
items: {
layout: 'hbox', layoutConfig: {align:'stretch'},
items: [leftPanel,rightPanel]
}
});
win.show();
});
</script>
</head><body>
</body></html>
I tried things like
grid1.on('collapse',function(){ rightPanel.doLayout()});
or
grid1.on('collapse',function(){ rightPanel.onResize()});
but without success.

Thanks in advance for any hint!

Luc

Animal
12 Sep 2010, 8:14 AM
vbox in 3.* doesn't handle collapsed panels well. It's a known issue. I suspect the 4.0 code will clean this up.

Meanwhile, I took a look at it: http://www.sencha.com/forum/showthread.php?98165-vbox-layout-with-two-grids-grid-collapse-does-not-stretch-non-collapsed-grid&p=463266#post463266

lsaffre
16 Sep 2010, 11:44 AM
Thank you, Animal! Yes, my problem is a duplicate of nolo866's post.
I applied your patch to my showcase, but unfortunately didn't manage to make it work (using Ext 3.2.1).
Here is what I did:


<html><head>
<!-- -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id="title">2010-09-12</title>
<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<!-- overrides to base library -->
<!-- ** Javascript ** -->
<!-- ExtJS library: base/adapter -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<!-- ExtJS library: all widgets -->
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript">


Ext.override(Ext.layout.BoxLayout, {
getVisibleItems: function(ct) {
var ct = ct || this.container,
t = ct.getLayoutTarget(),
cti = ct.items.items,
len = cti.length,
i, c, items = [];

for (i = 0; i < len; i++) {
if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true){ // no collapsed check
items.push(c);
}
}

return items;
}
});

Ext.override(Ext.layout.VBoxLayout, {
calculateChildBoxes: function(visibleItems, targetSize) {
var visibleCount = visibleItems.length,

padding = this.padding,
topOffset = padding.top,
leftOffset = padding.left,
paddingVert = topOffset + padding.bottom,
paddingHoriz = leftOffset + padding.right,

width = targetSize.width - this.scrollOffset,
height = targetSize.height,
availWidth = Math.max(0, width - paddingHoriz),

isStart = this.pack == 'start',
isCenter = this.pack == 'center',
isEnd = this.pack == 'end',

nonFlexHeight= 0,
maxWidth = 0,
totalFlex = 0,

//used to cache the calculated size and position values for each child item
boxes = [],

//used in the for loops below, just declared here for brevity
child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedHeight, horizMargins, stretchWidth;

//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];
childHeight = child.collapsed ? child.getHeight() : child.height;
childWidth = child.width;
canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);


// Static height (numeric) requires no calcs
if (!Ext.isNumber(childHeight)) {

// flex and not 'auto' height
if (child.flex && !childHeight) {
totalFlex += child.flex;

// Not flexed or 'auto' height or undefined height
} else {
//Render and layout sub-containers without a flex or width defined, as otherwise we
//don't know how wide the sub-container should be and cannot calculate flexed widths
if (!childHeight && canLayout) {
child.doLayout();
}

childSize = child.getSize();
childWidth = childSize.width;
childHeight = childSize.height;
}
}

childMargins = child.margins;

nonFlexHeight += (childHeight || 0) + childMargins.top + childMargins.bottom;

// Max width for align - force layout of non-layed out subcontainers without a numeric width
if (!Ext.isNumber(childWidth)) {
if (canLayout) {
child.doLayout();
}
childWidth = child.getWidth();
}

maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);

//cache the size of each child component
boxes.push({
component: child,
height : childHeight || undefined,
width : childWidth || undefined
});
}

//the height available to the flexed items
var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));

if (isCenter) {
topOffset += availableHeight / 2;
} else if (isEnd) {
topOffset += availableHeight;
}

//temporary variables used in the flex height calculations below
var remainingHeight = availableHeight,
remainingFlex = totalFlex;

//calculate the height of each flexed item, and the left + top positions of every item
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
calcs = boxes[i];

childMargins = child.margins;
horizMargins = childMargins.left + childMargins.right;

topOffset += childMargins.top;

if (isStart && child.flex && !child.collapsed && !child.height) {
flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
remainingHeight -= flexedHeight;
remainingFlex -= child.flex;

calcs.height = flexedHeight;
calcs.dirtySize = true;
}

calcs.left = leftOffset + childMargins.left;
calcs.top = topOffset;

switch (this.align) {
case 'stretch':
stretchWidth = availWidth - horizMargins;
calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
calcs.dirtySize = true;
break;
case 'stretchmax':
stretchWidth = maxWidth - horizMargins;
calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
calcs.dirtySize = true;
break;
case 'center':
var diff = availWidth - calcs.width - horizMargins;
if (diff > 0) {
calcs.left = leftOffset + horizMargins + (diff / 2);
}
}

topOffset += calcs.height + childMargins.bottom;
}

return {
boxes: boxes,
meta : {
maxWidth: maxWidth
}
};
}
});









// taken from http://examples.extjs.eu/
ExampleGrid = Ext.extend(Ext.grid.GridPanel, {
initComponent:function() {
// hard coded - cannot be changed from outside
var config = {
store: new Ext.data.SimpleStore({
id:0
,fields:[
{name: 'company'}
,{name: 'price', type: 'float'}
,{name: 'change', type: 'float'}
,{name: 'pctChange', type: 'float'}
,{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
,{name: 'industry'}
,{name: 'desc'}
]
,data:[
['3m Co',71.72,0.02,0.03,'8/1 12:00am', 'Manufacturing'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['Altria Group Inc',83.81,0.28,0.34,'10/1 12:00am', 'Manufacturing'],
['American Express Company',52.55,0.01,0.02,'9/1 10:00am', 'Finance'],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 11:00am', 'Services'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am', 'Manufacturing'],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am', 'Services'],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am', 'Finance'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am', 'Manufacturing'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am', 'Manufacturing'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am', 'Automotive'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am', 'Computer'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am', 'Manufacturing'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am', 'Computer'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am', 'Computer'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am', 'Medical'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am', 'Finance'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am', 'Food'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am', 'Medical'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am', 'Computer'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am', 'Services', 'Medical'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am', 'Food'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am', 'Retail'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am', 'Manufacturing'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am', 'Computer'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am', 'Services'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am', 'Retail'],
['Walt Disney Company (The) (Holding Company)',29.89,0.24,0.81,'9/1 12:00am', 'Services']
]
}
)
,columns:[
{id:'company',header: "Company", width: 80, sortable: true, dataIndex: 'company'}
,{header: "Price", width: 40, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'}
,{header: "Change", width: 40, sortable: true, dataIndex: 'change'}
,{header: "% Change", width: 40, sortable: true, dataIndex: 'pctChange'}
,{header: "Last Updated", width: 40, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]
,viewConfig:{forceFit:true}
,collapsible: true
,allowQueuedExpand: false
}; // eo config object

// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));

// call parent
ExampleGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent

});

//~ Ext.reg('examplegrid', ExampleGrid);



Ext.onReady(function() {
var leftPanel = {
layout: 'form',
flex:1,
autoScroll:true,
items: [
{xtype: 'textfield', fieldLabel: 'A', value:'A'},
{xtype: 'textfield', fieldLabel: 'B', value:'B'},
{xtype: 'textfield', fieldLabel: 'C', value:'C'},
{xtype: 'textfield', fieldLabel: 'D', value:'D'},
{xtype: 'textfield', fieldLabel: 'E', value:'E'},
{xtype: 'textfield', fieldLabel: 'F', value:'F'},
{xtype: 'textfield', fieldLabel: 'G', value:'G'}
]
};


var grid1 = new ExampleGrid({title:"First Grid",listeners: { 'expand': onExpandCollapse, 'collapse': onExpandCollapse }});
var gridbox1 = {flex:1,autoScroll:true,items:grid1,xtype:'container',layout:'fit'}
var grid2 = new ExampleGrid({title:"Second Grid",listeners: { 'expand': onExpandCollapse, 'collapse': onExpandCollapse }});
var gridbox2 = {flex:1,autoScroll:true,items:grid2,xtype:'container',layout:'fit'}
var grid3 = new ExampleGrid({title:"Third Grid",listeners: { 'expand': onExpandCollapse, 'collapse': onExpandCollapse }});
var gridbox3 = {flex:1,autoScroll:true,items:grid3,xtype:'container',layout:'fit'}

var rightPanel = new Ext.Panel({
//~ layout: 'form',

layout: { type: 'vbox', align: 'stretch'},
//~ layout: 'vbox', layoutConfig: {align:'stretch'},
flex:1,
autoScroll:true,
items: [ gridbox1, gridbox2, gridbox3 ]
});

function onExpandCollapse(c) {
// Horrible Ext 2.* collapse handling has to be defeated...
if (c.queuedBodySize) {
delete c.queuedBodySize.width;
delete c.queuedBodySize.height;
}
rightPanel.doLayout();
}


var win = new Ext.Window({
width: 600, height:400,
layout:'fit',
maximizable: true,
items: {
layout: 'hbox', layoutConfig: {align:'stretch'},
items: [leftPanel,rightPanel]
}
});
win.show();
});
</script>
</head><body>
</body></html>


What am I missing? Any hint welcome!

Luc