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.listClasses
13{
14
15import flash.display.DisplayObject;
16import flash.geom.Point;
17import flash.geom.Rectangle;
18
19import mx.core.IDataRenderer;
20import mx.core.IFlexDisplayObject;
21import mx.core.IFlexModuleFactory;
22import mx.core.IFontContextComponent;
23import mx.core.IToolTip;
24import mx.core.IUITextField;
25import mx.core.UIComponent;
26import mx.core.UITextField;
27import mx.core.mx_internal;
28import mx.events.FlexEvent;
29import mx.events.InterManagerRequest;
30import mx.events.ToolTipEvent;
31import mx.managers.ISystemManager;
32import mx.utils.PopUpUtil;
33
34use namespace mx_internal;
35
36//--------------------------------------
37//  Events
38//--------------------------------------
39
40/**
41 *  Dispatched when the <code>data</code> property changes.
42 *
43 *  <p>When you use a component as an item renderer,
44 *  the <code>data</code> property contains the data to display.
45 *  You can listen for this event and update the component
46 *  when the <code>data</code> property changes.</p>
47 *
48 *  @eventType mx.events.FlexEvent.DATA_CHANGE
49 *
50 *  @langversion 3.0
51 *  @playerversion Flash 9
52 *  @playerversion AIR 1.1
53 *  @productversion Flex 3
54 */
55[Event(name="dataChange", type="mx.events.FlexEvent")]
56
57//--------------------------------------
58//  Styles
59//--------------------------------------
60
61/**
62 *  Text color of a component label.
63 *
64 *  The default value for the Halo theme is <code>0x0B333C</code>.
65 *  The default value for the Spark theme is <code>0x000000</code>.
66 *
67 *  @langversion 3.0
68 *  @playerversion Flash 9
69 *  @playerversion AIR 1.1
70 *  @productversion Flex 3
71 */
72[Style(name="color", type="uint", format="Color", inherit="yes")]
73
74/**
75 *  Text color of the component if it is disabled.
76 *
77 *  @default 0xAAB3B3
78 *
79 *  @langversion 3.0
80 *  @playerversion Flash 9
81 *  @playerversion AIR 1.1
82 *  @productversion Flex 3
83 */
84[Style(name="disabledColor", type="uint", format="Color", inherit="yes")]
85
86/**
87 *  The ListItemRenderer class defines the default item renderer
88 *  for a List control.
89 *  By default, the item renderer draws the text associated
90 *  with each item in the list, and an optional icon.
91 *
92 *  <p>You can override the default item renderer
93 *  by creating a custom item renderer.</p>
94 *
95 *  @see mx.controls.List
96 *  @see mx.core.IDataRenderer
97 *  @see mx.controls.listClasses.IDropInListItemRenderer
98 *
99 *  @langversion 3.0
100 *  @playerversion Flash 9
101 *  @playerversion AIR 1.1
102 *  @productversion Flex 3
103 */
104public class ListItemRenderer extends UIComponent
105                              implements IDataRenderer,
106                              IDropInListItemRenderer, IListItemRenderer,
107                              IFontContextComponent
108{
109    include "../../core/Version.as";
110
111    //--------------------------------------------------------------------------
112    //
113    //  Constructor
114    //
115    //--------------------------------------------------------------------------
116
117    /**
118     *  Constructor.
119     *
120     *  @langversion 3.0
121     *  @playerversion Flash 9
122     *  @playerversion AIR 1.1
123     *  @productversion Flex 3
124     */
125    public function ListItemRenderer()
126    {
127        super();
128
129        addEventListener(ToolTipEvent.TOOL_TIP_SHOW, toolTipShowHandler);
130    }
131
132    //--------------------------------------------------------------------------
133    //
134    //  Variables
135    //
136    //--------------------------------------------------------------------------
137
138    /**
139     *  @private
140     */
141    private var listOwner:ListBase;
142
143    //--------------------------------------------------------------------------
144    //
145    //  Overridden properties: UIComponent
146    //
147    //--------------------------------------------------------------------------
148
149    //----------------------------------
150    //  baselinePosition
151    //----------------------------------
152
153    /**
154     *  @private
155     *  The baselinePosition of a ListItemRenderer is calculated
156     *  for its label.
157     */
158    override public function get baselinePosition():Number
159    {
160        if (!validateBaselinePosition())
161            return NaN;
162
163        return label.y + label.baselinePosition;
164    }
165
166    //--------------------------------------------------------------------------
167    //
168    //  Properties
169    //
170    //--------------------------------------------------------------------------
171
172    //----------------------------------
173    //  data
174    //----------------------------------
175
176    /**
177     *  @private
178     *  Storage for the data property.
179     */
180    private var _data:Object;
181
182    [Bindable("dataChange")]
183
184    /**
185     *  The implementation of the <code>data</code> property
186     *  as defined by the IDataRenderer interface.
187     *  When set, it stores the value and invalidates the component
188     *  to trigger a relayout of the component.
189     *
190     *  @see mx.core.IDataRenderer
191     *
192     *  @langversion 3.0
193     *  @playerversion Flash 9
194     *  @playerversion AIR 1.1
195     *  @productversion Flex 3
196     */
197    public function get data():Object
198    {
199        return _data;
200    }
201
202    /**
203     *  @private
204     */
205    public function set data(value:Object):void
206    {
207        _data = value;
208
209        invalidateProperties();
210
211        dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
212    }
213
214   //----------------------------------
215    //  fontContext
216    //----------------------------------
217
218    /**
219     *  @inheritDoc
220     *
221     *  @langversion 3.0
222     *  @playerversion Flash 9
223     *  @playerversion AIR 1.1
224     *  @productversion Flex 3
225     */
226    public function get fontContext():IFlexModuleFactory
227    {
228        return moduleFactory;
229    }
230
231    /**
232     *  @private
233     */
234    public function set fontContext(moduleFactory:IFlexModuleFactory):void
235    {
236        this.moduleFactory = moduleFactory;
237    }
238
239    //----------------------------------
240    //  icon
241    //----------------------------------
242
243    /**
244     *  The internal IFlexDisplayObject that displays the icon in this renderer.
245     *
246     *  @langversion 3.0
247     *  @playerversion Flash 9
248     *  @playerversion AIR 1.1
249     *  @productversion Flex 3
250     */
251    protected var icon:IFlexDisplayObject;
252
253    //----------------------------------
254    //  label
255    //----------------------------------
256
257    /**
258     *  The internal UITextField that displays the text in this renderer.
259     *
260     *  @langversion 3.0
261     *  @playerversion Flash 9
262     *  @playerversion AIR 1.1
263     *  @productversion Flex 3
264     */
265    protected var label:IUITextField;
266
267    //----------------------------------
268    //  listData
269    //----------------------------------
270
271    /**
272     *  @private
273     *  Storage for the listData property.
274     */
275    private var _listData:ListData;
276
277    [Bindable("dataChange")]
278
279    /**
280     *  The implementation of the <code>listData</code> property
281     *  as defined by the IDropInListItemRenderer interface.
282     *
283     *  @see mx.controls.listClasses.IDropInListItemRenderer
284     *
285     *  @langversion 3.0
286     *  @playerversion Flash 9
287     *  @playerversion AIR 1.1
288     *  @productversion Flex 3
289     */
290    public function get listData():BaseListData
291    {
292        return _listData;
293    }
294
295    /**
296     *  @private
297     */
298    public function set listData(value:BaseListData):void
299    {
300        _listData = ListData(value);
301
302        invalidateProperties();
303    }
304
305    //--------------------------------------------------------------------------
306    //
307    //  Overridden methods: UIComponent
308    //
309    //--------------------------------------------------------------------------
310
311    /**
312     *  @private
313     */
314    override protected function createChildren():void
315    {
316        super.createChildren();
317
318        if (!label)
319        {
320            label = IUITextField(createInFontContext(UITextField));
321            label.styleName = this;
322            addChild(DisplayObject(label));
323        }
324    }
325
326    /**
327     *  @private
328     *  Apply the data and listData.
329     *  Create an instance of the icon if specified,
330     *  and set the text into the text field.
331     */
332    override protected function commitProperties():void
333    {
334        super.commitProperties();
335
336        var childIndex:int = -1;
337        if (hasFontContextChanged() && label != null)
338        {
339            childIndex = getChildIndex(DisplayObject(label));
340            removeChild(DisplayObject(label));
341            label = null;
342        }
343
344        if (!label)
345        {
346            label = IUITextField(createInFontContext(UITextField));
347            label.styleName = this;
348
349            if (childIndex == -1)
350                addChild(DisplayObject(label));
351            else
352                addChildAt(DisplayObject(label), childIndex);
353        }
354
355        if (icon)
356        {
357            removeChild(DisplayObject(icon));
358            icon = null;
359        }
360
361        if (_data != null)
362        {
363            listOwner = ListBase(_listData.owner);
364
365            if (_listData.icon)
366            {
367                var iconClass:Class = _listData.icon;
368                icon = new iconClass();
369
370                addChild(DisplayObject(icon));
371            }
372
373            label.text = _listData.label ? _listData.label : " ";
374            label.multiline = listOwner.variableRowHeight;
375            label.wordWrap = listOwner.wordWrap;
376
377            if (listOwner.showDataTips)
378            {
379                if (label.textWidth > label.width ||
380                    listOwner.dataTipFunction != null)
381                {
382                    toolTip = listOwner.itemToDataTip(_data);
383                }
384                else
385                {
386                    toolTip = null;
387                }
388            }
389            else
390            {
391                toolTip = null;
392            }
393        }
394        else
395        {
396            label.text = " ";
397            toolTip = null;
398        }
399    }
400
401    /**
402     *  @private
403     */
404    override protected function measure():void
405    {
406        super.measure();
407
408        var w:Number = 0;
409
410        if (icon)
411            w = icon.measuredWidth;
412
413        // Guarantee that label width isn't zero
414        // because it messes up ability to measure.
415        if (label.width < 4 || label.height < 4)
416        {
417            label.width = 4;
418            label.height = 16;
419        }
420
421        if (isNaN(explicitWidth))
422        {
423            w += label.getExplicitOrMeasuredWidth();
424            measuredWidth = w;
425            measuredHeight = label.getExplicitOrMeasuredHeight();
426        }
427        else
428        {
429            measuredWidth = explicitWidth;
430            label.setActualSize(Math.max(explicitWidth - w, 4), label.height);
431            measuredHeight = label.getExplicitOrMeasuredHeight();
432            if (icon && icon.measuredHeight > measuredHeight)
433                measuredHeight = icon.measuredHeight;
434        }
435    }
436
437    /**
438     *  @private
439     */
440    override protected function updateDisplayList(unscaledWidth:Number,
441                                                  unscaledHeight:Number):void
442    {
443        super.updateDisplayList(unscaledWidth, unscaledHeight);
444
445        var startX:Number = 0;
446
447        if (icon)
448        {
449            icon.x = startX;
450            startX = icon.x + icon.measuredWidth;
451            icon.setActualSize(icon.measuredWidth, icon.measuredHeight);
452        }
453
454        label.x = startX;
455        label.setActualSize(unscaledWidth - startX, measuredHeight);
456
457        var verticalAlign:String = getStyle("verticalAlign");
458        if (verticalAlign == "top")
459        {
460            label.y = 0;
461            if (icon)
462                icon.y = 0;
463        }
464        else if (verticalAlign == "bottom")
465        {
466            label.y = unscaledHeight - label.height + 2; // 2 for gutter
467            if (icon)
468                icon.y = unscaledHeight - icon.height;
469        }
470        else
471        {
472            label.y = (unscaledHeight - label.height) / 2;
473            if (icon)
474                icon.y = (unscaledHeight - icon.height) / 2;
475        }
476
477        var labelColor:Number;
478
479        if (data && parent)
480        {
481            if (!enabled)
482                labelColor = getStyle("disabledColor");
483            else if (listOwner.isItemHighlighted(listData.uid))
484                labelColor = getStyle("textRollOverColor");
485            else if (listOwner.isItemSelected(listData.uid))
486                labelColor = getStyle("textSelectedColor");
487            else
488                labelColor = getStyle("color");
489
490            label.setColor(labelColor);
491        }
492    }
493
494
495    //--------------------------------------------------------------------------
496    //
497    //  Event handlers
498    //
499    //--------------------------------------------------------------------------
500
501    /**
502     *  Positions the ToolTip object.
503     *
504     *  @param The Event object.
505     *
506     *  @langversion 3.0
507     *  @playerversion Flash 9
508     *  @playerversion AIR 1.1
509     *  @productversion Flex 3
510     */
511    protected function toolTipShowHandler(event:ToolTipEvent):void
512    {
513        var toolTip:IToolTip = event.toolTip;
514
515        // We need to position the tooltip at same x coordinate,
516        // center vertically and make sure it doesn't overlap the screen.
517        // Call the helper function to handle this for us.
518        var pt:Point = PopUpUtil.positionOverComponent(DisplayObject(label),
519                                                       systemManager,
520                                                       toolTip.width,
521                                                       toolTip.height,
522                                                       height / 2);
523        toolTip.move(pt.x, pt.y);
524    }
525
526    /**
527     *  @private
528     */
529    mx_internal function getLabel():IUITextField
530    {
531        return label;
532    }
533
534
535}
536
537}
538