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