1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2003-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.containers
13{
14
15import flash.events.Event;
16import mx.containers.utilityClasses.BoxLayout;
17import mx.core.Container;
18import mx.core.IUIComponent;
19import mx.core.mx_internal;
20
21use namespace mx_internal;
22
23//--------------------------------------
24//  Styles
25//--------------------------------------
26
27include "../styles/metadata/AlignStyles.as";
28include "../styles/metadata/GapStyles.as";
29
30/**
31 *  Number of pixels between the container's bottom border
32 *  and the bottom of its content area.
33 *  The default value is 0.
34 *
35 *  @langversion 3.0
36 *  @playerversion Flash 9
37 *  @playerversion AIR 1.1
38 *  @productversion Flex 3
39 */
40[Style(name="paddingBottom", type="Number", format="Length", inherit="no")]
41
42/**
43 *  Number of pixels between the container's top border
44 *  and the top of its content area.
45 *  The default value is 0.
46 *
47 *  @langversion 3.0
48 *  @playerversion Flash 9
49 *  @playerversion AIR 1.1
50 *  @productversion Flex 3
51 */
52[Style(name="paddingTop", type="Number", format="Length", inherit="no")]
53
54//--------------------------------------
55//  Excluded APIs
56//--------------------------------------
57
58[Exclude(name="focusIn", kind="event")]
59[Exclude(name="focusOut", kind="event")]
60
61[Exclude(name="focusBlendMode", kind="style")]
62[Exclude(name="focusSkin", kind="style")]
63[Exclude(name="focusThickness", kind="style")]
64
65[Exclude(name="focusInEffect", kind="effect")]
66[Exclude(name="focusOutEffect", kind="effect")]
67
68//--------------------------------------
69//  Other metadata
70//--------------------------------------
71
72[IconFile("Box.png")]
73
74[Alternative(replacement="spark.components.HGroup", since="4.0")]
75[Alternative(replacement="spark.components.VGroup", since="4.0")]
76[Alternative(replacement="spark.components.BorderContainer", since="4.0")]
77
78/**
79 *  A Halo Box container lays out its children in a single vertical column
80 *  or a single horizontal row.
81 *  The <code>direction</code> property determines whether to use
82 *  vertical (default) or horizontal layout.
83 *
84 *  <p><b>Note:</b> Adobe recommends that, when possible, you use the Spark containers
85 *  with HorizontalLayout or VerticalLayout instead of the Halo Box container.</p>
86 *
87 *  <p>The Box class is the base class for the VBox and HBox classes.
88 *  You use the <code>&lt;mx:Box&gt;</code>, <code>&lt;mx:VBox&gt;</code>,
89 *  and <code>&lt;mx:HBox&gt;</code> tags to define Box containers.</p>
90 *
91 *  <p>A Box container has the following default sizing characteristics:</p>
92 *     <table class="innertable">
93 *        <tr>
94 *           <th>Characteristic</th>
95 *           <th>Description</th>
96 *        </tr>
97 *        <tr>
98 *           <td>Default size</td>
99 *           <td><strong>Vertical Box</strong> The height is large enough to hold all its children at the default
100 *               or explicit height of the children, plus any vertical gap between the children, plus the top and
101 *               bottom padding of the container. The width is the default or explicit width of the widest child,
102 *               plus the left and right padding of the container.
103 *               <br><strong>Horizontal Box</strong> The width is large enough to hold all of its children at the
104 *               default width of the children, plus any horizontal gap between the children, plus the left and
105 *               right padding of the container. The height is the default or explicit height of the tallest child,
106 *               plus the top and bottom padding for the container.</br>
107 *           </td>
108 *        </tr>
109 *        <tr>
110 *           <td>Default padding</td>
111 *           <td>0 pixels for the top, bottom, left, and right values.</td>
112 *        </tr>
113 *     </table>
114 *
115 *  @mxml
116 *
117 *  <p>The <code>&lt;mx:Box&gt;</code> tag inherits all of the tag
118 *  attributes of its superclass, and adds the following tag attributes:</p>
119 *
120 *  <p>
121 *  <pre>
122 *  &lt;mx:Box
123 *    <strong>Properties</strong>
124 *    direction="vertical|horizontal"
125 *    <strong>Styles</strong>
126 *    horizontalAlign="left|center|right"
127 *    horizontalGap="8"
128 *    paddingBottom="0"
129 *    paddingTop="0"
130 *    verticalAlign="top|middle|bottom"
131 *    verticalGap="6"
132 *    &gt;
133 *    ...
134 *      <i>child tags</i>
135 *    ...
136 *  &lt;/mx:Box&gt;
137 *  </pre>
138 *  </p>
139 *
140 *  @includeExample examples/SimpleBoxExample.mxml
141 *
142 *  @see mx.core.Container
143 *  @see mx.containers.HBox
144 *  @see mx.containers.VBox
145 *
146 *  @langversion 3.0
147 *  @playerversion Flash 9
148 *  @playerversion AIR 1.1
149 *  @productversion Flex 3
150 */
151public class Box extends Container
152{
153    include "../core/Version.as"
154
155    //--------------------------------------------------------------------------
156    //
157    //  Constructor
158    //
159    //--------------------------------------------------------------------------
160
161    /**
162     *  Constructor.
163     *
164     *  @langversion 3.0
165     *  @playerversion Flash 9
166     *  @playerversion AIR 1.1
167     *  @productversion Flex 3
168     */
169    public function Box()
170    {
171        super();
172
173        layoutObject.target = this;
174    }
175
176    //--------------------------------------------------------------------------
177    //
178    //  Variables
179    //
180    //--------------------------------------------------------------------------
181
182    /**
183     *  @private
184     */
185    mx_internal var layoutObject:BoxLayout = new BoxLayout();
186
187    //--------------------------------------------------------------------------
188    //
189    //  Public properties
190    //
191    //--------------------------------------------------------------------------
192
193    //----------------------------------
194    //  direction
195    //----------------------------------
196
197    [Bindable("directionChanged")]
198    [Inspectable(category="General", enumeration="vertical,horizontal", defaultValue="vertical")]
199
200    /**
201     *  The direction in which this Box container lays out its children.
202     *  Possible MXML values are
203     *  <code>"horizontal"</code> and <code>"vertical"</code>.
204     *  Possible values in ActionScript are <code>BoxDirection.HORIZONTAL</code>
205     *  and <code>BoxDirection.VERTICAL</code>.
206     *
207     *  @default BoxDirection.VERTICAL
208     *
209     *  @langversion 3.0
210     *  @playerversion Flash 9
211     *  @playerversion AIR 1.1
212     *  @productversion Flex 3
213     */
214    public function get direction():String
215    {
216        return layoutObject.direction;
217    }
218
219    /**
220     *  @private
221     */
222    public function set direction(value:String):void
223    {
224        layoutObject.direction = value;
225
226        invalidateSize();
227        invalidateDisplayList();
228
229        dispatchEvent(new Event("directionChanged"));
230    }
231
232    //--------------------------------------------------------------------------
233    //
234    //  Overridden methods
235    //
236    //--------------------------------------------------------------------------
237
238    /**
239     *  Calculates the default sizes and minimum and maximum values of the Box
240     *  container.
241     *
242     *  <p>If the Box container's <code>direction</code> property is set to
243     *  <code>BoxDirection.HORIZONTAL</code>, its <code>measuredWidth</code>
244     *  property is equal to the sum of default widths of all of its children,
245     *  plus the thickness of the borders, plus the left and right padding,
246     *  plus the horizontal gap between each child.
247     *  The value of the <code>measuredHeight</code> property is the maximum of
248     *  all the children's default heights, plus room for the borders and
249     *  padding.
250     *  If the Box container's <code>direction</code> property is set to
251     *  <code>BoxDirection.VERTICAL</code>, these two values are reversed.</p>
252     *
253     *  <p>The Box container's <code>minWidth</code> and <code>minHeight</code>
254     *  properties are calculated similarly, by combining the minimum widths
255     *  and minimum heights of the children.
256     *  If the child's <code>width</code> property is a percentage value,  the
257     *  Box container's minimum width is equal to the value of the child's
258     *  <code>minWidth</code> property.
259     *  If the child's <code>width</code> is unset or  set to a fixed value,
260     *  the child refuses to grow or shrink, so the Box container's minimum
261     *  width is equal to the value of the child's <code>explicitWidth</code>
262     *  property.
263     *  The child's minimum height is calculated similarly.</p>
264     *
265     *  <p>The Box container's <code>maxWidth</code> and
266     *  <code>maxHeight</code> properties are not calculated.
267     *  The Box container is assumed to have an infinite maximum width and
268     *  height.</p>
269     *
270     *  <p>All of the values described previously are the <i>measured</i>
271     *  widths and heights of the Box container.
272     *  The user can override the measured values by explicitly supplying
273     *  a value for the following properties:</p>
274     *
275     *  <ul>
276     *    <li><code>width</code></li>
277     *    <li><code>height</code></li>
278     *    <li><code>minWidth</code></li>
279     *    <li><code>minHeight</code></li>
280     *    <li><code>maxWidth</code></li>
281     *    <li><code>maxHeight</code></li>
282     *  </ul>
283     *
284     *  <p>You should not call the <code>measure()</code> method directly.
285     *  The Flex LayoutManager calls it at the appropriate time.
286     *  At application startup, the Flex LayoutManager attempts to measure
287     *  all components from the children to the parents before setting them
288     *  to their final sizes.</p>
289     *
290     *  <p>This is an advanced method for use in subclassing.
291     *  If you override this method, your implementation must call
292     *  the <code>super.measure()</code> method, or set the
293     *  <code>measuredHeight</code> and
294     *  <code>measuredWidth</code> properties.
295     *  You may also optionally set the following properties:</p>
296     *
297     *  <ul>
298     *    <li><code>measuredMinWidth</code></li>
299     *    <li><code>measuredMinHeight</code></li>
300     *  </ul>
301     *
302     *  <p>These properties correspond to the layout properties listed
303     *  previously and, therefore, are not separately documented.</p>
304     *
305     *  @langversion 3.0
306     *  @playerversion Flash 9
307     *  @playerversion AIR 1.1
308     *  @productversion Flex 3
309     */
310    override protected function measure():void
311    {
312        super.measure();
313
314        layoutObject.measure();
315    }
316
317    /**
318     *  Sets the size and position of each child of the Box container.
319     *
320     *  <p>To understand the layout algorithm for the Box container, assume
321     *  that the Box container's direction is horizontal.</p>
322     *
323     *  <p>All of the Box container's children are positioned side-by-side in a
324     *  single horizontal row, with <code>horizontalGap</code> pixels between
325     *  each pair of adjacent children.
326     *  Initially, the widths of children without an explicit
327     *  width value are set equal to the values of their
328     *  <code>measuredWidth</code> properties.</p>
329     *
330     *  <p>If the sum of the values of the <code>measuredWidth</code>
331     *  properties of the children is greater than or less than the width of
332     *  the Box container, and if some of the children have a percentage value
333     *  for the <code>width</code> property, the sizes of those children are
334     *  grown or shrunk until all children exactly fit in the Box.
335     *  However, no child is shrunk to less than the value of its
336     *  <code>minWidth</code> property or increased greater than the value of
337     *  its <code>maxWidth</code> property.
338     *  Among the growing (or shrinking) children, extra space is added
339     *  (or removed) in proportion to the child's <code>percentWidth</code>.
340     *  For example, a child with a <code>percentWidth</code> of 40 percent
341     *  will grow twice as much as a child with a <code>percentWidth</code> of
342     *  20 percent until all of the available space is filled or the prescribed
343     *  sizes are reached.</p>
344     *
345     *  <p>After all flexible children have grown or shrunk, Flex checks to see
346     *  if the sum of the children's widths match the width of the Box
347     *  container.
348     *  If not, the group of children are all shifted according to the value
349     *  of the Box container's <code>horizontalAlign</code> property, so the
350     *  children are aligned with the left edge of the Box, aligned with the
351     *  right edge of the Box, or centered in the middle of the Box.</p>
352     *
353     *  <p>To determine the height of each child, Flex examines the value
354     *  of the child's <code>height</code> property.
355     *  If the <code>height</code> is unset, the child's height
356     *  is set to its <code>measuredHeight</code>.
357     *  If the <code>height</code> is set to a pixel value, that value is used.
358     *  If the <code>height</code> is set to a percentage value,
359     *  the child's height is grown or shrunk to match the specified
360     *  percentage of the height of the Box, as long as the child's height
361     *  is not shrunk to less than the value of its <code>minHeight</code>
362     *  property or grown to be larger than the value of its
363     *  <code>maxHeight</code> property.</p>
364     *
365     *  <p>The vertical position of each child is determined by
366     *  the Box container's <code>verticalAlign</code> property.
367     *  Each child is shifted so that it is aligned with the top edge
368     *  of the box, aligned with the bottom edge of the box,
369     *  or centered in the Box.</p>
370     *
371     *  <p>If the Box container's <code>direction</code> is
372     *  <code>vertical</code>, the same rules apply, except that the widths and
373     *  heights are swapped.
374     *  The children are arranged in a single vertical column.</p>
375     *
376     *  <p>You should not call this method directly.
377     *  The Flex LayoutManager calls it at the appropriate time.
378     *  At application startup, the Flex LayoutManager calls the
379     *  <code>updateDisplayList()</code> method on every component,
380     *  starting with the Application object and working downward.</p>
381     *
382     *  <p>This is an advanced method for use in subclassing.
383     *  If you override this method, your implementation should call the
384     *  <code>super.updateDisplayList()</code> method and call the
385     *  <code>move()</code> and <code>setActualSize()</code> methods
386     *  on each of the children.
387     *  For the purposes of performing layout, you should get the size
388     *  of this container from the <code>unscaledWidth</code> and
389     *  <code>unscaledHeight</code> properties, not the <code>width</code>
390     *  and <code>height</code> properties.
391     *  The <code>width</code> and <code>height</code> properties
392     *  do not take into account the values of the <code>scaleX</code>
393     *  and <code>scaleY</code> properties for this container.</p>
394     *
395     *  @param unscaledWidth Specifies the width of the component, in pixels,
396     *  in the component's coordinates, regardless of the value of the
397     *  <code>scaleX</code> property of the component.
398     *
399     *  @param unscaledHeight Specifies the height of the component, in pixels,
400     *  in the component's coordinates, regardless of the value of the
401     *  <code>scaleY</code> property of the component.
402     *
403     *  @langversion 3.0
404     *  @playerversion Flash 9
405     *  @playerversion AIR 1.1
406     *  @productversion Flex 3
407     */
408    override protected function updateDisplayList(unscaledWidth:Number,
409                                                  unscaledHeight:Number):void
410    {
411        super.updateDisplayList(unscaledWidth, unscaledHeight);
412
413        layoutObject.updateDisplayList(unscaledWidth, unscaledHeight);
414    }
415
416    //--------------------------------------------------------------------------
417    //
418    //  Methods
419    //
420    //--------------------------------------------------------------------------
421
422    /**
423     *  Method used to convert number of pixels to a
424     *  percentage relative to the contents of this container.
425     *
426     *  <p>The percentage value is relevant only while the
427     *  container does not change size or layout.
428     *  After a resize and/or new layout has occurred,
429     *  the value returned from this method may be stale.</p>
430     *
431     *  <p>An example of how this method could be used would
432     *  be to restore a component's size to a specific number
433     *  of pixels after hiding it.</p>
434     *
435     *  @param pxl The number of pixels for which a percentage
436     *  value is desired.
437     *
438     *  @return The percentage value that would be equivalent
439     *  to <code>pxl</code> under the current layout conditions
440     *  of this container.
441     *  A negative value indicates that the container must grow
442     *  in order to accommodate the requested size.
443     *
444     *  @langversion 3.0
445     *  @playerversion Flash 9
446     *  @playerversion AIR 1.1
447     *  @productversion Flex 3
448     */
449    public function pixelsToPercent(pxl:Number):Number
450    {
451        var vertical:Boolean = isVertical();
452
453        // Compute our total percent and total # pixels for that percent.
454        var totalPerc:Number = 0;
455        var totalSize:Number = 0;
456
457        var n:int = numChildren;
458        for (var i:int = 0; i < n; i++)
459        {
460            var child:IUIComponent = getLayoutChildAt(i);
461
462            var size:Number = vertical ? child.height : child.width;
463            var perc:Number = vertical ? child.percentHeight : child.percentWidth;
464
465            if (!isNaN(perc))
466            {
467                totalPerc += perc;
468                totalSize += size;
469            }
470        }
471
472        // Now if we found one let's compute the percent amount
473        // that we'd require for a given number of pixels.
474        var p:Number = 100;
475        if (totalSize != pxl)
476        {
477            // Now we want the ratio of pixels per percent to
478            // remain constant as we assume the a component
479            // will consume them. So,
480            //
481            //  (totalSize - pxl) / totalPerc = totalSize / (totalPerc + p)
482            //
483            // where we solve for p.
484
485            p = ((totalSize * totalPerc) / (totalSize - pxl)) - totalPerc;
486        }
487
488        return p;
489    }
490
491    /**
492     *  @private
493     */
494    mx_internal function isVertical():Boolean
495    {
496        return direction != BoxDirection.HORIZONTAL;
497    }
498}
499
500}
501