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.colorPickerClasses
13{
14
15import flash.events.Event;
16import flash.events.EventPhase;
17import flash.events.KeyboardEvent;
18import flash.events.MouseEvent;
19import flash.geom.Rectangle;
20import flash.ui.Keyboard;
21import mx.collections.ArrayList;
22import mx.collections.IList;
23import mx.controls.ColorPicker;
24import mx.controls.TextInput;
25import mx.core.FlexVersion;
26import mx.core.UIComponent;
27import mx.core.mx_internal;
28import mx.events.ColorPickerEvent;
29import mx.managers.IFocusManagerContainer;
30import mx.skins.halo.SwatchPanelSkin;
31import mx.skins.halo.SwatchSkin;
32import mx.styles.StyleManager;
33
34use namespace mx_internal;
35
36//--------------------------------------
37//  Events
38//--------------------------------------
39
40/**
41 *  Dispatched when the selected color changes.
42 *
43 *  @eventType flash.events.Event.CHANGE
44 */
45[Event(name="change", type="flash.events.Event")]
46
47/**
48 *  Dispatched when the user presses the Enter key.
49 *
50 *  @eventType mx.events.FlexEvent.ENTER
51 */
52[Event(name="enter", type="flash.events.Event")]
53
54/**
55 *  Dispatched when the mouse rolls over a color.
56 *
57 *  @eventType mx.events.ColorPickerEvent.ITEM_ROLL_OVER
58 */
59[Event(name="itemRollOver", type="mx.events.ColorPickerEvent")]
60
61/**
62 *  Dispatched when the mouse rolls out of a color.
63 *
64 *  @eventType mx.events.ColorPickerEvent.ITEM_ROLL_OUT
65 */
66[Event(name="itemRollOut", type="mx.events.ColorPickerEvent")]
67
68//--------------------------------------
69//  Styles
70//--------------------------------------
71
72include "../../styles/metadata/GapStyles.as"
73include "../../styles/metadata/PaddingStyles.as"
74
75/**
76 *  Background color of the component.
77 *  You can either have a <code>backgroundColor</code> or a
78 *  <code>backgroundImage</code>, but not both.
79 *  Note that some components, like a Button, do not have a background
80 *  because they are completely filled with the button face or other graphics.
81 *  The DataGrid control also ignores this style.
82 *  The default value is <code>undefined</code>. If both this style and the
83 *  backgroundImage style are undefined, the control has a transparent background.
84 */
85[Style(name="backgroundColor", type="uint", format="Color", inherit="no")]
86
87/**
88 *  Black section of a three-dimensional border, or the color section
89 *  of a two-dimensional border.
90 *  The following components support this style: Button, CheckBox,
91 *  ComboBox, MenuBar,
92 *  NumericStepper, ProgressBar, RadioButton, ScrollBar, Slider, and all
93 *  components that support the <code>borderStyle</code> style.
94 *  The default value depends on the component class;
95 *  if not overriden for the class, it is <code>0xAAB3B3</code>.
96 */
97[Style(name="borderColor", type="uint", format="Color", inherit="no")]
98
99/**
100 *  Number of columns in the swatch grid.
101 *  The default value is 20.
102 */
103[Style(name="columnCount", type="int", inherit="no")]
104
105/**
106 *  Color of the control border highlight.
107 *  The default value is <code>0xC4CCCC</code> (medium gray) .
108 */
109[Style(name="highlightColor", type="uint", format="Color", inherit="yes")]
110
111/**
112 *  Color for the left and right inside edges of a component's skin.
113 *  The default value is <code>0xD5DDDD</code>.
114 */
115[Style(name="shadowCapColor", type="uint", format="Color", inherit="yes")]
116
117/**
118 *  Bottom inside color of a button's skin.
119 *  A section of the three-dimensional border.
120 *  The default value is <code>0xEEEEEE</code> (light gray).
121 */
122[Style(name="shadowColor", type="uint", format="Color", inherit="yes")]
123
124/**
125 *  Height of the larger preview swatch that appears above the swatch grid on
126 *  the top left of the SwatchPanel object.
127 *  The default value is 22.
128 */
129[Style(name="previewHeight", type="Number", format="Length", inherit="no")]
130
131/**
132 *  Width of the larger preview swatch.
133 *  The default value is 45.
134 */
135[Style(name="previewWidth", type="Number", format="Length", inherit="no")]
136
137/**
138 *  Size of the swatchBorder outlines.
139 *  The default value is 1.
140 */
141[Style(name="swatchBorderSize", type="Number", format="Length", inherit="no")]
142
143/**
144 *  Color of the swatch borders.
145 *  The default value is <code>0x000000</code>.
146 */
147[Style(name="swatchBorderColor", type="uint", format="Color", inherit="no")]
148
149/**
150 *  Size of the single border around the grid of swatches.
151 *  The default value is 0.
152 */
153[Style(name="swatchGridBorderSize", type="Number", format="Length", inherit="no")]
154
155/**
156 *  Color of the background rectangle behind the swatch grid.
157 *  The default value is <code>0x000000</code>.
158 */
159[Style(name="swatchGridBackgroundColor", type="uint", format="Color", inherit="no")]
160
161/**
162 *  Height of each swatch.
163 *  The default value is 12.
164 */
165[Style(name="swatchHeight", type="Number", format="Length", inherit="no")]
166
167/**
168 *  Color of the highlight that appears around the swatch when the user
169 *  rolls over a swatch.
170 *  The default value is <code>0xFFFFFF</code>.
171 */
172[Style(name="swatchHighlightColor", type="uint", format="Color", inherit="no")]
173
174/**
175 *  Size of the highlight that appears around the swatch when the user
176 *  rolls over a swatch.
177 *  The default value is 1.
178 */
179[Style(name="swatchHighlightSize", type="Number", format="Length", inherit="no")]
180
181/**
182 *  Width of each swatch.
183 *  The default value is 12.
184 */
185[Style(name="swatchWidth", type="Number", format="Length", inherit="no")]
186
187/**
188 *  @REVIEW
189 *  Name of the style sheet definition to configure the text input control.
190 *  The default value is "swatchPanelTextField"
191 */
192[Style(name="textFieldStyleName", type="String", inherit="no")]
193
194/**
195 *  Width of the hexadecimal text box that appears above the swatch grid.
196 *  The default value is 72.
197 */
198[Style(name="textFieldWidth", type="Number", format="Length", inherit="no")]
199
200//--------------------------------------
201//  Other metadata
202//--------------------------------------
203
204[ExcludeClass]
205
206/**
207 *  @private
208 */
209public class SwatchPanel extends UIComponent implements IFocusManagerContainer
210{
211    include "../../core/Version.as";
212
213    //--------------------------------------------------------------------------
214    //
215    //  Constructor
216    //
217    //--------------------------------------------------------------------------
218
219    /**
220     *  Constructor.
221     */
222    public function SwatchPanel()
223    {
224        super();
225
226        // Register for events.
227        addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
228        addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
229    }
230
231    //--------------------------------------------------------------------------
232    //
233    //  Variables
234    //
235    //--------------------------------------------------------------------------
236
237    /**
238     *  @private
239     */
240    mx_internal var textInput:TextInput;
241
242    /**
243     *  @private
244     */
245    private var border:SwatchPanelSkin;
246
247    /**
248     *  @private
249     */
250    private var preview:SwatchSkin;
251
252    /**
253     *  @private
254     */
255    private var swatches:SwatchSkin;
256
257    /**
258     *  @private
259     */
260    private var highlight:SwatchSkin;
261
262    /**
263     *  @private
264     *  Used by ColorPicker
265     */
266    mx_internal var isOverGrid:Boolean = false;
267
268    /**
269     *  @private
270     *  Used by ColorPicker
271     */
272    mx_internal var isOpening:Boolean = false;
273
274    /**
275     *  @private
276     *  Used by ColorPicker
277     */
278    mx_internal var focusedIndex:int = -1;
279
280    /**
281     *  @private
282     *  Used by ColorPicker
283     */
284    mx_internal var tweenUp:Boolean = false;
285
286    /**
287     *  @private
288     */
289    private var initializing:Boolean = true;
290
291    /**
292     *  @private
293     */
294    private var indexFlag:Boolean = false;
295
296    /**
297     *  @private
298     */
299    private var lastIndex:int = -1;
300
301    /**
302     *  @private
303     */
304    private var grid:Rectangle;
305
306    /**
307     *  @private
308     */
309    private var rows:int;
310
311    /**
312     *  @private
313	 *  Cached style.
314     */
315    private var horizontalGap:Number;
316
317    /**
318     *  @private
319	 *  Cached style.
320     */
321    private var verticalGap:Number;
322
323    /**
324     *  @private
325	 *  Cached style.
326     */
327    private var columnCount:int;
328
329    /**
330     *  @private
331	 *  Cached style.
332     */
333    private var paddingLeft:Number;
334
335    /**
336     *  @private
337	 *  Cached style.
338     */
339    private var paddingRight:Number;
340
341    /**
342     *  @private
343	 *  Cached style.
344     */
345    private var paddingTop:Number;
346
347    /**
348     *  @private
349	 *  Cached style.
350     */
351    private var paddingBottom:Number;
352
353    /**
354     *  @private
355	 *  Cached style.
356     */
357    private var textFieldWidth:Number;
358
359    /**
360     *  @private
361	 *  Cached style.
362     */
363    private var previewWidth:Number;
364
365    /**
366     *  @private
367	 *  Cached style.
368     */
369    private var previewHeight:Number;
370
371    /**
372     *  @private
373	 *  Cached style.
374     */
375    private var swatchWidth:Number;
376
377    /**
378     *  @private
379	 *  Cached style.
380     */
381    private var swatchHeight:Number;
382
383    /**
384     *  @private
385	 *  Cached style.
386     */
387    private var swatchGridBorderSize:Number;
388
389    /**
390     *  @private
391     */
392	private var cellOffset:Number = 1;
393
394    /**
395     *  @private
396     */
397    private var itemOffset:Number = 3;
398
399    //--------------------------------------------------------------------------
400    //
401    //  Overridden Properties
402    //
403    //--------------------------------------------------------------------------
404
405    //----------------------------------
406    //  height
407    //----------------------------------
408
409    /**
410     *  @private
411     *  We set our size internally based on style values.
412	 *  Setting height has no effect on the panel.
413	 *  Override to return the preferred width and height of our contents.
414     */
415    override public function get height():Number
416    {
417        return getExplicitOrMeasuredHeight();
418    }
419
420    /**
421     *  @private
422     */
423    override public function set height(value:Number):void
424    {
425        // do nothing...
426    }
427
428    //----------------------------------
429    //  width
430    //----------------------------------
431
432    /**
433     *  @private
434     *  We set our size internally based on style values.
435	 *  Setting width has no effect on the panel.
436	 *  Override to return the preferred width and height of our contents.
437     */
438    override public function get width():Number
439    {
440        return getExplicitOrMeasuredWidth();
441    }
442
443    /**
444     *  @private
445     */
446    override public function set width(value:Number):void
447    {
448        // do nothing...
449    }
450
451    //--------------------------------------------------------------------------
452    //
453    //  Properties
454    //
455    //--------------------------------------------------------------------------
456
457    //----------------------------------
458    //  colorField
459    //----------------------------------
460
461    /**
462	 *  Storage for the colorField property.
463	 */
464    private var _colorField:String = "color";
465
466    /**
467     *  @private
468     */
469    public function get colorField():String
470    {
471        return _colorField;
472    }
473
474    /**
475     *  @private
476     */
477    public function set colorField(value:String):void
478    {
479        _colorField = value;
480    }
481
482    //----------------------------------
483    //  dataProvider
484    //----------------------------------
485
486    /**
487	 *  Storage for the dataProvider property.
488	 */
489	private var _dataProvider:IList;
490
491    /**
492     *  @private
493     */
494    public function get dataProvider():Object
495    {
496        return _dataProvider;
497    }
498
499    /**
500     *  @private
501     */
502    public function set dataProvider(value:Object):void
503    {
504        if (value is IList)
505        {
506	        _dataProvider = IList(value);
507        }
508        else if (value is Array)
509		{
510			var tmpDP:IList = new ArrayList(value as Array);
511			value = tmpDP;
512		}
513		else
514		{
515	        _dataProvider = null;
516        }
517
518        if (!initializing)
519        {
520            // Adjust if dataProvider is empty
521            if (length == 0 || isNaN(length))
522            {
523                highlight.visible = false;
524                _selectedIndex = -1;
525            }
526
527			// Redraw using new dataProvider
528            refresh();
529        }
530    }
531
532    //----------------------------------
533    //  editable
534    //----------------------------------
535
536    /**
537	 *  Storage for the editable property.
538	 */
539	private var _editable:Boolean = true;
540
541    /**
542     *  @private
543     */
544    public function get editable():Boolean
545    {
546        return _editable;
547    }
548
549    /**
550     *  @private
551     */
552    public function set editable(value:Boolean):void
553    {
554        _editable = value;
555
556		if (!initializing)
557            textInput.editable = value;
558    }
559
560    //----------------------------------
561    //  labelField
562    //----------------------------------
563
564    /**
565	 *  Storage for the labelField property.
566	 */
567    private var _labelField:String = "label";
568
569    /**
570     *  @private
571     */
572    public function get labelField():String
573    {
574        return _labelField;
575    }
576
577    /**
578     *  @private
579     */
580    public function set labelField(value:String):void
581    {
582        _labelField = value;
583    }
584
585    //----------------------------------
586    //  length
587    //----------------------------------
588
589    /**
590     *  @private
591     */
592    public function get length():int
593    {
594        return _dataProvider ? _dataProvider.length : 0;
595    }
596
597    //----------------------------------
598    //  selectedColor
599    //----------------------------------
600
601    /**
602	 *  Storage for the selectedColor property.
603	 */
604    private var _selectedColor:uint = 0x000000;
605
606    /**
607     *  @private
608     */
609    public function get selectedColor():uint
610    {
611        return _selectedColor;
612    }
613
614    /**
615     *  @private
616     */
617    public function set selectedColor(value:uint):void
618    {
619        // Set index unless it set us
620        if (!indexFlag)
621        {
622            var SI:int = findColorByName(value);
623            if (SI != -1)
624            {
625                focusedIndex = findColorByName(value);
626                _selectedIndex = focusedIndex;
627            }
628            else
629			{
630                selectedIndex = -1;
631			}
632        }
633        else
634        {
635            indexFlag = false;
636        }
637
638		if (value != selectedColor || !isOverGrid || isOpening)
639        {
640            _selectedColor = value;
641            updateColor(value);
642
643            if (isOverGrid || isOpening)
644                setFocusOnSwatch(selectedIndex);
645            if (isOpening)
646                isOpening = false;
647        }
648    }
649
650    //----------------------------------
651    //  selectedIndex
652    //----------------------------------
653
654    /**
655	 *  Storage for the selectedIndex property.
656	 */
657    private var _selectedIndex:int = 0;
658
659    /**
660     *  @private
661     */
662    public function get selectedIndex():int
663    {
664        return _selectedIndex;
665    }
666
667    /**
668     *  @private
669     */
670    public function set selectedIndex(value:int):void
671    {
672        if (value != selectedIndex && !initializing)
673        {
674            focusedIndex = value;
675            _selectedIndex = focusedIndex;
676
677			if (value >= 0)
678            {
679                indexFlag = true;
680                selectedColor = getColor(value);
681            }
682        }
683    }
684
685    //----------------------------------
686    //  selectedItem
687    //----------------------------------
688
689    /**
690     *  @private
691     */
692    public function get selectedItem():Object
693    {
694        return dataProvider ? dataProvider.getItemAt(selectedIndex) : null;
695    }
696
697    /**
698     *  @private
699     */
700    public function set selectedItem(value:Object):void
701    {
702        if (value != selectedItem)
703        {
704            var color:Number;
705			if (typeof(value) == "object")
706                color = Number(value[colorField]);
707            else if (typeof(value) == "number")
708                color = Number(value);
709
710			selectedIndex = findColorByName(color);
711        }
712    }
713
714    //----------------------------------
715    //  showTextField
716    //----------------------------------
717
718    /**
719	 *  Storage for the showTextField property.
720	 */
721    private var _showTextField:Boolean = true;
722
723    /**
724     *  @private
725     */
726    public function get showTextField():Boolean
727    {
728        return _showTextField;
729    }
730
731    /**
732     *  @private
733     */
734    public function set showTextField(value:Boolean):void
735    {
736        _showTextField = value;
737
738        if (!initializing)
739            textInput.visible = value;
740    }
741
742    //--------------------------------------------------------------------------
743    //
744    //  Overridden methods: UIComponent
745    //
746    //--------------------------------------------------------------------------
747
748    /**
749     *  @private
750     */
751    override protected function createChildren():void
752    {
753        super.createChildren();
754
755        // Create the panel background
756        if (!border)
757		{
758			border = new SwatchPanelSkin();
759
760			border.styleName = this;
761			border.name = "swatchPanelBorder";
762
763			addChild(border);
764		}
765
766        // Create the preview swatch
767        if (!preview)
768		{
769			preview = new SwatchSkin();
770
771			preview.styleName = this;
772			preview.color = selectedColor;
773			preview.name = "swatchPreview";
774
775			preview.setStyle("swatchBorderSize", 0);
776
777			addChild(preview);
778		}
779
780        // Create the hex text field
781        if (!textInput)
782		{
783			textInput = new TextInput();
784
785			if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0)
786			{
787				textInput.styleName = this;
788				textInput.setStyle("borderCapColor", 0x919999);
789				textInput.setStyle("buttonColor", 0x6F7777);
790				textInput.setStyle("highlightColor", 0xC4CCCC);
791				textInput.setStyle("shadowColor", 0xc);
792				textInput.setStyle("shadowCapColor", 0xD5DDDD);
793				textInput.setStyle("borderStyle", "inset");
794				textInput.setStyle("backgroundColor", 0xFFFFFF);
795				textInput.setStyle("borderColor", 0xD5DDDD);
796			}
797			else
798			{
799				textInput.styleName = getStyle("textFieldStyleName");
800			}
801
802			textInput.editable = _editable;
803			textInput.maxChars = 6;
804			textInput.name = "inset";
805			textInput.text = rgbToHex(selectedColor);
806			textInput.restrict = "#xa-fA-F0-9";
807
808			textInput.addEventListener(Event.CHANGE, textInput_changeHandler);
809			textInput.addEventListener(KeyboardEvent.KEY_DOWN, textInput_keyDownHandler);
810
811			addChild(textInput);
812		}
813
814        // Create the swatches grid
815        if (!swatches)
816		{
817			swatches = new SwatchSkin();
818
819			swatches.styleName = this;
820			swatches.colorField = colorField;
821			swatches.name = "swatchGrid";
822
823			swatches.addEventListener(MouseEvent.CLICK, swatches_clickHandler);
824
825			addChild(swatches);
826		}
827
828        // Create the swatch highlight for grid rollovers
829        if (!highlight)
830		{
831			highlight = new SwatchSkin();
832
833			highlight.styleName = this;
834			highlight.visible = false;
835			highlight.name = "swatchHighlight";
836
837			addChild(highlight);
838		}
839
840        refresh();
841
842        initializing = false;
843    }
844
845    /**
846     *  @private
847     *  Change
848     */
849    override protected function measure():void
850    {
851		super.measure();
852
853        swatches.updateGrid(IList(dataProvider));
854
855        // Make sure we're at least 100 pixels wide
856
857		measuredWidth = Math.max(
858			paddingLeft + paddingRight + swatches.width, 100);
859
860		measuredHeight = Math.max(
861			paddingTop + previewHeight + itemOffset +
862			paddingBottom + swatches.height, 100);
863    }
864
865    /**
866     *  @private
867     */
868	override protected function updateDisplayList(unscaledWidth:Number,
869												  unscaledHeight:Number):void
870    {
871        super.updateDisplayList(unscaledWidth, unscaledHeight);
872
873        // Layout preview position.
874        preview.updateSkin(selectedColor);
875        preview.move(paddingLeft, paddingTop);
876
877        // Layout hex text field position.
878        textInput.setActualSize(textFieldWidth, previewHeight);
879        textInput.move(paddingLeft + previewWidth + itemOffset, paddingTop);
880
881        // Layout grid position.
882        swatches.updateGrid(IList(dataProvider));
883        swatches.move(paddingLeft, paddingTop + previewHeight + itemOffset);
884
885        // Layout highlight skin.
886		// Highlight doesn't require a color, hence we pass 0.
887        highlight.updateSkin(0);
888
889        // Layout panel skin.
890        border.setActualSize(unscaledWidth, unscaledHeight);
891
892        // Define area surrounding the swatches.
893        if (!grid)
894            grid = new Rectangle();
895        grid.left = swatches.x + swatchGridBorderSize;
896        grid.top = swatches.y + swatchGridBorderSize;
897        grid.right = swatches.x + swatchGridBorderSize +
898					 (swatchWidth - 1) * columnCount + 1 +
899					 horizontalGap * (columnCount - 1);
900        grid.bottom = swatches.y + swatchGridBorderSize +
901					  (swatchHeight - 1) * rows + 1 +
902					  verticalGap * (rows - 1);
903    }
904
905
906    /**
907     *  @private
908     */
909    override public function styleChanged(styleProp:String):void
910    {
911        if (!initializing)
912            refresh();
913    }
914
915    /**
916     *  @private
917     */
918    override public function drawFocus(isFocused:Boolean):void
919    {
920        // do nothing...
921    }
922
923    /**
924     *  @private
925     */
926    override public function setFocus():void
927    {
928        // Our text field controls focus
929        if (showTextField && editable)
930        {
931            textInput.setFocus();
932            //ensure text field has the correct color value
933	        textInput.text = rgbToHex(selectedColor);
934        }
935    }
936
937    //--------------------------------------------------------------------------
938    //
939    //  Methods
940    //
941    //--------------------------------------------------------------------------
942
943    /**
944     *  @private
945     */
946    private function updateStyleCache():void
947    {
948        horizontalGap = getStyle("horizontalGap");
949        verticalGap = getStyle("verticalGap");
950        columnCount = getStyle("columnCount");
951        paddingLeft = getStyle("paddingLeft");
952        paddingRight = getStyle("paddingRight");
953        paddingTop = getStyle("paddingTop");
954        paddingBottom = getStyle("paddingBottom");
955        textFieldWidth = getStyle("textFieldWidth");
956        previewWidth = getStyle("previewWidth");
957        previewHeight = getStyle("previewHeight");
958        swatchWidth = getStyle("swatchWidth");
959        swatchHeight = getStyle("swatchHeight");
960        swatchGridBorderSize = getStyle("swatchGridBorderSize");
961
962        // Adjust if columnCount is greater than # of swatches
963        if (columnCount > length)
964            columnCount = length;
965
966        // Rows based on columnCount and list length
967        rows = Math.ceil(length / columnCount);
968    }
969
970    /**
971     *  @private
972     */
973    private function refresh():void
974    {
975        updateStyleCache();
976        updateDisplayList(unscaledWidth, unscaledHeight);
977
978        // Changes may have invalidated the size, so make sure we re-measure - SDK-13855
979        invalidateSize();
980    }
981
982    /**
983     *  @private
984	 *  Update color values in preview
985     */
986    private function updateColor(color:uint):void
987    {
988        if (initializing || isNaN(color))
989            return;
990
991        // Update the preview swatch
992        preview.updateSkin(color);
993
994        // Set hex field
995        if (isOverGrid)
996        {
997            var label:String = null;
998
999			if (focusedIndex >= 0 &&
1000                typeof(dataProvider.getItemAt(focusedIndex)) == "object")
1001            {
1002                label = dataProvider.getItemAt(focusedIndex)[labelField];
1003            }
1004
1005            textInput.text = label != null && label.length != 0 ?
1006							 label :
1007                             rgbToHex(color);
1008        }
1009    }
1010
1011    /**
1012     *  @private
1013	 *  Convert RGB offset to Hex.
1014     */
1015    private function rgbToHex(color:uint):String
1016    {
1017        // Find hex number in the RGB offset
1018        var colorInHex:String = color.toString(16);
1019        var c:String = "00000" + colorInHex;
1020        var e:int = c.length;
1021        c = c.substring(e - 6, e);
1022        return c.toUpperCase();
1023    }
1024
1025    /**
1026     *  @private
1027     */
1028    private function findColorByName(name:Number):int
1029    {
1030        if (name == getColor(selectedIndex))
1031            return selectedIndex;
1032
1033        for (var i:int = 0; i < length; i++)
1034		{
1035            if (name == getColor(i))
1036                return i;
1037		}
1038
1039        return -1;
1040    }
1041
1042    /**
1043     *  @private
1044     */
1045    private function getColor(index:int):uint
1046    {
1047		if (!dataProvider || dataProvider.length < 1 ||
1048			index < 0 || index >= length)
1049		{
1050			return StyleManager.NOT_A_COLOR;
1051		}
1052
1053		return uint(typeof(dataProvider.getItemAt(index)) == "object" ?
1054        	   		dataProvider.getItemAt(index)[colorField] :
1055					dataProvider.getItemAt(index));
1056    }
1057
1058    /**
1059     *  @private
1060     */
1061    private function setFocusOnSwatch(index:int):void
1062    {
1063        if (index < 0 || index > length - 1)
1064        {
1065            highlight.visible = false;
1066            return;
1067        }
1068
1069		// Swatch highlight activated by mouse move or key events
1070        var row:Number = Math.floor(index / columnCount);
1071        var column:Number = index - (row * columnCount);
1072
1073		var xPos:Number = swatchWidth * column + horizontalGap * column -
1074						  cellOffset * column + paddingLeft +
1075						  swatchGridBorderSize;
1076        var yPos:Number = swatchHeight * row + verticalGap * row -
1077						  cellOffset * row + paddingTop + previewHeight +
1078						  itemOffset + swatchGridBorderSize;
1079
1080		highlight.move(xPos, yPos);
1081        highlight.visible = true;
1082
1083		isOverGrid = true;
1084
1085		updateColor(getColor(index));
1086    }
1087
1088    //--------------------------------------------------------------------------
1089    //
1090    //  Overridden event handlers: UIComponent
1091    //
1092    //--------------------------------------------------------------------------
1093
1094    /**
1095     *  @private
1096     */
1097    override protected function keyDownHandler(event:KeyboardEvent):void
1098    {
1099		// Ignore events that bubbling from the owner ColorPicker.
1100		// through the textInput's keyDownHandler
1101		if (event.eventPhase != EventPhase.AT_TARGET || !enabled)
1102			return;
1103
1104        if (focusedIndex == -1 || isNaN(focusedIndex))
1105            focusedIndex = 0;
1106
1107        var currentRow:int = Math.floor(focusedIndex / columnCount);
1108
1109        switch (event.keyCode)
1110        {
1111            case Keyboard.UP:
1112            {
1113                // Move up in column / jump to bottom of next column at end.
1114                focusedIndex = focusedIndex - columnCount < 0 ?
1115							   (rows - 1) * columnCount + focusedIndex + 1 :
1116							   focusedIndex - columnCount;
1117                isOverGrid = true;
1118                break;
1119            }
1120
1121            case Keyboard.DOWN:
1122            {
1123                // Move down in column / jump to top of last column at end.
1124                focusedIndex = focusedIndex + columnCount > length ?
1125							   (focusedIndex - 1) - (rows - 1) * columnCount :
1126							   focusedIndex + columnCount;
1127                isOverGrid = true;
1128                break;
1129            }
1130
1131            case Keyboard.LEFT:
1132            {
1133                // Move left in row / jump to right of last row at end.
1134                focusedIndex = focusedIndex < 1 ?
1135							   length - 1 :
1136							   focusedIndex - 1;
1137                isOverGrid = true;
1138                break;
1139            }
1140
1141            case Keyboard.RIGHT:
1142            {
1143                // Move right in row / jump to left of next row at end.
1144                focusedIndex = focusedIndex >= length - 1 ?
1145							   0 :
1146							   focusedIndex + 1;
1147                isOverGrid = true;
1148                break;
1149            }
1150
1151            case Keyboard.PAGE_UP:
1152            {
1153                // Move to first swatch in column.
1154                focusedIndex = focusedIndex - currentRow * columnCount;
1155                isOverGrid = true;
1156                break;
1157            }
1158
1159            case Keyboard.PAGE_DOWN:
1160            {
1161                // Move to last swatch in column.
1162                focusedIndex = focusedIndex + (rows - 1) * columnCount -
1163							   currentRow * columnCount;
1164                isOverGrid = true;
1165                break;
1166            }
1167
1168            case Keyboard.HOME:
1169            {
1170                // Move to first swatch in row.
1171                focusedIndex = focusedIndex -
1172							   (focusedIndex - currentRow * columnCount);
1173                isOverGrid = true;
1174                break;
1175            }
1176
1177            case Keyboard.END:
1178            {
1179                // Move to last swatch in row.
1180                focusedIndex = focusedIndex +
1181							   (currentRow * columnCount - focusedIndex) +
1182							   (columnCount - 1);
1183                isOverGrid = true;
1184                break;
1185            }
1186        }
1187
1188        // Draw focus on new swatch.
1189        if (focusedIndex < length && isOverGrid)
1190        {
1191            setFocusOnSwatch(focusedIndex);
1192			dispatchEvent(new Event("change"));
1193        }
1194    }
1195
1196    //--------------------------------------------------------------------------
1197    //
1198    //  Event handlers
1199    //
1200    //--------------------------------------------------------------------------
1201
1202    /**
1203     *  @private
1204     */
1205    private function mouseMoveHandler(event:MouseEvent):void
1206    {
1207        if (ColorPicker(owner).isDown && enabled)
1208        {
1209            var colorPickerEvent:ColorPickerEvent;
1210
1211            // Only assess movements that occur over the swatch grid.
1212            if (mouseX > grid.left && mouseX < grid.right &&
1213                mouseY > grid.top && mouseY < grid.bottom)
1214            {
1215                // Calculate location
1216                var column:Number = Math.floor(
1217					(Math.floor(mouseX) - (grid.left + verticalGap)) /
1218					(swatchWidth + horizontalGap - cellOffset));
1219				var row:Number = Math.floor(
1220					(Math.floor(mouseY) - grid.top) /
1221					((swatchHeight + verticalGap) - cellOffset));
1222                var index:Number = row * columnCount + column;
1223
1224                // Adjust for edges
1225                if (column == -1)
1226					index++;
1227                else if (column > (columnCount - 1))
1228				    index--;
1229                else if (row > (rows - 1))
1230					index -= columnCount;
1231                else if (index < 0)
1232					index += columnCount;
1233
1234                // Set state
1235                if ((lastIndex != index || highlight.visible == false) &&
1236					index < length)
1237                {
1238                    if (lastIndex != -1 && lastIndex != index)
1239                    {
1240                        // Dispatch a ColorPickerEvent with type "itemRollOut".
1241						colorPickerEvent = new ColorPickerEvent(
1242                            ColorPickerEvent.ITEM_ROLL_OUT);
1243                        colorPickerEvent.index = lastIndex;
1244						colorPickerEvent.color = getColor(lastIndex);
1245                        dispatchEvent(colorPickerEvent);
1246                    }
1247
1248                    focusedIndex = index;
1249                    lastIndex = focusedIndex;
1250                    setFocusOnSwatch(focusedIndex);
1251
1252                    // Dispatch a ColorPickerEvent with type "itemRollOver".
1253					colorPickerEvent = new ColorPickerEvent(
1254                        ColorPickerEvent.ITEM_ROLL_OVER);
1255                    colorPickerEvent.index =  focusedIndex;
1256					colorPickerEvent.color = getColor(focusedIndex);
1257                    dispatchEvent(colorPickerEvent);
1258                }
1259            }
1260            else
1261            {
1262                if (highlight.visible == true && isOverGrid && lastIndex != -1)
1263                {
1264                    highlight.visible = false;
1265
1266                    // Dispatch a ColorPickerEvent with type "itemRollOut".
1267                    colorPickerEvent = new ColorPickerEvent(
1268                        ColorPickerEvent.ITEM_ROLL_OUT);
1269                    colorPickerEvent.index = lastIndex;
1270					colorPickerEvent.color = getColor(lastIndex);
1271                    dispatchEvent(colorPickerEvent);
1272                }
1273
1274                isOverGrid = false;
1275            }
1276        }
1277    }
1278
1279    /**
1280     *  @private
1281     */
1282    private function swatches_clickHandler(event:MouseEvent):void
1283    {
1284		if (!enabled)
1285			return;
1286
1287        if (mouseX > grid.left && mouseX < grid.right &&
1288            mouseY > grid.top && mouseY < grid.bottom)
1289        {
1290            selectedIndex = focusedIndex;
1291
1292			if (ColorPicker(owner).selectedIndex != selectedIndex)
1293            {
1294                ColorPicker(owner).selectedIndex = selectedIndex;
1295
1296				var cpEvent:ColorPickerEvent =
1297                    new ColorPickerEvent(ColorPickerEvent.CHANGE);
1298                cpEvent.index = selectedIndex;
1299                cpEvent.color = getColor(selectedIndex);
1300                ColorPicker(owner).dispatchEvent(cpEvent);
1301            }
1302
1303            ColorPicker(owner).close(); // owner = ColorPicker
1304        }
1305    }
1306
1307    /**
1308     *  @private
1309     */
1310    private function textInput_keyDownHandler(event:KeyboardEvent):void
1311    {
1312        // Redispatch the event from the ColorPicker
1313		// and let its keyDownHandler() handle it.
1314        ColorPicker(owner).dispatchEvent(event);
1315    }
1316
1317    /**
1318     *  @private
1319     */
1320    private function textInput_changeHandler(event:Event):void
1321    {
1322        // Handle events from hex TextField.
1323        var color:String = TextInput(event.target).text;
1324        if (color.charAt(0) == "#")
1325        {
1326            textInput.maxChars = 7;
1327            color = "0x"+color.substring(1);
1328        }
1329        else if (color.substring(0,2) == "0x")
1330        {
1331            textInput.maxChars = 8;
1332        }
1333        else
1334        {
1335            textInput.maxChars = 6;
1336            color = "0x"+color;
1337        }
1338
1339		highlight.visible = false;
1340        isOverGrid = false;
1341		selectedColor = Number(color);
1342
1343		dispatchEvent(new Event("change"));
1344    }
1345}
1346
1347}
1348