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