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 * <fx:style> 575 * @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 * </fx:style> 585 * ... 586 * <mx:Button ... styleName="myBoldStyle"/> 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><mx:Button></code> tag inherits all the tag attributes 600 * of its superclass, and adds the following tag attributes:</p> 601 * 602 * <pre> 603 * <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 * /> 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