1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 
 25 /**
 26  * Base class for ccui.Widget
 27  * @sample
 28  * var uiWidget = ccui.Widget.create();
 29  * this.addChild(uiWidget);
 30  * @class
 31  * @extends ccui.Node
 32  *
 33  * @property {Number}           xPercent        - Position x in percentage of width
 34  * @property {Number}           yPercent        - Position y in percentage of height
 35  * @property {Number}           widthPercent    - Width in percentage of parent width
 36  * @property {Number}           heightPercent   - Height in percentage of parent height
 37  * @property {ccui.Widget}       widgetParent    - <@readonly> The direct parent when it's a widget also, otherwise equals null
 38  * @property {Boolean}          enabled         - Indicate whether the widget is enabled
 39  * @property {Boolean}          focused         - Indicate whether the widget is focused
 40  * @property {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT}     sizeType        - The size type of the widget
 41  * @property {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER}   widgetType      - <@readonly> The type of the widget
 42  * @property {Boolean}          touchEnabled    - Indicate whether touch events are enabled
 43  * @property {Boolean}          updateEnabled   - Indicate whether the update function is scheduled
 44  * @property {Boolean}          bright          - Indicate whether the widget is bright
 45  * @property {String}           name            - The name of the widget
 46  * @property {Number}           actionTag       - The action tag of the widget
 47  */
 48 ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{
 49     _enabled: true,            ///< Highest control of widget
 50     _bright: true,             ///< is this widget bright
 51     _touchEnabled: false,       ///< is this widget touch endabled
 52     _touchPassedEnabled: false, ///< is the touch event should be passed
 53     _focus: false,              ///< is the widget on focus
 54     _brightStyle: null, ///< bright style
 55     _updateEnabled: false,      ///< is "update" method scheduled
 56     _touchStartPos: null,    ///< touch began point
 57     _touchMovePos: null,     ///< touch moved point
 58     _touchEndPos: null,      ///< touch ended point
 59 
 60     _touchEventListener: null,
 61     _touchEventSelector: null,
 62 
 63     _name: "default",
 64     _widgetType: null,
 65     _actionTag: 0,
 66     _size: null,
 67     _customSize: null,
 68     _layoutParameterDictionary: null,
 69     _ignoreSize: false,
 70     _widgetChildren: null,
 71     _affectByClipping: false,
 72 
 73     _sizeType: null,
 74     _sizePercent: null,
 75     positionType: null,
 76     _positionPercent: null,
 77     _reorderWidgetChildDirty: false,
 78     _hitted: false,
 79     _nodes: null,
 80     _touchListener : null,
 81     _color:null,
 82     _className:"Widget",
 83     _flippedX: false,
 84     _flippedY: false,
 85     ctor: function () {
 86         cc.Node.prototype.ctor.call(this);
 87         this._enabled = true;
 88         this._bright = true;
 89         this._touchEnabled = false;
 90         this._touchPassedEnabled = false;
 91         this._focus = false;
 92         this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE;
 93         this._updateEnabled = false;
 94         this._touchStartPos = cc.p(0,0);
 95         this._touchMovePos = cc.p(0,0);
 96         this._touchEndPos = cc.p(0,0);
 97         this._touchEventListener = null;
 98         this._touchEventSelector = null;
 99         this._name = "default";
100         this._widgetType = ccui.Widget.TYPE_WIDGET;
101         this._actionTag = 0;
102         this._size = cc.size(0, 0);
103         this._customSize = cc.size(0, 0);
104         this._layoutParameterDictionary = {};
105         this._ignoreSize = false;
106         this._widgetChildren = [];
107         this._affectByClipping = false;
108         this._sizeType = ccui.Widget.SIZE_ABSOLUTE;
109         this._sizePercent = cc.p(0,0);
110         this.positionType = ccui.Widget.POSITION_ABSOLUTE;
111         this._positionPercent = cc.p(0,0);
112         this._reorderWidgetChildDirty = false;
113         this._hitted = false;
114         this._nodes = [];
115         this._color = cc.color(255,255,255,255);
116         this._touchListener = null;
117         this._flippedX = false;
118         this._flippedY = false;
119     },
120 
121     /**
122      * initializes state of widget.
123      * @returns {boolean}
124      */
125     init: function () {
126         if (cc.Node.prototype.init.call(this)){
127             this._layoutParameterDictionary = {};
128             this._widgetChildren = [];
129             this.initRenderer();
130             this.setBright(true);
131             this.ignoreContentAdaptWithSize(true);
132             this.setAnchorPoint(cc.p(0.5, 0.5));
133         }
134         return true;
135     },
136 
137     onEnter: function () {
138         this.updateSizeAndPosition();
139         cc.Node.prototype.onEnter.call(this);
140     },
141 
142     visit: function (ctx) {
143         if (this._enabled) {
144             cc.Node.prototype.visit.call(this,ctx);
145         }
146     },
147 
148     sortAllChildren: function () {
149         this._reorderWidgetChildDirty = this._reorderChildDirty;
150         cc.Node.prototype.sortAllChildren.call(this);
151         if (this._reorderWidgetChildDirty) {
152             var _children = this._widgetChildren;
153             var i, j, length = _children.length, tempChild;
154 
155             // insertion sort
156             for (i = 0; i < length; i++) {
157                 var tempItem = _children[i];
158                 j = i - 1;
159                 tempChild = _children[j];
160 
161                 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
162                 while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder ||
163                     ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) {
164                     _children[j + 1] = tempChild;
165                     j = j - 1;
166                     tempChild = _children[j];
167                 }
168                 _children[j + 1] = tempItem;
169             }
170 
171             //don't need to check children recursively, that's done in visit of each child
172 
173             this._reorderWidgetChildDirty = false;
174         }
175     },
176 
177     /**
178      * Adds a child to the container.
179      * @param {ccui.Widget} widget
180      * @param {Number} zOrder
181      * @param {Number} tag
182      */
183     addChild: function (widget, zOrder, tag) {
184         if(widget instanceof ccui.Widget){
185             cc.Node.prototype.addChild.call(this, widget, zOrder, tag);
186             this._widgetChildren.push(widget);
187             return;
188         }
189         if(widget instanceof cc.Node){
190             cc.log("Please use addNode to add a CCNode.");
191             return;
192         }
193     },
194 
195     /**
196      *
197      * @param tag
198      * @returns {ccui.Widget}
199      */
200     getChildByTag:function(tag){
201         var __children = this._widgetChildren;
202         if (__children != null) {
203             for (var i = 0; i < __children.length; i++) {
204                 var node = __children[i];
205                 if (node && node._tag == tag)
206                     return node;
207             }
208         }
209         return null;
210     },
211 
212     /**
213      * Return an array of children
214      * @returns {Array}
215      */
216     getChildren: function () {
217         return this._widgetChildren;
218     },
219 
220     /**
221      * get the count of children
222      * @returns {Number}
223      */
224     getChildrenCount: function () {
225         return this._widgetChildren.length;
226     },
227 
228     getWidgetParent: function () {
229         var widget = this.getParent();
230         if(widget instanceof ccui.Widget){
231             return widget;
232         }
233         return null;
234     },
235 
236     /**
237      * remove  child
238      * @param {ccui.Widget} widget
239      * @param {Boolean} cleanup
240      */
241     removeChild: function (widget, cleanup) {
242         if(!(widget instanceof ccui.Widget)){
243             cc.log("child must a type of ccui.Widget");
244             return;
245         }
246         cc.Node.prototype.removeChild.call(this, widget, cleanup);
247         cc.arrayRemoveObject(this._widgetChildren, widget);
248     },
249 
250     removeChildByTag: function (tag, cleanup) {
251         var child = this.getChildByTag(tag);
252 
253         if (child == null) {
254             cc.log("cocos2d: removeChildByTag(tag = " + tag + "): child not found!");
255         }
256         else {
257             this.removeChild(child, cleanup);
258         }
259     },
260 
261     /**
262      * Removes all children from the container, and do a cleanup to all running actions depending on the cleanup parameter.
263      */
264     removeAllChildren: function (cleanup) {
265         for (var i = 0; i < this._widgetChildren.length; i++) {
266             var widget = this._widgetChildren[i];
267             cc.Node.prototype.removeChild.call(this, widget, cleanup);
268         }
269         this._widgetChildren.length = 0;
270     },
271 
272     /**
273      * Set enabled renderer
274      * @param {Boolean} enabled
275      */
276     setEnabled: function (enabled) {
277         this._enabled = enabled;
278         var arrayChildren = this._widgetChildren;
279         var childrenCount = arrayChildren.length;
280         for (var i = 0; i < childrenCount; i++) {
281             var child = arrayChildren[i];
282             child.setEnabled(enabled);
283         }
284     },
285 
286     /**
287      * Gets a child from the container with its name
288      * @param {string} name
289      * @returns {ccui.Widget}
290      */
291     getChildByName: function (name) {
292         var arrayChildren = this._widgetChildren;
293         var childrenCount = arrayChildren.length;
294         for (var i = 0; i < childrenCount; i++) {
295             var child = arrayChildren[i];
296             if (child.getName() == name) {
297                 return child;
298             }
299         }
300     },
301 
302     /**
303      * initializes renderer of widget.
304      */
305     initRenderer: function () {
306     },
307 
308     /**
309      * add node for widget
310      * @param {cc.Node} node
311      * @param {Number} zOrder
312      * @param {Number} tag
313      */
314     addNode: function (node, zOrder, tag) {
315         if (node instanceof ccui.Widget) {
316             cc.log("Please use addChild to add a Widget.");
317             return;
318         }
319         cc.Node.prototype.addChild.call(this, node, zOrder, tag);
320         this._nodes.push(node);
321     },
322 
323     /**
324      * get node by tag
325      * @param {Number} tag
326      * @returns {cc.Node}
327      */
328     getNodeByTag: function (tag) {
329         var _nodes = this._nodes;
330         for (var i = 0; i < _nodes.length; i++) {
331             var node = _nodes[i];
332             if (node && node.getTag() == tag) {
333                 return node;
334             }
335         }
336         return null;
337     },
338 
339     /**
340      * get all node
341      * @returns {Array}
342      */
343     getNodes: function () {
344         return this._nodes;
345     },
346 
347     /**
348      * remove node
349      * @param {cc.Node} node
350      * @param {Boolean} cleanup
351      */
352     removeNode: function (node, cleanup) {
353         cc.Node.prototype.removeChild.call(this, node);
354         cc.arrayRemoveObject(this._nodes, node);
355     },
356 
357     /**
358      *  remove node by tag
359      * @param {Number} tag
360      * @param {Boolean} cleanup
361      */
362     removeNodeByTag: function (tag, cleanup) {
363         var node = this.getNodeByTag(tag);
364         if (!node) {
365             cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag);
366         }
367         else {
368             this.removeNode(node);
369         }
370     },
371 
372     /**
373      * remove all node
374      */
375     removeAllNodes: function () {
376         for (var i = 0; i < this._nodes.length; i++) {
377             var node = this._nodes[i];
378             cc.Node.prototype.removeChild.call(this, node);
379         }
380         this._nodes.length = 0;
381     },
382 
383     /**
384      * Changes the size that is widget's size
385      * @param {cc.Size} size
386      */
387     setSize: function (size) {
388         var locW = this._customSize.width = size.width;
389         var locH = this._customSize.height = size.height;
390         if (this._ignoreSize) {
391 	        locW = this.width;
392 	        locH = this.height;
393         }
394 	    this._size.width = locW;
395 	    this._size.height = locH;
396 
397         if(this._running){
398             var  widgetParent = this.getWidgetParent();
399             if(widgetParent){
400                 locW = widgetParent.width;
401 	            locH = widgetParent.height;
402             }else{
403 	            locW = this._parent.width;
404 	            locH = this._parent.height;
405             }
406 	        this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0;
407 	        this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0;
408         }
409         this.onSizeChanged();
410     },
411 	_setWidth: function (w) {
412 		var locW = this._customSize.width = w;
413 		this._ignoreSize && (locW = this.width);
414 		this._size.width = locW;
415 
416 		if(this._running){
417 			var  widgetParent = this.getWidgetParent();
418 			locW = widgetParent ? widgetParent.width : this._parent.width;
419 			this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0;
420 		}
421 		this.onSizeChanged();
422 	},
423 	_setHeight: function (h) {
424 		var locH = this._customSize.height = h;
425 		this._ignoreSize && (locH = this.height);
426 		this._size.height = locH;
427 
428 		if(this._running){
429 			var  widgetParent = this.getWidgetParent();
430 			locH = widgetParent ? widgetParent.height : this._parent.height;
431 			this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0;
432 		}
433 		this.onSizeChanged();
434 	},
435 
436     /**
437      * Changes the percent that is widget's percent size
438      * @param {cc.Point} percent
439      */
440     setSizePercent: function (percent) {
441         this._sizePercent.x = percent.x;
442         this._sizePercent.y = percent.y;
443         var width = this._customSize.width, height = this._customSize.height;
444         if (this._running) {
445             var widgetParent = this.getWidgetParent();
446             if (widgetParent) {
447                 width = widgetParent.width * percent.x;
448                 height = widgetParent.height * percent.y;
449             }
450             else {
451                 width = this._parent.width * percent.x;
452                 height = this._parent.height * percent.y;
453             }
454         }
455         if (!this._ignoreSize) {
456 	        this._size.width = width;
457 	        this._size.height = height;
458         }
459         this._customSize.width = width;
460         this._customSize.height = height;
461         this.onSizeChanged();
462     },
463 	_setWidthPercent: function (percent) {
464 		this._sizePercent.x = percent;
465 		var width = this._customSize.width;
466 		if (this._running) {
467 			var widgetParent = this.getWidgetParent();
468 			width = (widgetParent ? widgetParent.width : this._parent.width) * percent;
469 		}
470 		this._ignoreSize || (this._size.width = width);
471 		this._customSize.width = width;
472 		this.onSizeChanged();
473 	},
474 	_setHeightPercent: function (percent) {
475 		this._sizePercent.y = percent;
476 		var height = this._customSize.height;
477 		if (this._running) {
478 			var widgetParent = this.getWidgetParent();
479 			height = (widgetParent ? widgetParent.height : this._parent.height) * percent;
480 		}
481 		this._ignoreSize || (this._size.height = height);
482 		this._customSize.height = height;
483 		this.onSizeChanged();
484 	},
485 
486     /**
487      * update size and position
488      */
489     updateSizeAndPosition: function () {
490         switch (this._sizeType) {
491             case ccui.Widget.SIZE_ABSOLUTE:
492                 var locSize;
493                 if (this._ignoreSize) {
494                     locSize = this.getContentSize();
495                 }
496                 else {
497                     locSize = this._customSize;
498                 }
499                 this._size.width = locSize.width;
500                 this._size.height = locSize.height;
501 
502                 var pSize, spx = 0, spy = 0;
503                 var widgetParent = this.getWidgetParent();
504                 if (widgetParent){
505                     pSize = widgetParent.getSize();
506                 }else{
507                     pSize = this._parent.getContentSize();
508                 }
509                 if (pSize.width > 0) {
510                     spx = this._customSize.width / pSize.width;
511                 }
512                 if (pSize.height > 0) {
513                     spy = this._customSize.height / pSize.height;
514                 }
515                 this._sizePercent.x = spx;
516                 this._sizePercent.y = spy;
517                 break;
518             case ccui.Widget.SIZE_PERCENT:
519                 var widgetParent = this.getWidgetParent();
520                 var cSize = cc.size(0,0);
521                 if (widgetParent){
522                     cSize.width = widgetParent.getSize().width * this._sizePercent.x;
523                     cSize.height = widgetParent.getSize().height * this._sizePercent.y;
524                 }else{
525                     cSize.width = this._parent.getContentSize().width * this._sizePercent.x;
526                     cSize.height = this._parent.getContentSize().height * this._sizePercent.y;
527                 }
528                 var locSize;
529                 if (this._ignoreSize) {
530                     locSize = this.getContentSize();
531                 }
532                 else {
533                     locSize = cSize;
534                 }
535                 this._size.width = locSize.width;
536                 this._size.height = locSize.height;
537                 this._customSize.width = cSize.width;
538                 this._customSize.height = cSize.height;
539                 break;
540             default:
541                 break;
542         }
543         this.onSizeChanged();
544         var absPos = this.getPosition();
545         switch (this.positionType) {
546             case ccui.Widget.POSITION_ABSOLUTE:
547                 var widgetParent = this.getWidgetParent();
548                 var pSize;
549                 if(widgetParent){
550                     pSize = widgetParent.getSize();
551                 }else{
552                     pSize = this._parent.getContentSize();
553                 }
554                 if(pSize.width<=0||pSize.height<=0){
555                     this._positionPercent.x = 0;
556                     this._positionPercent.y = 0;
557                 }else{
558                     this._positionPercent.x = absPos.x / pSize.width;
559                     this._positionPercent.y = absPos.y / pSize.height;
560                 }
561                 break;
562             case ccui.Widget.POSITION_PERCENT:
563                 var widgetParent = this.getWidgetParent();
564                 var pSize;
565                 if(widgetParent){
566                     pSize = widgetParent.getSize();
567                 }else{
568                     pSize = this._parent.getContentSize();
569                 }
570                 absPos = cc.p(pSize.width * this._positionPercent.x, pSize.height * this._positionPercent.y);
571                 break;
572             default:
573                 break;
574         }
575         this.setPosition(absPos);
576     },
577 
578     /**TEXTURE_RES_TYPE
579      * Changes the size type of widget.
580      * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type
581      */
582     setSizeType: function (type) {
583         this._sizeType = type;
584     },
585 
586     /**
587      * Gets the size type of widget.
588      * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT}
589      */
590     getSizeType: function () {
591         return this._sizeType;
592     },
593 
594     /**
595      * Ignore the widget size
596      * @param {Boolean} ignore
597      */
598     ignoreContentAdaptWithSize: function (ignore) {
599         this._ignoreSize = ignore;
600         var locSize;
601         if (this._ignoreSize) {
602             locSize = this.getContentSize();
603         }
604         else {
605             locSize = this._customSize;
606         }
607         this._size.width = locSize.width;
608         this._size.height = locSize.height;
609         this.onSizeChanged();
610     },
611 
612     /**
613      * Gets the widget if is ignore it's size.
614      * @returns {boolean}
615      */
616     isIgnoreContentAdaptWithSize: function () {
617         return this._ignoreSize;
618     },
619 
620     /**
621      * Returns size of widget
622      * @returns {cc.Size}
623      */
624     getSize: function () {
625         return this._size;
626     },
627 
628     /**
629      * Get custom size
630      * @returns {cc.Size}
631      */
632     getCustomSize:function(){
633         return this._customSize
634     },
635 
636     /**
637      * Returns size percent of widget
638      * @returns {cc.Point}
639      */
640     getSizePercent: function () {
641         return this._sizePercent;
642     },
643 	_getWidthPercent: function () {
644 		return this._sizePercent.x;
645 	},
646 	_getHeightPercent: function () {
647 		return this._sizePercent.y;
648 	},
649 
650     /**
651      *  Gets world position of widget.
652      * @returns {cc.Point}
653      */
654     getWorldPosition: function () {
655         return this.convertToWorldSpace(cc.p(0,0));
656     },
657 
658     /**
659      * Gets the Virtual Renderer of widget.
660      * @returns {cc.Node}
661      */
662     getVirtualRenderer: function () {
663         return this;
664     },
665 
666     /**
667      * call back function called when size changed.
668      */
669     onSizeChanged: function () {
670         for (var i = 0; i < this._widgetChildren.length; i++) {
671             var child = this._widgetChildren[i];
672             child.updateSizeAndPosition();
673         }
674     },
675 
676     /**
677      * Gets the content size of widget.
678      * @returns {cc.Size}
679      */
680     getContentSize: function () {
681         return this._size;
682     },
683 	_getWidth: function () {
684 		return this._size.width;
685 	},
686 	_getHeight: function () {
687 		return this._size.height;
688 	},
689 
690     /**
691      * Sets whether the widget is touch enabled
692      * @param enable
693      */
694     setTouchEnabled: function (enable) {
695         if (this._touchEnabled === enable) {
696             return;
697         }
698         this._touchEnabled = enable;
699         if(this._touchEnabled){
700             this._touchListener = cc.EventListener.create({
701                 event: cc.EventListener.TOUCH_ONE_BY_ONE,
702                 swallowTouches: true,
703                 onTouchBegan: this.onTouchBegan.bind(this),
704                 onTouchMoved: this.onTouchMoved.bind(this),
705                 onTouchEnded: this.onTouchEnded.bind(this)
706             });
707             cc.eventManager.addListener(this._touchListener, this);
708         }else{
709             cc.eventManager.removeListener(this._touchListener);
710         }
711     },
712 
713     /**
714      * To set the bright style of widget.
715      * @returns {boolean}
716      */
717     isTouchEnabled: function () {
718         return this._touchEnabled;
719     },
720 
721     /**
722      * Schedules the "update" method.
723      * @param enable
724      */
725     setUpdateEnabled: function (enable) {
726         if (this._updateEnabled == enable) {
727             return;
728         }
729         this._updateEnabled = enable;
730         if (enable) {
731             this.scheduleUpdate();
732         }
733         else {
734             this.unscheduleUpdate();
735         }
736     },
737 
738     /**
739      * is the "update" method scheduled.
740      * @returns {boolean}
741      */
742     isUpdateEnabled: function () {
743         return this._updateEnabled;
744     },
745 
746     /**
747      * Determines if the widget is on focused
748      * @returns {boolean}
749      */
750     isFocused: function () {
751         return this._focus;
752     },
753 
754     /**
755      * Sets whether the widget is on focused
756      * The default value is false, a widget is default to not on focused
757      * @param {boolean} fucos
758      */
759     setFocused: function (fucos) {
760         if (fucos == this._focus) {
761             return;
762         }
763         this._focus = fucos;
764         if (this._bright) {
765             if (this._focus) {
766                 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT);
767             }
768             else {
769                 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL);
770             }
771         }
772         else {
773             this.onPressStateChangedToDisabled();
774         }
775     },
776 
777     setBright: function (bright, containChild) {
778         this._bright = bright;
779         if (this._bright) {
780             this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE;
781             this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL);
782         }
783         else {
784             this.onPressStateChangedToDisabled();
785         }
786     },
787 
788     /**
789      * To set the bright style of widget.
790      * @param {ccui.Widget.BRIGHT_STYLE_NONE|ccui.Widget.BRIGHT_STYLE_NORMAL|ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT} style
791      */
792     setBrightStyle: function (style) {
793         if (this._brightStyle == style) {
794             return;
795         }
796         style = style|| ccui.Widget.BRIGHT_STYLE_NORMAL;
797         this._brightStyle = style;
798         switch (this._brightStyle) {
799             case ccui.Widget.BRIGHT_STYLE_NORMAL:
800                 this.onPressStateChangedToNormal();
801                 break;
802             case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT:
803                 this.onPressStateChangedToPressed();
804                 break;
805             default:
806                 break;
807         }
808     },
809 
810     /**
811      * call back function called widget's state changed to normal.
812      */
813     onPressStateChangedToNormal: function () {
814 
815     },
816 
817     /**
818      * call back function called widget's state changed to selected.
819      */
820     onPressStateChangedToPressed: function () {
821 
822     },
823 
824     /**
825      * call back function called widget's state changed to dark.
826      */
827     onPressStateChangedToDisabled: function () {
828 
829     },
830 
831     /**
832      * A call back function when widget lost of focus.
833      */
834     didNotSelectSelf: function () {
835 
836     },
837 
838     onTouchBegan: function (touch,event) {
839         var touchPoint = touch.getLocation();
840         this._touchStartPos.x = touchPoint.x;
841         this._touchStartPos.y = touchPoint.y;
842         this._hitted = this.isEnabled() && this.isTouchEnabled()&& this.hitTest(touchPoint)&& this.clippingParentAreaContainPoint(touchPoint);
843         if(!this._hitted){
844             return false;
845         }
846         this.setFocused(true);
847         var widgetParent = this.getWidgetParent();
848         if (widgetParent) {
849             widgetParent.checkChildInfo(0, this, touchPoint);
850         }
851         this.pushDownEvent();
852         return !this._touchPassedEnabled;
853     },
854 
855     onTouchMoved: function (touch,event) {
856         var touchPoint = touch.getLocation();
857         this._touchMovePos.x = touchPoint.x;
858         this._touchMovePos.y = touchPoint.y;
859         this.setFocused(this.hitTest(touchPoint));
860         var widgetParent = this.getWidgetParent();
861         if (widgetParent) {
862             widgetParent.checkChildInfo(1, this, touchPoint);
863         }
864         this.moveEvent();
865     },
866 
867 
868     onTouchEnded: function (touch,event) {
869         var touchPoint = touch.getLocation();
870         this._touchEndPos.x = touchPoint.x;
871         this._touchEndPos.y = touchPoint.y;
872         var focus = this._focus;
873         this.setFocused(false);
874         var widgetParent = this.getWidgetParent();
875         if (widgetParent) {
876             widgetParent.checkChildInfo(2, this, touchPoint);
877         }
878         if (focus) {
879             this.releaseUpEvent();
880         }
881         else {
882             this.cancelUpEvent();
883         }
884     },
885 
886     /**
887      * A call back function called when widget is selected, and on touch canceled.
888      * @param {cc.Point} touchPoint
889      */
890     onTouchCancelled: function (touchPoint) {
891         this.setFocused(false);
892         this.cancelUpEvent();
893     },
894 
895     /**
896      * A call back function called when widget is selected, and on touch long clicked.
897      * @param {cc.Point} touchPoint
898      */
899     onTouchLongClicked: function (touchPoint) {
900         this.longClickEvent();
901     },
902 
903     //call back function called widget's state changed to dark.
904 
905     pushDownEvent: function () {
906         if (this._touchEventListener && this._touchEventSelector) {
907             if (this._touchEventSelector) {
908                 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN);
909             }
910         }
911     },
912 
913     moveEvent: function () {
914         if (this._touchEventListener && this._touchEventSelector) {
915             if (this._touchEventSelector) {
916                 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED);
917             }
918         }
919     },
920 
921     releaseUpEvent: function () {
922         if (this._touchEventListener && this._touchEventSelector) {
923             if (this._touchEventSelector) {
924                 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED);
925             }
926         }
927     },
928 
929     cancelUpEvent: function () {
930         if (this._touchEventSelector) {
931             this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_CANCELED);
932         }
933     },
934 
935     longClickEvent: function () {
936 
937     },
938 
939     /**
940      * Sets the touch event target/selector of the menu item
941      * @param {Function} selector
942      * @param {Object} target
943      */
944     addTouchEventListener: function (selector, target) {
945         this._touchEventSelector = selector;
946         this._touchEventListener = target;
947     },
948 
949     /**
950      * Checks a point if is in widget's space
951      * @param {cc.Point} pt
952      * @returns {boolean}
953      */
954     hitTest: function (pt) {
955         var nsp = this.convertToNodeSpace(pt);
956         var bb = cc.rect(-this._size.width * this._anchorPoint.x, -this._size.height * this._anchorPoint.y, this._size.width, this._size.height);
957         if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) {
958             return true;
959         }
960         return false;
961     },
962 
963     /**
964      * Checks a point if in parent's area.
965      * @param {cc.Point} pt
966      * @returns {Boolean}
967      */
968     clippingParentAreaContainPoint: function (pt) {
969         this._affectByClipping = false;
970         var parent = this.getParent();
971         var clippingParent = null;
972         while (parent) {
973             if (parent instanceof ccui.Layout) {
974                 if (parent.isClippingEnabled()) {
975                     this._affectByClipping = true;
976                     clippingParent = parent;
977                     break;
978                 }
979             }
980             parent = parent.getParent();
981         }
982 
983         if (!this._affectByClipping) {
984             return true;
985         }
986 
987 
988         if (clippingParent) {
989             var bRet = false;
990             if (clippingParent.hitTest(pt)) {
991                 bRet = true;
992             }
993             if (bRet) {
994                 return clippingParent.clippingParentAreaContainPoint(pt);
995             }
996             return false;
997         }
998         return true;
999     },
1000 
1001     /**
1002      * Sends the touch event to widget's parent
1003      * @param {number} handleState
1004      * @param {ccui.Widget} sender
1005      * @param {cc.Point} touchPoint
1006      */
1007     checkChildInfo: function (handleState, sender, touchPoint) {
1008         var widgetParent = this.getWidgetParent();
1009         if (widgetParent) {
1010             widgetParent.checkChildInfo(handleState, sender, touchPoint);
1011         }
1012     },
1013 
1014     /**
1015      * Changes the position (x,y) of the widget .
1016      * @param {cc.Point||Number} pos
1017      * @param {Number} posY
1018      */
1019     setPosition: function (pos, posY) {
1020         if (this._running) {
1021             var widgetParent = this.getWidgetParent();
1022             if (widgetParent) {
1023                 var pSize = widgetParent.getSize();
1024                 if (pSize.width <= 0 || pSize.height <= 0) {
1025                     this._positionPercent.x = 0;
1026                     this._positionPercent.y = 0;
1027                 }
1028                 else {
1029                     if(posY){
1030                         this._positionPercent.x = pos / pSize.width;
1031                         this._positionPercent.y = posY / pSize.height;
1032                     }else{
1033                         this._positionPercent.x = pos.x / pSize.width;
1034                         this._positionPercent.y = pos.y / pSize.height;
1035                     }
1036                 }
1037             }
1038         }
1039 
1040         cc.Node.prototype.setPosition.apply(this, arguments);
1041     },
1042 
1043 	setPositionX: function (x) {
1044 		if (this._running) {
1045 			var widgetParent = this.getWidgetParent();
1046 			if (widgetParent) {
1047 				var pw = widgetParent.width;
1048 				if (pw <= 0)
1049 					this._positionPercent.x = 0;
1050 				else
1051 					this._positionPercent.x = x / pw;
1052 			}
1053 		}
1054 
1055 		cc.Node.prototype.setPositionX.call(this, x);
1056 	},
1057 	setPositionY: function (y) {
1058 		if (this._running) {
1059 			var widgetParent = this.getWidgetParent();
1060 			if (widgetParent) {
1061 				var ph = widgetParent.height;
1062 				if (ph <= 0)
1063 					this._positionPercent.y = 0;
1064 				else
1065 					this._positionPercent.y = y / ph;
1066 			}
1067 		}
1068 
1069 		cc.Node.prototype.setPositionY.call(this, y);
1070 	},
1071 
1072     /**
1073      * Changes the position (x,y) of the widget
1074      * @param {cc.Point} percent
1075      */
1076     setPositionPercent: function (percent) {
1077         this._positionPercent = percent;
1078         if (this._running) {
1079             var widgetParent = this.getWidgetParent();
1080             if(widgetParent){
1081                 var parentSize = widgetParent.getSize();
1082                 this.setPosition(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y);
1083             }
1084         }
1085     },
1086 	_setXPercent: function (percent) {
1087 		this._positionPercent.x = percent;
1088 		if (this._running) {
1089 			var widgetParent = this.getWidgetParent();
1090 			if(widgetParent){
1091 				var absX = widgetParent.width * percent;
1092 				this.setPositionX(absX);
1093 			}
1094 		}
1095 	},
1096 	_setYPercent: function (percent) {
1097 		this._positionPercent.y = percent;
1098 		if (this._running) {
1099 			var widgetParent = this.getWidgetParent();
1100 			if(widgetParent){
1101 				var absY = widgetParent.height * percent;
1102 				this.setPositionY(absY);
1103 			}
1104 		}
1105 	},
1106 
1107     updateAnchorPoint:function(){
1108         this.setAnchorPoint(this.getAnchorPoint());
1109     },
1110 
1111     /**
1112      * Gets the percent (x,y) of the widget
1113      * @returns {cc.Point}
1114      */
1115     getPositionPercent: function () {
1116         return this._positionPercent;
1117     },
1118 	_getXPercent: function () {
1119 		return this._positionPercent.x;
1120 	},
1121 	_getYPercent: function () {
1122 		return this._positionPercent.y;
1123 	},
1124 
1125     /**
1126      * Changes the position type of the widget
1127      * @param {ccui.Widget.POSITION_ABSOLUTE|ccui.Widget.POSITION_PERCENT} type
1128      */
1129     setPositionType: function (type) {
1130         this.positionType = type;
1131     },
1132 
1133     /**
1134      * Gets the position type of the widget
1135      * @returns {cc.pPositionType}
1136      */
1137     getPositionType: function () {
1138         return this.positionType;
1139     },
1140 
1141     /**
1142      * Set flipped x
1143      * @param {Boolean} flipX
1144      */
1145     setFlippedX: function (flipX) {
1146         this._flippedX = flipX;
1147         this.updateFlippedX();
1148     },
1149 
1150     /**
1151      * Get flipped x
1152      * @returns {Boolean}
1153      */
1154     isFlippedX: function () {
1155         return this._flippedX;
1156     },
1157 
1158     /**
1159      * Set flipped y
1160      * @param {Boolean} flipY
1161      */
1162     setFlippedY: function (flipY) {
1163         this._flippedY = flipY;
1164         this.updateFlippedY();
1165     },
1166 
1167     /**
1168      * Get flipped y
1169      * @returns {Boolean}
1170      */
1171     isFlippedY: function () {
1172         return this._flippedY;
1173     },
1174 
1175     updateFlippedX:function(){
1176 
1177     },
1178 
1179     updateFlippedY:function(){
1180 
1181     },
1182 
1183     /**
1184      * Determines if the widget is bright
1185      * @returns {boolean}
1186      */
1187     isBright: function () {
1188         return this._bright;
1189     },
1190 
1191     /**
1192      * Determines if the widget is enabled
1193      * @returns {boolean}
1194      */
1195     isEnabled: function () {
1196         return this._enabled;
1197     },
1198 
1199     /**
1200      * Gets the left boundary position of this widget.
1201      * @returns {number}
1202      */
1203     getLeftInParent: function () {
1204         return this.getPositionX() - this._getAnchorX() * this._size.width;
1205     },
1206 
1207     /**
1208      * Gets the bottom boundary position of this widget.
1209      * @returns {number}
1210      */
1211     getBottomInParent: function () {
1212         return this.getPositionY() - this._getAnchorY() * this._size.height;
1213     },
1214 
1215     /**
1216      * Gets the right boundary position of this widget.
1217      * @returns {number}
1218      */
1219     getRightInParent: function () {
1220         return this.getLeftInParent() + this._size.width;
1221     },
1222 
1223     /**
1224      * Gets the top boundary position of this widget.
1225      * @returns {number}
1226      */
1227     getTopInParent: function () {
1228         return this.getBottomInParent() + this._size.height;
1229     },
1230 
1231     /**
1232      * Gets touch start position
1233      * @returns {cc.Point}
1234      */
1235     getTouchStartPos: function () {
1236         return this._touchStartPos;
1237     },
1238 
1239     /**
1240      * Gets touch move position
1241      * @returns {cc.Point}
1242      */
1243     getTouchMovePos: function () {
1244         return this._touchMovePos;
1245     },
1246 
1247     /**
1248      * Gets touch end position
1249      * @returns {cc.Point}
1250      */
1251     getTouchEndPos: function () {
1252         return this._touchEndPos;
1253     },
1254 
1255     /**
1256      * Sets the name of widget
1257      * @param {String} name
1258      */
1259     setName: function (name) {
1260         this._name = name;
1261     },
1262 
1263     /**
1264      * Gets the name of widget
1265      * @returns {string}
1266      */
1267     getName: function () {
1268         return this._name;
1269     },
1270 
1271     /**
1272      * get widget type
1273      * @returns {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER}
1274      */
1275     getWidgetType: function () {
1276         return this._widgetType;
1277     },
1278 
1279     /**
1280      * Sets layout parameter
1281      * @param {ccui.LayoutParameter} parameter
1282      */
1283     setLayoutParameter: function (parameter) {
1284         this._layoutParameterDictionary[parameter.getLayoutType()] = parameter;
1285     },
1286 
1287     /**
1288      * Gets layout parameter
1289      * @param {ccui.LayoutParameter.NONE|ccui.LayoutParameter.LINEAR|ccui.LayoutParameter.RELATIVE} type
1290      * @returns {ccui.LayoutParameter}
1291      */
1292     getLayoutParameter: function (type) {
1293         return this._layoutParameterDictionary[type];
1294     },
1295 
1296     /**
1297      * Returns the "class name" of widget.
1298      * @returns {string}
1299      */
1300     getDescription: function () {
1301         return "Widget";
1302     },
1303 
1304     clone: function () {
1305         var clonedWidget = this.createCloneInstance();
1306         clonedWidget.copyProperties(this);
1307         clonedWidget.copyClonedWidgetChildren(this);
1308         return clonedWidget;
1309     },
1310 
1311     createCloneInstance: function () {
1312         return ccui.Widget.create();
1313     },
1314 
1315     copyClonedWidgetChildren: function (model) {
1316         var widgetChildren = model.getChildren();
1317         for (var i = 0; i < widgetChildren.length; i++) {
1318             var locChild = widgetChildren[i];
1319             if(locChild instanceof ccui.Widget){
1320                 this.addChild(locChild.clone());
1321             }
1322         }
1323     },
1324 
1325     copySpecialProperties: function (model) {
1326 
1327     },
1328 
1329     copyProperties: function (widget) {
1330         this.setEnabled(widget.isEnabled());
1331         this.setVisible(widget.isVisible());
1332         this.setBright(widget.isBright());
1333         this.setTouchEnabled(widget.isTouchEnabled());
1334         this._touchPassedEnabled = false;
1335         this.setLocalZOrder(widget.getLocalZOrder());
1336         this.setUpdateEnabled(widget.isUpdateEnabled());
1337         this.setTag(widget.getTag());
1338         this.setName(widget.getName());
1339         this.setActionTag(widget.getActionTag());
1340         this._ignoreSize = widget._ignoreSize;
1341         this._size = cc.size(widget._size.width, widget._size.height);
1342         this._customSize = cc.size(widget._customSize.width, widget._customSize.height);
1343         this.copySpecialProperties(widget);
1344         this._sizeType = widget.getSizeType();
1345         this._sizePercent = cc.p(widget._sizePercent.x, widget._sizePercent.y);
1346         this.positionType = widget.positionType;
1347         this._positionPercent = cc.p(widget._positionPercent.x, widget._positionPercent.y);
1348         this.setPosition(widget.getPosition());
1349         this.setAnchorPoint(widget.getAnchorPoint());
1350         this.setScaleX(widget.getScaleX());
1351         this.setScaleY(widget.getScaleY());
1352         this.setRotation(widget.getRotation());
1353         this.setRotationX(widget.getRotationX());
1354         this.setRotationY(widget.getRotationY());
1355         this.setFlippedX(widget.isFlippedX());
1356         this.setFlippedY(widget.isFlippedY());
1357         this.setColor(widget.getColor());
1358         this.setOpacity(widget.getOpacity());
1359         for (var key in widget._layoutParameterDictionary) {
1360             var parameter = widget._layoutParameterDictionary[key];
1361             if (parameter)
1362                 this.setLayoutParameter(parameter.clone());
1363         }
1364         this.onSizeChanged();
1365     },
1366     
1367     /*temp action*/
1368     setActionTag: function (tag) {
1369         this._actionTag = tag;
1370     },
1371 
1372     getActionTag: function () {
1373         return this._actionTag;
1374     },
1375     /**
1376      * Set color
1377      * @param {cc.Color} color
1378      */
1379     setColor: function (color) {
1380         this._color.r = color.r;
1381         this._color.g = color.g;
1382         this._color.b = color.b;
1383         this.updateTextureColor();
1384         if (color.a !== undefined && !color.a_undefined) {
1385             this.setOpacity(color.a);
1386         }
1387     },
1388 
1389     /**
1390      * Get color
1391      * @returns {cc.Color}
1392      */
1393     getColor:function(){
1394         return cc.color(this._color.r,this._color.g,this._color.b,this._color.a) ;
1395     },
1396 
1397     /**
1398      * Set opacity
1399      * @param {Number} opacity
1400      */
1401     setOpacity: function (opacity) {
1402         this._color.a = opacity;
1403         this.updateTextureOpacity();
1404     },
1405 
1406     /**
1407      * Get opacity
1408      * @returns {Number}
1409      */
1410     getOpacity: function () {
1411         return this._color.a;
1412     },
1413 
1414     updateTextureColor: function () {
1415 
1416     },
1417 
1418     updateTextureOpacity: function () {
1419 
1420     },
1421 
1422 
1423     updateColorToRenderer: function (renderer) {
1424         if (renderer.RGBAProtocol) {
1425             renderer.setColor(this._color);
1426         }
1427     },
1428 
1429     updateOpacityToRenderer: function (renderer) {
1430         if (renderer.RGBAProtocol) {
1431             renderer.setOpacity(this._color.a);
1432         }
1433     }
1434 });
1435 
1436 window._p = ccui.Widget.prototype;
1437 
1438 // Extended properties
1439 /** @expose */
1440 _p.xPercent;
1441 cc.defineGetterSetter(_p, "xPercent", _p._getXPercent, _p._setXPercent);
1442 /** @expose */
1443 _p.yPercent;
1444 cc.defineGetterSetter(_p, "yPercent", _p._getYPercent, _p._setYPercent);
1445 /** @expose */
1446 _p.widthPercent;
1447 cc.defineGetterSetter(_p, "widthPercent", _p._getWidthPercent, _p._setWidthPercent);
1448 /** @expose */
1449 _p.heightPercent;
1450 cc.defineGetterSetter(_p, "heightPercent", _p._getHeightPercent, _p._setHeightPercent);
1451 /** @expose */
1452 _p.widgetParent;
1453 cc.defineGetterSetter(_p, "widgetParent", _p.getWidgetParent);
1454 /** @expose */
1455 _p.enabled;
1456 cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled);
1457 /** @expose */
1458 _p.focused;
1459 cc.defineGetterSetter(_p, "focused", _p.isFocused, _p.setFocused);
1460 /** @expose */
1461 _p.sizeType;
1462 cc.defineGetterSetter(_p, "sizeType", _p.getSizeType, _p.setSizeType);
1463 /** @expose */
1464 _p.widgetType;
1465 cc.defineGetterSetter(_p, "widgetType", _p.getWidgetType);
1466 /** @expose */
1467 _p.touchEnabled;
1468 cc.defineGetterSetter(_p, "touchEnabled", _p.isTouchEnabled, _p.setTouchEnabled);
1469 /** @expose */
1470 _p.updateEnabled;
1471 cc.defineGetterSetter(_p, "updateEnabled", _p.isUpdateEnabled, _p.setUpdateEnabled);
1472 /** @expose */
1473 _p.bright;
1474 cc.defineGetterSetter(_p, "bright", _p.isBright, _p.setBright);
1475 /** @expose */
1476 _p.name;
1477 cc.defineGetterSetter(_p, "name", _p.getName, _p.setName);
1478 /** @expose */
1479 _p.actionTag;
1480 cc.defineGetterSetter(_p, "actionTag", _p.getActionTag, _p.setActionTag);
1481 
1482 delete window._p;
1483 
1484 /**
1485  * allocates and initializes a UIWidget.
1486  * @constructs
1487  * @return {ccui.Widget}
1488  * @example
1489  * // example
1490  * var uiWidget = ccui.Widget.create();
1491  */
1492 ccui.Widget.create = function () {
1493     var widget = new ccui.Widget();
1494     if (widget && widget.init()) {
1495         return widget;
1496     }
1497     return null;
1498 };
1499 
1500 
1501 // Constants
1502 //bright style
1503 ccui.Widget.BRIGHT_STYLE_NONE = -1;
1504 ccui.Widget.BRIGHT_STYLE_NORMAL = 0;
1505 ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT = 1;
1506 
1507 //widget type
1508 ccui.Widget.TYPE_WIDGET = 0;
1509 ccui.Widget.TYPE_CONTAINER = 1;
1510 
1511 //texture resource type
1512 ccui.Widget.LOCAL_TEXTURE = 0;
1513 ccui.Widget.PLIST_TEXTURE = 1;
1514 
1515 //touch event type
1516 ccui.Widget.TOUCH_BEGAN = 0;
1517 ccui.Widget.TOUCH_MOVED = 1;
1518 ccui.Widget.TOUCH_ENDED = 2;
1519 ccui.Widget.TOUCH_CANCELED = 3;
1520 
1521 //size type
1522 ccui.Widget.SIZE_ABSOLUTE = 0;
1523 ccui.Widget.SIZE_PERCENT = 1;
1524 
1525 //position type
1526 ccui.Widget.POSITION_ABSOLUTE = 0;
1527 ccui.Widget.POSITION_PERCENT = 1;