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