1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 ccui._FocusNavigationController = cc.Class.extend({
 27     _keyboardListener: null,
 28     _firstFocusedWidget: null,
 29     _enableFocusNavigation: false,
 30     _keyboardEventPriority: 1,
 31 
 32     enableFocusNavigation: function(flag){
 33         if (this._enableFocusNavigation === flag)
 34             return;
 35 
 36         this._enableFocusNavigation = flag;
 37         if (flag)
 38             this._addKeyboardEventListener();
 39         else
 40             this._removeKeyboardEventListener();
 41     },
 42 
 43     _setFirstFocsuedWidget: function(widget){
 44         this._firstFocusedWidget = widget;
 45     },
 46 
 47     _onKeyPressed: function(keyCode, event){
 48         if (this._enableFocusNavigation && this._firstFocusedWidget) {
 49             if (keyCode === cc.KEY.dpadDown) {
 50                 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.DOWN, this._firstFocusedWidget);
 51             }
 52             if (keyCode === cc.KEY.dpadUp){
 53                 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.UP, this._firstFocusedWidget);
 54             }
 55             if (keyCode === cc.KEY.dpadLeft) {
 56                 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.LEFT, this._firstFocusedWidget);
 57             }
 58             if (keyCode === cc.KEY.dpadRight) {
 59                 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.RIGHT, this._firstFocusedWidget);
 60             }
 61         }
 62     },
 63 
 64     _addKeyboardEventListener: function(){
 65         if (!this._keyboardListener) {
 66             this._keyboardListener = cc.EventListener.create({
 67                 event: cc.EventListener.KEYBOARD,
 68                 onKeyReleased: this._onKeyPressed.bind(this)
 69             });
 70             cc.eventManager.addListener(this._keyboardListener, this._keyboardEventPriority);
 71         }
 72     },
 73 
 74     _removeKeyboardEventListener: function(){
 75         if (this._keyboardListener) {
 76             cc.eventManager.removeEventListener(this._keyboardListener);
 77             this._keyboardListener = null;
 78         }
 79     }
 80 });
 81 
 82 ccui.__LAYOUT_COMPONENT_NAME = "__ui_layout";
 83 
 84 /**
 85  * The base class for ccui controls and layout
 86  * @sample
 87  * var uiWidget = new ccui.Widget();
 88  * this.addChild(uiWidget);
 89  * @class
 90  * @extends ccui.ProtectedNode
 91  *
 92  * @property {Number}           xPercent        - Position x in percentage of width
 93  * @property {Number}           yPercent        - Position y in percentage of height
 94  * @property {Number}           widthPercent    - Width in percentage of parent width
 95  * @property {Number}           heightPercent   - Height in percentage of parent height
 96  * @property {ccui.Widget}      widgetParent    - <@readonly> The direct parent when it's a widget also, otherwise equals null
 97  * @property {Boolean}          enabled         - Indicate whether the widget is enabled
 98  * @property {Boolean}          focused         - Indicate whether the widget is focused
 99  * @property {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT}     sizeType        - The size type of the widget
100  * @property {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER}   widgetType      - <@readonly> The type of the widget
101  * @property {Boolean}          touchEnabled    - Indicate whether touch events are enabled
102  * @property {Boolean}          updateEnabled   - Indicate whether the update function is scheduled
103  * @property {Boolean}          bright          - Indicate whether the widget is bright
104  * @property {String}           name            - The name of the widget
105  * @property {Number}           actionTag       - The action tag of the widget
106  */
107 ccui.Widget = ccui.ProtectedNode.extend(/** @lends ccui.Widget# */{
108     _enabled: true,            ///< Highest control of widget
109     _bright: true,             ///< is this widget bright
110     _touchEnabled: false,       ///< is this widget touch endabled
111 
112     _brightStyle: null, ///< bright style
113 
114     _touchBeganPosition: null,    ///< touch began point
115     _touchMovePosition: null,     ///< touch moved point
116     _touchEndPosition: null,      ///< touch ended point
117 
118     _touchEventListener: null,
119     _touchEventSelector: null,
120 
121     _name: "default",
122     _widgetType: null,
123     _actionTag: 0,
124     _customSize: null,
125     _layoutParameterDictionary: null,
126     _layoutParameterType:0,
127 
128     _focused: false,
129     _focusEnabled: true,
130 
131     _ignoreSize: false,
132     _affectByClipping: false,
133 
134     _sizeType: null,
135     _sizePercent: null,
136     _positionType: null,
137     _positionPercent: null,
138     _hit: false,
139     _nodes: null,
140     _touchListener: null,
141     _className: "Widget",
142     _flippedX: false,
143     _flippedY: false,
144     _opacity: 255,
145     _highlight: false,
146 
147     _touchEventCallback: null,
148     _clickEventListener: null,
149 
150     _propagateTouchEvents: true,
151     _unifySize: false,
152 
153     _callbackName: null,
154     _callbackType: null,
155     _usingLayoutComponent: false,
156     _inViewRect: true,
157 
158     /**
159      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
160      * @function
161      */
162     ctor: function () {
163         cc.ProtectedNode.prototype.ctor.call(this);
164         this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE;
165         this._touchBeganPosition = cc.p(0, 0);
166         this._touchMovePosition = cc.p(0, 0);
167         this._touchEndPosition = cc.p(0, 0);
168         this._widgetType = ccui.Widget.TYPE_WIDGET;
169         this._customSize = cc.size(0, 0);
170         this._layoutParameterDictionary = {};
171         this._sizeType = ccui.Widget.SIZE_ABSOLUTE;
172         this._sizePercent = cc.p(0, 0);
173         this._positionType = ccui.Widget.POSITION_ABSOLUTE;
174         this._positionPercent = cc.p(0, 0);
175         this._nodes = [];
176         this._layoutParameterType = ccui.LayoutParameter.NONE;
177         this.init();                        //TODO
178     },
179 
180     /**
181      * initializes state of widget. please do not call this function by yourself, you should pass the parameters to constructor to initialize it
.
182      * @returns {boolean}
183      */
184     init: function () {
185         if (cc.ProtectedNode.prototype.init.call(this)) {
186             this._layoutParameterDictionary = {};
187             this._initRenderer();
188             this.setBright(true);
189 
190             this.onFocusChanged = this.onFocusChange.bind(this);
191             this.onNextFocusedWidget = null;
192             this.setAnchorPoint(cc.p(0.5, 0.5));
193 
194             this.ignoreContentAdaptWithSize(true);
195             return true;
196         }
197         return false;
198     },
199 
200     /**
201      * Calls updateSizeAndPosition and its parent's onEnter
202      * @override
203      */
204     onEnter: function () {
205         var locListener = this._touchListener;
206         if (locListener && !locListener._isRegistered() && this._touchEnabled)
207             cc.eventManager.addListener(locListener, this);
208         if(!this._usingLayoutComponent)
209             this.updateSizeAndPosition();
210         cc.ProtectedNode.prototype.onEnter.call(this);
211     },
212 
213     /**
214      * Calls unscheduleUpdate and its parent's onExit
215      * @override
216      */
217     onExit: function(){
218         this.unscheduleUpdate();
219         cc.ProtectedNode.prototype.onExit.call(this);
220     },
221 
222     _getOrCreateLayoutComponent: function(){
223         var layoutComponent = this.getComponent(ccui.__LAYOUT_COMPONENT_NAME);
224         if (null == layoutComponent){
225             layoutComponent = new ccui.LayoutComponent();
226             this.addComponent(layoutComponent);
227         }
228         return layoutComponent;
229     },
230 
231     /**
232      * The direct parent when it's a widget also, otherwise equals null
233      * @returns {ccui.Widget|null}
234      */
235     getWidgetParent: function () {
236         var widget = this.getParent();
237         if (widget instanceof ccui.Widget)
238             return widget;
239         return null;
240     },
241 
242     _updateContentSizeWithTextureSize: function(size){
243         if(this._unifySize){
244             this.setContentSize(size);
245             return;
246         }
247         this.setContentSize(this._ignoreSize ? size : this._customSize);
248     },
249 
250     _isAncestorsEnabled: function(){
251         var parentWidget = this._getAncensterWidget(this);
252         if (parentWidget == null)
253             return true;
254         if (parentWidget && !parentWidget.isEnabled())
255             return false;
256 
257         return parentWidget._isAncestorsEnabled();
258     },
259 
260     /**
261      * Allow widget touch events to propagate to its parents. Set false will disable propagation
262      * @since v3.2
263      * @param {Boolean} isPropagate
264      */
265     setPropagateTouchEvents: function(isPropagate){
266         this._propagateTouchEvents = isPropagate;
267     },
268 
269     /**
270      * Return whether the widget is propagate touch events to its parents or not
271      * @since v3.2
272      * @returns {boolean}
273      */
274     isPropagateTouchEvents: function(){
275         return this._propagateTouchEvents;
276     },
277 
278     /**
279      * Specify widget to swallow touches or not
280      * @since v3.2
281      * @param {Boolean} swallow
282      */
283     setSwallowTouches: function(swallow){
284         if (this._touchListener)
285             this._touchListener.setSwallowTouches(swallow);
286     },
287 
288     /**
289      * Return whether the widget is swallowing touch or not
290      * @since v3.2
291      * @returns {boolean}
292      */
293     isSwallowTouches: function(){
294         if (this._touchListener){
295             //return true;                           //todo need test
296             return this._touchListener.isSwallowTouches();
297         }
298         return false;
299     },
300 
301     _getAncensterWidget: function(node){
302         if (null == node)
303             return null;
304 
305         var parent = node.getParent();
306         if (null == parent)
307             return null;
308 
309         if (parent instanceof ccui.Widget)
310             return parent;
311         else
312             return this._getAncensterWidget(parent.getParent());
313     },
314 
315     _isAncestorsVisible: function(node){
316         if (null == node)
317             return true;
318 
319         var parent = node.getParent();
320 
321         if (parent && !parent.isVisible())
322             return false;
323         return this._isAncestorsVisible(parent);
324     },
325 
326     _cleanupWidget: function(){
327         //clean up _touchListener
328         this._eventDispatcher.removeEventListener(this._touchListener);
329         this._touchEnabled = false;
330         this._touchListener = null;
331 
332         //cleanup focused widget and focus navigation controller
333         if (ccui.Widget._focusedWidget === this){
334             ccui.Widget._focusedWidget = null;
335             ccui.Widget._focusNavigationController = null;
336         }
337     },
338 
339     /**
340      * <p>
341      *     Sets whether the widget is enabled                                                                                    <br/>
342      *     true if the widget is enabled, widget may be touched , false if the widget is disabled, widget cannot be touched.     <br/>
343      *     The default value is true, a widget is default to enabled
344      * </p>
345      * @param {Boolean} enabled
346      */
347     setEnabled: function (enabled) {
348         this._enabled = enabled;
349     },
350 
351     /**
352      * initializes renderer of widget.
353      */
354     _initRenderer: function () {},
355 
356     /**
357      * Sets _customSize of ccui.Widget, if ignoreSize is true, the content size is its renderer's contentSize, otherwise the content size is parameter.
358      * and updates size percent by parent content size. At last, updates its children's size and position.
359      * @param {cc.Size|Number} contentSize content size or width of content size
360      * @param {Number} [height]
361      * @override
362      */
363     setContentSize: function(contentSize, height){
364         var locWidth = (height === undefined) ? contentSize.width : contentSize;
365         var locHeight = (height === undefined) ? contentSize.height : height;
366         cc.Node.prototype.setContentSize.call(this, locWidth, locHeight);
367 
368         this._customSize.width = locWidth;
369         this._customSize.height = locHeight;
370         if(this._unifySize){
371             //unify size logic
372         } else if (this._ignoreSize){
373             this._contentSize = this.getVirtualRendererSize();
374         }
375         if (!this._usingLayoutComponent && this._running) {
376             var widgetParent = this.getWidgetParent();
377             var pSize = widgetParent ? widgetParent.getContentSize() : this._parent.getContentSize();
378             this._sizePercent.x = (pSize.width > 0.0) ? locWidth / pSize.width : 0.0;
379             this._sizePercent.y = (pSize.height > 0.0) ? locHeight / pSize.height : 0.0;
380         }
381         this._onSizeChanged();
382     },
383 
384     _setWidth: function (w) {
385         cc.Node.prototype._setWidth.call(this, w);
386         this._customSize.width = w;
387         if(this._unifySize){
388             //unify size logic
389         } else if (this._ignoreSize){
390             this._contentSize = this.getVirtualRendererSize();
391         }
392 
393         if (!this._usingLayoutComponent && this._running) {
394             var widgetParent = this.getWidgetParent();
395             var locWidth = widgetParent ? widgetParent.width : this._parent.width;
396             this._sizePercent.x = locWidth > 0 ? this._customSize.width / locWidth : 0;
397         }
398         this._onSizeChanged();
399     },
400     _setHeight: function (h) {
401         cc.Node.prototype._setHeight.call(this, h);
402         this._customSize.height = h;
403         if(this._unifySize){
404             //unify size logic
405         } else if (this._ignoreSize){
406             this._contentSize = this.getVirtualRendererSize();
407         }
408 
409         if (!this._usingLayoutComponent && this._running) {
410             var widgetParent = this.getWidgetParent();
411             var locH = widgetParent ? widgetParent.height : this._parent.height;
412             this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0;
413         }
414         this._onSizeChanged();
415     },
416 
417     /**
418      * Changes the percent that is widget's percent size
419      * @param {cc.Point} percent that is widget's percent size, width and height value from 0 to 1.
420      */
421     setSizePercent: function (percent) {
422         if(this._usingLayoutComponent){
423             var component = this._getOrCreateLayoutComponent();
424             component.setUsingPercentContentSize(true);
425             component.setPercentContentSize(percent);
426             component.refreshLayout();            
427             return;
428         }
429 
430         this._sizePercent.x = percent.x;
431         this._sizePercent.y = percent.y;
432         var width = this._customSize.width, height = this._customSize.height;
433         if (this._running) {
434             var widgetParent = this.getWidgetParent();
435             if (widgetParent) {
436                 width = widgetParent.width * percent.x;
437                 height = widgetParent.height * percent.y;
438             } else {
439                 width = this._parent.width * percent.x;
440                 height = this._parent.height * percent.y;
441             }
442         }
443         if (this._ignoreSize)
444             this.setContentSize(this.getVirtualRendererSize());
445         else
446             this.setContentSize(width, height);
447 
448         this._customSize.width = width;
449         this._customSize.height = height;
450     },
451 
452     _setWidthPercent: function (percent) {
453         this._sizePercent.x = percent;
454         var width = this._customSize.width;
455         if (this._running) {
456             var widgetParent = this.getWidgetParent();
457             width = (widgetParent ? widgetParent.width : this._parent.width) * percent;
458         }
459         if (this._ignoreSize)
460             this._setWidth(this.getVirtualRendererSize().width);
461         else
462             this._setWidth(width);
463         this._customSize.width = width;
464     },
465     _setHeightPercent: function (percent) {
466         this._sizePercent.y = percent;
467         var height = this._customSize.height;
468         if (this._running) {
469             var widgetParent = this.getWidgetParent();
470             height = (widgetParent ? widgetParent.height : this._parent.height) * percent;
471         }
472         if (this._ignoreSize)
473             this._setHeight(this.getVirtualRendererSize().height);
474         else
475             this._setHeight(height);
476         this._customSize.height = height;
477     },
478 
479     /**
480      * updates its size by size type and its position by position type.
481      * @param {cc.Size} [parentSize] parent size
482      */
483     updateSizeAndPosition: function (parentSize) {
484         if(!parentSize){
485             var widgetParent = this.getWidgetParent();
486             if(widgetParent)
487                 parentSize = widgetParent.getLayoutSize();
488             else
489                 parentSize = this._parent.getContentSize();
490         }
491 
492         switch (this._sizeType) {
493             case ccui.Widget.SIZE_ABSOLUTE:
494                 if(this._ignoreSize)
495                     this.setContentSize(this.getVirtualRendererSize());
496                 else
497                     this.setContentSize(this._customSize);
498                 this._sizePercent.x = (parentSize.width > 0) ? this._customSize.width / parentSize.width : 0;
499                 this._sizePercent.y = (parentSize.height > 0) ? this._customSize.height / parentSize.height : 0;
500                 break;
501             case ccui.Widget.SIZE_PERCENT:
502                 var cSize = cc.size(parentSize.width * this._sizePercent.x , parentSize.height * this._sizePercent.y);
503                 if(this._ignoreSize)
504                     this.setContentSize(this.getVirtualRendererSize());
505                 else
506                     this.setContentSize(cSize);
507                 this._customSize.width = cSize.width;
508                 this._customSize.height = cSize.height;
509                 break;
510             default:
511                 break;
512         }
513         this._onSizeChanged();
514         var absPos = this.getPosition();
515         switch (this._positionType) {
516             case ccui.Widget.POSITION_ABSOLUTE:
517                 if (parentSize.width <= 0 || parentSize.height <= 0) {
518                     this._positionPercent.x = this._positionPercent.y = 0;
519                 } else {
520                     this._positionPercent.x = absPos.x / parentSize.width;
521                     this._positionPercent.y = absPos.y / parentSize.height;
522                 }
523                 break;
524             case ccui.Widget.POSITION_PERCENT:
525                 absPos = cc.p(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y);
526                 break;
527             default:
528                 break;
529         }
530         if(this._parent instanceof ccui.ImageView){
531             var renderer = this._parent._imageRenderer;
532             if(renderer && !renderer._textureLoaded)
533                 return;
534         }
535         this.setPosition(absPos);
536     },
537 
538     /**TEXTURE_RES_TYPE
539      * Changes the size type of widget.
540      * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type that is widget's size type
541      */
542     setSizeType: function (type) {
543         this._sizeType = type;
544         if (this._usingLayoutComponent) {
545             var component = this._getOrCreateLayoutComponent();
546             component.setUsingPercentContentSize(this._sizeType === ccui.SIZE_PERCENT);
547         }
548     },
549 
550     /**
551      * Gets the size type of widget.
552      * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} that is widget's size type
553      */
554     getSizeType: function () {
555         return this._sizeType;
556     },
557 
558     /**
559      * Ignore the widget size
560      * @param {Boolean} ignore true that widget will ignore it's size, use texture size, false otherwise. Default value is true.
561      */
562     ignoreContentAdaptWithSize: function (ignore) {
563         if(this._unifySize){
564             this.setContentSize(this._customSize);
565             return;
566         }
567 
568         if(this._ignoreSize === ignore)
569             return;
570 
571         this._ignoreSize = ignore;
572         this.setContentSize( ignore ? this.getVirtualRendererSize() : this._customSize );
573         //this._onSizeChanged();
574     },
575 
576     /**
577      * Gets whether ignore the content size (custom size)
578      * @returns {boolean}  true that widget will ignore it's size, use texture size, false otherwise.
579      */
580     isIgnoreContentAdaptWithSize: function () {
581         return this._ignoreSize;
582     },
583 
584     /**
585      * Get custom size of ccui.Widget
586      * @returns {cc.Size}
587      */
588     getCustomSize: function () {
589         return cc.size(this._customSize);
590     },
591 
592     /**
593      * Gets layout size of ccui.Widget.
594      * @returns {cc.Size}
595      */
596     getLayoutSize: function(){
597         return cc.size(this._contentSize);
598     },
599 
600     /**
601      * Returns size percent of ccui.Widget
602      * @returns {cc.Point}
603      */
604     getSizePercent: function () {
605         if(this._usingLayoutComponent){
606             var component = this._getOrCreateLayoutComponent();
607             this._sizePercent = component.getPercentContentSize();
608         }
609         return this._sizePercent;
610     },
611     _getWidthPercent: function () {
612         return this._sizePercent.x;
613     },
614     _getHeightPercent: function () {
615         return this._sizePercent.y;
616     },
617 
618     /**
619      *  Gets world position of ccui.Widget.
620      * @returns {cc.Point} world position of ccui.Widget.
621      */
622     getWorldPosition: function () {
623         return this.convertToWorldSpace(cc.p(this._anchorPoint.x * this._contentSize.width, this._anchorPoint.y * this._contentSize.height));
624     },
625 
626     /**
627      * Gets the Virtual Renderer of widget.
628      * @returns {ccui.Widget}
629      */
630     getVirtualRenderer: function () {
631         return this;
632     },
633 
634     /**
635      * Gets the content size of widget.  Content size is widget's texture size.
636      */
637     getVirtualRendererSize:function(){
638         return cc.size(this._contentSize);
639     },
640 
641     /**
642      * call back function called when size changed.
643      */
644     _onSizeChanged: function () {
645         if(!this._usingLayoutComponent){
646             var locChildren =  this.getChildren();
647             for (var i = 0, len = locChildren.length; i < len; i++) {
648                 var child = locChildren[i];
649                 if(child instanceof ccui.Widget)
650                     child.updateSizeAndPosition();
651             }
652         }
653     },
654 
655     /**
656      * Sets whether the widget is touch enabled. The default value is false, a widget is default to touch disabled
657      * @param {Boolean} enable  true if the widget is touch enabled, false if the widget is touch disabled.
658      */
659     setTouchEnabled: function (enable) {
660         if (this._touchEnabled === enable)
661             return;
662 
663         this._touchEnabled = enable;                                  //TODO need consider remove and re-add.
664         if (this._touchEnabled) {
665             if(!this._touchListener)
666                 this._touchListener = cc.EventListener.create({
667                     event: cc.EventListener.TOUCH_ONE_BY_ONE,
668                     swallowTouches: true,
669                     onTouchBegan: this.onTouchBegan.bind(this),
670                     onTouchMoved: this.onTouchMoved.bind(this),
671                     onTouchEnded: this.onTouchEnded.bind(this)
672                 });
673             cc.eventManager.addListener(this._touchListener, this);
674         } else {
675             cc.eventManager.removeListener(this._touchListener);
676         }
677     },
678 
679     /**
680      * Returns whether or not touch is enabled.
681      * @returns {boolean} true if the widget is touch enabled, false if the widget is touch disabled.
682      */
683     isTouchEnabled: function () {
684         return this._touchEnabled;
685     },
686 
687     /**
688      * Determines if the widget is highlighted
689      * @returns {boolean} true if the widget is highlighted, false if the widget is not highlighted .
690      */
691     isHighlighted: function(){
692         return this._highlight;
693     },
694 
695     /**
696      * Sets whether the widget is highlighted. The default value is false, a widget is default to not highlighted
697      * @param highlight true if the widget is highlighted, false if the widget is not highlighted.
698      */
699     setHighlighted:function(highlight){
700         if (highlight === this._highlight)
701             return;
702         this._highlight = highlight;
703         if (this._bright) {
704             if (this._highlight)
705                 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT);
706             else
707                 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL);
708         } else
709             this._onPressStateChangedToDisabled();
710     },
711 
712     /**
713      * Determines if the widget is on focused
714      * @returns {boolean} whether the widget is focused or not
715      */
716     isFocused: function () {
717         return this._focused;
718     },
719 
720     /**
721      * Sets whether the widget is on focused
722      * The default value is false, a widget is default to not on focused
723      * @param {boolean} focus  pass true to let the widget get focus or pass false to let the widget lose focus
724      */
725     setFocused: function (focus) {
726         this._focused = focus;
727         //make sure there is only one focusedWidget
728         if (focus){
729             ccui.Widget._focusedWidget = this;
730             if(ccui.Widget._focusNavigationController)
731                 ccui.Widget._focusNavigationController._setFirstFocsuedWidget(this);
732         }
733     },
734 
735     /**
736      * returns whether the widget could accept focus.
737      * @returns {boolean} true represent the widget could accept focus, false represent the widget couldn't accept focus
738      */
739     isFocusEnabled: function(){
740         return this._focusEnabled;
741     },
742 
743     /**
744      * sets whether the widget could accept focus.
745      * @param {Boolean} enable true represent the widget could accept focus, false represent the widget couldn't accept focus
746      */
747     setFocusEnabled: function(enable){
748         this._focusEnabled = enable;
749     },
750 
751     /**
752      * <p>
753      *     When a widget is in a layout, you could call this method to get the next focused widget within a specified direction. <br/>
754      *     If the widget is not in a layout, it will return itself
755      * </p>
756      * @param direction the direction to look for the next focused widget in a layout
757      * @param current  the current focused widget
758      * @return  the next focused widget in a layout
759      */
760     findNextFocusedWidget: function( direction, current){
761         if (null === this.onNextFocusedWidget || null == this.onNextFocusedWidget(direction) ) {
762             var isLayout = current instanceof ccui.Layout;
763             if (this.isFocused() || isLayout) {
764                 var layout = this.getParent();
765                 if (null === layout || !(layout instanceof ccui.Layout)){
766                     //the outer layout's default behaviour is : loop focus
767                     if (isLayout)
768                         return current.findNextFocusedWidget(direction, current);
769                     return current;
770                 } else
771                     return layout.findNextFocusedWidget(direction, current);
772             } else
773                 return current;
774         } else {
775             var getFocusWidget = this.onNextFocusedWidget(direction);
776             this.dispatchFocusEvent(this, getFocusWidget);
777             return getFocusWidget;
778         }
779     },
780 
781     /**
782      * when a widget calls this method, it will get focus immediately.
783      */
784     requestFocus: function(){
785         if (this === ccui.Widget._focusedWidget)
786             return;
787         this.dispatchFocusEvent(ccui.Widget._focusedWidget, this);
788     },
789 
790     /**
791      * no matter what widget object you call this method on , it will return you the exact one focused widget
792      */
793     getCurrentFocusedWidget: function(){
794         return ccui.Widget._focusedWidget;
795     },
796 
797     /**
798      * <p>
799      *    When a widget lose/get focus, this method will be called. Be Caution when you provide your own version,       <br/>
800      *    you must call widget.setFocused(true/false) to change the focus state of the current focused widget;
801      * </p>
802      */
803     onFocusChanged: null,
804 
805     /**
806      * use this function to manually specify the next focused widget regards to each direction
807      */
808     onNextFocusedWidget: null,
809 
810     /**
811      * Sends the touch event to widget's parent, its subclass will override it, e.g. ccui.ScrollView, ccui.PageView
812      * @param {Number}  eventType
813      * @param {ccui.Widget} sender
814      * @param {cc.Touch} touch
815      */
816     interceptTouchEvent: function(eventType, sender, touch){
817         var widgetParent = this.getWidgetParent();
818         if (widgetParent)
819             widgetParent.interceptTouchEvent(eventType,sender,touch);
820     },
821 
822     /**
823      * This method is called when a focus change event happens
824      * @param {ccui.Widget} widgetLostFocus
825      * @param {ccui.Widget} widgetGetFocus
826      */
827     onFocusChange: function(widgetLostFocus, widgetGetFocus){
828         //only change focus when there is indeed a get&lose happens
829         if (widgetLostFocus)
830             widgetLostFocus.setFocused(false);
831         if (widgetGetFocus)
832             widgetGetFocus.setFocused(true);
833     },
834 
835     /**
836      * Dispatch a EventFocus through a EventDispatcher
837      * @param {ccui.Widget} widgetLostFocus
838      * @param {ccui.Widget} widgetGetFocus
839      */
840     dispatchFocusEvent: function(widgetLostFocus, widgetGetFocus){
841         //if the widgetLoseFocus doesn't get focus, it will use the previous focused widget instead
842         if (widgetLostFocus && !widgetLostFocus.isFocused())
843             widgetLostFocus = ccui.Widget._focusedWidget;
844 
845         if (widgetGetFocus !== widgetLostFocus){
846             if (widgetGetFocus && widgetGetFocus.onFocusChanged)
847                 widgetGetFocus.onFocusChanged(widgetLostFocus, widgetGetFocus);
848             if (widgetLostFocus && widgetGetFocus.onFocusChanged)
849                 widgetLostFocus.onFocusChanged(widgetLostFocus, widgetGetFocus);
850             cc.eventManager.dispatchEvent(new cc.EventFocus(widgetLostFocus, widgetGetFocus));
851         }
852     },
853 
854     /**
855      *  Sets whether the widget is bright. The default value is true, a widget is default to bright
856      * @param {Boolean} bright true if the widget is bright, false if the widget is dark.
857      */
858     setBright: function (bright) {
859         this._bright = bright;
860         if (this._bright) {
861             this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE;
862             this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL);
863         } else
864             this._onPressStateChangedToDisabled();
865     },
866 
867     /**
868      * To set the bright style of ccui.Widget.
869      * @param {Number} style BRIGHT_NORMAL the widget is normal state, BRIGHT_HIGHLIGHT the widget is height light state.
870      */
871     setBrightStyle: function (style) {
872         if (this._brightStyle === style)
873             return;
874 
875         style = style || ccui.Widget.BRIGHT_STYLE_NORMAL;
876         this._brightStyle = style;
877         switch (this._brightStyle) {
878             case ccui.Widget.BRIGHT_STYLE_NORMAL:
879                 this._onPressStateChangedToNormal();
880                 break;
881             case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT:
882                 this._onPressStateChangedToPressed();
883                 break;
884             default:
885                 break;
886         }
887     },
888 
889     _onPressStateChangedToNormal: function () {},
890 
891     _onPressStateChangedToPressed: function () {},
892 
893     _onPressStateChangedToDisabled: function () {},
894 
895     _updateChildrenDisplayedRGBA: function(){
896         this.setColor(this.getColor());
897         this.setOpacity(this.getOpacity());
898     },
899 
900     /**
901      * A call back function when widget lost of focus.
902      */
903     didNotSelectSelf: function () {},
904 
905     /**
906      * <p>
907      *    The callback of touch began event.                                                               <br/>
908      *    If the bounding box of ccui.Widget contains the touch point, it will do the following things:    <br/>
909      *      1. sets highlight state,                                                                       <br/>
910      *      2. sends event to parent widget by interceptTouchEvent                                         <br/>
911      *      3. calls the callback of touch began event.                                                    <br/>
912      *      4. returns true,                                                                               <br/>
913      *    otherwise returns false directly.                                                                <br/>
914      * </p>
915      * @override
916      * @param {cc.Touch} touch
917      * @param {cc.Event} event
918      * @returns {boolean}
919      */
920     onTouchBegan: function (touch, event) {
921         this._hit = false;
922         if (this.isVisible() && this.isEnabled() && this._isAncestorsEnabled() && this._isAncestorsVisible(this) ){
923             var touchPoint = touch.getLocation();
924             this._touchBeganPosition.x = touchPoint.x;
925             this._touchBeganPosition.y = touchPoint.y;
926             if(this.hitTest(this._touchBeganPosition) && this.isClippingParentContainsPoint(this._touchBeganPosition))
927                 this._hit = true;
928         }
929         if (!this._hit) {
930             return false;
931         }
932         this.setHighlighted(true);
933 
934         /*
935          * Propagate touch events to its parents
936          */
937         if (this._propagateTouchEvents) {
938             this.propagateTouchEvent(ccui.Widget.TOUCH_BEGAN, this, touch);
939         }
940 
941         this._pushDownEvent();
942         return true;
943     },
944 
945     propagateTouchEvent: function(event, sender, touch){
946         var widgetParent = this.getWidgetParent();
947         if (widgetParent){
948             widgetParent.interceptTouchEvent(event, sender, touch);
949         }
950     },
951 
952     /**
953      * <p>
954      *    The callback of touch moved event.                                                                                                <br/>
955      *    It sets the highlight state by touch, sends event to parent widget by interceptTouchEvent and calls the callback of touch moved event.
956      * </p>
957      * @param {cc.Touch} touch
958      * @param {cc.Event} event
959      */
960     onTouchMoved: function (touch, event) {
961         var touchPoint = touch.getLocation();
962         this._touchMovePosition.x = touchPoint.x;
963         this._touchMovePosition.y = touchPoint.y;
964         this.setHighlighted(this.hitTest(touchPoint));
965         /*
966          * Propagate touch events to its parents
967          */
968         if (this._propagateTouchEvents)
969             this.propagateTouchEvent(ccui.Widget.TOUCH_MOVED, this, touch);
970         this._moveEvent();
971     },
972 
973     /**
974      * <p>
975      *      The callback of touch end event
976      *      It sends event to parent widget by interceptTouchEvent,
977      *      calls the callback of touch end event (highlight= true) or touch canceled event (highlight= false).
978      *      sets the highlight state to false ,
979      * </p>
980      * @param touch
981      * @param event
982      */
983     onTouchEnded: function (touch, event) {
984         var touchPoint = touch.getLocation();
985         this._touchEndPosition.x = touchPoint.x;
986         this._touchEndPosition.y = touchPoint.y;
987         /*
988          * Propagate touch events to its parents
989          */
990         if (this._propagateTouchEvents)
991             this.propagateTouchEvent(ccui.Widget.TOUCH_ENDED, this, touch);
992 
993         var highlight = this._highlight;
994         this.setHighlighted(false);
995         if (highlight)
996             this._releaseUpEvent();
997         else
998             this._cancelUpEvent();
999     },
1000 
1001     /**
1002      * A call back function called when widget is selected, and on touch canceled.
1003      * @param {cc.Point} touchPoint
1004      */
1005     onTouchCancelled: function (touchPoint) {
1006         this.setHighlighted(false);
1007         this._cancelUpEvent();
1008     },
1009 
1010     /**
1011      * A call back function called when widget is selected, and on touch long clicked.
1012      * @param {cc.Point} touchPoint
1013      */
1014     onTouchLongClicked: function (touchPoint) {
1015         this.longClickEvent();
1016     },
1017 
1018     //call back function called widget's state changed to dark.
1019     _pushDownEvent: function () {
1020         if (this._touchEventCallback)
1021             this._touchEventCallback(this, ccui.Widget.TOUCH_BEGAN);
1022         if (this._touchEventListener && this._touchEventSelector)
1023             this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN);
1024     },
1025 
1026     _moveEvent: function () {
1027         if (this._touchEventCallback)
1028             this._touchEventCallback(this, ccui.Widget.TOUCH_MOVED);
1029         if (this._touchEventListener && this._touchEventSelector)
1030             this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED);
1031     },
1032 
1033     _releaseUpEvent: function () {
1034         if (this._touchEventCallback)
1035             this._touchEventCallback(this, ccui.Widget.TOUCH_ENDED);
1036         if (this._touchEventListener && this._touchEventSelector)
1037             this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED);
1038         if (this._clickEventListener)
1039             this._clickEventListener(this);
1040     },
1041 
1042     _cancelUpEvent: function () {
1043         if (this._touchEventCallback)
1044             this._touchEventCallback(this, ccui.Widget.TOUCH_CANCELED);
1045         if (this._touchEventListener && this._touchEventSelector)
1046             this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_CANCELED);
1047     },
1048 
1049     longClickEvent: function () {
1050         //TODO it will implement in v3.1
1051     },
1052 
1053     /**
1054      * Sets the touch event target/selector of the ccui.Widget
1055      * @param {Function} selector
1056      * @param {Object} target
1057      */
1058     addTouchEventListener: function (selector, target) {
1059         if(target === undefined)
1060             this._touchEventCallback = selector;
1061         else {
1062             this._touchEventSelector = selector;
1063             this._touchEventListener = target;
1064         }
1065     },
1066 
1067     addClickEventListener: function(callback){
1068         this._clickEventListener = callback;
1069     },
1070 
1071     /**
1072      * Checks a point if is in widget's space
1073      * @param {cc.Point} pt
1074      * @returns {boolean} true if the point is in widget's space, false otherwise.
1075      */
1076     hitTest: function (pt) {
1077         var bb = cc.rect(0,0, this._contentSize.width, this._contentSize.height);
1078         return cc.rectContainsPoint(bb, this.convertToNodeSpace(pt));
1079     },
1080 
1081     /**
1082      * returns whether clipping parent widget contains point.
1083      * @param {cc.Point} pt location point
1084      * @returns {Boolean}
1085      */
1086     isClippingParentContainsPoint: function(pt){
1087         this._affectByClipping = false;
1088         var parent = this.getParent();
1089         var clippingParent = null;
1090         while (parent) {
1091             if (parent instanceof ccui.Layout) {
1092                 if (parent.isClippingEnabled()) {
1093                     this._affectByClipping = true;
1094                     clippingParent = parent;
1095                     break;
1096                 }
1097             }
1098             parent = parent.getParent();
1099         }
1100 
1101         if (!this._affectByClipping)
1102             return true;
1103 
1104         if (clippingParent) {
1105             if (clippingParent.hitTest(pt))
1106                 return clippingParent.isClippingParentContainsPoint(pt);
1107             return false;
1108         }
1109         return true;
1110     },
1111 
1112     /**
1113      * Calls the checkChildInfo of widget's parent, its subclass will override it.
1114      * @param {number} handleState
1115      * @param {ccui.Widget} sender
1116      * @param {cc.Point} touchPoint
1117      */
1118     checkChildInfo: function (handleState, sender, touchPoint) {
1119         var widgetParent = this.getWidgetParent();
1120         if (widgetParent)
1121             widgetParent.checkChildInfo(handleState, sender, touchPoint);
1122     },
1123 
1124     /**
1125      * Changes the position (x,y) of the widget .
1126      * The original point (0,0) is at the left-bottom corner of screen.
1127      * @override
1128      * @param {cc.Point|Number} pos
1129      * @param {Number} [posY]
1130      */
1131     setPosition: function (pos, posY) {
1132         if (!this._usingLayoutComponent && this._running) {
1133             var widgetParent = this.getWidgetParent();
1134             if (widgetParent) {
1135                 var pSize = widgetParent.getContentSize();
1136                 if (pSize.width <= 0 || pSize.height <= 0) {
1137                     this._positionPercent.x = 0;
1138                     this._positionPercent.y = 0;
1139                 } else {
1140                     if (posY === undefined) {
1141                         this._positionPercent.x = pos.x / pSize.width;
1142                         this._positionPercent.y = pos.y / pSize.height;
1143                     } else {
1144                         this._positionPercent.x = pos / pSize.width;
1145                         this._positionPercent.y = posY / pSize.height;
1146                     }
1147                 }
1148             }
1149         }
1150 
1151         cc.Node.prototype.setPosition.call(this, pos, posY);
1152         //this._positionType = ccui.Widget.POSITION_ABSOLUTE;
1153     },
1154 
1155     setPositionX: function (x) {
1156         if (this._running) {
1157             var widgetParent = this.getWidgetParent();
1158             if (widgetParent) {
1159                 var pw = widgetParent.width;
1160                 if (pw <= 0)
1161                     this._positionPercent.x = 0;
1162                 else
1163                     this._positionPercent.x = x / pw;
1164             }
1165         }
1166 
1167         cc.Node.prototype.setPositionX.call(this, x);
1168     },
1169     setPositionY: function (y) {
1170         if (this._running) {
1171             var widgetParent = this.getWidgetParent();
1172             if (widgetParent) {
1173                 var ph = widgetParent.height;
1174                 if (ph <= 0)
1175                     this._positionPercent.y = 0;
1176                 else
1177                     this._positionPercent.y = y / ph;
1178             }
1179         }
1180 
1181         cc.Node.prototype.setPositionY.call(this, y);
1182     },
1183 
1184     /**
1185      * Changes the position (x,y) of the widget
1186      * @param {cc.Point} percent
1187      */
1188     setPositionPercent: function (percent) {
1189         if (this._usingLayoutComponent){
1190             var component = this._getOrCreateLayoutComponent();
1191             component.setPositionPercentX(percent.x);
1192             component.setPositionPercentY(percent.y);
1193             component.refreshLayout();
1194             return;
1195         }else{
1196             this._setXPercent(percent.x);
1197             this._setYPercent(percent.y);
1198         }
1199         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
1200     },
1201     _setXPercent: function (percent) {
1202         if (this._usingLayoutComponent){
1203             var component = this._getOrCreateLayoutComponent();
1204             component.setPositionPercentX(percent.x);
1205             component.refreshLayout();
1206             return;
1207         }
1208         this._positionPercent.x = percent;
1209     },
1210     _setYPercent: function (percent) {
1211         if (this._usingLayoutComponent){
1212             var component = this._getOrCreateLayoutComponent();
1213             component.setPositionPercentY(percent.x);
1214             component.refreshLayout();
1215             return;
1216         }
1217         this._positionPercent.y = percent;
1218     },
1219 
1220     /**
1221      * Gets the percent (x,y) of the widget
1222      * @returns {cc.Point} The percent (x,y) of the widget in OpenGL coordinates
1223      */
1224     getPositionPercent: function () {
1225         if (this._usingLayoutComponent) {
1226             var component = this._getOrCreateLayoutComponent();
1227             this._positionPercent.x = component.getPositionPercentX();
1228             this._positionPercent.y = component.getPositionPercentY();
1229         }
1230         return cc.p(this._positionPercent);
1231     },
1232 
1233     _getXPercent: function () {
1234         if (this._usingLayoutComponent) {
1235             var component = this._getOrCreateLayoutComponent();
1236             this._positionPercent.x = component.getPositionPercentX();
1237             this._positionPercent.y = component.getPositionPercentY();
1238         }
1239         return this._positionPercent.x;
1240     },
1241     _getYPercent: function () {
1242         if (this._usingLayoutComponent) {
1243             var component = this._getOrCreateLayoutComponent();
1244             this._positionPercent.x = component.getPositionPercentX();
1245             this._positionPercent.y = component.getPositionPercentY();
1246         }
1247         return this._positionPercent.y;
1248     },
1249 
1250     /**
1251      * Changes the position type of the widget
1252      * @param {Number} type  the position type of widget
1253      */
1254     setPositionType: function (type) {
1255         this._positionType = type;
1256         if(this._usingLayoutComponent){
1257             var component = this._getOrCreateLayoutComponent();
1258             if (type === ccui.POSITION_ABSOLUTE){
1259                 component.setPositionPercentXEnabled(false);
1260                 component.setPositionPercentYEnabled(false);
1261             } else {
1262                 component.setPositionPercentXEnabled(true);
1263                 component.setPositionPercentYEnabled(true);
1264             }
1265         }
1266         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
1267     },
1268 
1269     /**
1270      * Gets the position type of the widget
1271      * @returns {Number} the position type of widget
1272      */
1273     getPositionType: function () {
1274         return this._positionType;
1275     },
1276 
1277     /**
1278      * Sets whether the widget should be flipped horizontally or not.
1279      * @param {Boolean} flipX true if the widget should be flipped horizontally, false otherwise.
1280      */
1281     setFlippedX: function (flipX) {
1282         var realScale = this.getScaleX();
1283         this._flippedX = flipX;
1284         this.setScaleX(realScale);
1285     },
1286 
1287     /**
1288      * <p>
1289      *   Returns the flag which indicates whether the widget is flipped horizontally or not.             <br/>
1290      *   It only flips the texture of the widget, and not the texture of the widget's children.          <br/>
1291      *   Also, flipping the texture doesn't alter the anchorPoint.                                       <br/>
1292      *   If you want to flip the anchorPoint too, and/or to flip the children too use:                   <br/>
1293      *   widget.setScaleX(sprite.getScaleX() * -1);
1294      * </p>
1295      * @returns {Boolean} true if the widget is flipped horizontally, false otherwise.
1296      */
1297     isFlippedX: function () {
1298         return this._flippedX;
1299     },
1300 
1301     /**
1302      * Sets whether the widget should be flipped vertically or not.
1303      * @param {Boolean} flipY  true if the widget should be flipped vertically, false otherwise.
1304      */
1305     setFlippedY: function (flipY) {
1306         var realScale = this.getScaleY();
1307         this._flippedY = flipY;
1308         this.setScaleY(realScale);
1309     },
1310 
1311     /**
1312      * <p>
1313      *     Return the flag which indicates whether the widget is flipped vertically or not.                <br/>
1314      *     It only flips the texture of the widget, and not the texture of the widget's children.          <br/>
1315      *     Also, flipping the texture doesn't alter the anchorPoint.                                       <br/>
1316      *     If you want to flip the anchorPoint too, and/or to flip the children too use:                   <br/>
1317      *     widget.setScaleY(widget.getScaleY() * -1);
1318      * </p>
1319      * @returns {Boolean} true if the widget is flipped vertically, false otherwise.
1320      */
1321     isFlippedY: function () {
1322         return this._flippedY;
1323     },
1324 
1325     _adaptRenderers: function(){},
1326 
1327     /**
1328      * Determines if the widget is bright
1329      * @returns {boolean} true if the widget is bright, false if the widget is dark.
1330      */
1331     isBright: function () {
1332         return this._bright;
1333     },
1334 
1335     /**
1336      * Determines if the widget is enabled
1337      * @returns {boolean}
1338      */
1339     isEnabled: function () {
1340         return this._enabled;
1341     },
1342 
1343     /**
1344      * Gets the left boundary position of this widget.
1345      * @returns {number}
1346      */
1347     getLeftBoundary: function () {
1348         return this.getPositionX() - this._getAnchorX() * this._contentSize.width;
1349     },
1350 
1351     /**
1352      * Gets the bottom boundary position of this widget.
1353      * @returns {number}
1354      */
1355     getBottomBoundary: function () {
1356         return this.getPositionY() - this._getAnchorY() * this._contentSize.height;
1357     },
1358 
1359     /**
1360      * Gets the right boundary position of this widget.
1361      * @returns {number}
1362      */
1363     getRightBoundary: function () {
1364         return this.getLeftBoundary() + this._contentSize.width;
1365     },
1366 
1367     /**
1368      * Gets the top boundary position of this widget.
1369      * @returns {number}
1370      */
1371     getTopBoundary: function () {
1372         return this.getBottomBoundary() + this._contentSize.height;
1373     },
1374 
1375     /**
1376      * Gets the position of touch began event.
1377      * @returns {cc.Point}
1378      */
1379     getTouchBeganPosition: function(){
1380          return cc.p(this._touchBeganPosition);
1381     },
1382 
1383     /**
1384      * Gets the position of touch moved event
1385      * @returns {cc.Point}
1386      */
1387     getTouchMovePosition: function(){
1388         return cc.p(this._touchMovePosition);
1389     },
1390 
1391     /**
1392      * Gets the position of touch end event
1393      * @returns {cc.Point}
1394      */
1395     getTouchEndPosition:function(){
1396         return cc.p(this._touchEndPosition);
1397     },
1398 
1399     /**
1400      * get widget type
1401      * @returns {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER}
1402      */
1403     getWidgetType: function () {
1404         return this._widgetType;
1405     },
1406 
1407     /**
1408      * Gets LayoutParameter of widget.
1409      * @param {ccui.LayoutParameter} parameter
1410      */
1411     setLayoutParameter: function (parameter) {
1412         if(!parameter)
1413             return;
1414         this._layoutParameterDictionary[parameter.getLayoutType()] = parameter;
1415         this._layoutParameterType = parameter.getLayoutType();
1416     },
1417 
1418     /**
1419      * Gets layout parameter
1420      * @param {ccui.LayoutParameter.NONE|ccui.LayoutParameter.LINEAR|ccui.LayoutParameter.RELATIVE} type
1421      * @returns {ccui.LayoutParameter}
1422      */
1423     getLayoutParameter: function (type) {
1424         type = type || this._layoutParameterType;
1425         return this._layoutParameterDictionary[type];
1426     },
1427 
1428     /**
1429      * Returns the "class name" of widget.
1430      * @returns {string}
1431      */
1432     getDescription: function () {
1433         return "Widget";
1434     },
1435 
1436     /**
1437      * Clones a new widget.
1438      * @returns {ccui.Widget}
1439      */
1440     clone: function () {
1441         var clonedWidget = this._createCloneInstance();
1442         clonedWidget._copyProperties(this);
1443         clonedWidget._copyClonedWidgetChildren(this);
1444         return clonedWidget;
1445     },
1446 
1447     _createCloneInstance: function () {
1448         return new ccui.Widget();
1449     },
1450 
1451     _copyClonedWidgetChildren: function (model) {
1452         var widgetChildren = model.getChildren();
1453         for (var i = 0; i < widgetChildren.length; i++) {
1454             var locChild = widgetChildren[i];
1455             if (locChild instanceof ccui.Widget)
1456                 this.addChild(locChild.clone());
1457         }
1458     },
1459 
1460     _copySpecialProperties: function (model) {},
1461 
1462     _copyProperties: function (widget) {
1463         this.setEnabled(widget.isEnabled());
1464         this.setVisible(widget.isVisible());
1465         this.setBright(widget.isBright());
1466         this.setTouchEnabled(widget.isTouchEnabled());
1467         this.setLocalZOrder(widget.getLocalZOrder());
1468         this.setTag(widget.getTag());
1469         this.setName(widget.getName());
1470         this.setActionTag(widget.getActionTag());
1471 
1472         this._ignoreSize = widget._ignoreSize;
1473 
1474         this.setContentSize(widget._contentSize);
1475         this._customSize.width = widget._customSize.width;
1476         this._customSize.height = widget._customSize.height;
1477 
1478         this._copySpecialProperties(widget);
1479         this._sizeType = widget.getSizeType();
1480         this._sizePercent.x = widget._sizePercent.x;
1481         this._sizePercent.y = widget._sizePercent.y;
1482 
1483         this._positionType = widget._positionType;
1484         this._positionPercent.x = widget._positionPercent.x;
1485         this._positionPercent.y = widget._positionPercent.y;
1486 
1487         this.setPosition(widget.getPosition());
1488         this.setAnchorPoint(widget.getAnchorPoint());
1489         this.setScaleX(widget.getScaleX());
1490         this.setScaleY(widget.getScaleY());
1491         this.setRotation(widget.getRotation());
1492         this.setRotationX(widget.getRotationX());
1493         this.setRotationY(widget.getRotationY());
1494         this.setFlippedX(widget.isFlippedX());
1495         this.setFlippedY(widget.isFlippedY());
1496         this.setColor(widget.getColor());
1497         this.setOpacity(widget.getOpacity());
1498 
1499         this._touchEventCallback = widget._touchEventCallback;
1500         this._touchEventListener = widget._touchEventListener;
1501         this._touchEventSelector = widget._touchEventSelector;
1502         this._clickEventListener = widget._clickEventListener;
1503         this._focused = widget._focused;
1504         this._focusEnabled = widget._focusEnabled;
1505         this._propagateTouchEvents = widget._propagateTouchEvents;
1506 
1507         for (var key in widget._layoutParameterDictionary) {
1508             var parameter = widget._layoutParameterDictionary[key];
1509             if (parameter)
1510                 this.setLayoutParameter(parameter.clone());
1511         }
1512         this._onSizeChanged();
1513     },
1514 
1515     /*temp action*/
1516     setActionTag: function (tag) {
1517         this._actionTag = tag;
1518     },
1519 
1520     getActionTag: function () {
1521         return this._actionTag;
1522     },
1523 
1524     /**
1525      * Gets the left boundary position of this widget.
1526      * @deprecated since v3.0, please use getLeftBoundary instead.
1527      * @returns {number}
1528      */
1529     getLeftInParent: function(){
1530         cc.log("getLeftInParent is deprecated. Please use getLeftBoundary instead.");
1531         return this.getLeftBoundary();
1532     },
1533 
1534     /**
1535      * Gets the bottom boundary position of this widget.
1536      * @deprecated since v3.0, please use getBottomBoundary instead.
1537      * @returns {number}
1538      */
1539     getBottomInParent: function(){
1540         cc.log("getBottomInParent is deprecated. Please use getBottomBoundary instead.");
1541         return this.getBottomBoundary();
1542     },
1543 
1544     /**
1545      * Gets the right boundary position of this widget.
1546      * @deprecated since v3.0, please use getRightBoundary instead.
1547      * @returns {number}
1548      */
1549     getRightInParent: function(){
1550         cc.log("getRightInParent is deprecated. Please use getRightBoundary instead.");
1551         return this.getRightBoundary();
1552     },
1553 
1554     /**
1555      * Gets the top boundary position of this widget.
1556      * @deprecated since v3.0, please use getTopBoundary instead.
1557      * @returns {number}
1558      */
1559     getTopInParent: function(){
1560         cc.log("getTopInParent is deprecated. Please use getTopBoundary instead.");
1561         return this.getTopBoundary();
1562     },
1563 
1564     /**
1565      * Gets the touch end point of widget when widget is selected.
1566      * @deprecated since v3.0, please use getTouchEndPosition instead.
1567      * @returns {cc.Point} the touch end point.
1568      */
1569     getTouchEndPos: function () {
1570         cc.log("getTouchEndPos is deprecated. Please use getTouchEndPosition instead.");
1571         return this.getTouchEndPosition();
1572     },
1573 
1574     /**
1575      *Gets the touch move point of widget when widget is selected.
1576      * @deprecated since v3.0, please use getTouchMovePosition instead.
1577      * @returns {cc.Point} the touch move point.
1578      */
1579     getTouchMovePos: function () {
1580         cc.log("getTouchMovePos is deprecated. Please use getTouchMovePosition instead.");
1581         return this.getTouchMovePosition();
1582     },
1583 
1584     /**
1585      * Checks a point if in parent's area.
1586      * @deprecated since v3.0, please use isClippingParentContainsPoint instead.
1587      * @param {cc.Point} pt
1588      * @returns {Boolean}
1589      */
1590     clippingParentAreaContainPoint: function (pt) {
1591         cc.log("clippingParentAreaContainPoint is deprecated. Please use isClippingParentContainsPoint instead.");
1592         this.isClippingParentContainsPoint(pt);
1593     },
1594 
1595     /**
1596      * Gets the touch began point of widget when widget is selected.
1597      * @deprecated since v3.0, please use getTouchBeganPosition instead.
1598      * @returns {cc.Point} the touch began point.
1599      */
1600     getTouchStartPos: function () {
1601         cc.log("getTouchStartPos is deprecated. Please use getTouchBeganPosition instead.");
1602         return this.getTouchBeganPosition();
1603     },
1604 
1605     /**
1606      * Changes the size that is widget's size
1607      * @deprecated since v3.0, please use setContentSize instead.
1608      * @param {cc.Size} size  that is widget's size
1609      */
1610     setSize: function (size) {
1611         this.setContentSize(size);
1612     },
1613 
1614     /**
1615      * Returns size of widget
1616      * @deprecated since v3.0, please use getContentSize instead.
1617      * @returns {cc.Size}
1618      */
1619     getSize: function () {
1620         return this.getContentSize();
1621     },
1622 
1623     /**
1624      * Adds a node for widget (this function is deleted in -x)
1625      * @param {cc.Node} node
1626      * @param {Number} zOrder
1627      * @param {Number} tag
1628      * @deprecated since v3.0, please use addChild instead.
1629      */
1630     addNode: function (node, zOrder, tag) {
1631         if (node instanceof ccui.Widget) {
1632             cc.log("Please use addChild to add a Widget.");
1633             return;
1634         }
1635         cc.Node.prototype.addChild.call(this, node, zOrder, tag);
1636         this._nodes.push(node);
1637     },
1638 
1639     /**
1640      * Gets node by tag
1641      * @deprecated since v3.0, please use getChildByTag instead.
1642      * @param {Number} tag
1643      * @returns {cc.Node}
1644      */
1645     getNodeByTag: function (tag) {
1646         var _nodes = this._nodes;
1647         for (var i = 0; i < _nodes.length; i++) {
1648             var node = _nodes[i];
1649             if (node && node.getTag() === tag) {
1650                 return node;
1651             }
1652         }
1653         return null;
1654     },
1655 
1656     /**
1657      * Returns all children.
1658      * @deprecated since v3.0, please use getChildren instead.
1659      * @returns {Array}
1660      */
1661     getNodes: function () {
1662         return this._nodes;
1663     },
1664 
1665     /**
1666      * Removes a node from ccui.Widget
1667      * @deprecated since v3.0, please use removeChild instead.
1668      * @param {cc.Node} node
1669      * @param {Boolean} cleanup
1670      */
1671     removeNode: function (node, cleanup) {
1672         cc.Node.prototype.removeChild.call(this, node, cleanup);
1673         cc.arrayRemoveObject(this._nodes, node);
1674     },
1675 
1676     /**
1677      * Removes node by tag
1678      * @deprecated since v3.0, please use removeChildByTag instead.
1679      * @param {Number} tag
1680      * @param {Boolean} [cleanup]
1681      */
1682     removeNodeByTag: function (tag, cleanup) {
1683         var node = this.getChildByTag(tag);
1684         if (!node)
1685             cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag);
1686         else
1687             this.removeChild(node, cleanup);
1688     },
1689 
1690     /**
1691      * Removes all node
1692      * @deprecated since v3.0, please use removeAllChildren instead.
1693      */
1694     removeAllNodes: function () {
1695         for (var i = 0; i < this._nodes.length; i++) {
1696             var node = this._nodes[i];
1697             cc.Node.prototype.removeChild.call(this, node);
1698         }
1699         this._nodes.length = 0;
1700     },
1701 
1702     _findLayout: function(){
1703         cc.renderer.childrenOrderDirty = true;
1704         var layout = this._parent;
1705         while(layout){
1706             if(layout._doLayout){
1707                 layout._doLayoutDirty = true;
1708                 break;
1709             }else
1710                 layout = layout._parent;
1711         }
1712     },
1713 
1714     /**
1715      * @since v3.2
1716      * @returns {boolean} true represent the widget use Unify Size, false represent the widget couldn't use Unify Size
1717      */
1718     isUnifySizeEnabled: function(){
1719         return this._unifySize;
1720     },
1721 
1722     /**
1723      * @since v3.2
1724      * @param {Boolean} enable enable Unify Size of a widget
1725      */
1726     setUnifySizeEnabled: function(enable){
1727         this._unifySize = enable;
1728     },
1729 
1730     //v3.3
1731     _ccEventCallback: null,
1732     /**
1733      * Set a event handler to the widget in order to use cocostudio editor and framework
1734      * @since v3.3
1735      * @param {function} callback
1736      */
1737     addCCSEventListener: function(callback){
1738         this._ccEventCallback = callback;
1739     },
1740 
1741     //override the scale functions.
1742     setScaleX: function(scaleX){
1743         if (this._flippedX)
1744             scaleX = scaleX * -1;
1745         cc.Node.prototype.setScaleX.call(this, scaleX);
1746     },
1747     setScaleY: function(scaleY){
1748         if (this._flippedY)
1749             scaleY = scaleY * -1;
1750         cc.Node.prototype.setScaleY.call(this, scaleY);
1751     },
1752     setScale: function(scaleX, scaleY){
1753         if(scaleY === undefined)
1754             scaleY = scaleX;
1755         this.setScaleX(scaleX);
1756         this.setScaleY(scaleY);
1757     },
1758 
1759     getScaleX: function(){
1760         var originalScale = cc.Node.prototype.getScaleX.call(this);
1761         if (this._flippedX)
1762             originalScale = originalScale * -1.0;
1763         return originalScale;
1764     },
1765     getScaleY: function(){
1766         var originalScale = cc.Node.prototype.getScaleY.call(this);
1767         if (this._flippedY)
1768             originalScale = originalScale * -1.0;
1769         return originalScale;
1770     },
1771     getScale: function(){
1772         if(this.getScaleX() !== this.getScaleY())
1773             cc.log("Widget#scale. ScaleX != ScaleY. Don't know which one to return");
1774         return this.getScaleX();
1775     },
1776 
1777     /**
1778      * Sets callback name to widget.
1779      * @since v3.3
1780      * @param {String} callbackName
1781      */
1782     setCallbackName: function(callbackName){
1783         this._callbackName = callbackName;
1784     },
1785 
1786     /**
1787      * Gets callback name of widget
1788      * @since v3.3
1789      * @returns {String|Null}
1790      */
1791     getCallbackName: function(){
1792         return this._callbackName;
1793     },
1794 
1795     /**
1796      * Sets callback type to widget
1797      * @since v3.3
1798      * @param {String} callbackType
1799      */
1800     setCallbackType: function(callbackType){
1801         this._callbackType = callbackType;
1802     },
1803 
1804     /**
1805      * Gets callback type of widget
1806      * @since v3.3
1807      * @returns {String|null}
1808      */
1809     getCallbackType: function(){
1810         return this._callbackType;
1811     },
1812 
1813     /**
1814      * Whether enable layout component of a widget
1815      * @since v3.3
1816      * @param {Boolean} enable enable layout Component of a widget
1817      */
1818     setLayoutComponentEnabled: function(enable){
1819         this._usingLayoutComponent = enable;
1820     },
1821 
1822     /**
1823      * Returns whether enable layout component of a widget
1824      * @return {Boolean} true represent the widget use Layout Component, false represent the widget couldn't use Layout Component.
1825      */
1826     isLayoutComponentEnabled: function(){
1827         return this._usingLayoutComponent;
1828     },
1829 
1830 
1831     _createRenderCmd: function(){
1832         if(cc._renderType === cc.game.RENDER_TYPE_WEBGL)
1833             return new ccui.Widget.WebGLRenderCmd(this);
1834         else
1835             return new ccui.Widget.CanvasRenderCmd(this);
1836     }
1837 });
1838 
1839 var _p = ccui.Widget.prototype;
1840 
1841 // Extended properties
1842 /** @expose */
1843 _p.xPercent;
1844 cc.defineGetterSetter(_p, "xPercent", _p._getXPercent, _p._setXPercent);
1845 /** @expose */
1846 _p.yPercent;
1847 cc.defineGetterSetter(_p, "yPercent", _p._getYPercent, _p._setYPercent);
1848 /** @expose */
1849 _p.widthPercent;
1850 cc.defineGetterSetter(_p, "widthPercent", _p._getWidthPercent, _p._setWidthPercent);
1851 /** @expose */
1852 _p.heightPercent;
1853 cc.defineGetterSetter(_p, "heightPercent", _p._getHeightPercent, _p._setHeightPercent);
1854 /** @expose */
1855 _p.widgetParent;
1856 cc.defineGetterSetter(_p, "widgetParent", _p.getWidgetParent);
1857 /** @expose */
1858 _p.enabled;
1859 cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled);
1860 /** @expose */
1861 _p.focused;
1862 cc.defineGetterSetter(_p, "focused", _p.isFocused, _p.setFocused);
1863 /** @expose */
1864 _p.sizeType;
1865 cc.defineGetterSetter(_p, "sizeType", _p.getSizeType, _p.setSizeType);
1866 /** @expose */
1867 _p.widgetType;
1868 cc.defineGetterSetter(_p, "widgetType", _p.getWidgetType);
1869 /** @expose */
1870 _p.touchEnabled;
1871 cc.defineGetterSetter(_p, "touchEnabled", _p.isTouchEnabled, _p.setTouchEnabled);
1872 /** @expose */
1873 _p.updateEnabled;
1874 cc.defineGetterSetter(_p, "updateEnabled", _p.isUpdateEnabled, _p.setUpdateEnabled);
1875 /** @expose */
1876 _p.bright;
1877 cc.defineGetterSetter(_p, "bright", _p.isBright, _p.setBright);
1878 /** @expose */
1879 _p.name;
1880 cc.defineGetterSetter(_p, "name", _p.getName, _p.setName);
1881 /** @expose */
1882 _p.actionTag;
1883 cc.defineGetterSetter(_p, "actionTag", _p.getActionTag, _p.setActionTag);
1884 /** @expose */
1885 _p.opacity;
1886 cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity);
1887 
1888 _p = null;
1889 
1890 /**
1891  * allocates and initializes a UIWidget.
1892  * @deprecated
1893  * @return {ccui.Widget}
1894  */
1895 ccui.Widget.create = function () {
1896     return new ccui.Widget();
1897 };
1898 
1899 ccui.Widget._focusedWidget = null;                        //both layout & widget will be stored in this variable
1900 ccui.Widget._focusNavigationController = null;
1901 
1902 /**
1903  * call this method with parameter true to enable the Android Dpad focus navigation feature
1904  * @note it doesn't implemented on Web
1905  * @param {Boolean} enable set true to enable dpad focus navigation, otherwise disable dpad focus navigation
1906  */
1907 ccui.Widget.enableDpadNavigation = function(enable){
1908     if (enable){
1909         if (null == ccui.Widget._focusNavigationController) {
1910             ccui.Widget._focusNavigationController = new ccui._FocusNavigationController();
1911             if (ccui.Widget._focusedWidget) {
1912                 ccui.Widget._focusNavigationController._setFirstFocsuedWidget(ccui.Widget._focusedWidget);
1913             }
1914         }
1915         ccui.Widget._focusNavigationController.enableFocusNavigation(true);
1916     } else {
1917         if(ccui.Widget._focusNavigationController){
1918             ccui.Widget._focusNavigationController.enableFocusNavigation(false);
1919             ccui.Widget._focusNavigationController = null;
1920         }
1921     }
1922 };
1923 
1924 /**
1925  * Gets the focused widget of current stage.
1926  * @function
1927  * @returns {null|ccui.Widget}
1928  */
1929 ccui.Widget.getCurrentFocusedWidget = function(){
1930     return ccui.Widget._focusedWidget;
1931 };
1932 
1933 // Constants
1934 //bright style
1935 /**
1936  * None bright style of ccui.Widget.
1937  * @constant
1938  * @type {number}
1939  */
1940 ccui.Widget.BRIGHT_STYLE_NONE = -1;
1941 /**
1942  * Normal bright style of ccui.Widget.
1943  * @constant
1944  * @type {number}
1945  */
1946 ccui.Widget.BRIGHT_STYLE_NORMAL = 0;
1947 /**
1948  * Light bright style of ccui.Widget.
1949  * @constant
1950  * @type {number}
1951  */
1952 ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT = 1;
1953 
1954 //widget type
1955 /**
1956  * The type code of Widget for ccui controls.
1957  * @constant
1958  * @type {number}
1959  */
1960 ccui.Widget.TYPE_WIDGET = 0;
1961 /**
1962  * The type code of Container for ccui controls.
1963  * @constant
1964  * @type {number}
1965  */
1966 ccui.Widget.TYPE_CONTAINER = 1;
1967 
1968 //Focus Direction
1969 /**
1970  * The left of Focus direction for ccui.Widget
1971  * @constant
1972  * @type {number}
1973  */
1974 ccui.Widget.LEFT = 0;
1975 /**
1976  * The right of Focus direction for ccui.Widget
1977  * @constant
1978  * @type {number}
1979  */
1980 ccui.Widget.RIGHT = 1;
1981 /**
1982  * The up of Focus direction for ccui.Widget
1983  * @constant
1984  * @type {number}
1985  */
1986 ccui.Widget.UP = 2;
1987 /**
1988  * The down of Focus direction for ccui.Widget
1989  * @constant
1990  * @type {number}
1991  */
1992 ccui.Widget.DOWN = 3;
1993 
1994 //texture resource type
1995 /**
1996  * The image file texture type of ccui.Widget loads.
1997  * @constant
1998  * @type {number}
1999  */
2000 ccui.Widget.LOCAL_TEXTURE = 0;
2001 /**
2002  * The sprite frame texture type of ccui.Widget loads.
2003  * @constant
2004  * @type {number}
2005  */
2006 ccui.Widget.PLIST_TEXTURE = 1;
2007 
2008 //touch event type
2009 /**
2010  * The touch began type of ccui.Widget's touch event
2011  * @constant
2012  * @type {number}
2013  */
2014 ccui.Widget.TOUCH_BEGAN = 0;
2015 /**
2016  * The touch moved type of ccui.Widget's touch event
2017  * @constant
2018  * @type {number}
2019  */
2020 ccui.Widget.TOUCH_MOVED = 1;
2021 /**
2022  * The touch end type of ccui.Widget's touch event
2023  * @constant
2024  * @type {number}
2025  */
2026 ccui.Widget.TOUCH_ENDED = 2;
2027 /**
2028  * The touch canceled type of ccui.Widget's touch event
2029  * @constant
2030  * @type {number}
2031  */
2032 ccui.Widget.TOUCH_CANCELED = 3;
2033 
2034 //size type
2035 /**
2036  * The absolute of ccui.Widget's size type.
2037  * @constant
2038  * @type {number}
2039  */
2040 ccui.Widget.SIZE_ABSOLUTE = 0;
2041 /**
2042  * The percent of ccui.Widget's size type.
2043  * @constant
2044  * @type {number}
2045  */
2046 ccui.Widget.SIZE_PERCENT = 1;
2047 
2048 //position type
2049 /**
2050  * The absolute of ccui.Widget's position type.
2051  * @constant
2052  * @type {number}
2053  */
2054 ccui.Widget.POSITION_ABSOLUTE = 0;
2055 /**
2056  * The percent of ccui.Widget's position type.
2057  * @constant
2058  * @type {number}
2059  */
2060 ccui.Widget.POSITION_PERCENT = 1;
2061