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