1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2004-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.sliderClasses 13{ 14 15import flash.display.DisplayObject; 16import flash.display.Graphics; 17import flash.display.Sprite; 18import flash.events.Event; 19import flash.events.FocusEvent; 20import flash.events.KeyboardEvent; 21import flash.events.MouseEvent; 22import flash.geom.Point; 23import flash.utils.getTimer; 24import mx.core.FlexVersion; 25import mx.core.IFlexDisplayObject; 26import mx.core.mx_internal; 27import mx.core.UIComponent; 28import mx.effects.Tween; 29import mx.events.FlexEvent; 30import mx.events.SliderEvent; 31import mx.events.SliderEventClickTarget; 32import mx.formatters.NumberFormatter; 33import mx.managers.ISystemManager; 34import mx.managers.SystemManager; 35import mx.styles.ISimpleStyleClient; 36import mx.styles.StyleProxy; 37 38use namespace mx_internal; 39 40//-------------------------------------- 41// Events 42//-------------------------------------- 43 44/** 45 * Dispatched when the slider changes value due to mouse or keyboard interaction. 46 * 47 * <p>If the <code>liveDragging</code> property is <code>true</code>, 48 * the event is dispatched continuously as the user moves the thumb. 49 * If <code>liveDragging</code> is <code>false</code>, 50 * the event is dispatched when the user releases the slider thumb.</p> 51 * 52 * @eventType mx.events.SliderEvent.CHANGE 53 */ 54[Event(name="change", type="mx.events.SliderEvent")] 55 56/** 57 * Dispatched when the slider's thumb is pressed and then moved by the mouse. 58 * This event is always preceded by a <code>thumbPress</code> event. 59 * @eventType mx.events.SliderEvent.THUMB_DRAG 60 */ 61[Event(name="thumbDrag", type="mx.events.SliderEvent")] 62 63/** 64 * Dispatched when the slider's thumb is pressed, meaning 65 * the user presses the mouse button over the thumb. 66 * 67 * @eventType mx.events.SliderEvent.THUMB_PRESS 68 */ 69[Event(name="thumbPress", type="mx.events.SliderEvent")] 70 71/** 72 * Dispatched when the slider's thumb is released, 73 * meaning the user releases the mouse button after 74 * a <code>thumbPress</code> event. 75 * 76 * @eventType mx.events.SliderEvent.THUMB_RELEASE 77 */ 78[Event(name="thumbRelease", type="mx.events.SliderEvent")] 79 80//-------------------------------------- 81// Styles 82//-------------------------------------- 83 84include "../../styles/metadata/FillStyles.as"; 85 86/** 87 * The color of the black section of the border. 88 * 89 * @default 0x919999 90 */ 91[Style(name="borderColor", type="uint", format="Color", inherit="no")] 92 93/** 94 * Invert the direction of the thumbs. 95 * If <code>true</code>, the thumbs will be flipped. 96 * 97 * @default false 98 */ 99[Style(name="invertThumbDirection", type="Boolean", inherit="no")] 100 101/** 102 * The y-position offset (if direction is horizontal) 103 * or x-position offset (if direction is vertical) 104 * of the labels relative to the track. 105 * 106 * @default -10 107 */ 108[Style(name="labelOffset", type="Number", format="Length", inherit="no")] 109 110/** 111 * The name of the style to use for the slider label. 112 * 113 * @default undefined 114 */ 115[Style(name="labelStyleName", type="String", inherit="no")] 116 117/** 118 * Duration in milliseconds for the sliding animation 119 * when you click on the track to move a thumb. 120 * 121 * @default 300 122 */ 123[Style(name="slideDuration", type="Number", format="Time", inherit="no")] 124 125/** 126 * Tweening function used by the sliding animation 127 * when you click on the track to move a thumb. 128 * 129 * @default undefined 130 */ 131[Style(name="slideEasingFunction", type="Function", inherit="no")] 132 133/** 134 * The y-position offset (if direction is horizontal) 135 * or x-position offset (if direction is vertical) 136 * of the thumb relative to the track. 137 * 138 * @default 0 139 */ 140[Style(name="thumbOffset", type="Number", format="Length", inherit="no")] 141 142/** 143 * The color of the tick marks. 144 * Can be a hex color value or the string name of a known color. 145 * 146 * @default 0x6F7777. 147 */ 148[Style(name="tickColor", type="uint", format="Color", inherit="no")] 149 150/** 151 * The length in pixels of the tick marks. 152 * If <code>direction</code> is <code>Direction.HORIZONTAL</code>, 153 * then adjust the height of the tick marks. 154 * If <code>direction</code> is <code>Direction.VERTICAL</code>, 155 * then adjust the width. 156 * 157 * @default 3 158 */ 159[Style(name="tickLength", type="Number", format="Length", inherit="no")] 160 161/** 162 * The y-position offset (if direction is horizontal) 163 * or x-position offset (if direction is vertical) 164 * of the tick marks relative to the track. 165 * 166 * @default -6 167 */ 168[Style(name="tickOffset", type="Number", format="Length", inherit="no")] 169 170/** 171 * The thickness in pixels of the tick marks. 172 * If direction is horizontal, 173 * then adjust the width of the tick marks. 174 * If direction is vertical, 175 * then adjust the height. 176 * 177 * @default 1 178 */ 179[Style(name="tickThickness", type="Number", format="Length", inherit="no")] 180 181/** 182 * The colors of the track, as an array of two colors. 183 * You can use the same color twice for a solid track color. 184 * 185 * <p>You use this property along with the <code>fillAlphas</code> 186 * property. Typically you set <code>fillAlphas</code> to [ 1.0, 1.0 ] 187 * when setting <code>trackColors</code>.</p> 188 * 189 * @default [ 0xE7E7E7, 0xE7E7E7 ] 190 */ 191[Style(name="trackColors", type="Array", arrayType="uint", format="Color", inherit="no")] 192 193/** 194 * Specifies whether to enable track highlighting between thumbs 195 * (or a single thumb and the beginning of the track). 196 * 197 * @default false 198 */ 199[Style(name="showTrackHighlight", type="Boolean", inherit="no")] 200 201/** 202 * The size of the track margins, in pixels. 203 * If <code>undefined</code>, then the track margins will be determined 204 * by the length of the first and last labels. 205 * If given a value, Flex attempts to fit the labels in the available space. 206 * 207 * @default undefined 208 */ 209[Style(name="trackMargin", type="Number", format="Length", inherit="no")] 210 211/** 212 * The name of the style declaration to use for the data tip. 213 * 214 * @default undefined 215 */ 216[Style(name="dataTipStyleName", type="String", inherit="no")] 217 218/** 219 * The offset, in pixels, of the data tip relative to the thumb. 220 * Used in combination with the <code>dataTipPlacement</code> 221 * style property of the HSlider and VSlider controls. 222 * 223 * @default 16 224 */ 225[Style(name="dataTipOffset", type="Number", format="Length", inherit="no")] 226 227/** 228 * Number of decimal places to use for the data tip text. 229 * A value of 0 means to round all values to an integer. 230 * 231 * @default 2 232 */ 233[Style(name="dataTipPrecision", type="int", inherit="no")] 234 235/** 236 * The default skin for the slider thumb. 237 * 238 * @default SliderThumbSkin 239 */ 240[Style(name="thumbSkin", type="Class", inherit="no", states="up, over, down, disabled")] 241 242/** 243 * The skin for the slider thumb up state. 244 * 245 * @default SliderThumbSkin 246 */ 247[Style(name="thumbUpSkin", type="Class", inherit="no")] 248 249/** 250 * The skin for the slider thumb over state. 251 * 252 * @default SliderThumbSkin 253 */ 254[Style(name="thumbOverSkin", type="Class", inherit="no")] 255 256/** 257 * The skin for the slider thumb down state. 258 * 259 * @default SliderThumbSkin 260 */ 261[Style(name="thumbDownSkin", type="Class", inherit="no")] 262 263/** 264 * The skin for the slider thumb disabled state. 265 * 266 * @default SliderThumbSkin 267 */ 268[Style(name="thumbDisabledSkin", type="Class", inherit="no")] 269 270/** 271 * The skin for the slider track when it is selected. 272 */ 273[Style(name="trackHighlightSkin", type="Class", inherit="no")] 274 275/** 276 * The skin for the slider track. 277 */ 278[Style(name="trackSkin", type="Class", inherit="no")] 279 280//-------------------------------------- 281// Other metadata 282//-------------------------------------- 283 284[AccessibilityClass(implementation="mx.accessibility.SliderAccImpl")] 285 286[ResourceBundle("SharedResources")] 287 288/** 289 * The Slider class is the base class for the Flex slider controls. 290 * The slider controls let users select a value by moving a slider thumb 291 * between the end points of the slider 292 * track. The current value of the slider is determined by 293 * the relative location of the thumb between the 294 * end points of the slider, corresponding to the slider's minimum and maximum values. 295 * The Slider class is subclassed by HSlider and VSlider. 296 * 297 * @mxml 298 * 299 * <p>The Slider class cannot be used as an MXML tag. Use the <code><mx:HSlider></code> 300 * and <code><mx:VSlider></code> tags instead. However, the Slider class does define tag 301 * attributes used by the <code><mx:HSlider></code> and <code><mx:VSlider></code> tags. </p> 302 * 303 * <p>The Slider class inherits all of the tag attributes 304 * of its superclass, and adds the following tag attributes:</p> 305 * 306 * <pre> 307 * <mx:<i>tagname</i> 308 * <strong>Properties</strong> 309 * allowThumbOverlap="false|true" 310 * allowTrackClick="true|false" 311 * dataTipFormatFunction="undefined" 312 * direction="horizontal|vertical" 313 * labels="undefined" 314 * liveDragging="false|true" 315 * maximum="10" 316 * minimum="0" 317 * showDataTip="true|false" 318 * sliderDataTipClass="sliderDataTip" 319 * sliderThumbClass="SliderThumb" 320 * snapInterval="0" 321 * thumbCount="1" 322 * tickInterval="0" 323 * tickValues="undefined" 324 * value="<i>The value of the minimum property.</i>" 325 * 326 * <strong>Styles</strong> 327 * borderColor="0x919999" 328 * dataTipOffset="16" 329 * dataTipPrecision="2" 330 * dataTipStyleName="undefined" 331 * fillAlphas="[0.6, 0.4, 0.75, 0.65]" 332 * fillColors="[0xFFFFFF, 0xCCCCCC, 0xFFFFFF, 0xEEEEEE;]" 333 * labelOffset="-10" 334 * labelStyleName="undefined" 335 * showTrackHighlight="false" 336 * slideDuration="300" 337 * slideEasingFunction="undefined" 338 * thumbDisabledSkin="SliderThumbSkin" 339 * thumbDownSkin="SliderThumbSkin" 340 * thumbOffset="0" 341 * thumbOverSkin="SliderThumbSkin" 342 * thumbUpSkin="SliderThumbSkin" 343 * tickColor="0x6F7777" 344 * tickLength="3" 345 * tickOffset="-6" 346 * tickThickness="1" 347 * trackColors="[ 0xEEEEEE, 0xFFFFFF ]" 348 * tracHighlightSkin="SliderHighlightSkin" 349 * trackMargin="undefined" 350 * trackSkin="SliderTrackSkin" 351 * 352 * <strong>Events</strong> 353 * change="<i>No default</i>" 354 * thumbDrag="<i>No default</i>" 355 * thumbPress="<i>No default</i>" 356 * thumbRelease="<i>No default</i>" 357 * /> 358 * </pre> 359 */ 360public class Slider extends UIComponent 361{ 362 include "../../core/Version.as"; 363 364 //-------------------------------------------------------------------------- 365 // 366 // Class mixins 367 // 368 //-------------------------------------------------------------------------- 369 370 /** 371 * @private 372 * Placeholder for mixin by SliderAccImpl. 373 */ 374 mx_internal static var createAccessibilityImplementation:Function; 375 376 //-------------------------------------------------------------------------- 377 // 378 // Constructor 379 // 380 //-------------------------------------------------------------------------- 381 382 /** 383 * Constructor. 384 */ 385 public function Slider() 386 { 387 super(); 388 389 tabChildren = true; 390 } 391 392 //-------------------------------------------------------------------------- 393 // 394 // Variables 395 // 396 //-------------------------------------------------------------------------- 397 398 /** 399 * @private 400 */ 401 private var track:IFlexDisplayObject; 402 403 /** 404 * @private 405 */ 406 private var thumbs:UIComponent; 407 408 /** 409 * @private 410 */ 411 private var thumbsChanged:Boolean = true; 412 413 /** 414 * @private 415 */ 416 private var ticks:UIComponent; 417 418 /** 419 * @private 420 */ 421 private var ticksChanged:Boolean = false; 422 423 /** 424 * @private 425 */ 426 private var labelObjects:UIComponent; 427 428 /** 429 * @private 430 */ 431 private var highlightTrack:IFlexDisplayObject; 432 433 /** 434 * @private 435 */ 436 mx_internal var innerSlider:UIComponent; 437 438 /** 439 * @private 440 */ 441 private var trackHitArea:UIComponent; 442 443 /** 444 * @private 445 */ 446 mx_internal var dataTip:SliderDataTip; 447 448 /** 449 * @private 450 */ 451 private var trackHighlightChanged:Boolean = true; 452 453 /** 454 * @private 455 */ 456 private var initValues:Boolean = true; // Always initValues at startup 457 458 /** 459 * @private 460 */ 461 private var dataFormatter:NumberFormatter; 462 463 /** 464 * @private 465 */ 466 private var interactionClickTarget:String; 467 468 /** 469 * @private 470 */ 471 private var labelStyleChanged:Boolean = false; 472 473 /** 474 * @private 475 * is the last interaction from the keyboard? 476 */ 477 mx_internal var keyInteraction:Boolean = false; 478 479 //-------------------------------------------------------------------------- 480 // 481 // Overridden properties 482 // 483 //-------------------------------------------------------------------------- 484 485 //---------------------------------- 486 // baselinePosition 487 //---------------------------------- 488 489 /** 490 * @private 491 */ 492 override public function get baselinePosition():Number 493 { 494 if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0) 495 return super.baselinePosition; 496 497 if (!validateBaselinePosition()) 498 return NaN; 499 500 return int(0.75 * height); 501 } 502 503 //---------------------------------- 504 // enabled 505 //---------------------------------- 506 507 /** 508 * @private 509 */ 510 private var _enabled:Boolean; 511 512 /** 513 * @private 514 */ 515 private var enabledChanged:Boolean = false; 516 517 [Inspectable(category="General", enumeration="true,false", defaultValue="true")] 518 519 /** 520 * @private 521 */ 522 override public function get enabled():Boolean 523 { 524 return _enabled; 525 } 526 527 /** 528 * @private 529 */ 530 override public function set enabled(value:Boolean):void 531 { 532 _enabled = value; 533 enabledChanged = true; 534 535 invalidateProperties(); 536 } 537 538 /** 539 * @private 540 */ 541 private var _tabIndex:Number; 542 543 /** 544 * @private 545 */ 546 private var tabIndexChanged:Boolean; 547 548 /** 549 * @private 550 */ 551 override public function set tabIndex(value:int):void 552 { 553 super.tabIndex = value; 554 _tabIndex = value; 555 556 tabIndexChanged = true; 557 invalidateProperties(); 558 } 559 560 //-------------------------------------------------------------------------- 561 // 562 // Properties 563 // 564 //-------------------------------------------------------------------------- 565 566 //---------------------------------- 567 // allowThumbOverlap 568 //---------------------------------- 569 570 [Inspectable(defaultValue="false")] 571 572 /** 573 * If set to <code>false</code>, then each thumb can only be moved to the edge of 574 * the adjacent thumb. 575 * If <code>true</code>, then each thumb can be moved to any position on the track. 576 * 577 * @default false 578 */ 579 public var allowThumbOverlap:Boolean = false; 580 581 //---------------------------------- 582 // allowTrackClick 583 //---------------------------------- 584 585 [Inspectable(defaultValue="true")] 586 587 /** 588 * Specifies whether clicking on the track will move the slider thumb. 589 * 590 * @default true 591 */ 592 public var allowTrackClick:Boolean = true; 593 594 //---------------------------------- 595 // dataTipFormatFunction 596 //---------------------------------- 597 598 /** 599 * @private 600 */ 601 private var _dataTipFormatFunction:Function; 602 603 /** 604 * Callback function that formats the data tip text. 605 * The function takes a single Number as an argument 606 * and returns a formatted String. 607 * 608 * <p>The function has the following signature:</p> 609 * <pre> 610 * funcName(value:Number):String 611 * </pre> 612 * 613 * <p>The following example prefixes the data tip text with a dollar sign and 614 * formats the text using the <code>dataTipPrecision</code> 615 * of a Slider Control named 'slide': </p> 616 * 617 * <pre> 618 * import mx.formatters.NumberBase; 619 * function myDataTipFormatter(value:Number):String { 620 * var dataFormatter:NumberBase = new NumberBase(".", ",", ".", ""); 621 * return "$ " + dataFormatter.formatPrecision(String(value), slide.getStyle("dataTipPrecision")); 622 * } 623 * </pre> 624 * 625 * @default undefined 626 */ 627 public function get dataTipFormatFunction():Function 628 { 629 return _dataTipFormatFunction; 630 } 631 632 /** 633 * @private 634 */ 635 public function set dataTipFormatFunction(value:Function):void 636 { 637 _dataTipFormatFunction = value; 638 } 639 640 //---------------------------------- 641 // direction 642 //---------------------------------- 643 644 /** 645 * @private 646 */ 647 private var _direction:String = SliderDirection.HORIZONTAL; 648 649 /** 650 * @private 651 */ 652 private var directionChanged:Boolean = false; 653 654 [Inspectable(defaultValue="horizontal")] 655 656 /** 657 * The orientation of the slider control. 658 * Valid values in MXML are <code>"horizontal"</code> or <code>"vertical"</code>. 659 * 660 * <p>In ActionScript, you use the following constants 661 * to set this property: 662 * <code>SliderDirection.VERTICAL</code> and 663 * <code>SliderDirection.HORIZONTAL</code>.</p> 664 * 665 * The HSlider and VSlider controls set this property for you; 666 * do not set it when using those controls. 667 * 668 * @default SliderDirection.HORIZONTAL 669 * @see mx.controls.sliderClasses.SliderDirection 670 */ 671 public function get direction():String 672 { 673 return _direction; 674 } 675 676 /** 677 * @private 678 */ 679 public function set direction(value:String):void 680 { 681 _direction = value; 682 directionChanged = true; 683 684 invalidateProperties(); 685 invalidateSize(); 686 invalidateDisplayList(); 687 } 688 689 //---------------------------------- 690 // labels 691 //---------------------------------- 692 693 /** 694 * @private 695 */ 696 private var _labels:Array = []; 697 698 /** 699 * @private 700 */ 701 private var labelsChanged:Boolean = false; 702 703 [Inspectable(category="General", arrayType="String", defaultValue="undefined")] 704 705 /** 706 * An array of strings used for the slider labels. 707 * Flex positions the labels at the beginning of the track, 708 * and spaces them evenly between the beginning of the track 709 * and the end of the track. 710 * 711 * <p>For example, if the array contains three items, 712 * the first item is placed at the beginning of the track, 713 * the second item in the middle, and the last item 714 * at the end of the track.</p> 715 * 716 * <p>If only one label is specified, it is placed at the 717 * beginning of the track. 718 * By default, labels are placed above the tick marks 719 * (if present) or above the track. 720 * To align the labels with the tick marks, make sure that 721 * the number of tick marks is equal to the number of labels.</p> 722 * 723 * @default undefined 724 */ 725 public function get labels():Array 726 { 727 return _labels; 728 } 729 730 /** 731 * @private 732 */ 733 public function set labels(value:Array):void 734 { 735 _labels = value; 736 labelsChanged = true; 737 738 invalidateProperties(); 739 invalidateSize(); 740 invalidateDisplayList(); 741 } 742 743 //---------------------------------- 744 // liveDragging 745 //---------------------------------- 746 747 [Inspectable(category="General", defaultValue="false")] 748 749 /** 750 * Specifies whether live dragging is enabled for the slider. 751 * If <code>false</code>, Flex sets the <code>value</code> and 752 * <code>values</code> properties and dispatches the <code>change</code> 753 * event when the user stops dragging the slider thumb. 754 * If <code>true</code>, Flex sets the <code>value</code> and 755 * <code>values</code> properties and dispatches the <code>change</code> 756 * event continuously as the user moves the thumb. 757 * 758 * @default false 759 */ 760 public var liveDragging:Boolean = false; 761 762 //---------------------------------- 763 // maximum 764 //---------------------------------- 765 766 /** 767 * @private 768 * Storage for the maximum property. 769 */ 770 private var _maximum:Number = 10; 771 772 [Inspectable(category="General", defaultValue="10")] 773 774 /** 775 * The maximum allowed value on the slider. 776 * 777 * @default 10 778 */ 779 public function get maximum():Number 780 { 781 return _maximum; 782 } 783 784 /** 785 * @private 786 */ 787 public function set maximum(value:Number):void 788 { 789 _maximum = value; 790 ticksChanged = true; 791 if (!initValues) 792 valuesChanged = true; 793 794 invalidateProperties(); 795 invalidateDisplayList(); 796 } 797 798 //---------------------------------- 799 // minimum 800 //---------------------------------- 801 802 /** 803 * @private 804 * Storage for the minimum property. 805 */ 806 private var _minimum:Number = 0; 807 808 /** 809 * @private 810 */ 811 private var minimumSet:Boolean = false; 812 813 [Inspectable(category="General", defaultValue="0")] 814 815 /** 816 * The minimum allowed value on the slider control. 817 * 818 * @default 0 819 */ 820 public function get minimum():Number 821 { 822 return _minimum; 823 } 824 825 /** 826 * @private 827 */ 828 public function set minimum(value:Number):void 829 { 830 _minimum = value; 831 ticksChanged = true; 832 833 if (!initValues) 834 valuesChanged = true; 835 836 invalidateProperties(); 837 invalidateDisplayList(); 838 } 839 840 //---------------------------------- 841 // showDataTip 842 //---------------------------------- 843 844 [Inspectable(category="General", defaultValue="true")] 845 846 /** 847 * If set to <code>true</code>, show a data tip during user interaction 848 * containing the current value of the slider. 849 * 850 * @default true 851 */ 852 public var showDataTip:Boolean = true; 853 854 //---------------------------------- 855 // sliderThumbClass 856 //---------------------------------- 857 858 /** 859 * @private 860 */ 861 private var _thumbClass:Class = SliderThumb; 862 863 /** 864 * A reference to the class to use for each thumb. 865 * 866 * @default SliderThumb 867 */ 868 public function get sliderThumbClass():Class 869 { 870 return _thumbClass; 871 } 872 873 /** 874 * @private 875 */ 876 public function set sliderThumbClass(value:Class):void 877 { 878 _thumbClass = value; 879 thumbsChanged = true; 880 881 invalidateProperties(); 882 invalidateDisplayList(); 883 } 884 885 //---------------------------------- 886 // sliderDataTipClass 887 //---------------------------------- 888 889 /** 890 * @private 891 */ 892 private var _sliderDataTipClass:Class = SliderDataTip; 893 894 /** 895 * A reference to the class to use for the data tip. 896 * 897 * @default SliderDataTip 898 */ 899 public function get sliderDataTipClass():Class 900 { 901 return _sliderDataTipClass; 902 } 903 904 /** 905 * @private 906 */ 907 public function set sliderDataTipClass(value:Class):void 908 { 909 _sliderDataTipClass = value; 910 911 invalidateProperties(); 912 } 913 914 //---------------------------------- 915 // snapInterval 916 //---------------------------------- 917 918 /** 919 * @private 920 */ 921 private var _snapInterval:Number = 0; 922 923 /** 924 * @private 925 */ 926 private var snapIntervalPrecision:int = -1; 927 928 /** 929 * @private 930 */ 931 private var snapIntervalChanged:Boolean = false; 932 933 [Inspectable(category="General", defaultValue="0")] 934 935 /** 936 * Specifies the increment value of the slider thumb 937 * as the user moves the thumb. 938 * For example, if <code>snapInterval</code> is 2, 939 * the <code>minimum</code> value is 0, 940 * and the <code>maximum</code> value is 10, 941 * the thumb snaps to the values 0, 2, 4, 6, 8, and 10 942 * as the user move the thumb. 943 * A value of 0, means that the slider moves continuously 944 * between the <code>minimum</code> and <code>maximum</code> values. 945 * 946 * @default 0 947 */ 948 public function get snapInterval():Number 949 { 950 return _snapInterval; 951 } 952 953 /** 954 * @private 955 */ 956 public function set snapInterval(value:Number):void 957 { 958 _snapInterval = value; 959 960 var parts:Array = (new String(1 + value)).split("."); 961 if (parts.length == 2) 962 snapIntervalPrecision = parts[1].length; 963 else 964 snapIntervalPrecision = -1; 965 966 if (!isNaN(value) && value != 0) 967 { 968 snapIntervalChanged = true; 969 970 invalidateProperties(); 971 invalidateDisplayList(); 972 } 973 } 974 975 //---------------------------------- 976 // thumbCount 977 //---------------------------------- 978 979 /** 980 * @private 981 * Storage for the thumbCount property. 982 */ 983 private var _thumbCount:int = 1; 984 985 [Inspectable(category="General", defaultValue="1")] 986 987 /** 988 * The number of thumbs allowed on the slider. 989 * Possible values are 1 or 2. 990 * If set to 1, then the <code>value</code> property contains 991 * the current value of the slider. 992 * If set to 2, then the <code>values</code> property contains 993 * an array of values representing the value for each thumb. 994 * 995 * @default 1 996 */ 997 public function get thumbCount():int 998 { 999 return _thumbCount; 1000 } 1001 1002 /** 1003 * @private 1004 */ 1005 public function set thumbCount(value:int):void 1006 { 1007 var numThumbs:int = (value > 2) ? 2 : value; 1008 numThumbs = value < 1 ? 1 : value; 1009 1010 if (numThumbs != _thumbCount) 1011 { 1012 _thumbCount = numThumbs; 1013 thumbsChanged = true; 1014 1015 initValues = true; 1016 1017 invalidateProperties(); 1018 invalidateDisplayList(); 1019 } 1020 } 1021 1022 //---------------------------------- 1023 // thumbStyleFilters 1024 //---------------------------------- 1025 1026 /** 1027 * Set of styles to pass from the Slider to the thumbs. 1028 * @see mx.styles.StyleProxy 1029 */ 1030 protected function get thumbStyleFilters():Object 1031 { 1032 return null; 1033 } 1034 //---------------------------------- 1035 // tickInterval 1036 //---------------------------------- 1037 1038 /** 1039 * @private 1040 */ 1041 private var _tickInterval:Number = 0; 1042 1043 [Inspectable(category="General", defaultValue="0")] 1044 1045 /** 1046 * The spacing of the tick marks relative to the <code>maximum</code> value 1047 * of the control. 1048 * Flex displays tick marks whenever you set the <code>tickInterval</code> 1049 * property to a nonzero value. 1050 * 1051 * <p>For example, if <code>tickInterval</code> is 1 and 1052 * <code>maximum</code> is 10, then a tick mark is placed at each 1053 * 1/10th interval along the slider. 1054 * A value of 0 shows no tick marks. If the <code>tickValues</code> property 1055 * is set to a non-empty Array, then this property is ignored.</p> 1056 * 1057 * @default 0 1058 */ 1059 public function get tickInterval():Number 1060 { 1061 return _tickInterval; 1062 } 1063 1064 /** 1065 * @private 1066 */ 1067 public function set tickInterval(value:Number):void 1068 { 1069 _tickInterval = value; 1070 ticksChanged = true; 1071 1072 invalidateProperties(); 1073 invalidateDisplayList(); 1074 } 1075 1076 1077 //---------------------------------- 1078 // tickValues 1079 //---------------------------------- 1080 1081 /** 1082 * @private 1083 */ 1084 private var _tickValues:Array = []; 1085 1086 [Inspectable(category="General", defaultValue="undefined", arrayType="Number")] 1087 1088 /** 1089 * The positions of the tick marks on the slider. The positions correspond 1090 * to the values on the slider and should be between 1091 * the <code>minimum</code> and <code>maximum</code> values. 1092 * For example, if the <code>tickValues</code> property 1093 * is [0, 2.5, 7.5, 10] and <code>maximum</code> is 10, then a tick mark is placed 1094 * in the following positions along the slider: the beginning of the slider, 1095 * 1/4 of the way in from the left, 1096 * 3/4 of the way in from the left, and at the end of the slider. 1097 * 1098 * <p>If this property is set to a non-empty Array, then the <code>tickInterval</code> property 1099 * is ignored.</p> 1100 * 1101 * @default undefined 1102 */ 1103 public function get tickValues():Array 1104 { 1105 return _tickValues; 1106 } 1107 1108 /** 1109 * @private 1110 */ 1111 public function set tickValues(value:Array):void 1112 { 1113 _tickValues = value; 1114 ticksChanged = true; 1115 1116 invalidateProperties(); 1117 invalidateDisplayList(); 1118 } 1119 1120 //---------------------------------- 1121 // value 1122 //---------------------------------- 1123 1124 [Bindable("change")] 1125 [Bindable("valueCommit")] 1126 [Inspectable(category="General", defaultValue="undefined")] 1127 1128 /** 1129 * Contains the position of the thumb, and is a number between the 1130 * <code>minimum</code> and <code>maximum</code> properties. 1131 * Use the <code>value</code> property when <code>thumbCount</code> is 1. 1132 * When <code>thumbCount</code> is greater than 1, use the 1133 * <code>values</code> property instead. 1134 * The default value is equal to the minimum property. 1135 */ 1136 public function get value():Number 1137 { 1138 return _values[0]; 1139 } 1140 1141 /** 1142 * @private 1143 */ 1144 public function set value(val:Number):void 1145 { 1146 setValueAt(val, 0, true); 1147 valuesChanged = true; 1148 minimumSet = true; 1149 1150 invalidateProperties(); 1151 invalidateDisplayList(); 1152 1153 dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT)); 1154 } 1155 1156 //---------------------------------- 1157 // values 1158 //---------------------------------- 1159 1160 /** 1161 * @private 1162 */ 1163 private var _values:Array = [ 0, 0 ]; 1164 1165 /** 1166 * @private 1167 */ 1168 private var valuesChanged:Boolean = false; 1169 1170 [Bindable("change")] 1171 [Inspectable(category="General", arrayType="Number")] 1172 1173 /** 1174 * An array of values for each thumb when <code>thumbCount</code> 1175 * is greater than 1. 1176 */ 1177 public function get values():Array 1178 { 1179 return _values; 1180 } 1181 1182 /** 1183 * @private 1184 */ 1185 public function set values(value:Array):void 1186 { 1187 _values = value; 1188 valuesChanged = true; 1189 minimumSet = true; 1190 1191 invalidateProperties(); 1192 invalidateDisplayList(); 1193 } 1194 1195 //-------------------------------------------------------------------------- 1196 // 1197 // Overridden methods 1198 // 1199 //-------------------------------------------------------------------------- 1200 1201 /** 1202 * @private 1203 */ 1204 override protected function initializeAccessibility():void 1205 { 1206 if (Slider.createAccessibilityImplementation != null) 1207 Slider.createAccessibilityImplementation(this); 1208 } 1209 1210 /** 1211 * @private 1212 */ 1213 override protected function createChildren():void 1214 { 1215 super.createChildren(); 1216 1217 if (!innerSlider) 1218 { 1219 innerSlider = new UIComponent(); 1220 UIComponent(innerSlider).tabChildren = true; 1221 addChild(innerSlider); 1222 } 1223 1224 createBackgroundTrack(); 1225 1226 if (!trackHitArea) 1227 { 1228 trackHitArea = new UIComponent(); 1229 innerSlider.addChild(trackHitArea); // trackHitArea should always be on top 1230 1231 trackHitArea.addEventListener(MouseEvent.MOUSE_DOWN, 1232 track_mouseDownHandler); 1233 } 1234 1235 invalidateProperties(); // Force commitProperties to be called on instantiation 1236 } 1237 1238 /** 1239 * @private 1240 */ 1241 override public function styleChanged(styleProp:String):void 1242 { 1243 var anyStyle:Boolean = styleProp == null || styleProp == "styleName"; 1244 1245 super.styleChanged(styleProp); 1246 1247 if (styleProp == "showTrackHighlight" || anyStyle) 1248 { 1249 trackHighlightChanged = true; 1250 invalidateProperties(); 1251 } 1252 1253 if (styleProp == "trackHighlightSkin" || anyStyle) 1254 { 1255 if (innerSlider && highlightTrack) 1256 { 1257 innerSlider.removeChild(DisplayObject(highlightTrack)); 1258 highlightTrack = null; 1259 } 1260 trackHighlightChanged = true; 1261 invalidateProperties(); 1262 } 1263 1264 if (styleProp == "labelStyleName" || anyStyle) 1265 { 1266 labelStyleChanged = true; 1267 invalidateProperties(); 1268 } 1269 1270 if (styleProp == "trackMargin" || anyStyle) 1271 { 1272 invalidateSize(); 1273 } 1274 1275 if (styleProp == "trackSkin" || anyStyle) 1276 { 1277 if (track) 1278 { 1279 innerSlider.removeChild(DisplayObject(track)); 1280 track = null; 1281 createBackgroundTrack(); 1282 } 1283 } 1284 1285 invalidateDisplayList(); 1286 } 1287 1288 /** 1289 * @private 1290 */ 1291 override protected function commitProperties():void 1292 { 1293 super.commitProperties(); 1294 1295 var n:int; 1296 var i:int; 1297 1298 if (trackHighlightChanged) 1299 { 1300 trackHighlightChanged = false; 1301 1302 if (getStyle("showTrackHighlight")) 1303 { 1304 createHighlightTrack(); 1305 } 1306 else if (highlightTrack) 1307 { 1308 innerSlider.removeChild(DisplayObject(highlightTrack)); 1309 highlightTrack = null; 1310 } 1311 } 1312 1313 if (directionChanged) 1314 { 1315 directionChanged = false; 1316 var isHorizontal:Boolean = _direction == SliderDirection.HORIZONTAL; 1317 1318 if (isHorizontal) 1319 { 1320 DisplayObject(innerSlider).rotation = 0; 1321 } 1322 else 1323 { 1324 DisplayObject(innerSlider).rotation = -90; 1325 innerSlider.y = unscaledHeight; 1326 } 1327 1328 if (labelObjects) 1329 { 1330 for (var labelIndex:int = labelObjects.numChildren - 1; labelIndex >= 0; labelIndex--) 1331 { 1332 var labelObj:SliderLabel = SliderLabel( 1333 labelObjects.getChildAt(labelIndex)); 1334 labelObj.rotation = isHorizontal ? 0 : 90; 1335 } 1336 } 1337 } 1338 1339 if (labelStyleChanged && !labelsChanged) 1340 { 1341 labelStyleChanged = false; 1342 1343 if (labelObjects) 1344 { 1345 var labelStyleName:String = getStyle("labelStyleName"); 1346 n = labelObjects.numChildren; 1347 for (i = 0; i < n; i++) 1348 { 1349 ISimpleStyleClient(labelObjects.getChildAt(i)).styleName = labelStyleName; 1350 } 1351 } 1352 } 1353 1354 if (ticksChanged) 1355 { 1356 ticksChanged = false; 1357 1358 createTicks(); 1359 } 1360 1361 if (labelsChanged) 1362 { 1363 labelsChanged = false; 1364 1365 createLabels(); 1366 } 1367 1368 if (thumbsChanged) 1369 { 1370 thumbsChanged = false; 1371 1372 createThumbs(); 1373 } 1374 1375 1376 if (initValues) 1377 { 1378 initValues = false; 1379 1380 if (!valuesChanged) 1381 { 1382 var val:Number = minimum; 1383 1384 n = _thumbCount; 1385 for (i = 0; i < n; i++) 1386 { 1387 _values[i] = val; 1388 setValueAt(val, i); 1389 if (_snapInterval && _snapInterval != 0) 1390 val += snapInterval; 1391 else 1392 val++; 1393 } 1394 1395 snapIntervalChanged = false; 1396 } 1397 } 1398 1399 if (snapIntervalChanged) 1400 { 1401 snapIntervalChanged = false; 1402 1403 if (!valuesChanged) 1404 { 1405 n = thumbs.numChildren; 1406 for (i = 0; i < n; i++) 1407 { 1408 setValueAt(getValueFromX(SliderThumb(thumbs.getChildAt(i)).xPosition), i); 1409 } 1410 } 1411 } 1412 1413 1414 1415 if (valuesChanged) 1416 { 1417 valuesChanged = false; 1418 1419 n = _thumbCount; 1420 for (i = 0; i < n; i++) 1421 { 1422 setValueAt(getValueFromX(getXFromValue(Math.min(Math.max(values[i], minimum), maximum))), i); 1423 } 1424 } 1425 1426 if (enabledChanged) 1427 { 1428 enabledChanged = false; 1429 1430 n = thumbs.numChildren; 1431 for (i = 0; i < n; i++) 1432 { 1433 SliderThumb(thumbs.getChildAt(i)).enabled = _enabled; 1434 } 1435 1436 n = labelObjects ? labelObjects.numChildren : 0; 1437 for (i = 0; i < n; i++) 1438 { 1439 SliderLabel(labelObjects.getChildAt(i)).enabled = _enabled; 1440 } 1441 } 1442 1443 if (tabIndexChanged) 1444 { 1445 tabIndexChanged = false; 1446 1447 n = thumbs.numChildren; 1448 for (i = 0; i < n; i++) 1449 { 1450 SliderThumb(thumbs.getChildAt(i)).tabIndex = _tabIndex; 1451 } 1452 } 1453 } 1454 1455 /** 1456 * Calculates the amount of space that the component takes up. 1457 * A horizontal slider control calculates its height by examining 1458 * the position of its labels, tick marks, and thumbs 1459 * relative to the track. 1460 * The height of the control is equivalent to the position 1461 * of the bottom of the lowest element subtracted 1462 * from the position of the top of the highest element. 1463 * The width of a horizontal slider control defaults to 250 pixels. 1464 * For a vertical slider control, the width and the length 1465 * measurements are reversed. 1466 */ 1467 override protected function measure():void 1468 { 1469 super.measure(); 1470 1471 var isHorizontal:Boolean = (direction == SliderDirection.HORIZONTAL); 1472 var numLabels:int = labelObjects ? labelObjects.numChildren : 0; 1473 var trackMargin:Number = getStyle("trackMargin"); 1474 var length:Number = DEFAULT_MEASURED_WIDTH; 1475 1476 if (!isNaN(trackMargin)) 1477 { 1478 if (numLabels > 0) 1479 { 1480 length += (isHorizontal ? 1481 SliderLabel(labelObjects.getChildAt(0)).getExplicitOrMeasuredWidth() / 2 : 1482 SliderLabel(labelObjects.getChildAt(0)).getExplicitOrMeasuredHeight() / 2); 1483 } 1484 if (numLabels > 1) 1485 { 1486 length += (isHorizontal ? 1487 SliderLabel(labelObjects.getChildAt(numLabels - 1)).getExplicitOrMeasuredWidth() / 2 : 1488 SliderLabel(labelObjects.getChildAt(numLabels - 1)).getExplicitOrMeasuredHeight() / 2); 1489 } 1490 //length += track.width; 1491 } 1492 1493 var bounds:Object = getComponentBounds(); 1494 var thickness:Number = bounds.lower - bounds.upper; 1495 1496 measuredMinWidth = measuredWidth = isHorizontal ? length : thickness; 1497 measuredMinHeight = measuredHeight = isHorizontal ? thickness : length; 1498 } 1499 1500 /** 1501 * Positions the elements of the control. 1502 * The track, thumbs, labels, and tick marks are all positioned 1503 * and sized by this method. 1504 * The track is sized based on the length of the labels and on the track margin. 1505 * If you specify a <code>trackMargin</code>, then the size of the track 1506 * is equal to the available width minus the <code>trackMargin</code> times 2. 1507 * 1508 * <p>Tick marks are spaced at even intervals along the track starting from the beginning of the track. An additional tick mark is placed 1509 * at the end of the track if one doesn't already exist (if the tick interval isn't a multiple of the maximum value). The tick mark 1510 * y-position is based on the <code>tickOffset</code>. An offset of 0 places the bottom of the tick at the top of the track. Negative offsets 1511 * move the ticks upwards while positive offsets move them downward through the track.</p> 1512 * 1513 * <p>Labels are positioned at even intervals along the track. The labels are always horizontally centered above their 1514 * interval position unless the <code>trackMargin</code> setting is too small. If you specify a <code>trackMargin</code>, then the first and last labels will 1515 * position themselves at the left and right borders of the control. Labels will not crop or resize themselves if they overlap, 1516 * so be sure to allow enough space for them to fit on the track. The y-position is based on the <code>labelOffset</code> property. An offset of 0 1517 * places the bottom of the label at the top of the track. Unlike tick marks, the labels can not be positioned to overlap the track. 1518 * If the offset is a positive number, then the top of the label will be positioned below the bottom of the track.</p> 1519 * 1520 * <p>The thumbs are positioned to overlap the track. Their x-position is determined by their value. The y-position is 1521 * controlled by the <code>thumbOffset</code> property. An offset of 0 places the center of the thumb at the center of the track. A negative 1522 * offset moves the thumbs upwards while a positive offset moves the thumbs downwards.</p> 1523 * 1524 * <p>The placement of the tick marks, labels and thumbs are all independent from each other. They will not attempt to reposition 1525 * themselves if they overlap.</p> 1526 * 1527 * <p>For a vertical slider control, the same rules apply. In the above description, substitute width for height, height for width, 1528 * left for up or top, right for down or bottom, x-position for y-position, and y-position for x-position.</p> 1529 * 1530 * @param unscaledWidth Specifies the width of the component, in pixels, 1531 * in the component's coordinates, regardless of the value of the 1532 * <code>scaleX</code> property of the component. 1533 * 1534 * @param unscaledHeight Specifies the height of the component, in pixels, 1535 * in the component's coordinates, regardless of the value of the 1536 * <code>scaleY</code> property of the component. 1537 */ 1538 override protected function updateDisplayList(unscaledWidth:Number, 1539 unscaledHeight:Number):void 1540 { 1541 super.updateDisplayList(unscaledWidth, unscaledHeight); 1542 1543// graphics.beginFill(0xEEEEEE); 1544// graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); 1545// graphics.endFill(); 1546 1547 var isHorizontal:Boolean = (_direction == SliderDirection.HORIZONTAL); 1548 var numLabels:int = labelObjects ? labelObjects.numChildren : 0; 1549 var numThumbs:int = thumbs ? thumbs.numChildren : 0; 1550 var trackMargin:Number = getStyle("trackMargin"); 1551 var widestThumb:Number = 6; 1552 var firstThumb:SliderThumb = SliderThumb(thumbs.getChildAt(0)); 1553 if (thumbs && firstThumb) 1554 widestThumb = firstThumb.getExplicitOrMeasuredWidth(); 1555 1556 var trackLeftOffset:Number = widestThumb / 2; // Enough space for the thumb to rest at the edges 1557 var trackRightOffset:Number = trackLeftOffset; 1558 1559 var availSpace:Number; 1560 1561 var firstLabelSize:Number = 0; 1562 if (numLabels > 0) 1563 { 1564 var firstLabel:SliderLabel = 1565 SliderLabel(labelObjects.getChildAt(0)); 1566 1567 firstLabelSize = isHorizontal ? 1568 firstLabel.getExplicitOrMeasuredWidth() : 1569 firstLabel.getExplicitOrMeasuredHeight(); 1570 } 1571 1572 var lastLabelSize:Number = 0; 1573 if (numLabels > 1) 1574 { 1575 var lastLabel:SliderLabel = 1576 SliderLabel(labelObjects.getChildAt(numLabels - 1)); 1577 lastLabelSize = isHorizontal ? 1578 lastLabel.getExplicitOrMeasuredWidth(): 1579 lastLabel.getExplicitOrMeasuredHeight(); 1580 } 1581 1582 if (!isNaN(trackMargin)) 1583 availSpace = trackMargin; 1584 else 1585 availSpace = (firstLabelSize + lastLabelSize) / 2; 1586 1587 if (numLabels > 0) 1588 { 1589 if (!isNaN(trackMargin)) 1590 { 1591 trackLeftOffset = Math.max(trackLeftOffset, 1592 availSpace / (numLabels > 1 ? 2 : 1)); 1593 } 1594 else 1595 { 1596 trackLeftOffset = Math.max(trackLeftOffset, firstLabelSize / 2); 1597 } 1598 } 1599 else 1600 { 1601 1602 trackLeftOffset = Math.max(trackLeftOffset, availSpace / 2); 1603 } 1604 1605 var bounds:Object = getComponentBounds(); 1606 1607 //track.x = Math.round(trackLeftOffset); 1608 1609 var trackY:Number = (((isHorizontal ? unscaledHeight : unscaledWidth) - 1610 (Number(bounds.lower) - Number(bounds.upper))) / 2) - Number(bounds.upper); 1611 1612 track.move(Math.round(trackLeftOffset), Math.round(trackY)); 1613 track.setActualSize((isHorizontal ? unscaledWidth: unscaledHeight) - (trackLeftOffset * 2), track.height); 1614 1615 // Layout the thumbs' y positions. 1616 var tY:Number = track.y + 1617 (track.height - firstThumb.getExplicitOrMeasuredHeight()) / 2 + 1618 getStyle("thumbOffset"); 1619 1620 var n:int = _thumbCount; 1621 for (var i:int = 0; i < n; i++) 1622 { 1623 var currentThumb:SliderThumb = SliderThumb(thumbs.getChildAt(i)); 1624 currentThumb.move(currentThumb.x, tY); 1625 currentThumb.visible = true; 1626 currentThumb.setActualSize(currentThumb.getExplicitOrMeasuredWidth(), 1627 currentThumb.getExplicitOrMeasuredHeight()); 1628 } 1629 1630 var g:Graphics = trackHitArea.graphics; 1631 1632 var tLength:Number = 0 1633 if (_tickInterval > 0 || (_tickValues && _tickValues.length > 0)) 1634 tLength = getStyle("tickLength"); 1635 g.clear(); 1636 g.beginFill(0,0); 1637 var fullThumbHeight:Number = firstThumb.getExplicitOrMeasuredHeight(); 1638 var halfThumbHeight:Number = (!fullThumbHeight) ? 0 : (fullThumbHeight / 2); 1639 g.drawRect(track.x, 1640 track.y - halfThumbHeight - tLength, 1641 track.width, 1642 track.height + fullThumbHeight + tLength); 1643 g.endFill(); 1644 1645 if (_direction != SliderDirection.HORIZONTAL) 1646 innerSlider.y = unscaledHeight; 1647 1648 layoutTicks(); 1649 1650 layoutLabels(); 1651 1652 setPosFromValue(); // use the value to position the thumb's x 1653 1654 drawTrackHighlight(); 1655 } 1656 1657 //-------------------------------------------------------------------------- 1658 // 1659 // Methods 1660 // 1661 //-------------------------------------------------------------------------- 1662 1663 /** 1664 * @private 1665 */ 1666 private function createBackgroundTrack():void 1667 { 1668 if (!track) 1669 { 1670 var trackSkinClass:Class = getStyle("trackSkin"); 1671 1672 track = new trackSkinClass(); 1673 1674 if (track is ISimpleStyleClient) 1675 ISimpleStyleClient(track).styleName = this; 1676 1677 innerSlider.addChildAt(DisplayObject(track),0); 1678 } 1679 } 1680 1681 /** 1682 * @private 1683 */ 1684 private function createHighlightTrack():void 1685 { 1686 var showTrackHighlight:Boolean = getStyle("showTrackHighlight"); 1687 if (!highlightTrack && showTrackHighlight) 1688 { 1689 var trackHighlightClass:Class = 1690 getStyle("trackHighlightSkin"); 1691 highlightTrack = new trackHighlightClass(); 1692 1693 if (highlightTrack is ISimpleStyleClient) 1694 ISimpleStyleClient(highlightTrack).styleName = this; 1695 1696 innerSlider.addChildAt(DisplayObject(highlightTrack), 1697 innerSlider.getChildIndex(DisplayObject(track)) + 1); 1698 } 1699 } 1700 1701 /** 1702 * @private 1703 */ 1704 private function createThumbs():void 1705 { 1706 var n:int; 1707 var i:int; 1708 1709 // Delete all thumb children 1710 if (thumbs) 1711 { 1712 n = thumbs.numChildren; 1713 for (i = n - 1; i >= 0; i--) 1714 { 1715 // we don't need to bother to remove the event listeners here 1716 // they will be removed by the garbage collector automatically 1717 thumbs.removeChildAt(i); 1718 } 1719 } 1720 else 1721 { 1722 thumbs = new UIComponent(); 1723 thumbs.tabChildren = true; 1724 thumbs.tabEnabled = false; 1725 innerSlider.addChild(thumbs); 1726 } 1727 1728 var thumb:SliderThumb; // We want to force the thumb to be a subclass of SliderThumb 1729 1730 n = _thumbCount; 1731 for (i = 0; i < n; i++) 1732 { 1733 thumb = SliderThumb(new _thumbClass()); 1734 1735 thumb.owner = this; 1736 thumb.styleName = new StyleProxy(this, thumbStyleFilters); 1737 thumb.thumbIndex = i; 1738 thumb.visible = true; 1739 thumb.enabled = enabled; 1740 1741 thumb.upSkinName = "thumbUpSkin"; 1742 thumb.downSkinName = "thumbDownSkin"; 1743 thumb.disabledSkinName = "thumbDisabledSkin"; 1744 thumb.overSkinName = "thumbOverSkin"; 1745 thumb.skinName = "thumbSkin"; 1746 1747 thumbs.addChild(thumb); 1748 1749 thumb.addEventListener(FocusEvent.FOCUS_IN, 1750 thumb_focusInHandler); 1751 thumb.addEventListener(FocusEvent.FOCUS_OUT, 1752 thumb_focusOutHandler); 1753 } 1754 } 1755 1756 /** 1757 * @private 1758 */ 1759 private function createLabels():void 1760 { 1761 var labelObj:SliderLabel; 1762 1763 if (labelObjects) 1764 { 1765 for (var i:int = labelObjects.numChildren - 1; i >= 0; i--) 1766 { 1767 labelObjects.removeChildAt(i); 1768 } 1769 } 1770 else 1771 { 1772 labelObjects = new UIComponent(); 1773 innerSlider.addChildAt(labelObjects, innerSlider.getChildIndex(trackHitArea)); 1774 } 1775 1776 if (_labels) 1777 { 1778 var numLabels:int = _labels.length; 1779 1780 for (var j:int = 0; j < numLabels; j++) 1781 { 1782 labelObj = new SliderLabel(); 1783 1784 labelObj.text = _labels[j] is String ? 1785 _labels[j] : 1786 _labels[j].toString(); 1787 1788 if (_direction != SliderDirection.HORIZONTAL) 1789 labelObj.rotation = 90; 1790 1791 var labelStyleName:String = getStyle("labelStyleName"); 1792 if (labelStyleName) 1793 labelObj.styleName = labelStyleName; 1794 1795 labelObjects.addChild(labelObj); 1796 } 1797 } 1798 } 1799 1800 /** 1801 * @private 1802 */ 1803 private function createTicks():void 1804 { 1805 if (!ticks) 1806 { 1807 ticks = new UIComponent(); 1808 1809 innerSlider.addChild(ticks); 1810 } 1811 } 1812 1813 /** 1814 * @private 1815 */ 1816 private function getComponentBounds():Object 1817 { 1818 var isHorizontal:Boolean = (direction == SliderDirection.HORIZONTAL); 1819 var numLabels:int = labelObjects ? labelObjects.numChildren : 0; 1820 var labelY:Number; 1821 var labelSize:Number = 0; 1822 var thumbY:Number; 1823 var upperBound:Number = 0; 1824 var lowerBound:Number = track.height; 1825 1826 if (numLabels > 0) 1827 { 1828 var sliderLabel:SliderLabel = 1829 SliderLabel(labelObjects.getChildAt(0)); 1830 1831 if (isHorizontal) 1832 { 1833 labelSize = sliderLabel.getExplicitOrMeasuredHeight(); 1834 } 1835 else 1836 { 1837 for (var i:int = 0; i < numLabels; i++) 1838 { 1839 sliderLabel = SliderLabel(labelObjects.getChildAt(i)); 1840 labelSize = Math.max(labelSize, 1841 sliderLabel.getExplicitOrMeasuredWidth()); 1842 } 1843 } 1844 1845 var labOffset:Number = getStyle("labelOffset"); 1846 labelY = labOffset - (labOffset > 0 ? 0 : labelSize); 1847 1848 upperBound = Math.min(upperBound, labelY); 1849 lowerBound = Math.max(lowerBound, labOffset + (labOffset > 0 ? labelSize : 0)); 1850 } 1851 1852 if (ticks) 1853 { 1854 var tLen:Number = getStyle("tickLength"); 1855 var tOff:Number = getStyle("tickOffset"); 1856 1857 upperBound = Math.min(upperBound, tOff - tLen); 1858 lowerBound = Math.max(lowerBound, tOff); 1859 } 1860 1861 if (thumbs.numChildren > 0) 1862 { 1863 thumbY = (track.height - SliderThumb(thumbs.getChildAt(0)).getExplicitOrMeasuredHeight()) / 2 + 1864 getStyle("thumbOffset"); 1865 1866 upperBound = Math.min(upperBound, thumbY); 1867 lowerBound = Math.max(lowerBound, thumbY + SliderThumb(thumbs.getChildAt(0)).getExplicitOrMeasuredHeight()); 1868 } 1869 1870 return { lower: lowerBound, upper: upperBound }; 1871 } 1872 1873 /** 1874 * @private 1875 */ 1876 private function layoutTicks():void 1877 { 1878 if (ticks) 1879 { 1880 var g:Graphics = ticks.graphics; 1881 var tLength:Number = getStyle("tickLength"); 1882 var tOffset:Number = getStyle("tickOffset"); 1883 var tickWidth:Number = getStyle("tickThickness"); 1884 var xPos:Number; 1885 var tColor:Number = getStyle("tickColor"); 1886 1887 var usePositions:Boolean = _tickValues && _tickValues.length > 0 ? true : false; 1888 var positionIndex:int = 0; 1889 var val:Number = usePositions ? _tickValues[positionIndex++] : minimum; 1890 1891 g.clear(); 1892 1893 if (_tickInterval > 0 || usePositions) 1894 { 1895 g.lineStyle(tickWidth,tColor,100); 1896 1897 do 1898 { 1899 xPos = Math.round(getXFromValue(val)); 1900 g.moveTo(xPos, tLength); 1901 g.lineTo(xPos, 0); 1902 val = usePositions ? (positionIndex < _tickValues.length ? _tickValues[positionIndex++] : NaN) : _tickInterval + val; 1903 } while (val < maximum || (usePositions && positionIndex < _tickValues.length)) 1904 1905 // draw the last tick 1906 if (!usePositions || val == maximum) 1907 { 1908 xPos = track.x + track.width - 1; 1909 g.moveTo(xPos, tLength); 1910 g.lineTo(xPos, 0); 1911 } 1912 1913 ticks.y = Math.round(track.y + tOffset - tLength); 1914 } 1915 } 1916 } 1917 1918 /** 1919 * @private 1920 */ 1921 private function layoutLabels():void 1922 { 1923 var numLabels:Number = labelObjects ? labelObjects.numChildren : 0; 1924 var availSpace:Number; 1925 1926 if (numLabels > 0) 1927 { 1928 var labelInterval:Number = track.width / (numLabels - 1); 1929 // The amount of space we have available for the labels to hang past the track 1930 availSpace = Math.max((_direction == SliderDirection.HORIZONTAL ? 1931 unscaledWidth : 1932 unscaledHeight) - track.width, 1933 SliderThumb(thumbs.getChildAt(0)).getExplicitOrMeasuredWidth()); 1934 1935 var labelPos:Number; 1936 var left:Number = track.x; 1937 var curLabel:Object; 1938 1939 for (var i:int = 0; i < numLabels; i++) 1940 { 1941 curLabel = labelObjects.getChildAt(i); 1942 curLabel.setActualSize(curLabel.getExplicitOrMeasuredWidth(), curLabel.getExplicitOrMeasuredHeight()); 1943 1944 var yPos:Number = track.y - curLabel.height + getStyle("labelOffset"); 1945 1946 if (_direction == SliderDirection.HORIZONTAL) 1947 { 1948 labelPos = curLabel.getExplicitOrMeasuredWidth() / 2; 1949 1950 if (i == 0) 1951 labelPos = Math.min(labelPos, availSpace / (numLabels > Number(1) ? Number(2) : Number(1))); 1952 else if (i == (numLabels - 1)) 1953 labelPos = Math.max(labelPos, curLabel.getExplicitOrMeasuredWidth() - availSpace / 2); 1954 1955 curLabel.move(left - labelPos,yPos); 1956 } 1957 else 1958 { 1959 var labelOff:Number = getStyle("labelOffset"); 1960 1961 labelPos = curLabel.getExplicitOrMeasuredHeight() / 2; 1962 1963 if (i == 0) 1964 labelPos = Math.max(labelPos, curLabel.getExplicitOrMeasuredHeight() - availSpace / (numLabels > Number(1) ? Number(2) : Number(1))); 1965 else if (i == (numLabels-1)) 1966 labelPos = Math.min(labelPos,availSpace / 2); 1967 1968 curLabel.move(left + labelPos,track.y + labelOff + 1969 (labelOff > 0 ? 0 : -curLabel.getExplicitOrMeasuredWidth())); 1970 } 1971 left += labelInterval; 1972 } 1973 } 1974 } 1975 1976 /** 1977 * @private 1978 */ 1979 mx_internal function drawTrackHighlight():void 1980 { 1981 if (highlightTrack) 1982 { 1983 var xPos:Number; 1984 var tWidth:Number; 1985 1986 var firstThumb:SliderThumb = SliderThumb(thumbs.getChildAt(0)); 1987 1988 if (_thumbCount > 1) 1989 { 1990 xPos = firstThumb.xPosition; 1991 var secondThumb:SliderThumb = SliderThumb(thumbs.getChildAt(1)); 1992 tWidth = secondThumb.xPosition - firstThumb.xPosition; 1993 } 1994 else 1995 { 1996 xPos = track.x; 1997 tWidth = firstThumb.xPosition - xPos; 1998 } 1999 2000 2001 highlightTrack.move(xPos, track.y + 1); 2002 highlightTrack.setActualSize(tWidth > 0 ? tWidth : 0, highlightTrack.height); 2003 } 2004 } 2005 2006 /** 2007 * @private 2008 * Helper function that starts the dataTip and dispatches the press event. 2009 */ 2010 mx_internal function onThumbPress(thumb:Object):void 2011 { 2012 if (showDataTip) 2013 { 2014 // Setup number formatter 2015 dataFormatter = new NumberFormatter(); 2016 dataFormatter.precision = getStyle("dataTipPrecision"); 2017 2018 if (!dataTip) 2019 { 2020 dataTip = SliderDataTip(new sliderDataTipClass()); 2021 systemManager.toolTipChildren.addChild(dataTip); 2022 2023 var dataTipStyleName:String = getStyle("dataTipStyleName"); 2024 if (dataTipStyleName) 2025 { 2026 dataTip.styleName = dataTipStyleName; 2027 } 2028 } 2029 2030 var formattedVal:String; 2031 if (_dataTipFormatFunction != null) 2032 { 2033 formattedVal = this._dataTipFormatFunction( 2034 getValueFromX(thumb.xPosition)); 2035 } 2036 else 2037 { 2038 formattedVal = dataFormatter.format(getValueFromX(thumb.xPosition)); 2039 } 2040 2041 dataTip.text = formattedVal; 2042 2043 // Tool tip has been freshly created and new text assigned to it. 2044 // Hence force a validation so that we can set the 2045 // size required to show the text completely. 2046 dataTip.validateNow(); 2047 dataTip.setActualSize(dataTip.getExplicitOrMeasuredWidth(),dataTip.getExplicitOrMeasuredHeight()); 2048 positionDataTip(thumb); 2049 } 2050 keyInteraction = false; 2051 2052 var event:SliderEvent = new SliderEvent(SliderEvent.THUMB_PRESS); 2053 event.value = getValueFromX(thumb.xPosition);; 2054 event.thumbIndex = thumb.thumbIndex; 2055 dispatchEvent(event); 2056 } 2057 2058 /** 2059 * @private 2060 */ 2061 mx_internal function onThumbRelease(thumb:Object):void 2062 { 2063 interactionClickTarget = SliderEventClickTarget.THUMB; 2064 2065 destroyDataTip(); 2066 2067 setValueFromPos(thumb.thumbIndex); 2068 2069 dataFormatter = null; 2070 2071 var event:SliderEvent = new SliderEvent(SliderEvent.THUMB_RELEASE); 2072 event.value = getValueFromX(thumb.xPosition);; 2073 event.thumbIndex = thumb.thumbIndex; 2074 dispatchEvent(event); 2075 } 2076 2077 /** 2078 * @private 2079 */ 2080 mx_internal function onThumbMove(thumb:Object):void 2081 { 2082 var value:Number = getValueFromX(thumb.xPosition); 2083 2084 if (showDataTip) 2085 { 2086 dataTip.text = _dataTipFormatFunction != null ? 2087 _dataTipFormatFunction(value) : 2088 dataFormatter.format(value); 2089 2090 dataTip.setActualSize(dataTip.getExplicitOrMeasuredWidth(), 2091 dataTip.getExplicitOrMeasuredHeight()); 2092 2093 positionDataTip(thumb); 2094 } 2095 2096 if (liveDragging) 2097 { 2098 interactionClickTarget = SliderEventClickTarget.THUMB; 2099 setValueAt(value, thumb.thumbIndex); 2100 } 2101 2102 var event:SliderEvent = new SliderEvent(SliderEvent.THUMB_DRAG); 2103 event.value = value; 2104 event.thumbIndex = thumb.thumbIndex; 2105 dispatchEvent(event); 2106 } 2107 2108 /** 2109 * @private 2110 */ 2111 private function positionDataTip(thumb:Object):void 2112 { 2113 var relX:Number; 2114 var relY:Number; 2115 2116 var tX:Number = thumb.x; 2117 var tY:Number = thumb.y; 2118 2119 var tPlacement:String = getStyle("dataTipPlacement"); 2120 var tOffset:Number = getStyle("dataTipOffset"); 2121 2122 // Need to special case tooltip position because the tooltip movieclip 2123 // resides in the root movie clip, instead of the Slider movieclip 2124 if (_direction == SliderDirection.HORIZONTAL) 2125 { 2126 relX = tX; 2127 relY = tY; 2128 2129 if (tPlacement == "left") 2130 { 2131 relX -= tOffset + dataTip.width; 2132 relY += (thumb.height - dataTip.height) / 2; 2133 } 2134 else if (tPlacement == "right") 2135 { 2136 relX += tOffset + thumb.width; 2137 relY += (thumb.height - dataTip.height) / 2; 2138 } 2139 else if (tPlacement == "top") 2140 { 2141 relY -= tOffset + dataTip.height; 2142 relX -= (dataTip.width - thumb.width) / 2; 2143 } 2144 else if (tPlacement == "bottom") 2145 { 2146 relY += tOffset + thumb.height; 2147 relX -= (dataTip.width - thumb.width) / 2; 2148 } 2149 } 2150 else 2151 { 2152 relX = tY; 2153 relY = unscaledHeight - tX - (dataTip.height + thumb.width) / 2; 2154 2155 if (tPlacement == "left") 2156 { 2157 relX -= tOffset + dataTip.width; 2158 } 2159 else if (tPlacement == "right") 2160 { 2161 relX += tOffset + thumb.height; 2162 } 2163 else if (tPlacement == "top") 2164 { 2165 relY -= tOffset + (dataTip.height + thumb.width) / 2; 2166 relX -= (dataTip.width - thumb.height) / 2; 2167 } 2168 else if (tPlacement == "bottom") 2169 { 2170 relY += tOffset + (dataTip.height + thumb.width) / 2; 2171 relX -= (dataTip.width - thumb.height) / 2; 2172 } 2173 } 2174 2175 var o:Point = new Point(relX, relY); 2176 var r:Point = localToGlobal(o); 2177 r = dataTip.parent.globalToLocal(r); 2178 2179 dataTip.x = r.x < 0 ? 0 : r.x; 2180 dataTip.y = r.y < 0 ? 0 : r.y; 2181 } 2182 2183 /** 2184 * @private 2185 */ 2186 private function destroyDataTip():void 2187 { 2188 if (dataTip) 2189 { 2190 systemManager.toolTipChildren.removeChild(dataTip); 2191 dataTip = null; 2192 } 2193 } 2194 2195 /** 2196 * @private 2197 * Utility for finding the x position which corresponds 2198 * to the given value. 2199 */ 2200 mx_internal function getXFromValue(v:Number):Number 2201 { 2202 var val:Number; 2203 2204 if (v == minimum) 2205 val = track.x; 2206 else if (v == maximum) 2207 val = track.x + track.width; 2208 else 2209 val = track.x + (v - minimum) * (track.width) / (maximum - minimum); 2210 2211 return val; 2212 } 2213 2214 /** 2215 * @private 2216 */ 2217 mx_internal function getXBounds(selectedThumbIndex:int):Object 2218 { 2219 var maxX:Number = track.x + track.width; 2220 var minX:Number = track.x; 2221 if (allowThumbOverlap) 2222 { 2223 return { max: maxX, min: minX }; 2224 } 2225 2226 var minBound:Number = NaN; 2227 var maxBound:Number = NaN; 2228 2229 var prevThumb:SliderThumb = 2230 selectedThumbIndex > 0 ? 2231 SliderThumb(thumbs.getChildAt(selectedThumbIndex - 1)) : 2232 null; 2233 2234 var nextThumb:SliderThumb = 2235 selectedThumbIndex + 1 < thumbs.numChildren ? 2236 SliderThumb(thumbs.getChildAt(selectedThumbIndex + 1)) : 2237 null; 2238 2239 if (prevThumb) 2240 minBound = prevThumb.xPosition + prevThumb.width / 2; 2241 2242 if (nextThumb) 2243 maxBound = nextThumb.xPosition - nextThumb.width / 2; 2244 2245 if (isNaN(minBound)) 2246 minBound = minX; 2247 else 2248 minBound = Math.min(Math.max(minX,minBound),maxX); 2249 2250 if (isNaN(maxBound)) 2251 maxBound = maxX; 2252 else 2253 maxBound = Math.max(Math.min(maxX, maxBound),minX); 2254 2255 return { max: maxBound, min: minBound }; 2256 } 2257 2258 /** 2259 * @private 2260 * Utility for positioning the thumb(s) from the current value. 2261 */ 2262 private function setPosFromValue():void 2263 { 2264 var n:int = _thumbCount; 2265 for (var i:int = 0; i < n; i++) 2266 { 2267 var thumb:SliderThumb = SliderThumb(thumbs.getChildAt(i)); 2268 thumb.xPosition = getXFromValue(values[i]); 2269 } 2270 } 2271 2272 /** 2273 * @private 2274 * Utility for getting a value corresponding to a given x. 2275 */ 2276 mx_internal function getValueFromX(xPos:Number):Number 2277 { 2278 var v:Number = (xPos - track.x) * 2279 (maximum - minimum) / 2280 (track.width) + minimum; 2281 2282 // kill rounding error at the edges. 2283 if (v - minimum <= 0.002) 2284 { 2285 v = minimum; 2286 } 2287 else if (maximum - v <= 0.002) 2288 { 2289 v = maximum; 2290 } 2291 else if (!isNaN(_snapInterval) && _snapInterval != 0) 2292 { 2293 v = Math.round((v - minimum) / _snapInterval) * 2294 _snapInterval + minimum; 2295 } 2296 2297 return v; 2298 } 2299 2300 /** 2301 * @private 2302 * Utility for committing a value of a given thumb. 2303 */ 2304 private function setValueFromPos(thumbIndex:int):void 2305 { 2306 var thumb:SliderThumb = SliderThumb(thumbs.getChildAt(thumbIndex)); 2307 setValueAt(getValueFromX(thumb.xPosition), thumbIndex); 2308 } 2309 2310 /** 2311 * @private 2312 */ 2313 mx_internal function getSnapValue(value:Number, thumb:SliderThumb = null):Number 2314 { 2315 if (!isNaN(_snapInterval) && _snapInterval != 0) 2316 { 2317 var val:Number = getValueFromX(value); 2318 2319 if (thumb && (thumbs.numChildren > 1) && !allowThumbOverlap) 2320 { 2321 var check_bounds:Boolean = true; 2322 var bounds:Object 2323 2324 bounds = getXBounds(thumb.thumbIndex); 2325 2326 var prevThumb:SliderThumb = 2327 thumb.thumbIndex > 0 ? 2328 SliderThumb(thumbs.getChildAt(thumb.thumbIndex- 1)) : 2329 null; 2330 2331 var nextThumb:SliderThumb = 2332 thumb.thumbIndex + 1 < thumbs.numChildren ? 2333 SliderThumb(thumbs.getChildAt(thumb.thumbIndex + 1)) : 2334 null; 2335 2336 if (prevThumb) 2337 { 2338 bounds.min -= (prevThumb.width / 2); 2339 // check if thumb is at minimum, if not we can ignore the bounds logic 2340 if (val == minimum) 2341 if (getValueFromX((prevThumb.xPosition - prevThumb.width/2)) != minimum) 2342 check_bounds = false; 2343 } 2344 else 2345 { 2346 if (val == minimum) 2347 check_bounds = false; 2348 } 2349 2350 if (nextThumb) 2351 { 2352 bounds.max += (nextThumb.width / 2); 2353 // check if thumb is at maximum, if not we can ignore the bounds logic 2354 if (val == maximum) 2355 if (getValueFromX((nextThumb.xPosition + nextThumb.width/2)) != maximum) 2356 check_bounds = false; 2357 } 2358 else 2359 { 2360 if (val == maximum) 2361 check_bounds = false; 2362 } 2363 if (check_bounds) 2364 val = Math.min(Math.max(val, getValueFromX(Math.round(bounds.min)) + _snapInterval), 2365 getValueFromX(Math.round(bounds.max)) - _snapInterval); 2366 2367 } 2368 return getXFromValue(val); 2369 } 2370 2371 return value; 2372 } 2373 2374 /** 2375 * @private Accessed by the Thumb to find out the snap interval 2376 */ 2377 mx_internal function getSnapIntervalWidth():Number 2378 { 2379 return _snapInterval * track.width / (maximum - minimum); 2380 } 2381 2382 /** 2383 * @private 2384 */ 2385 mx_internal function updateThumbValue(thumbIndex:int):void 2386 { 2387 setValueFromPos(thumbIndex); 2388 } 2389 2390 /** 2391 * Returns the thumb object at the given index. Use this method to 2392 * style and customize individual thumbs in a slider control. 2393 * 2394 * @param index The zero-based index number of the thumb. 2395 * 2396 * @return A reference to the SliderThumb object. 2397 */ 2398 public function getThumbAt(index:int):SliderThumb 2399 { 2400 return index >= 0 && index < thumbs.numChildren ? 2401 SliderThumb(thumbs.getChildAt(index)) : 2402 null; 2403 } 2404 2405 /** 2406 * This method sets the value of a slider thumb, and updates the display. 2407 * 2408 * @param index The zero-based index number of the thumb to set 2409 * the value of, where a value of 0 corresponds to the first thumb. 2410 * 2411 * @param value The value to set the thumb to 2412 */ 2413 public function setThumbValueAt(index:int, value:Number):void 2414 { 2415 setValueAt(value, index, true); 2416 valuesChanged = true; 2417 2418 invalidateProperties(); 2419 invalidateDisplayList(); 2420 } 2421 2422 /** 2423 * @private 2424 */ 2425 private function setValueAt(value:Number, index:int, 2426 isProgrammatic:Boolean = false):void 2427 { 2428 var oldValue:Number = _values[index]; 2429 2430 // we need to do the round of (to remove the floating point error) 2431 // if the stepSize had a fractional value 2432 if (snapIntervalPrecision != -1) 2433 { 2434 var scale:Number = Math.pow(10, snapIntervalPrecision); 2435 value = Math.round(value * scale) / scale; 2436 } 2437 2438 _values[index] = value; 2439 2440 if (!isProgrammatic) 2441 { 2442 var event:SliderEvent = new SliderEvent(SliderEvent.CHANGE); 2443 event.value = value; 2444 event.thumbIndex = index; 2445 event.clickTarget = interactionClickTarget; 2446 //set the triggerEvent correctly 2447 if (keyInteraction) 2448 { 2449 event.triggerEvent = new KeyboardEvent(KeyboardEvent.KEY_DOWN); 2450 //reset to mouse default 2451 keyInteraction = false; 2452 } 2453 else 2454 { 2455 event.triggerEvent = new MouseEvent(MouseEvent.CLICK); 2456 } 2457 2458 if (!isNaN(oldValue)) 2459 { 2460 if (Math.abs(oldValue - value) > 0.002) 2461 dispatchEvent(event) 2462 } 2463 // Handle case of changing from NaN to a valid value 2464 else if (!isNaN(value)) 2465 { 2466 dispatchEvent(event); 2467 } 2468 } 2469 2470 invalidateDisplayList(); 2471 } 2472 2473 /** 2474 * @private 2475 */ 2476 mx_internal function registerMouseMove(listener:Function):void 2477 { 2478 innerSlider.addEventListener(MouseEvent.MOUSE_MOVE, listener); 2479 } 2480 2481 /** 2482 * @private 2483 */ 2484 mx_internal function unRegisterMouseMove(listener:Function):void 2485 { 2486 innerSlider.removeEventListener(MouseEvent.MOUSE_MOVE, listener); 2487 } 2488 2489 //-------------------------------------------------------------------------- 2490 // 2491 // Event handlers 2492 // 2493 //-------------------------------------------------------------------------- 2494 2495 /** 2496 * @private 2497 * Move the thumb when pressed. 2498 */ 2499 private function track_mouseDownHandler(event:MouseEvent):void 2500 { 2501 if (event.target != trackHitArea && event.target != ticks) 2502 return; 2503 if (enabled && allowTrackClick) 2504 { 2505 interactionClickTarget = SliderEventClickTarget.TRACK; 2506 //this is a mouse event 2507 keyInteraction = false; 2508 var pt:Point = new Point(event.localX, event.localY); 2509 var xM:Number = pt.x; 2510 var minIndex:Number = 0; 2511 var minDistance:Number = 10000000; 2512 2513 // find the nearest thumb 2514 var n:int = _thumbCount; 2515 for (var i:int = 0; i < n; i++) 2516 { 2517 var d:Number = Math.abs(SliderThumb(thumbs.getChildAt(i)).xPosition - xM); 2518 if (d < minDistance) 2519 { 2520 minIndex = i; 2521 minDistance = d; 2522 } 2523 } 2524 var thumb:SliderThumb = SliderThumb(thumbs.getChildAt(minIndex)); 2525 if (!isNaN(_snapInterval) && _snapInterval != 0) 2526 xM = getXFromValue(getValueFromX(xM)); 2527 2528 var duration:Number = getStyle("slideDuration"); 2529 var t:Tween = new Tween(thumb, thumb.xPosition, xM, duration); 2530 2531 var easingFunction:Function = getStyle("slideEasingFunction") as Function; 2532 if (easingFunction != null) 2533 t.easingFunction = easingFunction; 2534 2535 drawTrackHighlight(); 2536 } 2537 } 2538 2539 /** 2540 * @private 2541 */ 2542 private function thumb_focusInHandler(event:FocusEvent):void 2543 { 2544 dispatchEvent(event); 2545 } 2546 2547 /** 2548 * @private 2549 */ 2550 private function thumb_focusOutHandler(event:FocusEvent):void 2551 { 2552 dispatchEvent(event); 2553 } 2554 2555 /** 2556 * @private 2557 */ 2558 mx_internal function getTrackHitArea():UIComponent 2559 { 2560 return trackHitArea; 2561 } 2562 2563} 2564 2565} 2566