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.controls
13{
14
15import flash.display.DisplayObject;
16import flash.events.Event;
17import flash.events.FocusEvent;
18import flash.events.KeyboardEvent;
19import flash.events.MouseEvent;
20import flash.events.TimerEvent;
21import flash.text.TextFormatAlign;
22import flash.text.TextLineMetrics;
23import flash.ui.Keyboard;
24import flash.utils.Timer;
25
26import mx.controls.dataGridClasses.DataGridListData;
27import mx.controls.listClasses.BaseListData;
28import mx.controls.listClasses.IDropInListItemRenderer;
29import mx.controls.listClasses.IListItemRenderer;
30import mx.core.EdgeMetrics;
31import mx.core.FlexVersion;
32import mx.core.IBorder;
33import mx.core.IButton;
34import mx.core.IDataRenderer;
35import mx.core.IFlexAsset;
36import mx.core.IFlexDisplayObject;
37import mx.core.IFlexModuleFactory;
38import mx.core.IFontContextComponent;
39import mx.core.IInvalidating;
40import mx.core.ILayoutDirectionElement;
41import mx.core.IProgrammaticSkin;
42import mx.core.IStateClient;
43import mx.core.IUIComponent;
44import mx.core.IUITextField;
45import mx.core.UIComponent;
46import mx.core.UITextField;
47import mx.core.mx_internal;
48import mx.events.FlexEvent;
49import mx.events.MoveEvent;
50import mx.events.SandboxMouseEvent;
51import mx.managers.IFocusManagerComponent;
52import mx.styles.ISimpleStyleClient;
53
54
55use namespace mx_internal;
56
57//--------------------------------------
58//  Events
59//--------------------------------------
60
61/**
62 *  Dispatched when the user presses the Button control.
63 *  If the <code>autoRepeat</code> property is <code>true</code>,
64 *  this event is dispatched repeatedly as long as the button stays down.
65 *
66 *  @eventType mx.events.FlexEvent.BUTTON_DOWN
67 *
68 *  @langversion 3.0
69 *  @playerversion Flash 9
70 *  @playerversion AIR 1.1
71 *  @productversion Flex 3
72 */
73[Event(name="buttonDown", type="mx.events.FlexEvent")]
74
75/**
76 *  Dispatched when the <code>selected</code> property
77 *  changes for a toggle Button control. A toggle Button control means that the
78 *  <code>toggle</code> property is set to <code>true</code>.
79 *
80 *  For the RadioButton controls, this event is dispatched when the <code>selected</code>
81 *  property changes.
82 *
83 *  For the CheckBox controls, this event is dispatched only when the
84 *  user interacts with the control by using the mouse.
85 *
86 *  @eventType flash.events.Event.CHANGE
87 *
88 *  @langversion 3.0
89 *  @playerversion Flash 9
90 *  @playerversion AIR 1.1
91 *  @productversion Flex 3
92 */
93[Event(name="change", type="flash.events.Event")]
94
95/**
96 *  Dispatched when the <code>data</code> property changes.
97 *
98 *  <p>When you use a component as an item renderer,
99 *  the <code>data</code> property contains the data to display.
100 *  You can listen for this event and update the component
101 *  when the <code>data</code> property changes.</p>
102 *
103 *  @eventType mx.events.FlexEvent.DATA_CHANGE
104 *
105 *  @langversion 3.0
106 *  @playerversion Flash 9
107 *  @playerversion AIR 1.1
108 *  @productversion Flex 3
109 */
110[Event(name="dataChange", type="mx.events.FlexEvent")]
111
112//--------------------------------------
113//  Styles
114//--------------------------------------
115
116include "../styles/metadata/FocusStyles.as"
117include "../styles/metadata/LeadingStyle.as"
118include "../styles/metadata/PaddingStyles.as"
119include "../styles/metadata/SkinStyles.as"
120include "../styles/metadata/TextStyles.as"
121
122/**
123 *  Color applied to the button when the emphasized flag is true.
124 *
125 *  @default #0099FF
126 *
127 *  @langversion 3.0
128 *  @playerversion Flash 10
129 *  @playerversion AIR 1.5
130 *  @productversion Flex 4
131 */
132[Style(name="accentColor", type="uint", format="Color", inherit="yes", theme="spark")]
133
134/**
135 *  Color of focus ring when the component is in focus
136 *
137 *  @default 0x70B2EE
138 *
139 *  @langversion 3.0
140 *  @playerversion Flash 10
141 *  @playerversion AIR 1.5
142 *  @productversion Flex 4
143 */
144[Style(name="focusColor", type="uint", format="Color", inherit="yes", theme="spark")]
145
146/**
147 *  Gap between the label and icon, when the <code>labelPlacement</code> property
148 *  is set to <code>left</code> or <code>right</code>.
149 *
150 *  @default 2
151 *
152 *  @langversion 3.0
153 *  @playerversion Flash 9
154 *  @playerversion AIR 1.1
155 *  @productversion Flex 3
156 */
157[Style(name="horizontalGap", type="Number", format="Length", inherit="no")]
158
159/**
160 *  Number of pixels of vertical offset to apply to the label position.
161 *  Positive numbers move the label down.
162 *
163 *  The default value for the Halo theme is <code>0</code>.
164 *  The default value for the Spark theme is <code>1</code>.
165 *
166 *  @langversion 3.0
167 *  @playerversion Flash 10
168 *  @playerversion AIR 1.5
169 *  @productversion Flex 4
170 */
171[Style(name="labelVerticalOffset", type="Number", format="Length", inherit="no")]
172
173/**
174 *  Number of pixels between the component's bottom border
175 *  and the bottom of its content area.
176 *
177 *  The default value for the Halo theme is <code>2</code>.
178 *  The default value for the Spark theme is <code>0</code>.
179 *
180 *  @langversion 3.0
181 *  @playerversion Flash 9
182 *  @playerversion AIR 1.1
183 *  @productversion Flex 3
184 */
185[Style(name="paddingBottom", type="Number", format="Length", inherit="no")]
186
187/**
188 *  Number of pixels between the component's top border
189 *  and the top of its content area.
190 *
191 *  The default value for the Halo theme is <code>2</code>.
192 *  The default value for the Spark theme is <code>0</code>.
193 *
194 *  @langversion 3.0
195 *  @playerversion Flash 9
196 *  @playerversion AIR 1.1
197 *  @productversion Flex 3
198 */
199[Style(name="paddingTop", type="Number", format="Length", inherit="no")]
200
201/**
202 *  Number of milliseconds to wait after the first <code>buttonDown</code>
203 *  event before repeating <code>buttonDown</code> events at each
204 *  <code>repeatInterval</code>.
205 *
206 *  @default 500
207 *
208 *  @langversion 3.0
209 *  @playerversion Flash 9
210 *  @playerversion AIR 1.1
211 *  @productversion Flex 3
212 */
213[Style(name="repeatDelay", type="Number", format="Time", inherit="no")]
214
215/**
216 *  Number of milliseconds between <code>buttonDown</code> events
217 *  if the user presses and holds the mouse on a button.
218 *
219 *  @default 35
220 *
221 *  @langversion 3.0
222 *  @playerversion Flash 9
223 *  @playerversion AIR 1.1
224 *  @productversion Flex 3
225 */
226[Style(name="repeatInterval", type="Number", format="Time", inherit="no")]
227
228/**
229 *  Text color of the label as the user moves the mouse pointer over the button.
230 *
231 *  The default value for the Halo theme is <code>0x2B333C</code>.
232 *  The default value for the Spark theme is <code>0x000000</code>.
233 *
234 *  @langversion 3.0
235 *  @playerversion Flash 9
236 *  @playerversion AIR 1.1
237 *  @productversion Flex 3
238 */
239[Style(name="textRollOverColor", type="uint", format="Color", inherit="yes")]
240
241/**
242 *  Text color of the label as the user presses it.
243 *
244 *  The default value for the Halo theme is <code>0x2B333C</code>.
245 *  The default value for the Spark theme is <code>0x000000</code>.
246 *
247 *  @langversion 3.0
248 *  @playerversion Flash 9
249 *  @playerversion AIR 1.1
250 *  @productversion Flex 3
251 */
252[Style(name="textSelectedColor", type="uint", format="Color", inherit="yes")]
253
254/**
255 *  Gap between the button's label and icon when the <code>labelPlacement</code>
256 *  property is set to <code>"top"</code> or <code>"bottom"</code>.
257 *
258 *  @default 2
259 *
260 *  @langversion 3.0
261 *  @playerversion Flash 9
262 *  @playerversion AIR 1.1
263 *  @productversion Flex 3
264 */
265[Style(name="verticalGap", type="Number", format="Length", inherit="no")]
266
267//--------------------------------------
268//  Skins
269//--------------------------------------
270
271/**
272 *  Name of the class to use as the default skin for the background and border.
273 *
274 *  The default value for the Halo theme is <code>mx.skins.halo.ButtonSkin</code>.
275 *  The default value for the Spark theme is <code>mx.skins.spark.ButtonSkin</code>.
276 *
277 *  @langversion 3.0
278 *  @playerversion Flash 9
279 *  @playerversion AIR 1.1
280 *  @productversion Flex 3
281 */
282[Style(name="skin", type="Class", inherit="no", states="up, over, down, disabled, selectedUp, selectedOver, selectedDown, selectedDisabled")]
283
284/**
285 *  Name of the class to use as the skin for the background and border
286 *  when the button is not selected and the mouse is not over the control.
287 *
288 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
289 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
290 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
291 *
292 *  @langversion 3.0
293 *  @playerversion Flash 9
294 *  @playerversion AIR 1.1
295 *  @productversion Flex 3
296 */
297[Style(name="upSkin", type="Class", inherit="no")]
298
299/**
300 *  Name of the class to use as the skin for the background and border
301 *  when the button is not selected and the mouse is over the control.
302 *
303 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
304 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
305 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
306 *
307 *  @langversion 3.0
308 *  @playerversion Flash 9
309 *  @playerversion AIR 1.1
310 *  @productversion Flex 3
311 */
312[Style(name="overSkin", type="Class", inherit="no")]
313
314/**
315 *  Name of the class to use as the skin for the background and border
316 *  when the button is not selected and the mouse button is down.
317 *
318 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
319 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
320 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
321 *
322 *  @langversion 3.0
323 *  @playerversion Flash 9
324 *  @playerversion AIR 1.1
325 *  @productversion Flex 3
326 */
327[Style(name="downSkin", type="Class", inherit="no")]
328
329/**
330 *  Name of the class to use as the skin for the background and border
331 *  when the button is not selected and is disabled.
332 *
333 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
334 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
335 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
336 *
337 *  @langversion 3.0
338 *  @playerversion Flash 9
339 *  @playerversion AIR 1.1
340 *  @productversion Flex 3
341 */
342[Style(name="disabledSkin", type="Class", inherit="no")]
343
344/**
345 *  Name of the class to use as the skin for the button when the button
346 *  is <code>emphasized</code> (such as when serving as the default
347 *  button for a container).
348 *
349 *  The default value for the Halo theme is <code>mx.skins.halo.ButtonSkin</code>.
350 *  The default value for the Spark theme is <code>mx.skins.spark.DefaultButtonSkin</code>.
351 *
352 *  @langversion 3.0
353 *  @playerversion Flash 9
354 *  @playerversion AIR 1.1
355 *  @productversion Flex 3
356 */
357[Style(name="emphasizedSkin", type="Class", inherit="no", states="up, over, down, disabled, selectedUp, selectedOver, selectedDown, selectedDisabled")]
358
359/**
360 *  Name of the class to use as the skin for the background and border
361 *  when a toggle button is selected and the mouse is not over the control.
362 *
363 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
364 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
365 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
366 *
367 *  @langversion 3.0
368 *  @playerversion Flash 9
369 *  @playerversion AIR 1.1
370 *  @productversion Flex 3
371 */
372[Style(name="selectedUpSkin", type="Class", inherit="no")]
373
374/**
375 *  Name of the class to use as the skin for the background and border
376 *  when a toggle button is selected and the mouse is over the control.
377 *
378 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
379 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
380 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
381 *
382 *  @langversion 3.0
383 *  @playerversion Flash 9
384 *  @playerversion AIR 1.1
385 *  @productversion Flex 3
386 */
387[Style(name="selectedOverSkin", type="Class", inherit="no")]
388
389/**
390 *  Name of the class to use as the skin for the background and border
391 *  when a toggle button is selected and the mouse button is down.
392 *
393 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
394 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
395 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
396 *
397 *  @langversion 3.0
398 *  @playerversion Flash 9
399 *  @playerversion AIR 1.1
400 *  @productversion Flex 3
401 */
402[Style(name="selectedDownSkin", type="Class", inherit="no")]
403
404/**
405 *  Name of the class to use as the skin for the background and border
406 *  when a toggle button is selected and disabled.
407 *
408 *  <p>The default skin class is based on the theme. For example, with the Halo theme,
409 *  the default skin class is <code>mx.skins.halo.ButtonSkin</code>. For the Spark theme, the default skin
410 *  class is <code>mx.skins.spark.ButtonSkin</code>.</p>
411 *
412 *  @langversion 3.0
413 *  @playerversion Flash 9
414 *  @playerversion AIR 1.1
415 *  @productversion Flex 3
416 */
417[Style(name="selectedDisabledSkin", type="Class", inherit="no")]
418
419/**
420 *  Name of the class to use as the default icon.
421 *  Setting any other icon style overrides this setting.
422 *
423 *  @default null
424 *
425 *  @langversion 3.0
426 *  @playerversion Flash 9
427 *  @playerversion AIR 1.1
428 *  @productversion Flex 3
429 */
430[Style(name="icon", type="Class", inherit="no", states="up, over, down, disabled, selectedUp, selectedOver, selectedDown, selectedDisabled")]
431
432/**
433 *  Name of the class to use as the icon when a toggle button is not
434 *  selected and the mouse is not over the button.
435 *
436 *  @default null
437 *
438 *  @langversion 3.0
439 *  @playerversion Flash 9
440 *  @playerversion AIR 1.1
441 *  @productversion Flex 3
442 */
443[Style(name="upIcon", type="Class", inherit="no")]
444
445/**
446 *  Name of the class to use as the icon when the button is not
447 *  selected and the mouse is over the control.
448 *
449 *  @default null
450 *
451 *  @langversion 3.0
452 *  @playerversion Flash 9
453 *  @playerversion AIR 1.1
454 *  @productversion Flex 3
455 */
456[Style(name="overIcon", type="Class", inherit="no")]
457
458/**
459 *  Name of the class to use as the icon when the button is not
460 *  selected and the mouse button is down.
461 *
462 *  @default null
463 *
464 *  @langversion 3.0
465 *  @playerversion Flash 9
466 *  @playerversion AIR 1.1
467 *  @productversion Flex 3
468 */
469[Style(name="downIcon", type="Class", inherit="no")]
470
471/**
472 *  Name of the class to use as the icon
473 *  when the button is disabled and not selected.
474 *
475 *  @default null
476 *
477 *  @langversion 3.0
478 *  @playerversion Flash 9
479 *  @playerversion AIR 1.1
480 *  @productversion Flex 3
481 */
482[Style(name="disabledIcon", type="Class", inherit="no")]
483
484/**
485 *  Name of the class to use as the icon
486 *  when the button is selected and the mouse button is up.
487 *
488 *  @default null
489 *
490 *  @langversion 3.0
491 *  @playerversion Flash 9
492 *  @playerversion AIR 1.1
493 *  @productversion Flex 3
494 */
495[Style(name="selectedUpIcon", type="Class", inherit="no")]
496
497/**
498 *  Name of the class to use as the icon
499 *  when the button is selected and the mouse is over the control.
500 *
501 *  @default null
502 *
503 *  @langversion 3.0
504 *  @playerversion Flash 9
505 *  @playerversion AIR 1.1
506 *  @productversion Flex 3
507 */
508[Style(name="selectedOverIcon", type="Class", inherit="no")]
509
510/**
511 *  Name of the class to use as the icon
512 *  when the button is selected and the mouse button is down.
513 *
514 *  @default null
515 *
516 *  @langversion 3.0
517 *  @playerversion Flash 9
518 *  @playerversion AIR 1.1
519 *  @productversion Flex 3
520 */
521[Style(name="selectedDownIcon", type="Class", inherit="no")]
522
523/**
524 *  Name of the class to use as the icon
525 *  when the button is selected and disabled.
526 *
527 *  @default null
528 *
529 *  @langversion 3.0
530 *  @playerversion Flash 9
531 *  @playerversion AIR 1.1
532 *  @productversion Flex 3
533 */
534[Style(name="selectedDisabledIcon", type="Class", inherit="no")]
535
536//--------------------------------------
537//  Other metadata
538//--------------------------------------
539
540[AccessibilityClass(implementation="mx.accessibility.ButtonAccImpl")]
541
542[DefaultBindingProperty(source="selected", destination="label")]
543
544[DefaultTriggerEvent("click")]
545
546[IconFile("Button.png")]
547
548[Alternative(replacement="spark.components.Button", since="4.0")]
549
550/**
551 *  The Button control is a commonly used rectangular button.
552 *  Button controls look like they can be pressed.
553 *  They can have a text label, an icon, or both on their face.
554 *
555 *  <p>Buttons typically use event listeners to perform an action
556 *  when the user selects the control. When a user clicks the mouse
557 *  on a Button control, and the Button control is enabled,
558 *  it dispatches a <code>click</code> event and a <code>buttonDown</code> event.
559 *  A button always dispatches events such as the <code>mouseMove</code>,
560 *  <code>mouseOver</code>, <code>mouseOut</code>, <code>rollOver</code>,
561 *  <code>rollOut</code>, <code>mouseDown</code>, and
562 *  <code>mouseUp</code> events whether enabled or disabled.</p>
563 *
564 *  <p>You can customize the look of a Button control
565 *  and change its functionality from a push button to a toggle button.
566 *  You can change the button appearance by using a skin
567 *  for each of the button's states.</p>
568 *
569 *  <p>The label of a Button control uses a bold typeface. If you embed
570 *  a font that you want to use for the label of the Button control, you must
571 *  embed the bold typeface; for example:</p>
572 *
573 *  <pre>
574 *  &lt;fx:style&gt;
575 *    &#64;font-face {
576 *      src:url("../MyFont-Bold.ttf");
577 *      fontFamily: myFont;
578 *      fontWeight: bold;
579 *    }
580 *   .myBoldStyle {
581 *      fontFamily: myFont;
582 *      fontWeight: bold;
583 *    }
584 *  &lt;/fx:style&gt;
585 *  ...
586 *  &lt;mx:Button ... styleName="myBoldStyle"/&gt;
587 *  </pre>
588 *
589 *  <p>The Button control has the following default characteristics:</p>
590 *  <table class="innertable">
591 *     <tr><th>Characteristic</th><th>Description</th></tr>
592 *     <tr><td>Default size</td><td>A size large enough to hold the label text, and any icon</td></tr>
593 *     <tr><td>Minimum size</td><td>0 pixels</td></tr>
594 *     <tr><td>Maximum size</td><td>No limit</td></tr>
595 *  </table>
596 *
597 *  @mxml
598 *
599 *  <p>The <code>&lt;mx:Button&gt;</code> tag inherits all the tag attributes
600 *  of its superclass, and adds the following tag attributes:</p>
601 *
602 *  <pre>
603 *  &lt;mx:Button
604 *    <b>Properties</b>
605 *    autoRepeat="false|true"
606 *    emphasized="false|true"
607 *    fontContext="<i>IFontModuleFactory</i>"
608 *    label=""
609 *    labelPlacement="right|left|bottom|top"
610 *    selected="false|true"
611 *    selectedField="null"
612 *    stickyHighlighting="false|true"
613 *    toggle="false|true"
614 *
615 *    <b>Styles</b>
616 *    borderColor="0xAAB3B3"
617 *    color="0x0B333C"
618 *    cornerRadius="4"
619 *    disabledColor="0xAAB3B3"
620 *    disabledIcon="null"
621 *    disabledSkin="mx.skins.halo.ButtonSkin"
622 *    downIcon="null"
623 *    downSkin="mx.skins.halo.ButtonSkin"
624 *    fillAlphas="[0.6, 0.4]"
625 *    fillColors="[0xE6EEEE, 0xFFFFFF]"
626 *    focusAlpha="0.5"
627 *    focusRoundedCorners"tl tr bl br"
628 *    fontAntiAliasType="advanced"
629 *    fontFamily="Verdana"
630 *    fontGridFitType="pixel"
631 *    fontSharpness="0"
632 *    fontSize="10"
633 *    fontStyle="normal|italic"
634 *    fontThickness="0"
635 *    fontWeight="bold|normal"
636 *    highlightAlphas="[0.3, 0.0]"
637 *    horizontalGap="2"
638 *    icon="null"
639 *    kerning="false|true"
640 *    leading="2"
641 *    letterSpacing="0"
642 *    overIcon="null"
643 *    overSkin="mx.skins.halo.ButtonSkin"
644 *    paddingBottom="2"
645 *    paddingLeft="0"
646 *    paddingRight="0"
647 *    paddingTop="2"
648 *    repeatDelay="500"
649 *    repeatInterval="35"
650 *    selectedDisabledIcon="null"
651 *    selectedDisabledSkin="mx.skins.halo.ButtonSkin"
652 *    selectedDownIcon="null"
653 *    selectedDownSkin="mx.skins.halo.ButtonSkin"
654 *    selectedOverIcon="null"
655 *    selectedOverSkin="mx.skins.halo.ButtonSkin"
656 *    selectedUpIcon="null"
657 *    selectedUpSkin="mx.skins.halo.ButtonSkin"
658 *    skin="mx.skins.halo.ButtonSkin"
659 *    textAlign="center|left|right"
660 *    textDecoration="none|underline"
661 *    textIndent="0"
662 *    textRollOverColor="0x2B333C"
663 *    textSelectedColor="0x000000"
664 *    upIcon="null"
665 *    upSkin="mx.skins.halo.ButtonSkin"
666 *    verticalGap="2"
667 *
668 *    <b>Events</b>
669 *    buttonDown="<i>No default</i>"
670 *    change="<i>No default</i>"
671 *    dataChange="<i>No default</i>"
672 *  /&gt;
673 *  </pre>
674 *
675 *  @includeExample examples/ButtonExample.mxml
676 *
677 *  @langversion 3.0
678 *  @playerversion Flash 9
679 *  @playerversion AIR 1.1
680 *  @productversion Flex 3
681 */
682public class Button extends UIComponent
683       implements IDataRenderer, IDropInListItemRenderer,
684       IFocusManagerComponent, IListItemRenderer,
685       IFontContextComponent, IButton
686{
687    include "../core/Version.as";
688
689    //--------------------------------------------------------------------------
690    //
691    //  Class mixins
692    //
693    //--------------------------------------------------------------------------
694
695    /**
696     *  @private
697     *  Placeholder for mixin by ButtonAccImpl.
698     */
699    mx_internal static var createAccessibilityImplementation:Function;
700
701    //--------------------------------------------------------------------------
702    //
703    //  Constructor
704    //
705    //--------------------------------------------------------------------------
706
707    /**
708     *  Constructor.
709     *
710     *  @langversion 3.0
711     *  @playerversion Flash 9
712     *  @playerversion AIR 1.1
713     *  @productversion Flex 3
714     */
715    public function Button()
716    {
717        super();
718
719        // DisplayObjectContainer properties.
720        // Setting mouseChildren to false ensure that mouse events
721        // are dispatched from the Button itself,
722        // not from its skins, icons, or TextField.
723        // One reason for doing this is that if you press the mouse button
724        // while over the TextField and release the mouse button while over
725        // a skin or icon, we want the player to dispatch a "click" event.
726        // Another is that if mouseChildren were true and someone uses
727        // Sprites rather than Shapes for the skins or icons,
728        // then we we wouldn't get a click because the current skin or icon
729        // changes between the mouseDown and the mouseUp.
730        // (This doesn't happen even when mouseChildren is true if the skins
731        // and icons are Shapes, because Shapes never dispatch mouse events;
732        // they are dispatched from the Button in this case.)
733        mouseChildren = false;
734
735        // Register for player events.
736        addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
737        addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
738        addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
739        addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
740        addEventListener(MouseEvent.CLICK, clickHandler);
741    }
742
743    //--------------------------------------------------------------------------
744    //
745    //  Variables
746    //
747    //--------------------------------------------------------------------------
748
749    /**
750     *  @private
751     *  Skins for the various states (falseUp, trueOver, etc.)
752     *  are created just-in-time as they are needed.
753     *  Each skin is a child Sprite of this Button.
754     *  Each skin has a name property indicating which skin it is;
755     *  for example, the instance of the class specified by the falseUpSkin
756     *  style has the name "falseUpSkin" and can be found using
757     *  getChildByName(). Note that there is no falseUpSkin property
758     *  of Button containing a reference to this skin instance.
759     *  This array contains references to all skins that have been created,
760     *  for looping over them; without this array we wouldn't know
761     *  which of the children are the skins.
762     *  New skins are created and added to this array in viewSkin().
763     */
764    private var skins:Array /* of Sprite */ = [];
765
766    /**
767     *  @private
768     *  A reference to the current skin.
769     *  Set by viewSkin().
770     */
771    mx_internal var currentSkin:IFlexDisplayObject;
772
773    /**
774     *  The icons array contains references to all icons
775     *  that have been created. Since each icon is a child
776     *  Sprite of this button, we need this array to keep
777     *  track of which children are icons. Each icon has a
778     *  name property indicating which icon it is; for example,
779     *  the instance of the class specified by the falseUpIcon
780     *  style has the name "falseUpIcon" and can be found using
781     *  getChildByName(). Note that there is no falseUpIcon property
782     *  of Button containing a reference to this icon instance.
783     *  New icons are created and added to this array in viewIcon().
784     *
785     *  @langversion 3.0
786     *  @playerversion Flash 9
787     *  @playerversion AIR 1.1
788     *  @productversion Flex 3
789     */
790    protected var icons:Array /* of Sprite */ = [];
791
792    /**
793     *  @private
794     *  A reference to the current icon.
795     *  Set by viewIcon().
796     */
797    mx_internal var currentIcon:IFlexDisplayObject;
798
799    /**
800     *  @private
801     *  Timer for doing auto-repeat.
802     */
803    private var autoRepeatTimer:Timer;
804
805    /**
806     *  @private
807     *  Number used to offset the label and/or icon
808     *  when button is pressed.
809     */
810    mx_internal var buttonOffset:Number = 0;
811
812    /**
813     *  @private
814     *  used by old measure/layout logic
815     */
816    mx_internal var centerContent:Boolean = true;
817
818    /**
819     *  @private
820     *  used by old measure/layout logic
821     */
822    mx_internal var extraSpacing:Number = 10 + 10;
823
824     /**
825     *  @private
826     */
827    mx_internal static var TEXT_WIDTH_PADDING:Number = UITextField.TEXT_WIDTH_PADDING + 1;
828
829    /**
830     *  @private
831     */
832    private var styleChangedFlag:Boolean = true;
833
834    /**
835     *  @private
836     *  The measured width of the first skin loaded.
837     */
838    private var skinMeasuredWidth:Number;
839
840    /**
841     *  @private
842     *  The measured height of the first skin loaded.
843     */
844    private var skinMeasuredHeight:Number;
845
846    /**
847     *  @private
848     *  The value of the unscaledWidth parameter during the most recent
849     *  call to updateDisplayList
850     */
851    private var oldUnscaledWidth:Number;
852
853    /**
854     *  @private
855     *  Flags that will block default data/listData behavior
856     */
857    private var selectedSet:Boolean;
858    private var labelSet:Boolean;
859
860    /**
861     *  @private
862     *  Flags used to save information about the skin and icon styles
863     */
864    mx_internal var checkedDefaultSkin:Boolean = false;
865    mx_internal var defaultSkinUsesStates:Boolean = false;
866    mx_internal var checkedDefaultIcon:Boolean = false;
867    mx_internal var defaultIconUsesStates:Boolean = false;
868
869    /**
870     *  @private
871     *  Skin names.
872     *  Allows subclasses to re-define the skin property names.
873     */
874    mx_internal var skinName:String = "skin";
875    mx_internal var emphasizedSkinName:String = "emphasizedSkin";
876    mx_internal var upSkinName:String = "upSkin";
877    mx_internal var overSkinName:String = "overSkin";
878    mx_internal var downSkinName:String = "downSkin";
879    mx_internal var disabledSkinName:String = "disabledSkin";
880    mx_internal var selectedUpSkinName:String = "selectedUpSkin";
881    mx_internal var selectedOverSkinName:String = "selectedOverSkin";
882    mx_internal var selectedDownSkinName:String = "selectedDownSkin";
883    mx_internal var selectedDisabledSkinName:String = "selectedDisabledSkin";
884
885    /**
886     *  @private
887     *  Icon names.
888     *  Allows subclasses to re-define the icon property names.
889     */
890    mx_internal var iconName:String = "icon";
891    mx_internal var upIconName:String = "upIcon";
892    mx_internal var overIconName:String = "overIcon";
893    mx_internal var downIconName:String = "downIcon";
894    mx_internal var disabledIconName:String = "disabledIcon";
895    mx_internal var selectedUpIconName:String = "selectedUpIcon";
896    mx_internal var selectedOverIconName:String = "selectedOverIcon";
897    mx_internal var selectedDownIconName:String = "selectedDownIcon";
898    mx_internal var selectedDisabledIconName:String = "selectedDisabledIcon";
899
900    //--------------------------------------------------------------------------
901    //
902    //  Overridden properties
903    //
904    //--------------------------------------------------------------------------
905
906    //----------------------------------
907    //  baselinePosition
908    //----------------------------------
909
910    /**
911     *  @private
912     *  The baselinePosition of a Button is calculated for its label.
913     */
914    override public function get baselinePosition():Number
915    {
916        if (!validateBaselinePosition())
917            return NaN;
918
919        return textField.y + textField.baselinePosition;
920    }
921
922    //----------------------------------
923    //  enabled
924    //----------------------------------
925
926    /**
927     *  @private
928     */
929    private var enabledChanged:Boolean = false;
930
931    [Inspectable(category="General", enumeration="true,false", defaultValue="true")]
932
933    /**
934     *  @private
935     *  This is called whenever the enabled state changes.
936     */
937    override public function set enabled(value:Boolean):void
938    {
939        if (super.enabled == value)
940            return;
941
942        super.enabled = value;
943        enabledChanged = true;
944
945        invalidateProperties();
946        invalidateDisplayList();
947    }
948
949    //----------------------------------
950    //  textField
951    //----------------------------------
952
953    /**
954     *  The internal UITextField object that renders the label of this Button.
955     *
956     *  @default null
957     *
958     *  @langversion 3.0
959     *  @playerversion Flash 9
960     *  @playerversion AIR 1.1
961     *  @productversion Flex 3
962     */
963    protected var textField:IUITextField;
964
965    //----------------------------------
966    //  toolTip
967    //----------------------------------
968
969    /**
970     *  @private
971     */
972    private var toolTipSet:Boolean = false;
973
974    [Inspectable(category="General", defaultValue="null")]
975
976    /**
977     *  @private
978     */
979    override public function set toolTip(value:String):void
980    {
981        super.toolTip = value;
982
983        if (value)
984        {
985            toolTipSet = true;
986        }
987        else
988        {
989            toolTipSet = false;
990            invalidateDisplayList();
991        }
992    }
993
994    //--------------------------------------------------------------------------
995    //
996    //  Properties
997    //
998    //--------------------------------------------------------------------------
999
1000    //----------------------------------
1001    //  autoRepeat
1002    //----------------------------------
1003
1004    /**
1005     *  @private
1006     *  Storage for the autoRepeat property.
1007     */
1008    private var _autoRepeat:Boolean = false;
1009
1010    [Inspectable(defaultValue="false")]
1011
1012    /**
1013     *  Specifies whether to dispatch repeated <code>buttonDown</code>
1014     *  events if the user holds down the mouse button.
1015     *
1016     *  @default false
1017     *
1018     *  @langversion 3.0
1019     *  @playerversion Flash 9
1020     *  @playerversion AIR 1.1
1021     *  @productversion Flex 3
1022     */
1023    public function get autoRepeat():Boolean
1024    {
1025        return _autoRepeat;
1026    }
1027
1028    /**
1029     *  @private
1030     */
1031    public function set autoRepeat(value:Boolean):void
1032    {
1033        _autoRepeat = value;
1034
1035        if (value)
1036        {
1037            // Create a Timer object for driving the autorepeat.
1038            // The duration gets set in mouseDownHandler and reset
1039            // in autoRepeatTimer_timerDelayHandler, because
1040            // there is a delay before the first autorepeat
1041            // and then a possibly different interval
1042            // between subsequent ones.
1043            autoRepeatTimer = new Timer(1);
1044        }
1045        else
1046        {
1047            autoRepeatTimer = null;
1048        }
1049    }
1050
1051    //----------------------------------
1052    //  data
1053    //----------------------------------
1054
1055    /**
1056     *  @private
1057     *  Storage for the data property;
1058     */
1059    private var _data:Object;
1060
1061    [Bindable("dataChange")]
1062    [Inspectable(environment="none")]
1063
1064    /**
1065     *  The <code>data</code> property lets you pass a value
1066     *  to the component when you use it as an item renderer or item editor.
1067     *  You typically use data binding to bind a field of the <code>data</code>
1068     *  property to a property of this component.
1069     *
1070     *  <p>When you use the control as a drop-in item renderer or drop-in
1071     *  item editor, Flex automatically writes the current value of the item
1072     *  to the <code>selected</code> property of this control.</p>
1073     *
1074     *  <p>You do not set this property in MXML.</p>
1075     *
1076     *  @default null
1077     *  @see mx.core.IDataRenderer
1078     *
1079     *  @langversion 3.0
1080     *  @playerversion Flash 9
1081     *  @playerversion AIR 1.1
1082     *  @productversion Flex 3
1083     */
1084    public function get data():Object
1085    {
1086        return _data;
1087    }
1088
1089    /**
1090     *  @private
1091     */
1092    public function set data(value:Object):void
1093    {
1094        var newSelected:*;
1095        var newLabel:*;
1096
1097        _data = value;
1098
1099        if (_listData && _listData is DataGridListData &&
1100            DataGridListData(_listData).dataField !=null)
1101        {
1102            newSelected = _data[DataGridListData(_listData).dataField];
1103
1104            newLabel = "";
1105        }
1106        else if (_listData)
1107        {
1108            if (selectedField)
1109                newSelected = _data[selectedField];
1110
1111            newLabel = _listData.label;
1112        }
1113        else
1114        {
1115            newSelected = _data;
1116        }
1117
1118        if (newSelected !== undefined && !selectedSet)
1119        {
1120            selected = newSelected as Boolean;
1121            selectedSet = false;
1122        }
1123        if (newLabel !== undefined && !labelSet)
1124        {
1125            label = newLabel;
1126            labelSet = false;
1127        }
1128
1129        dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
1130    }
1131
1132    //----------------------------------
1133    //  emphasized
1134    //----------------------------------
1135
1136    /**
1137     *  @private
1138     *  Storage for the emphasized property.
1139     */
1140    mx_internal var _emphasized:Boolean = false;
1141
1142    /**
1143     *  @private
1144     */
1145    private var emphasizedChanged:Boolean = false;
1146
1147
1148    [Inspectable(category="General", defaultValue="false")]
1149
1150    /**
1151     *  Draws a thick border around the Button control
1152     *  when the control is in its up state if <code>emphasized</code>
1153     *  is set to <code>true</code>.
1154     *
1155     *  @default false
1156     *
1157     *  @langversion 3.0
1158     *  @playerversion Flash 9
1159     *  @playerversion AIR 1.1
1160     *  @productversion Flex 3
1161     */
1162    public function get emphasized():Boolean
1163    {
1164        return _emphasized;
1165    }
1166
1167    /**
1168     *  @private
1169     */
1170    public function set emphasized(value:Boolean):void
1171    {
1172        _emphasized = value;
1173        emphasizedChanged = true;
1174
1175        invalidateDisplayList();
1176    }
1177
1178    //----------------------------------
1179    //  fontContext
1180    //----------------------------------
1181
1182    /**
1183     *  @inheritDoc
1184     *
1185     *  @langversion 3.0
1186     *  @playerversion Flash 9
1187     *  @playerversion AIR 1.1
1188     *  @productversion Flex 3
1189     */
1190    public function get fontContext():IFlexModuleFactory
1191    {
1192        return moduleFactory;
1193    }
1194
1195    /**
1196     *  @private
1197     */
1198    public function set fontContext(moduleFactory:IFlexModuleFactory):void
1199    {
1200        this.moduleFactory = moduleFactory;
1201    }
1202
1203    //----------------------------------
1204    //  label
1205    //----------------------------------
1206
1207    /**
1208     *  @private
1209     *  Storage for label property.
1210     */
1211    private var _label:String = "";
1212
1213    /**
1214     *  @private
1215     */
1216    private var labelChanged:Boolean = false;
1217
1218    [Bindable("labelChanged")]
1219    [Inspectable(category="General", defaultValue="")]
1220
1221    /**
1222     *  Text to appear on the Button control.
1223     *
1224     *  <p>If the label is wider than the Button control,
1225     *  the label is truncated and terminated by an ellipsis (...).
1226     *  The full label displays as a tooltip
1227     *  when the user moves the mouse over the Button control.
1228     *  If you have also set a tooltip by using the <code>tooltip</code>
1229     *  property, the tooltip is displayed rather than the label text.</p>
1230     *
1231     *  @default ""
1232     *
1233     *  @langversion 3.0
1234     *  @playerversion Flash 9
1235     *  @playerversion AIR 1.1
1236     *  @productversion Flex 3
1237     */
1238    public function get label():String
1239    {
1240        return _label;
1241    }
1242
1243    /**
1244     *  @private
1245     */
1246    public function set label(value:String):void
1247    {
1248        labelSet = true;
1249
1250        if (_label != value)
1251        {
1252            _label = value;
1253            labelChanged = true;
1254
1255            invalidateSize();
1256            invalidateDisplayList();
1257
1258            dispatchEvent(new Event("labelChanged"));
1259        }
1260    }
1261
1262    //----------------------------------
1263    //  labelPlacement
1264    //----------------------------------
1265
1266    /**
1267     *  @private
1268     *  Storage for labelPlacement property.
1269     */
1270    mx_internal var _labelPlacement:String = ButtonLabelPlacement.RIGHT;
1271
1272    [Bindable("labelPlacementChanged")]
1273    [Inspectable(category="General", enumeration="left,right,top,bottom", defaultValue="right")]
1274
1275    /**
1276     *  Orientation of the label in relation to a specified icon.
1277     *  Valid MXML values are <code>right</code>, <code>left</code>,
1278     *  <code>bottom</code>, and <code>top</code>.
1279     *
1280     *  <p>In ActionScript, you can use the following constants
1281     *  to set this property:
1282     *  <code>ButtonLabelPlacement.RIGHT</code>,
1283     *  <code>ButtonLabelPlacement.LEFT</code>,
1284     *  <code>ButtonLabelPlacement.BOTTOM</code>, and
1285     *  <code>ButtonLabelPlacement.TOP</code>.</p>
1286     *
1287     *  @default ButtonLabelPlacement.RIGHT
1288     *
1289     *  @langversion 3.0
1290     *  @playerversion Flash 9
1291     *  @playerversion AIR 1.1
1292     *  @productversion Flex 3
1293     */
1294    public function get labelPlacement():String
1295    {
1296        return _labelPlacement;
1297    }
1298
1299    /**
1300     *  @private
1301     */
1302    public function set labelPlacement(value:String):void
1303    {
1304        _labelPlacement = value;
1305
1306        invalidateSize();
1307        invalidateDisplayList();
1308
1309        dispatchEvent(new Event("labelPlacementChanged"));
1310    }
1311
1312    //-----------------------------------
1313    //  listData
1314    //-----------------------------------
1315
1316    /**
1317     *  @private
1318     *  Storage for the listData property.
1319     */
1320    private var _listData:BaseListData;
1321
1322    [Bindable("dataChange")]
1323    [Inspectable(environment="none")]
1324
1325    /**
1326     *  When a component is used as a drop-in item renderer or drop-in
1327     *  item editor, Flex initializes the <code>listData</code> property
1328     *  of the component with the appropriate data from the list control.
1329     *  The component can then use the <code>listData</code> property
1330     *  to initialize the <code>data</code> property
1331     *  of the drop-in item renderer or drop-in item editor.
1332     *
1333     *  <p>You do not set this property in MXML or ActionScript;
1334     *  Flex sets it when the component is used as a drop-in item renderer
1335     *  or drop-in item editor.</p>
1336     *
1337     *  @default null
1338     *  @see mx.controls.listClasses.IDropInListItemRenderer
1339     *
1340     *  @langversion 3.0
1341     *  @playerversion Flash 9
1342     *  @playerversion AIR 1.1
1343     *  @productversion Flex 3
1344     */
1345    public function get listData():BaseListData
1346    {
1347        return _listData;
1348    }
1349
1350    /**
1351     *  @private
1352     */
1353    public function set listData(value:BaseListData):void
1354    {
1355        _listData = value;
1356    }
1357
1358    //----------------------------------
1359    //  phase
1360    //----------------------------------
1361
1362    /**
1363     *  @private
1364     *  Mouse and focus events set this to
1365     *  ButtonPhase.UP, ButtonPhase.OVER, or ButtonPhase.DOWN.
1366     */
1367    private var _phase:String = ButtonPhase.UP;
1368
1369    /**
1370     *  @private
1371     */
1372    mx_internal var phaseChanged:Boolean = false;
1373
1374    /**
1375     *  @private
1376     */
1377    mx_internal function get phase():String
1378    {
1379        return _phase;
1380    }
1381
1382    /**
1383     *  @private
1384     */
1385    mx_internal function set phase(value:String):void
1386    {
1387        _phase = value;
1388        phaseChanged = true;
1389
1390        invalidateSize();
1391        invalidateProperties();
1392        invalidateDisplayList();
1393    }
1394
1395    //----------------------------------
1396    //  selected
1397    //----------------------------------
1398
1399    /**
1400     *  @private
1401     *  Storage for selected property.
1402     */
1403    mx_internal var _selected:Boolean = false;
1404
1405    [Bindable("click")]
1406    [Bindable("valueCommit")]
1407    [Inspectable(category="General", defaultValue="false")]
1408
1409    /**
1410     *  Indicates whether a toggle button is toggled
1411     *  on (<code>true</code>) or off (<code>false</code>).
1412     *  This property can be set only if the <code>toggle</code> property
1413     *  is set to <code>true</code>.
1414     *
1415     *  <p>For a CheckBox control, indicates whether the box
1416     *  is displaying a check mark. For a RadioButton control,
1417     *  indicates whether the control is selected.</p>
1418     *
1419     *  <p>The user can change this property by clicking the control,
1420     *  but you can also set the property programmatically.</p>
1421     *
1422     *  <p>In previous versions, If the <code>toggle</code> property
1423     *  was set to <code>true</code>, changing this property also dispatched
1424     *  a <code>change</code> event. Starting in version 3.0, setting this
1425     *  property programmatically only dispatches a
1426     *  <code>valueCommit</code> event.</p>
1427     *
1428     *  @default false
1429     *
1430     *  @langversion 3.0
1431     *  @playerversion Flash 9
1432     *  @playerversion AIR 1.1
1433     *  @productversion Flex 3
1434     */
1435    public function get selected():Boolean
1436    {
1437        return _selected;
1438    }
1439
1440    /**
1441     *  @private
1442     */
1443    public function set selected(value:Boolean):void
1444    {
1445        selectedSet = true;
1446        setSelected(value, true);
1447    }
1448
1449    mx_internal function setSelected(value:Boolean,
1450                                     isProgrammatic:Boolean = false):void
1451    {
1452        if (_selected != value)
1453        {
1454            _selected = value;
1455
1456            invalidateDisplayList();
1457
1458            if (toggle && !isProgrammatic)
1459                dispatchEvent(new Event(Event.CHANGE));
1460
1461            dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
1462        }
1463    }
1464
1465    //----------------------------------
1466    //  selectedField
1467    //----------------------------------
1468
1469    /**
1470     *  The name of the field in the <code>data</code> property which specifies
1471     *  the value of the Button control's <code>selected</code> property.
1472     *  You can set this property when you use the Button control in an item renderer.
1473     *  The default value is null, which means that the Button control does
1474     *  not set its selected state based on a property in the <code>data</code> property.
1475     *
1476     *  @default null
1477     *
1478     *  @langversion 3.0
1479     *  @playerversion Flash 9
1480     *  @playerversion AIR 1.1
1481     *  @productversion Flex 3
1482     */
1483    public var selectedField:String = null;
1484
1485    //----------------------------------
1486    //  skinLayoutDirection
1487    //----------------------------------
1488
1489    private var skinLayoutDirectionSet:Boolean = false;
1490    private var _skinLayoutDirection:String;
1491    /**
1492     *  @private
1493     */
1494    mx_internal function set skinLayoutDirection(value:String):void
1495    {
1496        skinLayoutDirectionSet = true;
1497        _skinLayoutDirection = value;
1498    }
1499
1500    //----------------------------------
1501    //  stickyHighlighting
1502    //----------------------------------
1503
1504    /**
1505     *  If <code>false</code>, the Button displays its down skin
1506     *  when the user presses it but changes to its over skin when
1507     *  the user drags the mouse off of it.
1508     *  If <code>true</code>, the Button displays its down skin
1509     *  when the user presses it, and continues to display this skin
1510     *  when the user drags the mouse off of it.
1511     *
1512     *  <p>Button subclasses, such as the SliderThumb and ScrollThumb classes
1513     *  or the up and down arrows of a ScrollBar, set
1514     *  this property to <code>true</code>.</p>
1515     *
1516     *  @default false
1517     *
1518     *  @langversion 3.0
1519     *  @playerversion Flash 9
1520     *  @playerversion AIR 1.1
1521     *  @productversion Flex 3
1522     */
1523    public var stickyHighlighting:Boolean = false;
1524
1525    //----------------------------------
1526    //  toggle
1527    //----------------------------------
1528
1529    /**
1530     *  @private
1531     *  Storage for toggle property.
1532     */
1533    mx_internal var _toggle:Boolean = false;
1534
1535    /**
1536     *  @private
1537     */
1538    mx_internal var toggleChanged:Boolean = false;
1539
1540    [Bindable("toggleChanged")]
1541    [Inspectable(category="General", defaultValue="false")]
1542
1543    /**
1544     *  Controls whether a Button is in a toggle state or not.
1545     *
1546     *  If <code>true</code>, clicking the button toggles it
1547     *  between a selected and an unselected state.
1548     *  You can get or set this state programmatically
1549     *  by using the <code>selected</code> property.
1550     *
1551     *  If <code>false</code>, the button does not stay pressed
1552     *  after the user releases it.
1553     *  In this case, its <code>selected</code> property
1554     *  is always <code>false</code>.
1555     *  Buttons like this are used for performing actions.
1556     *
1557     *  When <code>toggle</code> is set to <code>false</code>,
1558     *  <code>selected</code> is forced to <code>false</code>
1559     *  because only toggle buttons can be selected.
1560     *
1561     *  @default false
1562     *
1563     *  @langversion 3.0
1564     *  @playerversion Flash 9
1565     *  @playerversion AIR 1.1
1566     *  @productversion Flex 3
1567     */
1568    public function get toggle():Boolean
1569    {
1570        return _toggle;
1571    }
1572
1573    /**
1574     *  @private
1575     */
1576    public function set toggle(value:Boolean):void
1577    {
1578        _toggle = value;
1579        toggleChanged = true;
1580
1581        invalidateProperties();
1582        invalidateDisplayList();
1583
1584        dispatchEvent(new Event("toggleChanged"));
1585    }
1586
1587    //--------------------------------------------------------------------------
1588    //
1589    //  Overridden methods: UIComponent
1590    //
1591    //--------------------------------------------------------------------------
1592
1593    /**
1594     *  @private
1595     */
1596    override protected function initializeAccessibility():void
1597    {
1598        if (Button.createAccessibilityImplementation != null)
1599            Button.createAccessibilityImplementation(this);
1600    }
1601
1602    /**
1603     *  @private
1604     */
1605    override protected function createChildren():void
1606    {
1607        super.createChildren();
1608
1609        // Create a UITextField to display the label.
1610        if (!textField)
1611        {
1612            textField = IUITextField(createInFontContext(UITextField));
1613            textField.styleName = this;
1614            addChild(DisplayObject(textField));
1615        }
1616
1617    }
1618
1619    /**
1620     *  @private
1621     */
1622    override protected function commitProperties():void
1623    {
1624        super.commitProperties();
1625
1626         // if the font changed and we already created the textfield, we will need to
1627        // destory it so it can be re-created, possibly in a different swf context.
1628        if (hasFontContextChanged() && textField != null)
1629        {
1630            removeChild(DisplayObject(textField));
1631            textField = null;
1632        }
1633
1634         // Create a UITextField to display the label.
1635        if (!textField)
1636        {
1637            textField = IUITextField(createInFontContext(UITextField));
1638            textField.styleName = this;
1639            addChild(DisplayObject(textField));
1640
1641            enabledChanged = true;
1642            toggleChanged = true;
1643        }
1644
1645        if (!initialized)
1646        {
1647            viewSkin();
1648            viewIcon();
1649        }
1650
1651        if (enabledChanged)
1652        {
1653            textField.enabled = enabled;
1654
1655            if (currentIcon && currentIcon is IUIComponent)
1656                IUIComponent(currentIcon).enabled = enabled;
1657
1658            enabledChanged = false;
1659        }
1660
1661        if (toggleChanged)
1662        {
1663            // If the button is no longer toggleable,
1664            // deselect it.
1665            if (!toggle)
1666                selected = false;
1667            toggleChanged = false;
1668        }
1669
1670        if (phaseChanged)
1671        {
1672            // Ensure all potential pseudo-selectors are reevaluated if
1673            // necessary.
1674            var prevState:String = _currentButtonState;
1675            if (prevState != getCurrentButtonState())
1676                stateChanged(prevState, _currentButtonState, false);
1677            phaseChanged = false;
1678        }
1679    }
1680
1681    /**
1682     *  @private
1683     */
1684    override protected function measure():void
1685    {
1686        super.measure();
1687
1688        var textWidth:Number = 0;
1689        var textHeight:Number = 0;
1690
1691        if (label)
1692        {
1693            var lineMetrics:TextLineMetrics = measureText(label);
1694            textWidth = lineMetrics.width + TEXT_WIDTH_PADDING;
1695            textHeight = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
1696        }
1697
1698        var tempCurrentIcon:IFlexDisplayObject = getCurrentIcon();
1699        var iconWidth:Number = tempCurrentIcon ? tempCurrentIcon.width : 0;
1700        var iconHeight:Number = tempCurrentIcon ? tempCurrentIcon.height : 0;
1701        var w:Number = 0;
1702        var h:Number = 0;
1703
1704        if (labelPlacement == ButtonLabelPlacement.LEFT ||
1705            labelPlacement == ButtonLabelPlacement.RIGHT)
1706        {
1707            w = textWidth + iconWidth;
1708            if (textWidth && iconWidth)
1709                w += getStyle("horizontalGap");
1710            h = Math.max(textHeight, iconHeight);
1711        }
1712        else
1713        {
1714            w = Math.max(textWidth, iconWidth);
1715            h = textHeight + iconHeight;
1716            if (textHeight && iconHeight)
1717                h += getStyle("verticalGap");
1718        }
1719
1720        // Add padding. !!!Need a hack here to only add padding if we don't
1721        // have text or icon. This is required to make small buttons (like scroll
1722        // arrows and numeric stepper buttons) look correct.
1723        if (textWidth || iconWidth)
1724        {
1725            w += getStyle("paddingLeft") + getStyle("paddingRight");
1726            h += getStyle("paddingTop") + getStyle("paddingBottom");
1727        }
1728
1729        var bm:EdgeMetrics = currentSkin &&
1730                             currentSkin is IBorder && !(currentSkin is IFlexAsset) ?
1731                             IBorder(currentSkin).borderMetrics :
1732                             null;
1733
1734        if (bm)
1735        {
1736            w += bm.left + bm.right;
1737            h += bm.top + bm.bottom
1738        }
1739
1740        // Use the larger of the measured sizes and the skin's preferred sizes.
1741        // Each skin should override measure() with their measuredWidth
1742        // and measuredHeight.
1743        if (currentSkin && (isNaN(skinMeasuredWidth) || isNaN(skinMeasuredHeight)))
1744        {
1745            skinMeasuredWidth = currentSkin.measuredWidth;
1746            skinMeasuredHeight = currentSkin.measuredHeight;
1747        }
1748
1749        if (!isNaN(skinMeasuredWidth))
1750            w = Math.max(skinMeasuredWidth, w);
1751
1752        if (!isNaN(skinMeasuredHeight))
1753            h = Math.max(skinMeasuredHeight, h);
1754
1755        measuredMinWidth = measuredWidth = w;
1756        measuredMinHeight = measuredHeight = h;
1757        // trace("measure: Button width = " + w + " height = " + h);
1758    }
1759
1760    /**
1761     *  @private
1762     */
1763    override protected function updateDisplayList(unscaledWidth:Number,
1764                                                  unscaledHeight:Number):void
1765    {
1766        super.updateDisplayList(unscaledWidth, unscaledHeight);
1767
1768        if (emphasizedChanged)
1769        {
1770            changeSkins();
1771            emphasizedChanged = false;
1772        }
1773
1774        // Set each skin's size to the layout size of this Button.
1775        var n:int = skins.length;
1776        for (var i:int = 0; i < n; i++)
1777        {
1778            var skin:IFlexDisplayObject = IFlexDisplayObject(skins[i]);
1779            skin.setActualSize(unscaledWidth, unscaledHeight);
1780        }
1781
1782        // Show the appropriate skin and icon, based on whether this
1783        // Button is enabled or disabled, whether it is selected
1784        // or unselected, and how it is currently interacting
1785        // with the mouse (i.e., the up/over/down phase).
1786        viewSkin();
1787        viewIcon();
1788
1789        /* if (currentIcon && currentIcon is IUIComponent)
1790            IUIComponent(currentIcon).enabled = enabled; */
1791
1792        layoutContents(unscaledWidth, unscaledHeight,
1793                       phase == ButtonPhase.DOWN);
1794
1795        // If our width changed, reset the label text to get it to fit.
1796        if (oldUnscaledWidth > unscaledWidth ||
1797            textField.text != label ||
1798            labelChanged ||
1799            styleChangedFlag)
1800        {
1801            textField.text = label;
1802            var truncated:Boolean = textField.truncateToFit();
1803            if (!toolTipSet)
1804            {
1805                if (truncated)
1806                    super.toolTip = label;
1807                else
1808                    super.toolTip = null;
1809            }
1810
1811            styleChangedFlag = false;
1812            labelChanged = false;
1813        }
1814
1815        oldUnscaledWidth = unscaledWidth;
1816    }
1817
1818    /**
1819     *  @private
1820     */
1821    override public function styleChanged(styleProp:String):void
1822    {
1823        styleChangedFlag = true;
1824
1825        super.styleChanged(styleProp);
1826
1827        // Check for skin/icon changes here.
1828        // We could only throw out any skins that change,
1829        // but since dynamic re-skinning is uncommon, we'll take
1830        // the simpler approach of throwing out all skins.
1831        if (!styleProp || styleProp == "styleName")
1832        {
1833            // All style props have changed, so dump skins and icons.
1834            changeSkins();
1835            changeIcons();
1836            if (initialized)
1837            {
1838                viewSkin();
1839                viewIcon();
1840            }
1841        }
1842        else if (styleProp.toLowerCase().indexOf("skin") != -1)
1843        {
1844            changeSkins();
1845        }
1846        else if (styleProp.toLowerCase().indexOf("icon") != -1)
1847        {
1848            changeIcons();
1849            invalidateSize();
1850        }
1851    }
1852
1853    /**
1854     *  @private
1855     */
1856    override protected function adjustFocusRect(
1857                                    object:DisplayObject = null):void
1858    {
1859        // If we don't have a skin, show focus around the icon.
1860        super.adjustFocusRect(!currentSkin ? DisplayObject(currentIcon) : this);
1861    }
1862
1863    /**
1864     *  @private
1865     *  The state to be used when matching CSS pseudo-selectors. This override
1866     *  returns the current button state.
1867     */
1868    override protected function get currentCSSState():String
1869    {
1870        return getCurrentButtonState();
1871    }
1872
1873    //--------------------------------------------------------------------------
1874    //
1875    //  Methods
1876    //
1877    //--------------------------------------------------------------------------
1878
1879    /**
1880     *  @private
1881     *  Displays one of the eight possible skins,
1882     *  creating it if it doesn't already exist.
1883     */
1884    mx_internal function viewSkin():void
1885    {
1886        // Determine which skin to display, based on whether this
1887        // button is enabled or disabled, whether it is
1888        // selected or unselected, and how it is currently interacting
1889        // with the mouse (i.e., the up/over/down state).
1890        var tempSkinName:String;
1891
1892        if (!enabled)
1893            tempSkinName = selected ? selectedDisabledSkinName : disabledSkinName;
1894        else if (phase == ButtonPhase.UP)
1895            tempSkinName = selected ? selectedUpSkinName : upSkinName;
1896        else if (phase == ButtonPhase.OVER)
1897            tempSkinName = selected ? selectedOverSkinName : overSkinName;
1898        else if (phase == ButtonPhase.DOWN)
1899            tempSkinName = selected ? selectedDownSkinName : downSkinName;
1900
1901        viewSkinForPhase(tempSkinName, getCurrentButtonState());
1902    }
1903
1904    /**
1905     *  @private
1906     *  Displays one of the several possible skins,
1907     *  depending on the skinName and creating
1908     *  it if it doesn't already exist.
1909     */
1910    mx_internal function viewSkinForPhase(tempSkinName:String, stateName:String):void
1911    {
1912        var newSkinClass:Class = Class(getStyle(tempSkinName));
1913        var newSkin:IFlexDisplayObject;
1914
1915        if (!newSkinClass)
1916        {
1917            // Try the default skin
1918            newSkinClass = _emphasized ? Class(getStyle(emphasizedSkinName)) : Class(getStyle(skinName));
1919            newSkinClass = !newSkinClass && _emphasized ? Class(getStyle(skinName)) : newSkinClass;
1920
1921            // If we are using the default skin, then
1922            if (defaultSkinUsesStates)
1923                tempSkinName = skinName;
1924
1925            if (!checkedDefaultSkin && newSkinClass)
1926            {
1927                newSkin = IFlexDisplayObject(new newSkinClass());
1928                // Check if the skin class is a state client or a programmatic skin
1929                if (!(newSkin is IProgrammaticSkin) && newSkin is IStateClient)
1930                {
1931                    defaultSkinUsesStates = true;
1932                    tempSkinName = skinName;
1933                }
1934
1935                if (newSkin)
1936                {
1937                    checkedDefaultSkin = true;
1938
1939                    if (newSkin is ILayoutDirectionElement && skinLayoutDirectionSet)
1940                        ILayoutDirectionElement(newSkin).layoutDirection = _skinLayoutDirection;
1941                }
1942            }
1943        }
1944
1945        // Has this skin already been created?
1946        newSkin = IFlexDisplayObject(getChildByName(tempSkinName));
1947        // If not, create it.
1948        if (!newSkin)
1949        {
1950            if (newSkinClass)
1951            {
1952                newSkin = IFlexDisplayObject(new newSkinClass());
1953                // Set its name so that we can find it in the future
1954                // using getChildByName().
1955                newSkin.name = tempSkinName;
1956
1957                // Make the getStyle() calls in ButtonSkin find the styles
1958                // for this Button.
1959                var styleableSkin:ISimpleStyleClient = newSkin as ISimpleStyleClient;
1960                if (styleableSkin)
1961                    styleableSkin.styleName = this;
1962
1963                if (newSkin is ILayoutDirectionElement && skinLayoutDirectionSet)
1964                    ILayoutDirectionElement(newSkin).layoutDirection = _skinLayoutDirection;
1965
1966                addChild(DisplayObject(newSkin));
1967
1968                // Make the skin the proper size for this Button.
1969                // This will cause to skin to be drawn by drawHaloRect()
1970                // in ButtonSkin.
1971                newSkin.setActualSize(unscaledWidth, unscaledHeight);
1972
1973                // If the skin is programmatic, and we've already been
1974                // initialized, update it now to avoid flicker.
1975                if (newSkin is IInvalidating && initialized)
1976                {
1977                    IInvalidating(newSkin).validateNow();
1978                }
1979                else if (newSkin is IProgrammaticSkin && initialized)
1980                {
1981                    IProgrammaticSkin(newSkin).validateDisplayList()
1982                }
1983
1984                // Keep track of all skin children that have been created.
1985                skins.push(newSkin);
1986            }
1987        }
1988
1989        // Hide the old skin.
1990        if (currentSkin)
1991            currentSkin.visible = false;
1992
1993        // Keep track of which skin is current.
1994        currentSkin = newSkin;
1995
1996        // Update the state of the skin if it accepts states and it implements the IStateClient interface.
1997        if (defaultSkinUsesStates && currentSkin is IStateClient)
1998        {
1999            IStateClient(currentSkin).currentState = stateName;
2000            if (currentSkin is IInvalidating)
2001                IInvalidating(currentSkin).validateNow();
2002        }
2003
2004        // Show the new skin.
2005        if (currentSkin)
2006            currentSkin.visible = true;
2007
2008        var labelColor:Number;
2009
2010        if (enabled)
2011        {
2012            if (phase == ButtonPhase.OVER)
2013                labelColor = textField.getStyle("textRollOverColor");
2014            else if (phase == ButtonPhase.DOWN)
2015                labelColor = textField.getStyle("textSelectedColor");
2016            else
2017                labelColor = textField.getStyle("color");
2018
2019            textField.setColor(labelColor);
2020        }
2021    }
2022
2023    /**
2024     *  @private
2025     *  Gets the currentIconName (string) based on the Button's phase.
2026     */
2027    mx_internal function getCurrentIconName():String
2028    {
2029        var tempIconName:String;
2030
2031        if (!enabled)
2032        {
2033            tempIconName = selected ?
2034                           selectedDisabledIconName :
2035                           disabledIconName;
2036        }
2037        else if (phase == ButtonPhase.UP)
2038        {
2039            tempIconName = selected ? selectedUpIconName : upIconName;
2040        }
2041        else if (phase == ButtonPhase.OVER)
2042        {
2043            tempIconName = selected ? selectedOverIconName : overIconName;
2044        }
2045        else if (phase == ButtonPhase.DOWN)
2046        {
2047            tempIconName = selected ? selectedDownIconName : downIconName;
2048        }
2049
2050        return tempIconName;
2051    }
2052
2053
2054    /**
2055     *  @private
2056     *  gets the currentIcon based on the button.phase
2057     */
2058    mx_internal function getCurrentIcon():IFlexDisplayObject
2059    {
2060        // Determine which icon will get displayed, based on whether this
2061        // Button is enabled or disabled, whether it is
2062        // selected or unselected, and how it is currently interacting
2063        // with the mouse (i.e., the up/over/down state).
2064
2065        var tempIconName:String = getCurrentIconName();
2066
2067        if (!tempIconName)
2068            return null;
2069
2070        return viewIconForPhase(tempIconName);
2071    }
2072
2073    /**
2074     *  @private
2075     *  Displays one of the eight possible icons,
2076     *  creating it if it doesn't already exist.
2077     */
2078    mx_internal function viewIcon():void
2079    {
2080        // Determine which icon to display, based on whether this
2081        // Button is enabled or disabled, whether it is
2082        // selected or unselected, and how it is currently interacting
2083        // with the mouse (i.e., the up/over/down state).
2084        var tempIconName:String = getCurrentIconName();
2085
2086        viewIconForPhase(tempIconName);
2087    }
2088
2089    /**
2090     *  @private
2091     *  Displays one of the several possible icons,
2092     *  depending on the iconName and creating it if it
2093     *  doesn't already exist.
2094     */
2095    mx_internal function viewIconForPhase(tempIconName:String):IFlexDisplayObject
2096    {
2097        var newIconClass:Class = Class(getStyle(tempIconName));
2098        var newIcon:IFlexDisplayObject;
2099
2100        if (!newIconClass)
2101        {
2102            newIconClass = Class(getStyle(iconName));
2103
2104            // If we are using the default icon, then set use the default icon name
2105            if (defaultIconUsesStates)
2106                tempIconName = iconName;
2107
2108            if (!checkedDefaultIcon && newIconClass)
2109            {
2110                newIcon = IFlexDisplayObject(new newIconClass());
2111                // Check if the icon class is a state client or a programmatic skin
2112                if (!(newIcon is IProgrammaticSkin) && newIcon is IStateClient)
2113                {
2114                    defaultIconUsesStates = true;
2115                    tempIconName = iconName;
2116                }
2117
2118                if (newIcon)
2119                    checkedDefaultIcon = true;
2120            }
2121        }
2122
2123        // Has this icon already been created?
2124        newIcon = IFlexDisplayObject(getChildByName(tempIconName));
2125        // If not, create it.
2126        if (newIcon == null)
2127        {
2128            if (newIconClass != null)
2129            {
2130                newIcon = IFlexDisplayObject(new newIconClass());
2131
2132                // Set its name so that we can find it in the future
2133                // using getChildByName().
2134                newIcon.name = tempIconName;
2135
2136                if (newIcon is ISimpleStyleClient)
2137                    ISimpleStyleClient(newIcon).styleName = this;
2138
2139                addChild(DisplayObject(newIcon));
2140
2141
2142                // If the skin is programmatic, and we've already been
2143                // initialized, update it now to avoid flicker.
2144                var sizeIcon:Boolean = false;
2145                if (newIcon is IInvalidating)
2146                {
2147                    IInvalidating(newIcon).validateNow();
2148                    sizeIcon = true;
2149                }
2150                else if (newIcon is IProgrammaticSkin)
2151                {
2152                    IProgrammaticSkin(newIcon).validateDisplayList();
2153                    sizeIcon = true;
2154                }
2155                if (newIcon && newIcon is IUIComponent)
2156                    IUIComponent(newIcon).enabled = enabled;
2157
2158                if (sizeIcon)
2159                    newIcon.setActualSize(newIcon.measuredWidth, newIcon.measuredHeight);
2160
2161
2162                // Keep track of all icon children that have been created.
2163                icons.push(newIcon);
2164            }
2165        }
2166
2167        // Hide the old icon.
2168        if (currentIcon != null)
2169            currentIcon.visible = false;
2170
2171        // Keep track of which icon is current.
2172        currentIcon = newIcon;
2173
2174        if (defaultIconUsesStates && currentIcon is IStateClient)
2175        {
2176            IStateClient(currentIcon).currentState = getCurrentButtonState();
2177            if (currentIcon is IInvalidating)
2178                IInvalidating(currentIcon).validateNow();
2179        }
2180
2181        // Show the new icon.
2182        if (currentIcon != null)
2183            currentIcon.visible = true;
2184
2185        return newIcon;
2186    }
2187
2188    /**
2189     *  @private
2190     *  Storage for the most recent button state.
2191     */
2192    protected var _currentButtonState:String;
2193
2194    /**
2195     *  @private
2196     *  Computes the current button state based on whether this button is
2197     *  enabled or disabled, whether it is selected or unselected, and how it
2198     *  is currently interacting with the mouse (i.e. the up/over/down state).
2199     */
2200    mx_internal function getCurrentButtonState():String
2201    {
2202        _currentButtonState = "";
2203
2204        if (!enabled)
2205            _currentButtonState = selected ? "selectedDisabled" : "disabled";
2206        else if (phase == ButtonPhase.UP)
2207            _currentButtonState = selected ? "selectedUp" : "up";
2208        else if (phase == ButtonPhase.OVER)
2209            _currentButtonState = selected ? "selectedOver" : "over";
2210        else if (phase == ButtonPhase.DOWN)
2211            _currentButtonState = selected ? "selectedDown" : "down";
2212
2213        return _currentButtonState;
2214    }
2215
2216   /**
2217     *  @private
2218     *  Controls the layout of the icon and the label within the button.
2219     *  The text/icon are aligned based on the textAlign style setting.
2220     */
2221    mx_internal function layoutContents(unscaledWidth:Number,
2222                                        unscaledHeight:Number,
2223                                        offset:Boolean):void
2224    {
2225        var labelWidth:Number = 0;
2226        var labelHeight:Number = 0;
2227
2228        var labelX:Number = 0;
2229        var labelY:Number = 0;
2230
2231        var iconWidth:Number = 0;
2232        var iconHeight:Number = 0;
2233
2234        var iconX:Number = 0;
2235        var iconY:Number = 0;
2236
2237        var horizontalGap:Number = 0;
2238        var verticalGap:Number = 0;
2239
2240        var paddingLeft:Number = getStyle("paddingLeft");
2241        var paddingRight:Number = getStyle("paddingRight");
2242        var paddingTop:Number = getStyle("paddingTop");
2243        var paddingBottom:Number = getStyle("paddingBottom");
2244
2245        var textWidth:Number = 0;
2246        var textHeight:Number = 0;
2247
2248        var lineMetrics:TextLineMetrics;
2249
2250        if (label)
2251        {
2252            lineMetrics = measureText(label);
2253            textWidth = lineMetrics.width + TEXT_WIDTH_PADDING;
2254            textHeight = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
2255        }
2256        else
2257        {
2258            lineMetrics = measureText("Wj");
2259            textHeight = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
2260        }
2261
2262        var n:Number = offset ? buttonOffset : 0;
2263
2264        var textAlign:String = getStyle("textAlign");
2265        // Map new Spark values that might be set in a selector
2266        // affecting both Halo and Spark components.
2267        if (textAlign == "start")
2268            textAlign = TextFormatAlign.LEFT;
2269        else if (textAlign == "end")
2270            textAlign = TextFormatAlign.RIGHT;
2271
2272        var viewWidth:Number = unscaledWidth;
2273        var viewHeight:Number = unscaledHeight;
2274
2275        var bm:EdgeMetrics = currentSkin &&
2276                             currentSkin is IBorder && !(currentSkin is IFlexAsset) ?
2277                             IBorder(currentSkin).borderMetrics :
2278                             null;
2279
2280        if (bm)
2281        {
2282            viewWidth -= bm.left + bm.right;
2283            viewHeight -= bm.top + bm.bottom;
2284        }
2285
2286        if (currentIcon)
2287        {
2288            iconWidth = currentIcon.width;
2289            iconHeight = currentIcon.height;
2290        }
2291
2292        if (labelPlacement == ButtonLabelPlacement.LEFT ||
2293            labelPlacement == ButtonLabelPlacement.RIGHT)
2294        {
2295            horizontalGap = getStyle("horizontalGap");
2296
2297            if (iconWidth == 0 || textWidth == 0)
2298                horizontalGap = 0;
2299
2300            if (textWidth > 0)
2301            {
2302                textField.width = labelWidth =
2303                    Math.max(Math.min(viewWidth - iconWidth - horizontalGap -
2304                                      paddingLeft - paddingRight, textWidth), 0);
2305            }
2306            else
2307            {
2308                textField.width = labelWidth = 0;
2309            }
2310            textField.height = labelHeight = Math.min(viewHeight, textHeight);
2311
2312            if (textAlign == "left")
2313            {
2314                labelX += paddingLeft;
2315            }
2316            else if (textAlign == "right")
2317            {
2318                labelX += (viewWidth - labelWidth - iconWidth -
2319                           horizontalGap - paddingRight);
2320            }
2321            else // "center" -- default value
2322            {
2323                labelX += ((viewWidth - labelWidth - iconWidth -
2324                           horizontalGap - paddingLeft - paddingRight) / 2) + paddingLeft;
2325            }
2326
2327            if (labelPlacement == ButtonLabelPlacement.RIGHT)
2328            {
2329                labelX += iconWidth + horizontalGap;
2330                iconX = labelX - (iconWidth + horizontalGap);
2331            }
2332            else
2333            {
2334                iconX  = labelX + labelWidth + horizontalGap;
2335            }
2336
2337            iconY  = ((viewHeight - iconHeight - paddingTop - paddingBottom) / 2) + paddingTop;
2338            labelY = ((viewHeight - labelHeight - paddingTop - paddingBottom) / 2) + paddingTop;
2339        }
2340        else
2341        {
2342            verticalGap = getStyle("verticalGap");
2343
2344            if (iconHeight == 0 || label == "")
2345                verticalGap = 0;
2346
2347            if (textWidth > 0)
2348            {
2349                textField.width = labelWidth = Math.max(viewWidth - paddingLeft - paddingRight, 0);
2350                textField.height = labelHeight =
2351                    Math.min(viewHeight - iconHeight - paddingTop - paddingBottom - verticalGap, textHeight);
2352            }
2353            else
2354            {
2355                textField.width = labelWidth = 0;
2356                textField.height = labelHeight = 0;
2357            }
2358
2359            labelX = paddingLeft;
2360
2361            if (textAlign == "left")
2362            {
2363                iconX += paddingLeft;
2364            }
2365            else if (textAlign == "right")
2366            {
2367                iconX += Math.max(viewWidth - iconWidth - paddingRight, paddingLeft);
2368            }
2369            else
2370            {
2371                iconX += ((viewWidth - iconWidth - paddingLeft - paddingRight) / 2) + paddingLeft;
2372            }
2373
2374            if (labelPlacement == ButtonLabelPlacement.TOP)
2375            {
2376                labelY += ((viewHeight - labelHeight - iconHeight -
2377                            paddingTop - paddingBottom - verticalGap) / 2) + paddingTop;
2378                iconY += labelY + labelHeight + verticalGap;
2379            }
2380            else
2381            {
2382                iconY += ((viewHeight - labelHeight - iconHeight -
2383                            paddingTop - paddingBottom - verticalGap) / 2) + paddingTop;
2384                labelY += iconY + iconHeight + verticalGap;
2385            }
2386
2387        }
2388        var buffX:Number = n;
2389        var buffY:Number = n;
2390
2391        if (bm)
2392        {
2393            buffX += bm.left;
2394            buffY += bm.top;
2395        }
2396
2397        if (FlexVersion.compatibilityVersion >= FlexVersion.VERSION_4_0)
2398            labelY += getStyle("labelVerticalOffset");
2399
2400        textField.x = Math.round(labelX + buffX);
2401        textField.y = Math.round(labelY + buffY);
2402
2403        if (currentIcon)
2404        {
2405            iconX += buffX;
2406            iconY += buffY;
2407
2408            // dispatch a move on behalf of the icon
2409            // the focus system uses that to adjust
2410            // focus rectangles
2411            var moveEvent:MoveEvent = new MoveEvent(MoveEvent.MOVE);
2412            moveEvent.oldX = currentIcon.x;
2413            moveEvent.oldY = currentIcon.y;
2414
2415            currentIcon.x = Math.round(iconX);
2416            currentIcon.y = Math.round(iconY);
2417            currentIcon.dispatchEvent(moveEvent);
2418        }
2419
2420        // The skins and icons get created on demand as the user interacts
2421        // with the Button, and as they are created they become the
2422        // frontmost child.
2423        // Here we ensure that the textField is the frontmost child,
2424        // with the current icon behind it and the current skin behind that.
2425        // Any other skins and icons are left behind these three,
2426        // with arbitrary layering.
2427        if (currentSkin)
2428            setChildIndex(DisplayObject(currentSkin), numChildren - 1);
2429        if (currentIcon)
2430            setChildIndex(DisplayObject(currentIcon), numChildren - 1);
2431        if (textField)
2432            setChildIndex(DisplayObject(textField), numChildren - 1);
2433    }
2434
2435    /**
2436     *  @private
2437     */
2438    mx_internal function changeSkins():void
2439    {
2440        var n:int = skins.length;
2441        for (var i:int = 0; i < n; i++)
2442        {
2443            removeChild(skins[i]);
2444        }
2445        skins = [];
2446
2447        skinMeasuredWidth = NaN;
2448        skinMeasuredHeight = NaN;
2449
2450        checkedDefaultSkin = false;
2451        defaultSkinUsesStates = false;
2452
2453        if (initialized)
2454        {
2455            viewSkin();
2456            invalidateSize();
2457        }
2458    }
2459
2460    /**
2461     *  @private
2462     */
2463    mx_internal function changeIcons():void
2464    {
2465        var n:int = icons.length;
2466        for (var i:int = 0; i < n; i++)
2467        {
2468            removeChild(icons[i]);
2469        }
2470        icons = [];
2471
2472        checkedDefaultIcon = false;
2473        defaultIconUsesStates = false;
2474    }
2475
2476    /**
2477     *  @private
2478     */
2479    mx_internal function buttonPressed():void
2480    {
2481        phase = ButtonPhase.DOWN;
2482
2483        dispatchEvent(new FlexEvent(FlexEvent.BUTTON_DOWN));
2484
2485        if (autoRepeat)
2486        {
2487            autoRepeatTimer.delay = getStyle("repeatDelay");
2488            autoRepeatTimer.addEventListener(
2489                TimerEvent.TIMER, autoRepeatTimer_timerDelayHandler);
2490            autoRepeatTimer.start();
2491        }
2492    }
2493
2494    /**
2495     *  @private
2496     */
2497    mx_internal function buttonReleased():void
2498    {
2499        // Remove the handlers that were added in mouseDownHandler().
2500        systemManager.getSandboxRoot().removeEventListener(
2501            MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);
2502        systemManager.getSandboxRoot().removeEventListener(
2503            SandboxMouseEvent.MOUSE_UP_SOMEWHERE, stage_mouseLeaveHandler);
2504
2505        if (autoRepeatTimer)
2506        {
2507            autoRepeatTimer.removeEventListener(
2508                TimerEvent.TIMER, autoRepeatTimer_timerDelayHandler);
2509            autoRepeatTimer.removeEventListener(
2510                TimerEvent.TIMER, autoRepeatTimer_timerHandler);
2511            autoRepeatTimer.reset();
2512        }
2513    }
2514
2515    /**
2516     *  @private
2517     *  Some other components which use a Button as an internal
2518     *  subcomponent need access to its UITextField, but can't access the
2519     *  textField var because it is protected and therefore available
2520     *  only to subclasses.
2521     */
2522    mx_internal function getTextField():IUITextField
2523    {
2524        return textField;
2525    }
2526
2527    //--------------------------------------------------------------------------
2528    //
2529    //  Overridden event handlers: UIComponent
2530    //
2531    //--------------------------------------------------------------------------
2532
2533    /**
2534     *  @private
2535     */
2536    override protected function focusOutHandler(event:FocusEvent):void
2537    {
2538        super.focusOutHandler(event);
2539
2540        // Most of the time the system sends a rollout, but there are
2541        // situations where the mouse is over something else
2542        // that you don't get one so we force one here.
2543        if (phase != ButtonPhase.UP)
2544            phase = ButtonPhase.UP;
2545    }
2546
2547    /**
2548     *  @private
2549     */
2550    override protected function keyDownHandler(event:KeyboardEvent):void
2551    {
2552        if (!enabled)
2553            return;
2554
2555        if (event.keyCode == Keyboard.SPACE)
2556            buttonPressed();
2557    }
2558
2559    /**
2560     *  @private
2561     */
2562    override protected function keyUpHandler(event:KeyboardEvent):void
2563    {
2564        if (!enabled)
2565            return;
2566
2567        if (event.keyCode == Keyboard.SPACE)
2568        {
2569            buttonReleased();
2570
2571            if (phase == ButtonPhase.DOWN)
2572                dispatchEvent(new MouseEvent(MouseEvent.CLICK));
2573            phase = ButtonPhase.UP;
2574        }
2575    }
2576
2577    //--------------------------------------------------------------------------
2578    //
2579    //  Event handlers
2580    //
2581    //--------------------------------------------------------------------------
2582
2583    /*
2584
2585    Mouse interaction sequences that Button must handle:
2586
2587    All start with Button in "up" phase, mouse outside Button,
2588    and mouse button up.
2589
2590    Normal click:
2591        roll over Button -> "over" phase
2592        mouse down on Button -> "down" phase, dispatch "buttonDown"
2593        mouse up while over Button -> "over" phase, dispatch "click"
2594        roll out of Button -> "up" phase
2595
2596    Click canceled:
2597        roll over Button -> "over" phase
2598        mouse down on Button -> "down" phase, dispatch "buttonDown"
2599        roll out of Button -> "over" phase
2600        maybe roll over and out of other objects -> dispatch events from them
2601        maybe roll off the stage, or off and back on
2602        mouse up while out of Button -> "up" phase
2603        if mouseup was over another Button, it goes into "over" phase
2604
2605    Click resumed:
2606        roll over Button -> "over" phase
2607        mouse down on Button -> "down" phase, dispatch "buttonDown"
2608        roll out of Button -> "over" phase
2609        maybe roll over and out of other objects -> dispatch events from them
2610        roll over Button -> "down" phase
2611        maybe roll off the stage, or off and back on
2612        maybe repeat last four steps
2613        mouse up while over Button -> "over" phase, dispatch "click"
2614        roll out of Button -> "up" phase
2615
2616    Drag over and out
2617        mouse down while out of Button
2618        roll over Button -> stay in "up" phase
2619        roll out of Button -> stay in "up" phase
2620
2621    Drag over and up
2622        mouse down while out of Button
2623        roll over Button -> stay in "up" phase
2624        mouse up while over Button -> "over" phase
2625        continue with step 2 of first three sequences above
2626
2627    */
2628
2629    /**
2630     *  The default handler for the <code>MouseEvent.ROLL_OVER</code> event.
2631     *
2632     *  @param The event object.
2633     *
2634     *  @langversion 3.0
2635     *  @playerversion Flash 9
2636     *  @playerversion AIR 1.1
2637     *  @productversion Flex 3
2638     */
2639    protected function rollOverHandler(event:MouseEvent):void
2640    {
2641
2642        // Note that we don't prevent the propagation of rollOver
2643        // from a disabled Button.
2644        // Developers may want to detect this low-level event.
2645
2646        if (phase == ButtonPhase.UP)
2647        {
2648            if (event.buttonDown)
2649                return;
2650
2651            phase = ButtonPhase.OVER;
2652
2653            // Force a "render" event, which will cause updateDisplayList()
2654            // to show the appropriate skin for the new phase.
2655            event.updateAfterEvent();
2656        }
2657
2658        else if (phase == ButtonPhase.OVER)
2659        {
2660            phase = ButtonPhase.DOWN;
2661
2662            // Force a "render" event, which will cause updateDisplayList()
2663            // to show the appropriate skin for the new phase.
2664            event.updateAfterEvent();
2665
2666            // The mouse is back over the Button and the Button is down again,
2667            // so resume auto-repeating.
2668            if (autoRepeatTimer)
2669                autoRepeatTimer.start();
2670        }
2671    }
2672
2673    /**
2674     *  The default handler for the <code>MouseEvent.ROLL_OUT</code> event.
2675     *
2676     *  @param The event object.
2677     *
2678     *  @langversion 3.0
2679     *  @playerversion Flash 9
2680     *  @playerversion AIR 1.1
2681     *  @productversion Flex 3
2682     */
2683    protected function rollOutHandler(event:MouseEvent):void
2684    {
2685
2686        // Note that we don't prevent the propagation of rollOut
2687        // from a disabled Button.
2688        // Developers may want to detect this low-level event.
2689
2690        if (phase == ButtonPhase.OVER)
2691        {
2692            phase = ButtonPhase.UP;
2693
2694            // Force a "render" event, which will cause updateDisplayList()
2695            // to show the appropriate skin for the new phase.
2696            event.updateAfterEvent();
2697        }
2698
2699        else if (phase == ButtonPhase.DOWN && !stickyHighlighting)
2700        {
2701            phase = ButtonPhase.OVER;
2702
2703            // Force a "render" event, which will cause updateDisplayList()
2704            // to show the appropriate skin for the new phase.
2705            event.updateAfterEvent();
2706
2707            // If the Button no longer looks "down", it shouldn't auto-repeat.
2708            if (autoRepeatTimer)
2709                autoRepeatTimer.stop();
2710        }
2711    }
2712
2713    /**
2714     *  The default handler for the <code>MouseEvent.MOUSE_DOWN</code> event.
2715     *
2716     *  @param The event object.
2717     *
2718     *  @langversion 3.0
2719     *  @playerversion Flash 9
2720     *  @playerversion AIR 1.1
2721     *  @productversion Flex 3
2722     */
2723    protected function mouseDownHandler(event:MouseEvent):void
2724    {
2725        if (!enabled)
2726            return;
2727
2728        // Note that we don't prevent the propagation of mouseDown
2729        // from a disabled Button.
2730        // Developers may want to detect this low-level event.
2731
2732        // In case the user drags out of the Button and then releases
2733        // the mouse button, we need to get the mouseUp.
2734        // To accomplish this, we temporarily place a capture-phase
2735        // mouseUp handler on the SystemManager.
2736        // We also place a mouseLeave handler on the stage
2737        // in case the user drags off the stage and releases the mouse.
2738        // These handlers are removed in buttonReleased().
2739        systemManager.getSandboxRoot().addEventListener(
2740            MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);
2741        systemManager.getSandboxRoot().addEventListener(
2742            SandboxMouseEvent.MOUSE_UP_SOMEWHERE, stage_mouseLeaveHandler);
2743
2744        buttonPressed();
2745
2746        // Force a "render" event, which will cause updateDisplayList()
2747        // to show the appropriate skin for the new phase.
2748        event.updateAfterEvent();
2749    }
2750
2751    /**
2752     *  The default handler for the <code>MouseEvent.MOUSE_UP</code> event.
2753     *
2754     *  @param The event object.
2755     *
2756     *  @langversion 3.0
2757     *  @playerversion Flash 9
2758     *  @playerversion AIR 1.1
2759     *  @productversion Flex 3
2760     */
2761    protected function mouseUpHandler(event:MouseEvent):void
2762    {
2763        if (!enabled)
2764            return;
2765
2766        // Note that we don't prevent the propagation of mouseUp
2767        // from a disabled Button.
2768        // Developers may want to detect this low-level event.
2769        phase = ButtonPhase.OVER;
2770        buttonReleased();
2771
2772        // Force a "render" event, which will cause updateDisplayList()
2773        // to show the appropriate skin for the new phase.
2774        if (!toggle)
2775            event.updateAfterEvent();
2776    }
2777
2778    /**
2779     *  The default handler for the <code>MouseEvent.CLICK</code> event.
2780     *
2781     *  @param The event object.
2782     *
2783     *  @langversion 3.0
2784     *  @playerversion Flash 9
2785     *  @playerversion AIR 1.1
2786     *  @productversion Flex 3
2787     */
2788    protected function clickHandler(event:MouseEvent):void
2789    {
2790        if (!enabled)
2791        {
2792            // Prevent the propagation of click from a disabled Button.
2793            // This is conceptually a higher-level event and
2794            // developers will expect their click handlers not to fire
2795            // if the Button is disabled.
2796            event.stopImmediatePropagation();
2797            return;
2798        }
2799
2800        if (toggle)
2801        {
2802            setSelected(!selected);
2803            event.updateAfterEvent();
2804        }
2805
2806
2807    }
2808
2809    /**
2810     *  @private
2811     *  This method is called when the user has pressed the Button
2812     *  and then released the mouse button anywhere.
2813     *  It's purpose is to get the mouseUp event when the user has
2814     *  dragged out of the Button before releasing.
2815     *  However, it gets an inside mouseUp as well;
2816     *  we have to check for this case becuase mouseHandler()
2817     *  already deals with it..
2818     */
2819    private function systemManager_mouseUpHandler(event:MouseEvent):void
2820    {
2821        // If the mouse button was released over the Button,
2822        // mouseUpHandler() will handle it, so do nothing.
2823        if (contains(DisplayObject(event.target)))
2824            return;
2825
2826        phase = ButtonPhase.UP;
2827        buttonReleased();
2828
2829        // Force a "render" event, which will cause updateDisplayList()
2830        // to show the appropriate skin for the new phase.
2831        event.updateAfterEvent();
2832    }
2833
2834    /**
2835     *  @private
2836     *  This method is called when the user has pressed the Button,
2837     *  dragged of the stage, and released the mouse button.
2838     */
2839    private function stage_mouseLeaveHandler(event:Event):void
2840    {
2841        phase = ButtonPhase.UP;
2842        buttonReleased();
2843    }
2844
2845    /**
2846     *  @private
2847     */
2848    private function autoRepeatTimer_timerDelayHandler(event:Event):void
2849    {
2850        if (!enabled)
2851            return;
2852
2853        dispatchEvent(new FlexEvent(FlexEvent.BUTTON_DOWN));
2854
2855        if (autoRepeat)
2856        {
2857            autoRepeatTimer.reset();
2858            autoRepeatTimer.removeEventListener(
2859                TimerEvent.TIMER, autoRepeatTimer_timerDelayHandler);
2860            autoRepeatTimer.delay = getStyle("repeatInterval");
2861            autoRepeatTimer.addEventListener(
2862                TimerEvent.TIMER, autoRepeatTimer_timerHandler);
2863            autoRepeatTimer.start();
2864        }
2865    }
2866
2867    /**
2868     *  @private
2869     */
2870    private function autoRepeatTimer_timerHandler(event:Event):void
2871    {
2872        if (!enabled)
2873            return;
2874
2875        dispatchEvent(new FlexEvent(FlexEvent.BUTTON_DOWN));
2876    }
2877}
2878
2879}
2880