1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2005-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.skins.halo
13{
14
15import flash.display.DisplayObject;
16import flash.display.GradientType;
17import mx.core.IFlexDisplayObject;
18import mx.core.UIComponent;
19import mx.core.mx_internal;
20import mx.styles.StyleManager;
21import mx.utils.ColorUtil;
22import mx.core.IProgrammaticSkin;
23
24use namespace mx_internal;
25
26/**
27 *  The skin for all the states of a PopUpButton.
28 *
29 *  @langversion 3.0
30 *  @playerversion Flash 9
31 *  @playerversion AIR 1.1
32 *  @productversion Flex 3
33 */
34public class PopUpButtonSkin extends UIComponent implements IProgrammaticSkin
35{
36    include "../../core/Version.as";
37
38    //--------------------------------------------------------------------------
39    //
40    //  Class variables
41    //
42    //--------------------------------------------------------------------------
43
44	/**
45	 *  @private
46	 */
47    private static var cache:Object = {};
48
49    //--------------------------------------------------------------------------
50    //
51    //  Class methods
52    //
53    //--------------------------------------------------------------------------
54
55    /**
56     *  @private
57	 *  Several colors used for drawing are calculated from the base colors
58	 *  of the component (themeColor, borderColor and fillColors).
59	 *  Since these calculations can be a bit expensive,
60	 *  we calculate once per color set and cache the results.
61     */
62    private static function calcDerivedStyles(themeColor:uint,
63                                              fillColor0:uint,
64                                              fillColor1:uint):Object
65    {
66        var key:String = HaloColors.getCacheKey(themeColor,
67												fillColor0, fillColor1);
68
69        if (!cache[key])
70        {
71            var o:Object = cache[key] = {};
72
73            // Cross-component styles.
74            HaloColors.addHaloColors(o, themeColor, fillColor0, fillColor1);
75        }
76
77        return cache[key];
78    }
79
80    //--------------------------------------------------------------------------
81    //
82    //  Constructor
83    //
84    //--------------------------------------------------------------------------
85
86    /**
87     *  Constructor.
88     *
89     *  @langversion 3.0
90     *  @playerversion Flash 9
91     *  @playerversion AIR 1.1
92     *  @productversion Flex 3
93     */
94    public function PopUpButtonSkin()
95    {
96        super();
97
98		mouseEnabled = false;
99    }
100
101    //--------------------------------------------------------------------------
102    //
103    //  Overridden properties
104    //
105    //--------------------------------------------------------------------------
106
107
108	//----------------------------------
109	//  measuredWidth
110	//----------------------------------
111
112	/**
113	 *  @private
114	 */
115	override public function get measuredWidth():Number
116	{
117		return DEFAULT_MEASURED_MIN_WIDTH;
118	}
119
120	//----------------------------------
121	//  measuredHeight
122	//----------------------------------
123
124	/**
125	 *  @private
126	 */
127	override public function get measuredHeight():Number
128	{
129		return DEFAULT_MEASURED_MIN_HEIGHT;
130	}
131
132    //--------------------------------------------------------------------------
133    //
134    //  Overridden methods
135    //
136    //--------------------------------------------------------------------------
137
138    /**
139     *  @private
140     */
141	override protected function updateDisplayList(w:Number, h:Number):void
142    {
143		super.updateDisplayList(w, h);
144
145        // User-defined styles.
146        var arrowColor:uint = getStyle("iconColor");
147        var borderColor:uint = getStyle("borderColor");
148        var cornerRadius:Number = getStyle("cornerRadius");
149		var fillAlphas:Array = getStyle("fillAlphas");
150		var fillColors:Array = getStyle("fillColors");
151        StyleManager.getStyleManager(moduleFactory).getColorNames(fillColors);
152		var highlightAlphas:Array = getStyle("highlightAlphas");
153        var themeColor:uint = getStyle("themeColor");
154
155        // Derivative styles.
156        var derStyles:Object = calcDerivedStyles(themeColor, fillColors[0],
157                                                 fillColors[1]);
158
159        var borderColorDrk1:Number =
160			ColorUtil.adjustBrightness2(borderColor, -50);
161
162		var themeColorDrk1:Number =
163			ColorUtil.adjustBrightness2(themeColor, -25);
164
165        var popUpIcon:IFlexDisplayObject =
166			IFlexDisplayObject(getChildByName("popUpIcon"));
167
168        if (!popUpIcon)
169        {
170            var popUpIconClass:Class = Class(getStyle("popUpIcon"));
171            popUpIcon = new popUpIconClass();
172            DisplayObject(popUpIcon).name = "popUpIcon";
173            addChild(DisplayObject(popUpIcon));
174            DisplayObject(popUpIcon).visible = true;
175        }
176
177        var arrowButtonWidth:Number = Math.max(getStyle("arrowButtonWidth"),
178											   popUpIcon.width + 3 + 1);
179
180		var dividerPosX:Number = w - arrowButtonWidth;
181
182		popUpIcon.move(w - (arrowButtonWidth + popUpIcon.width) / 2,
183					   (h - popUpIcon.height) / 2);
184
185        var cr:Number = Math.max(0, cornerRadius);
186        var cr1:Number = Math.max(0, cornerRadius - 1);
187
188		var upFillColors:Array;
189		var upFillAlphas:Array;
190
191		var overFillColors:Array;
192		var overFillAlphas:Array;
193
194		graphics.clear();
195
196        switch (name)
197        {
198            case "upSkin":
199            {
200   				upFillColors = [ fillColors[0], fillColors[1] ];
201   				upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
202
203				// button border/edge
204				drawRoundRect(
205					0, 0, w, h, cr,
206					[ borderColor, borderColorDrk1 ], 1,
207					verticalGradientMatrix(0, 0, w, h),
208					GradientType.LINEAR, null,
209					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
210
211				drawRoundRect(
212					dividerPosX, 1, 1, h - 2, 0,
213					[ borderColor, borderColorDrk1 ], 1,
214					verticalGradientMatrix(0, 0, w, h));
215
216				// button fill
217				drawRoundRect(
218					1, 1, w - 2, h - 2, cr1,
219					upFillColors, upFillAlphas,
220					verticalGradientMatrix(1, 1, w - 2, h - 2),
221					GradientType.LINEAR, null,
222					{ x: dividerPosX, y: 1, w: 1, h: h - 2, r: 0 });
223
224				// top highlight
225				drawRoundRect(
226					1, 1, w - 2, (h - 2) / 2,
227					{ tl: cr1, tr: cr1, bl: 0, br: 0 },
228					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
229					verticalGradientMatrix(1, 1, w - 2, (h - 2) / 2),
230					GradientType.LINEAR, null,
231					{ x: dividerPosX, y: 1, w: 1, h: (h - 2) / 2, r: 0 });
232
233				// side bevel highlight edges
234				drawRoundRect(
235					dividerPosX - 1, 1, 1, h - 2, 0,
236					borderColor, 0);
237				drawRoundRect(
238					dividerPosX + 1, 1, 1, h - 2, 0,
239					borderColor, 0);
240
241                break;
242            }
243
244            case "overSkin": // for hover on the main button (left) side
245            {
246   				upFillColors = [ fillColors[0], fillColors[1] ];
247				upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
248
249				if (fillColors.length > 2)
250					overFillColors = [ fillColors[2], fillColors[3] ];
251				else
252					overFillColors = [ fillColors[0], fillColors[1] ];
253
254				if (fillAlphas.length > 2)
255					overFillAlphas = [ fillAlphas[2], fillAlphas[3] ];
256  				else
257					overFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
258
259				// button border/edge
260				drawRoundRect(
261					0, 0, w, h, cr,
262					[ themeColor, themeColorDrk1 ], 1,
263					verticalGradientMatrix(0, 0, w, h),
264					GradientType.LINEAR, null,
265					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
266
267				drawRoundRect(
268					dividerPosX, 1, 1, h - 2, 0,
269					[ themeColor, themeColorDrk1 ], 1,
270					verticalGradientMatrix(0, 0, w, h));
271				// button fill
272				drawRoundRect(
273					1, 1, w - 2, h - 2, cr1,
274					upFillColors, upFillAlphas,
275					verticalGradientMatrix(1, 1, w - 2, h - 2),
276					GradientType.LINEAR, null,
277					{ x: dividerPosX, y: 1, w: 1, h: h - 2,
278					  r: getRadius(cr1, true) });
279
280				// left/main button fill
281				drawRoundRect(
282					1, 1, w - arrowButtonWidth - 2, h - 2,
283					getRadius(cr1, true),
284					overFillColors, overFillAlphas,
285					verticalGradientMatrix(1, 1, dividerPosX - 2, h - 2));
286
287				// top highlight
288				drawRoundRect(
289					1, 1, w - 2, (h -2) / 2,
290					{ tl: cr1, tr: cr1, bl: 0, br: 0 },
291					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
292					verticalGradientMatrix(1, 1, w - 2, (h - 2) / 2),
293					GradientType.LINEAR, null,
294					{ x: dividerPosX, y: 1, w: 1, h: (h - 2) / 2, r: 0 });
295
296				// side bevel highlight edges
297				drawRoundRect(
298					dividerPosX - 1, 1, 1, h - 2, 0,
299					themeColor, 0.35);
300
301                break;
302            }
303
304            case "popUpOverSkin": // for hover on the arrow-button (right) side
305            {
306   				upFillColors = [ fillColors[0], fillColors[1] ];
307				upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
308
309				if (fillColors.length > 2)
310					overFillColors = [ fillColors[2], fillColors[3] ];
311				else
312					overFillColors = [ fillColors[0], fillColors[1] ];
313
314				if (fillAlphas.length > 2)
315					overFillAlphas = [ fillAlphas[2], fillAlphas[3] ];
316  				else
317					overFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
318
319				// button border/edge
320				drawRoundRect(
321					0, 0, w, h, cr,
322					[ themeColor, themeColorDrk1 ], 1,
323					verticalGradientMatrix(0, 0, w, h),
324					GradientType.LINEAR, null,
325					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
326
327				drawRoundRect(
328					dividerPosX, 1, 1, h - 2, 0,
329					[ themeColor, themeColorDrk1 ], 1,
330					verticalGradientMatrix(0, 0, w, h));
331
332				// button fill
333				drawRoundRect(
334					1, 1, w - 2, h - 2, getRadius(cr1, true),
335					upFillColors, upFillAlphas,
336					verticalGradientMatrix(1, 1, w - 2, h - 2),
337					GradientType.LINEAR, null,
338					{ x: dividerPosX, y: 1, w: arrowButtonWidth - 1, h: h - 2,
339					  r: getRadius(cr1, true) });
340
341				// right button fill
342				drawRoundRect(
343					dividerPosX + 1, 1, arrowButtonWidth - 2, h - 2,
344					getRadius(cr1, false),
345					overFillColors, overFillAlphas,
346					verticalGradientMatrix(dividerPosX, 0,
347										   arrowButtonWidth - 1, h - 2));
348
349				// top highlight
350				drawRoundRect(
351					1, 1, w - 2, (h -2) / 2,
352					{ tl: cr1, tr: cr1, bl: 0, br: 0 },
353					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
354					verticalGradientMatrix(1, 1, w - 2, (h - 2) / 2),
355					GradientType.LINEAR, null,
356					{ x: dividerPosX, y: 1, w: 1, h: (h - 2) / 2, r: 0 });
357
358				// side bevel highlight edges
359				drawRoundRect(
360					dividerPosX + 1, 1, 1, h - 2, 0,
361					themeColor, 0.35);
362
363                break;
364            }
365
366            case "downSkin": // for press on the main button (left) side
367            {
368   				upFillColors = [ fillColors[0], fillColors[1] ];
369				upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
370
371				// button border/ddge
372				drawRoundRect(
373					0, 0, w, h, cr,
374					[ themeColor, themeColorDrk1 ], 1,
375					verticalGradientMatrix(0, 0, w, h ),
376					GradientType.LINEAR, null,
377					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
378
379				drawRoundRect(
380					dividerPosX, 1, 1, h - 2, 0,
381					[ themeColor, themeColorDrk1 ], 1,
382					verticalGradientMatrix(0, 0, w, h));
383
384				// button fill
385				drawRoundRect(
386					1, 1, w - 2, h - 2, cr1,
387					upFillColors, upFillAlphas,
388					verticalGradientMatrix(1, 1, w - 2, h - 2),
389					GradientType.LINEAR, null,
390					{ x: dividerPosX, y: 1, w: 1, h: h - 2, r: 0 });
391
392				// left/main button fill
393				drawRoundRect(
394					1, 1, w - arrowButtonWidth - 2, h - 2,
395					getRadius(cr1, true),
396					[ derStyles.fillColorPress1, derStyles.fillColorPress2], 1,
397					verticalGradientMatrix(1, 1, dividerPosX - 2, h - 2));
398
399				// top highlight (checked, works)
400				drawRoundRect(
401					1, 1, w - 2, (h -2) / 2,
402					{ tl: cr1, tr: cr1, bl: 0, br: 0 },
403					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
404					verticalGradientMatrix(1, 1, w - 2, (h - 2) / 2),
405					GradientType.LINEAR, null,
406					{ x: dividerPosX, y: 1, w: 1, h: (h -2) / 2, r: 0 });
407
408				// side bevel highlight edges
409				drawRoundRect(
410					dividerPosX - 1, 1, 1, h - 2, 0,
411					themeColorDrk1, 0.3);
412				drawRoundRect(
413					dividerPosX + 1, 1, 1, h - 2, 0,
414					borderColor, 0);
415
416                break;
417            }
418
419            case "popUpDownSkin": // for press on the arrow-button (right) side
420            {
421   				upFillColors = [ fillColors[0], fillColors[1] ];
422				upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
423
424				// button border/edge
425				drawRoundRect(
426					0, 0, w, h, cr,
427					[ themeColor, themeColorDrk1 ], 1,
428					verticalGradientMatrix(0, 0, w, h ),
429					GradientType.LINEAR, null,
430					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
431
432				drawRoundRect(
433					dividerPosX, 1, 1, h - 2, 0,
434					[ themeColor, themeColorDrk1 ], 1,
435					verticalGradientMatrix(0, 0, w, h));
436
437				// button fill
438				drawRoundRect(
439					1, 1, w - 2, h - 2, cr1,
440					upFillColors, upFillAlphas,
441					verticalGradientMatrix(1, 1, w - 2, h - 2),
442					GradientType.LINEAR, null,
443					{ x: dividerPosX, y: 1, w: 1, h: h - 2, r: 0 });
444
445			    // right button fill
446				drawRoundRect(
447					dividerPosX + 1, 1, arrowButtonWidth - 2, h - 2,
448					getRadius(cr1, false),
449					[ derStyles.fillColorPress1,
450					  derStyles.fillColorPress2], 1,
451					verticalGradientMatrix(dividerPosX, 0,
452										   arrowButtonWidth - 1, h - 2));
453
454				// top highlight
455				drawRoundRect(
456					1, 1, w - 2, (h -2) / 2,
457					{ tl: cr1, tr: cr1, bl: 0, br: 0 },
458					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
459					verticalGradientMatrix(1, 1, w - 2, (h - 2) / 2),
460					GradientType.LINEAR, null,
461					{ x: dividerPosX, y: 1, w: 1, h: (h - 2) / 2, r: 0 });
462
463				// side bevel highlight edges
464				drawRoundRect(
465					dividerPosX - 1, 1, 1, h - 2, 0,
466					borderColor, 0);
467				drawRoundRect(
468					dividerPosX + 1, 1, 1, h - 2, 0,
469					themeColorDrk1, 0.3);
470
471                break;
472            }
473
474            case "disabledSkin":
475            {
476                arrowColor = getStyle("disabledIconColor");
477
478   				var disFillColors:Array = [ fillColors[0], fillColors[1] ];
479
480				var disFillAlphas:Array =
481					[ Math.max(0, fillAlphas[0] - 0.15),
482					  Math.max(0, fillAlphas[1] - 0.15) ];
483
484				// outer edge
485				drawRoundRect(
486					0, 0, w, h, cornerRadius,
487					[ borderColor, borderColorDrk1 ], 0.5,
488					verticalGradientMatrix(0, 0, w, h ),
489					GradientType.LINEAR, null,
490					{ x: 1, y: 1, w: w - 2, h: h - 2, r: cornerRadius - 1 });
491
492				drawRoundRect(
493					dividerPosX, 1, 1, h - 2, 0,
494					[ borderColor, borderColorDrk1 ], 0.5);
495
496				// button fill
497				drawRoundRect(
498					1, 1, w - 2, h - 2, cr1,
499					disFillColors, disFillAlphas,
500					verticalGradientMatrix(1, 1, w - 2, h - 2),
501					null, null,
502					{ x: dividerPosX, y: 1, w: 1, h: h - 2, r: 0 });
503
504                break;
505            }
506        }
507
508        if (popUpIcon is PopUpIcon)
509        	PopUpIcon(popUpIcon).arrowColor = arrowColor;
510    }
511
512    //--------------------------------------------------------------------------
513    //
514    //  Methods
515    //
516    //--------------------------------------------------------------------------
517
518    /**
519     *  @private
520     */
521    private function getRadius(r:Number, left:Boolean):Object
522    {
523		return left ?
524			   { br: 0, bl: r, tr: 0, tl: r } :
525			   { br: r, bl: 0, tr: r, tl: 0 };
526    }
527}
528
529}
530