r20517: re-add cleaned-up webapps
[kai/samba.git] / webapps / qooxdoo-0.6.3-sdk / frontend / framework / source / class / qx / renderer / layout / FlowLayoutImpl.js
1 /* ************************************************************************
2
3    qooxdoo - the new era of web development
4
5    http://qooxdoo.org
6
7    Copyright:
8      2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org
9
10    License:
11      LGPL 2.1: http://www.gnu.org/licenses/lgpl.html
12
13    Authors:
14      * Sebastian Werner (wpbasti)
15      * Andreas Ecker (ecker)
16
17 ************************************************************************ */
18
19 /* ************************************************************************
20
21 #module(ui_layout)
22
23 ************************************************************************ */
24
25 qx.OO.defineClass("qx.renderer.layout.FlowLayoutImpl", qx.renderer.layout.LayoutImpl,
26 function(vWidget) {
27   qx.renderer.layout.LayoutImpl.call(this, vWidget);
28 });
29
30 qx.renderer.layout.FlowLayoutImpl.STR_FIRST = "getFirstVisibleChild";
31 qx.renderer.layout.FlowLayoutImpl.STR_LAST = "getLastVisibleChild";
32 qx.renderer.layout.FlowLayoutImpl.STR_NEXT = "getNextSibling";
33 qx.renderer.layout.FlowLayoutImpl.STR_PREVIOUS = "getPreviousSibling";
34
35
36 /*!
37   Global Structure:
38
39   [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD
40   [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN
41   [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS
42   [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT
43   [06] UPDATE LAYOUT ON JOB QUEUE FLUSH
44   [07] UPDATE CHILDREN ON JOB QUEUE FLUSH
45   [08] CHILDREN ADD/REMOVE/MOVE HANDLING
46   [09] FLUSH LAYOUT QUEUES OF CHILDREN
47   [10] LAYOUT CHILD
48   [11] DISPOSER
49
50   Inherits from qx.renderer.layout.LayoutImpl:
51
52   [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD
53   [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD
54   [06] UPDATE LAYOUT ON JOB QUEUE FLUSH
55   [11] DISPOSER
56 */
57
58
59
60
61
62
63 /*
64 ---------------------------------------------------------------------------
65   [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN
66 ---------------------------------------------------------------------------
67 */
68
69 /*!
70   Compute and return the width needed by all children of this widget
71 */
72 qx.Proto.computeChildrenNeededWidth = function()
73 {
74   var w = this.getWidget();
75   return qx.renderer.layout.LayoutImpl.prototype.computeChildrenNeededWidth_sum.call(this) + ((w.getVisibleChildrenLength()-1) * w.getHorizontalSpacing());
76 }
77
78 /*!
79   Calculate the layout to get the needed height of the children
80 */
81 qx.Proto.computeChildrenNeededHeight = function()
82 {
83   var vWidget = this.getWidget();
84
85   var vInnerWidth = vWidget.getInnerWidth();
86
87   var vHorizontalSpacing = vWidget.getHorizontalSpacing();
88   var vVerticalSpacing = vWidget.getVerticalSpacing();
89   var vReversed = vWidget.getReverseChildrenOrder();
90
91   var vRowWidth = 0;
92   var vRowHeight = 0;
93
94   var vRowHeightSum = 0;
95
96   for (var i=0, ch=vWidget.getVisibleChildren(), chl=ch.length, chc; i<chl; i++)
97   {
98     chc = vReversed ? ch[chl-1-i] : ch[i];
99
100     vRowWidth += chc.getNeededWidth();
101
102     if (vRowWidth > vInnerWidth)
103     {
104       vRowHeightSum += vRowHeight + vVerticalSpacing;
105       vRowWidth = chc.getNeededWidth();
106       vRowHeight = chc.getNeededHeight();
107     }
108     else
109     {
110       vRowHeight = Math.max(vRowHeight, chc.getNeededHeight());
111     }
112
113     vRowWidth += vHorizontalSpacing;
114   }
115
116   return vRowHeightSum + vRowHeight;
117 }
118
119
120
121
122
123
124
125 /*
126 ---------------------------------------------------------------------------
127   [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS
128 ---------------------------------------------------------------------------
129 */
130
131 /*!
132   Things to do and layout when any of the childs changes it's outer width.
133   Needed by layouts where the children depends on each-other, like flow- or box-layouts.
134 */
135 qx.Proto.updateSelfOnChildOuterWidthChange = function(vChild)
136 {
137   // If a child only change it's width also recompute the height
138   // as the layout flows around here
139   //this.getWidget()._recomputeNeededHeightHelper();
140   this.getWidget()._invalidatePreferredInnerHeight();
141 }
142
143
144
145
146
147
148 /*
149 ---------------------------------------------------------------------------
150   [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT
151 ---------------------------------------------------------------------------
152 */
153
154 /*!
155   Actions that should be done if the inner width of the widget was changed.
156   Normally this includes update to percent values and ranges.
157 */
158 qx.Proto.updateChildOnInnerWidthChange = function(vChild)
159 {
160   vChild._recomputePercentX();
161   vChild.addToLayoutChanges("location");
162
163   return true;
164 }
165
166 /*!
167   Actions that should be done if the inner height of the widget was changed.
168   Normally this includes update to percent values and ranges.
169 */
170 qx.Proto.updateChildOnInnerHeightChange = function(vChild)
171 {
172   vChild._recomputePercentY();
173   vChild.addToLayoutChanges("location");
174
175   return true;
176 }
177
178
179
180
181
182
183
184 /*
185 ---------------------------------------------------------------------------
186   [07] UPDATE CHILDREN ON JOB QUEUE FLUSH
187 ---------------------------------------------------------------------------
188 */
189
190 /*!
191   Updates children on special jobs
192 */
193 qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue)
194 {
195   if (vQueue.horizontalSpacing || vQueue.verticalSpacing || vQueue.reverseChildrenOrder || vQueue.horizontalChildrenAlign || vQueue.verticalChildrenAlign) {
196     this.getWidget()._addChildrenToLayoutQueue("location");
197   }
198 }
199
200
201
202
203
204
205 /*
206 ---------------------------------------------------------------------------
207   [08] CHILDREN ADD/REMOVE/MOVE HANDLING
208 ---------------------------------------------------------------------------
209 */
210
211 /*!
212   This method combines calls of methods which should be done if a widget should be removed from the current layout.
213   Needed by layouts where the children depends on each-other, like flow- or box-layouts.
214 */
215 qx.Proto.updateChildrenOnRemoveChild = function(vChild, vIndex)
216 {
217   var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i=-1;
218
219   if (w.getReverseChildrenOrder())
220   {
221     while((chc=ch[++i]) && i<vIndex) {
222       chc.addToLayoutChanges("location");
223     }
224   }
225   else
226   {
227     i+=vIndex;
228     while(chc=ch[++i]) {
229       chc.addToLayoutChanges("location");
230     }
231   }
232 }
233
234 /*!
235   This method combines calls of methods which should be done if a child should be moved
236   inside the same parent to a new positions.
237   Needed by layouts where the children depends on each-other, like flow- or box-layouts.
238 */
239 qx.Proto.updateChildrenOnMoveChild = function(vChild, vIndex, vOldIndex)
240 {
241   for (var i=Math.min(vIndex, vOldIndex), ch=this.getWidget().getVisibleChildren(), l=ch.length; i<l; i++) {
242     ch[i].addToLayoutChanges("location");
243   }
244 }
245
246
247
248
249
250
251 /*
252 ---------------------------------------------------------------------------
253   [09] FLUSH LAYOUT QUEUES OF CHILDREN
254 ---------------------------------------------------------------------------
255 */
256
257 /*!
258   This method have full control of the order in which the
259   registered (or also non-registered) children should be
260   layouted on the horizontal axis.
261 */
262
263 qx.Proto.flushChildrenQueue = function(vChildrenQueue)
264 {
265   var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, chh;
266
267   if (w.getReverseChildrenOrder())
268   {
269     // layout all childs from the first child
270     // with an own layout request to the end
271     var i=chl, changed=false;
272     while(chc=ch[--i])
273     {
274       chh = chc.toHashCode();
275
276       if (changed || vChildrenQueue[chh])
277       {
278         w._layoutChild(chc);
279         changed = true;
280       }
281     }
282   }
283   else
284   {
285     // layout all childs from the first child
286     // with an own layout request to the end
287     var i=-1, changed=false;
288     while(chc=ch[++i])
289     {
290       chh = chc.toHashCode();
291
292       if (changed || vChildrenQueue[chh])
293       {
294         w._layoutChild(chc);
295         changed = true;
296       }
297     }
298   }
299 }
300
301
302
303
304
305
306 /*
307 ---------------------------------------------------------------------------
308   [10] LAYOUT CHILD
309 ---------------------------------------------------------------------------
310 */
311
312 qx.Proto.layoutChild = function(vChild, vJobs)
313 {
314   this.layoutChild_sizeX_essentialWrapper(vChild, vJobs);
315   this.layoutChild_sizeY_essentialWrapper(vChild, vJobs);
316
317   this.layoutChild_sizeLimitX(vChild, vJobs);
318   this.layoutChild_sizeLimitY(vChild, vJobs);
319
320   this.layoutChild_marginX(vChild, vJobs);
321   this.layoutChild_marginY(vChild, vJobs);
322
323   this.layoutChild_location(vChild, vJobs);
324 }
325
326 if (qx.sys.Client.getInstance().isMshtml() || qx.sys.Client.getInstance().isOpera())
327 {
328   /*!
329     We need to respect all dimension properties on the horizontal axis in
330     internet explorer to set the 'width' style
331   */
332   qx.Proto.layoutChild_sizeX = function(vChild, vJobs)
333   {
334     if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth) {
335       vChild._computedWidthTypeNull && vChild._computedMinWidthTypeNull && vChild._computedMaxWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getBoxWidth());
336     }
337   }
338
339   /*!
340     We need to respect all dimension properties on the vertical axis in
341     internet explorer to set the 'height' style
342   */
343   qx.Proto.layoutChild_sizeY = function(vChild, vJobs)
344   {
345     if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight) {
346       vChild._computedHeightTypeNull && vChild._computedMinHeightTypeNull && vChild._computedMaxHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getBoxHeight());
347     }
348   }
349 }
350 else
351 {
352   qx.Proto.layoutChild_sizeX = function(vChild, vJobs)
353   {
354     if (vJobs.initial || vJobs.width) {
355       vChild._computedWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getWidthValue());
356     }
357   }
358
359   qx.Proto.layoutChild_sizeY = function(vChild, vJobs)
360   {
361     if (vJobs.initial || vJobs.height) {
362       vChild._computedHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getHeightValue());
363     }
364   }
365 }
366
367 qx.Proto.layoutChild_location = function(vChild, vJobs)
368 {
369   var vWidget = this.getWidget();
370   var vReverse = vWidget.getReverseChildrenOrder();
371
372   var vMethodBegin = vReverse ? qx.renderer.layout.FlowLayoutImpl.STR_LAST : qx.renderer.layout.FlowLayoutImpl.STR_FIRST;
373   var vMethodContinue = vReverse ? qx.renderer.layout.FlowLayoutImpl.STR_NEXT : qx.renderer.layout.FlowLayoutImpl.STR_PREVIOUS;
374
375   if (vChild == vWidget[vMethodBegin]())
376   {
377     vChild._cachedLocationHorizontal = vChild._cachedLocationVertical = vChild._cachedRow = 0;
378   }
379   else
380   {
381     var vTempChild = vChild[vMethodContinue]();
382
383     // stupidly update cache value (check them later)
384     vChild._cachedLocationHorizontal = vTempChild._cachedLocationHorizontal + vTempChild.getOuterWidth() + vWidget.getHorizontalSpacing();
385     vChild._cachedLocationVertical = vTempChild._cachedLocationVertical;
386     vChild._cachedRow = vTempChild._cachedRow;
387
388     // check now
389     if ((vChild._cachedLocationHorizontal + vChild.getOuterWidth()) > vWidget.getInnerWidth())
390     {
391       // evaluate width of previous row
392       vRowMax = vTempChild.getOuterHeight();
393       while((vTempChild = vTempChild[vMethodContinue]()) && vTempChild._cachedRow == vChild._cachedRow) {
394         vRowMax = Math.max(vRowMax, vTempChild.getOuterHeight());
395       }
396
397       // switch to new row
398       vChild._cachedLocationHorizontal = 0;
399       vChild._cachedLocationVertical += vWidget.getVerticalSpacing() + vRowMax;
400       vChild._cachedRow++;
401     }
402   }
403
404   // add margins and parent padding
405   if (vWidget.getHorizontalChildrenAlign() == "right")
406   {
407     vChild._resetRuntimeLeft();
408     vChild._applyRuntimeRight(vWidget.getPaddingRight() + vChild._cachedLocationHorizontal);
409   }
410   else
411   {
412     vChild._resetRuntimeRight();
413     vChild._applyRuntimeLeft(vWidget.getPaddingLeft() + vChild._cachedLocationHorizontal);
414   }
415
416   if (vWidget.getVerticalChildrenAlign() == "bottom")
417   {
418     vChild._resetRuntimeTop();
419     vChild._applyRuntimeBottom(vWidget.getPaddingBottom() + vChild._cachedLocationVertical);
420   }
421   else
422   {
423     vChild._resetRuntimeBottom();
424     vChild._applyRuntimeTop(vWidget.getPaddingTop() + vChild._cachedLocationVertical);
425   }
426 }