Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / src / resizer / SplitterTracker.js
1 /**
2  * @class Ext.resizer.SplitterTracker
3  * @extends Ext.dd.DragTracker
4  * Private utility class for Ext.Splitter.
5  * @private
6  */
7 Ext.define('Ext.resizer.SplitterTracker', {
8     extend: 'Ext.dd.DragTracker',
9     requires: ['Ext.util.Region'],
10     enabled: true,
11     
12     overlayCls: Ext.baseCSSPrefix + 'resizable-overlay',
13
14     getPrevCmp: function() {
15         var splitter = this.getSplitter();
16         return splitter.previousSibling();
17     },
18
19     getNextCmp: function() {
20         var splitter = this.getSplitter();
21         return splitter.nextSibling();
22     },
23
24     // ensure the tracker is enabled, store boxes of previous and next
25     // components and calculate the constrain region
26     onBeforeStart: function(e) {
27         var me = this,
28             prevCmp = me.getPrevCmp(),
29             nextCmp = me.getNextCmp();
30
31         // SplitterTracker is disabled if any of its adjacents are collapsed.
32         if (nextCmp.collapsed || prevCmp.collapsed) {
33             return false;
34         }
35         // store boxes of previous and next
36         me.prevBox  = prevCmp.getEl().getBox();
37         me.nextBox  = nextCmp.getEl().getBox();
38         me.constrainTo = me.calculateConstrainRegion();
39     },
40
41     // We move the splitter el. Add the proxy class.
42     onStart: function(e) {
43         var splitter = this.getSplitter(),
44             overlay;
45             
46         splitter.addCls(splitter.baseCls + '-active');
47         overlay = this.overlay =  Ext.getBody().createChild({
48             cls: this.overlayCls, 
49             html: ' '
50         });
51         overlay.unselectable();
52         overlay.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true));
53         overlay.show();
54     },
55
56     // calculate the constrain Region in which the splitter el may be moved.
57     calculateConstrainRegion: function() {
58         var me         = this,
59             splitter   = me.getSplitter(),
60             splitWidth = splitter.getWidth(),
61             defaultMin = splitter.defaultSplitMin,
62             orient     = splitter.orientation,
63             prevBox    = me.prevBox,
64             prevCmp    = me.getPrevCmp(),
65             nextBox    = me.nextBox,
66             nextCmp    = me.getNextCmp(),
67             // prev and nextConstrainRegions are the maximumBoxes minus the
68             // minimumBoxes. The result is always the intersection
69             // of these two boxes.
70             prevConstrainRegion, nextConstrainRegion;
71
72         // vertical splitters, so resizing left to right
73         if (orient === 'vertical') {
74
75             // Region constructor accepts (top, right, bottom, left)
76             // anchored/calculated from the left
77             prevConstrainRegion = Ext.create('Ext.util.Region',
78                 prevBox.y,
79                 // Right boundary is x + maxWidth if there IS a maxWidth.
80                 // Otherwise it is calculated based upon the minWidth of the next Component
81                 (prevCmp.maxWidth ? prevBox.x + prevCmp.maxWidth : nextBox.right - (nextCmp.minWidth || defaultMin)) + splitWidth,
82                 prevBox.bottom,
83                 prevBox.x + (prevCmp.minWidth || defaultMin)
84             );
85             // anchored/calculated from the right
86             nextConstrainRegion = Ext.create('Ext.util.Region',
87                 nextBox.y,
88                 nextBox.right - (nextCmp.minWidth || defaultMin),
89                 nextBox.bottom,
90                 // Left boundary is right - maxWidth if there IS a maxWidth.
91                 // Otherwise it is calculated based upon the minWidth of the previous Component
92                 (nextCmp.maxWidth ? nextBox.right - nextCmp.maxWidth : prevBox.x + (prevBox.minWidth || defaultMin)) - splitWidth
93             );
94         } else {
95             // anchored/calculated from the top
96             prevConstrainRegion = Ext.create('Ext.util.Region',
97                 prevBox.y + (prevCmp.minHeight || defaultMin),
98                 prevBox.right,
99                 // Bottom boundary is y + maxHeight if there IS a maxHeight.
100                 // Otherwise it is calculated based upon the minWidth of the next Component
101                 (prevCmp.maxHeight ? prevBox.y + prevCmp.maxHeight : nextBox.bottom - (nextCmp.minHeight || defaultMin)) + splitWidth,
102                 prevBox.x
103             );
104             // anchored/calculated from the bottom
105             nextConstrainRegion = Ext.create('Ext.util.Region',
106                 // Top boundary is bottom - maxHeight if there IS a maxHeight.
107                 // Otherwise it is calculated based upon the minHeight of the previous Component
108                 (nextCmp.maxHeight ? nextBox.bottom - nextCmp.maxHeight : prevBox.y + (prevCmp.minHeight || defaultMin)) - splitWidth,
109                 nextBox.right,
110                 nextBox.bottom - (nextCmp.minHeight || defaultMin),
111                 nextBox.x
112             );
113         }
114
115         // intersection of the two regions to provide region draggable
116         return prevConstrainRegion.intersect(nextConstrainRegion);
117     },
118
119     // Performs the actual resizing of the previous and next components
120     performResize: function(e) {
121         var me       = this,
122             offset   = me.getOffset('dragTarget'),
123             splitter = me.getSplitter(),
124             orient   = splitter.orientation,
125             prevCmp  = me.getPrevCmp(),
126             nextCmp  = me.getNextCmp(),
127             owner    = splitter.ownerCt,
128             layout   = owner.getLayout();
129
130         // Inhibit automatic container layout caused by setSize calls below.
131         owner.suspendLayout = true;
132
133         if (orient === 'vertical') {
134             if (prevCmp) {
135                 if (!prevCmp.maintainFlex) {
136                     delete prevCmp.flex;
137                     prevCmp.setSize(me.prevBox.width + offset[0], prevCmp.getHeight());
138                 }
139             }
140             if (nextCmp) {
141                 if (!nextCmp.maintainFlex) {
142                     delete nextCmp.flex;
143                     nextCmp.setSize(me.nextBox.width - offset[0], nextCmp.getHeight());
144                 }
145             }
146         // verticals
147         } else {
148             if (prevCmp) {
149                 if (!prevCmp.maintainFlex) {
150                     delete prevCmp.flex;
151                     prevCmp.setSize(prevCmp.getWidth(), me.prevBox.height + offset[1]);
152                 }
153             }
154             if (nextCmp) {
155                 if (!nextCmp.maintainFlex) {
156                     delete nextCmp.flex;
157                     nextCmp.setSize(prevCmp.getWidth(), me.nextBox.height - offset[1]);
158                 }
159             }
160         }
161         delete owner.suspendLayout;
162         layout.onLayout();
163     },
164
165     // perform the resize and remove the proxy class from the splitter el
166     onEnd: function(e) {
167         var me = this,
168             splitter = me.getSplitter();
169             
170         splitter.removeCls(splitter.baseCls + '-active');
171          if (me.overlay) {
172              me.overlay.remove();
173              delete me.overlay;
174         }
175         me.performResize();
176     },
177
178     // Track the proxy and set the proper XY coordinates
179     // while constraining the drag
180     onDrag: function(e) {
181         var me        = this,
182             offset    = me.getOffset('dragTarget'),
183             splitter  = me.getSplitter(),
184             splitEl   = splitter.getEl(),
185             orient    = splitter.orientation;
186
187         if (orient === "vertical") {
188             splitEl.setX(me.startRegion.left + offset[0]);
189         } else {
190             splitEl.setY(me.startRegion.top + offset[1]);
191         }
192     },
193
194     getSplitter: function() {
195         return Ext.getCmp(this.getDragCt().id);
196     }
197 });