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.UIWidget
 84  * @sample
 85  * var uiWidget = ccs.UIWidget.create();
 86  * var uiLayer = ccs.UILayer.create();
 87  * uiLayer.addWidget(uiWidget);
 88  * @class
 89  * @extends ccs.Class
 90  */
 91 ccs.UIWidget = ccs.Class.extend(/** @lends ccs.UIWidget# */{
 92     _enabled: true,            ///< Highest control of widget
 93     _visible: true,            ///< is this widget visible
 94     _bright: true,             ///< is this widget bright
 95     _touchEnabled: false,       ///< is this widget touch endabled
 96     _touchPassedEnabled: false, ///< is the touch event should be passed
 97     _focus: false,              ///< is the widget on focus
 98     _widgetZOrder: 0,        ///< z-order value that affects the draw order and touch order
 99     _anchorPoint: null,      ///< anchor point normalized
100     _widgetParent: null,  ///< parent of widget
101     _brightStyle: null, ///< bright style
102     _updateEnabled: false,      ///< is "update" method scheduled
103     _renderer: null,        ///< base renderer
104     _touchStartPos: null,    ///< touch began point
105     _touchMovePos: null,     ///< touch moved point
106     _touchEndPos: null,      ///< touch ended point
107 
108     _touchEventListener: null,
109     _touchEventSelector: null,
110 
111 
112     _widgetTag: -1,
113     _name: "default",
114     _widgetType: null,
115     _actionTag: 0,
116     _size: null,
117     _customSize: null,
118     _layoutParameterDictionary: null,
119     _ignoreSize: false,
120     _children: null,
121     _affectByClipping: false,
122 
123     _scheduler: null,
124 
125     _sizeType: null,
126     _sizePercent: null,
127     _positionType: null,
128     _positionPercent: null,
129     _isRunning: false,
130     _userObject: null,
131     ctor: function () {
132         this._enabled = true;
133         this._visible = true;
134         this._bright = true;
135         this._touchEnabled = false;
136         this._touchPassedEnabled = false;
137         this._focus = false;
138         this._widgetZOrder = 0;
139         this._anchorPoint = cc.p(0.5, 0.5);
140         this._widgetParent = null;
141         this._brightStyle = ccs.BrightStyle.none;
142         this._updateEnabled = false;
143         this._renderer = null;
144         this._touchStartPos = cc.PointZero();
145         this._touchMovePos = cc.PointZero();
146         this._touchEndPos = cc.PointZero();
147         this._touchEventListener = null;
148         this._touchEventSelector = null;
149         this._widgetTag = -1;
150         this._name = "default";
151         this._widgetType = ccs.WidgetType.widget;
152         this._actionTag = 0;
153         this._size = cc.SizeZero();
154         this._customSize = cc.SizeZero();
155         this._layoutParameterDictionary = {};
156         this._ignoreSize = false;
157         this._children = [];
158         this._affectByClipping = false;
159         this._scheduler = null;
160         this._sizeType = ccs.SizeType.absolute;
161         this._sizePercent = cc.PointZero();
162         this._positionType = ccs.PositionType.absolute;
163         this._positionPercent = cc.PointZero();
164         this._isRunning = false;
165     },
166 
167     /**
168      * initializes state of widget.
169      * @returns {boolean}
170      */
171     init: function () {
172         this._layoutParameterDictionary = {};
173         this._children = [];
174         this.initRenderer();
175         this._renderer.setZOrder(this._widgetZOrder);
176         if (this._renderer.RGBAProtocol) {
177             this._renderer.setCascadeColorEnabled(true);
178             this._renderer.setCascadeOpacityEnabled(true);
179         }
180         this.setBright(true);
181         this.ignoreContentAdaptWithSize(true);
182         this._scheduler = cc.Director.getInstance().getScheduler();
183         return true;
184     },
185     /**
186      * Release texture resoures of widget.
187      * Release renderer.
188      * If you override releaseResoures, you shall call its parent's one, e.g. UIWidget::releaseResoures().
189      */
190     releaseResoures: function () {
191         this.setUpdateEnabled(false);
192         this.removeAllChildren();
193         this._children=[];
194         this._renderer.removeAllChildren(true);
195         this._renderer.removeFromParent(true);
196         this._renderer.release();
197     },
198 
199     onEnter: function () {
200         var locChild;
201         for (var i = 0; i < this._children.length; i++) {
202             locChild = this._children[i];
203             if (locChild instanceof ccs.UIWidget)
204                 locChild.onEnter();
205         }
206         this._isRunning = true;
207         this.updateSizeAndPosition();
208     },
209 
210     onExit: function () {
211         this._isRunning = false;
212         var locChild;
213         for (var i = 0; i < this._children.length; i++) {
214             locChild = this._children[i];
215             if (locChild instanceof ccs.UIWidget)
216                 locChild.onExit();
217         }
218     },
219 
220     /**
221      * Adds a child to the container.
222      * @param {ccs.UIWidget}child
223      * @returns {boolean}
224      */
225     addChild: function (child) {
226         if (!child) {
227             return false;
228         }
229         if (cc.ArrayContainsObject(this._children, child)) {
230             return false;
231         }
232         child.setParent(this);
233         var childrenCount = this._children.length;
234         if (childrenCount <= 0) {
235             this._children.push(child);
236         }
237         else {
238             var seekSucceed = false;
239             for (var i = childrenCount - 1; i >= 0; --i) {
240                 var widget = this._children[i];
241                 if (child.getZOrder() >= widget.getZOrder()) {
242                     if (i == childrenCount - 1) {
243                         this._children.push(child);
244                         seekSucceed = true;
245                         break;
246                     }
247                     else {
248                         cc.ArrayAppendObjectToIndex(this._children, child, i + 1);
249                         seekSucceed = true;
250                         break;
251                     }
252                 }
253             }
254             if (!seekSucceed) {
255                 cc.ArrayAppendObjectToIndex(this._children, child, 0);
256             }
257         }
258         child.getRenderer().setZOrder(child.getZOrder());
259         this._renderer.addChild(child.getRenderer());
260         if (this._isRunning) {
261             child.onEnter();
262         }
263         return true;
264     },
265 
266     /**
267      * Adds a child to the container.
268      * @param {ccs.UIWidget} child
269      * @returns {boolean}
270      */
271     removeChild: function (child) {
272         if (!child) {
273             return false;
274         }
275         if (cc.ArrayContainsObject(this._children, child)) {
276             if (this._isRunning) {
277                 child.onExit();
278             }
279             child.setUpdateEnabled(false);
280             child.setParent(null);
281             this._renderer.removeChild(child.getRenderer());
282             cc.ArrayRemoveObject(this._children, child);
283             return true;
284         }
285         return false;
286     },
287 
288     /**
289      * Removes this widget itself from its parent widget.
290      * If the widget orphan, then it will destroy itself.
291      */
292     removeFromParent: function () {
293         if (this._widgetParent) {
294             this._widgetParent.removeChild(this);
295         }
296     },
297 
298     /**
299      * Removes all children from the container, and do a cleanup to all running actions depending on the cleanup parameter.
300      */
301     removeAllChildren: function () {
302         if (this._children.length <= 0) {
303             return;
304         }
305         var locChild;
306         for (var i = 0; i < this._children.length; ++i) {
307             locChild = this._children[i];
308             this.removeChild(this._children[i]);
309         }
310     },
311 
312     /**
313      * Reorders a child according to a new z value.
314      * @param {ccs.UIWidget} child
315      */
316     reorderChild: function (child) {
317         cc.ArrayRemoveObject(this._children, child);
318         var childrenCount = this._children.length;
319         if (childrenCount <= 0) {
320             this._children.push(child);
321         }
322         else {
323             var seekSucceed = false;
324             var arrayChildren = this._children;
325             for (var i = childrenCount - 1; i >= 0; --i) {
326                 var widget = arrayChildren[i];
327                 if (child.getZOrder() >= widget.getZOrder()) {
328                     if (i == childrenCount - 1) {
329                         this._children.push(child);
330                         seekSucceed = true;
331                         break;
332                     }
333                     else {
334                         cc.ArrayAppendObjectToIndex(this._children, child, i + 1);
335                         seekSucceed = true;
336                         break;
337                     }
338                 }
339             }
340             if (!seekSucceed) {
341                 cc.ArrayAppendObjectToIndex(this._children, child, 0);
342             }
343         }
344     },
345 
346     /**
347      * Set enabled renderer
348      * @param {Boolean} enabled
349      */
350     setEnabled: function (enabled) {
351         this._enabled = enabled;
352         this._renderer.setEnabled(enabled);
353         var arrayChildren = this._children;
354         var childrenCount = arrayChildren.length;
355         for (var i = 0; i < childrenCount; i++) {
356             var child = arrayChildren[i];
357             child.setEnabled(enabled);
358         }
359     },
360 
361     /**
362      * Gets a child from the container with its name
363      * @param {string} name
364      * @returns {ccs.UIWidget}
365      */
366     getChildByName: function (name) {
367         return ccs.UIHelper.seekWidgetByName(this, name);
368     },
369 
370     /**
371      * Gets a child from the container with its tag
372      * @param {number} tag
373      * @returns {ccs.UIWidget}
374      */
375     getChildByTag: function (tag) {
376         return ccs.UIHelper.seekWidgetByTag(this, tag);
377     },
378 
379     /**
380      * Return an array of children
381      * @returns {Array}
382      */
383     getChildren: function () {
384         return this._children;
385     },
386 
387     /**
388      * initializes renderer of widget.
389      */
390     initRenderer: function () {
391         this._renderer = ccs.GUIRenderer.create();
392     },
393 
394     /**
395      * Changes the size that is widget's size
396      * @param {cc.Size} size
397      */
398     setSize: function (size) {
399         this._customSize.width = size.width;
400         this._customSize.height = size.height;
401         var locSize;
402         if (this._ignoreSize) {
403              locSize = this.getContentSize();
404         }
405         else {
406             locSize = size;
407         }
408         this._size.width = locSize.width;
409         this._size.height = locSize.height;
410 
411         if (this._isRunning) {
412             this._sizePercent = (this._widgetParent == null) ? cc.PointZero() : cc.p(this._customSize.width / this._widgetParent.getSize().width, this._customSize.height / this._widgetParent.getSize().height);
413         }
414         this.onSizeChanged();
415     },
416 
417     /**
418      * Changes the percent that is widget's percent size
419      * @param {cc.Point} percent
420      */
421     setSizePercent: function (percent) {
422         this._sizePercent = percent;
423         if (!this._isRunning) {
424             return;
425         }
426         var size = (this._widgetParent == null) ? cc.SizeZero() : cc.size(this._widgetParent.getSize().width * percent.x, this._widgetParent.getSize().height * percent.y);
427         var locSize;
428         if (this._ignoreSize) {
429             locSize = this.getContentSize();
430         }
431         else {
432             locSize = size;
433         }
434         this._size.width = locSize.width;
435         this._size.height = locSize.height;
436         this._customSize.width = size.width;
437         this._customSize.height = size.height;
438         this.onSizeChanged();
439     },
440 
441     /**
442      * update size and position
443      */
444     updateSizeAndPosition: function () {
445         switch (this._sizeType) {
446             case ccs.SizeType.absolute:
447                 var locSize;
448                 if (this._ignoreSize) {
449                     locSize = this.getContentSize();
450                 }
451                 else {
452                     locSize = this._customSize;
453                 }
454                 this._size.width = locSize.width;
455                 this._size.height = locSize.height;
456                 this._sizePercent = (this._widgetParent == null) ? cc.PointZero() : cc.p(this._customSize.width / this._widgetParent.getSize().width, this._customSize.height / this._widgetParent.getSize().height);
457                 break;
458             case ccs.SizeType.percent:
459                 var cSize = (this._widgetParent == null) ? cc.SizeZero() : cc.size(this._widgetParent.getSize().width * this._sizePercent.x, this._widgetParent.getSize().height * this._sizePercent.y);
460                 var locSize;
461                 if (this._ignoreSize) {
462                     locSize = this.getContentSize();
463                 }
464                 else {
465                     locSize = cSize;
466                 }
467                 this._size.width = locSize.width;
468                 this._size.height = locSize.height;
469                 this._customSize.width = cSize.width;
470                 this._customSize.height = cSize.height;
471                 break;
472             default:
473                 break;
474         }
475         this.onSizeChanged();
476         var absPos = this.getPosition();
477         switch (this._positionType) {
478             case ccs.PositionType.absolute:
479                 this._positionPercent = (this._widgetParent == null) ? cc.PointZero() : cc.p(absPos.x / this._widgetParent.getSize().width, absPos.y / this._widgetParent.getSize().height);
480                 break;
481             case ccs.PositionType.percent:
482                 var parentSize = this._widgetParent.getSize();
483                 absPos = cc.p(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y);
484                 break;
485             default:
486                 break;
487         }
488         this._renderer.setPosition(absPos);
489     },
490 
491     /**
492      * Changes the size type of widget.
493      * @param {ccs.SizeType} type
494      */
495     setSizeType: function (type) {
496         this._sizeType = type;
497     },
498 
499     /**
500      * Gets the size type of widget.
501      * @returns {ccs.SizeType}
502      */
503     getSizeType: function () {
504         return this._sizeType;
505     },
506 
507     /**
508      * Ignore the widget size
509      * @param {Boolean} ignore
510      */
511     ignoreContentAdaptWithSize: function (ignore) {
512         this._ignoreSize = ignore;
513         var locSize = this.getContentSize();
514         if (this._ignoreSize) {
515             locSize = this.getContentSize();
516         }
517         else {
518             locSize = this._customSize;
519         }
520         this._size.width = locSize.width;
521         this._size.height = locSize.height;
522         this.onSizeChanged();
523     },
524 
525     /**
526      * Gets the widget if is ignore it's size.
527      * @returns {boolean}
528      */
529     isIgnoreContentAdaptWithSize: function () {
530         return this._ignoreSize;
531     },
532 
533     /**
534      * Returns size of widget
535      * @returns {cc.Size}
536      */
537     getSize: function () {
538         return this._size;
539     },
540 
541     /**
542      * Returns size percent of widget
543      * @returns {cc.Point}
544      */
545     getSizePercent: function () {
546         return this._sizePercent;
547     },
548 
549     /**
550      *  Gets world position of widget.
551      * @returns {cc.Point}
552      */
553     getWorldPosition: function () {
554         return this._renderer.convertToWorldSpace(cc.PointZero());
555     },
556 
557     /**
558      * Converts a Point to world space coordinates. The result is in Points.
559      * @param {cc.Point} pt
560      * @returns {cc.Point}
561      */
562     convertToWorldSpace: function (pt) {
563         return this._renderer.convertToWorldSpace(pt);
564     },
565 
566     /**
567      * Gets the Virtual Renderer of widget.
568      * @returns {cc.Node}
569      */
570     getVirtualRenderer: function () {
571         return this._renderer;
572     },
573 
574     /**
575      * call back function called when size changed.
576      */
577     onSizeChanged: function () {
578 
579     },
580 
581     /**
582      * Gets the content size of widget.
583      * @returns {cc.Size}
584      */
585     getContentSize: function () {
586         return this._size;
587     },
588 
589     /**
590      * set zOrder of widget
591      * @param {number} z
592      */
593     setZOrder: function (z) {
594         this._widgetZOrder = z;
595         this._renderer.setZOrder(z);
596         if (this._widgetParent) {
597             this._widgetParent.reorderChild(this);
598         }
599     },
600 
601     /**
602      * get zOrder of widget
603      * @returns {number}
604      */
605     getZOrder: function () {
606         return this._widgetZOrder;
607     },
608 
609     /**
610      * Sets whether the widget is touch enabled
611      * @param enable
612      */
613     setTouchEnabled: function (enable) {
614         this._touchEnabled = enable;
615     },
616 
617     /**
618      * To set the bright style of widget.
619      * @returns {boolean}
620      */
621     isTouchEnabled: function () {
622         return this._touchEnabled;
623     },
624 
625     /**
626      * Schedules the "update" method.
627      * @param enable
628      */
629     setUpdateEnabled: function (enable) {
630         if(this._updateEnabled == enable){
631             return;
632         }
633         this._updateEnabled = enable;
634         if (enable) {
635             if (this._scheduler) {
636                 this._scheduler.scheduleUpdateForTarget(this, 0, false);
637             }
638         }
639         else {
640             if (this._scheduler) {
641                 this._scheduler.unscheduleUpdateForTarget(this);
642             }
643         }
644     },
645 
646     /**
647      * is the "update" method scheduled.
648      * @returns {boolean}
649      */
650     isUpdateEnabled: function () {
651         return this._updateEnabled;
652     },
653 
654     /**
655      * Determines if the widget is on focused
656      * @returns {boolean}
657      */
658     isFocused: function () {
659         return this._focus;
660     },
661 
662     /**
663      * Sets whether the widget is on focused
664      * The default value is false, a widget is default to not on focused
665      * @param {boolean} fucos
666      */
667     setFocused: function (fucos) {
668         if (fucos == this._focus) {
669             return;
670         }
671         this._focus = fucos;
672         if (this._bright) {
673             if (this._focus) {
674                 this.setBrightStyle(ccs.BrightStyle.highlight);
675             }
676             else {
677                 this.setBrightStyle(ccs.BrightStyle.normal);
678             }
679         }
680         else {
681             this.onPressStateChangedToDisabled();
682         }
683     },
684 
685     /**
686      * To set the bright style of widget.
687      * @param {ccs.BrightStyle} style
688      */
689     setBrightStyle: function (style) {
690         if (this._brightStyle == style) {
691             return;
692         }
693         style = style|| ccs.BrightStyle.normal;
694         this._brightStyle = style;
695         switch (this._brightStyle) {
696             case ccs.BrightStyle.normal:
697                 this.onPressStateChangedToNormal();
698                 break;
699             case ccs.BrightStyle.highlight:
700                 this.onPressStateChangedToPressed();
701                 break;
702             default:
703                 break;
704         }
705     },
706 
707     /**
708      * call back function called widget's state changed to normal.
709      */
710     onPressStateChangedToNormal: function () {
711 
712     },
713 
714     /**
715      * call back function called widget's state changed to selected.
716      */
717     onPressStateChangedToPressed: function () {
718 
719     },
720 
721     /**
722      * call back function called widget's state changed to dark.
723      */
724     onPressStateChangedToDisabled: function () {
725 
726     },
727 
728     /**
729      * A call back function when widget lost of focus.
730      */
731     didNotSelectSelf: function () {
732 
733     },
734 
735     /**
736      * A call back function called when widget is selected, and on touch began.
737      * @param {cc.Ponit} touchPoint
738      * @returns {boolean}
739      */
740     onTouchBegan: function (touchPoint) {
741         this.setFocused(true);
742         this._touchStartPos.x = touchPoint.x;
743         this._touchStartPos.y = touchPoint.y;
744         if (this._widgetParent) {
745             this._widgetParent.checkChildInfo(0, this, touchPoint);
746         }
747         this.pushDownEvent();
748         return this._touchPassedEnabled;
749     },
750 
751     /**
752      * A call back function called when widget is selected, and on touch moved.
753      * @param {cc.Point} touchPoint
754      */
755     onTouchMoved: function (touchPoint) {
756         this._touchMovePos.x = touchPoint.x;
757         this._touchMovePos.y = touchPoint.y;
758         this.setFocused(this.hitTest(touchPoint));
759         if (this._widgetParent) {
760             this._widgetParent.checkChildInfo(1, this, touchPoint);
761         }
762         this.moveEvent();
763     },
764 
765     /**
766      * A call back function called when widget is selected, and on touch ended.
767      * @param {cc.Point} touchPoint
768      */
769     onTouchEnded: function (touchPoint) {
770         this._touchEndPos.x = touchPoint.x;
771         this._touchEndPos.y = touchPoint.y;
772         var focus = this._focus;
773         this.setFocused(false);
774         if (this._widgetParent) {
775             this._widgetParent.checkChildInfo(2, this, touchPoint);
776         }
777         if (focus) {
778             this.releaseUpEvent();
779         }
780         else {
781             this.cancelUpEvent();
782         }
783     },
784 
785     /**
786      * A call back function called when widget is selected, and on touch canceled.
787      * @param {cc.Point} touchPoint
788      */
789     onTouchCancelled: function (touchPoint) {
790         this.setFocused(false);
791         this.cancelUpEvent();
792     },
793 
794     /**
795      * A call back function called when widget is selected, and on touch long clicked.
796      * @param {cc.Point} touchPoint
797      */
798     onTouchLongClicked: function (touchPoint) {
799         this.longClickEvent();
800     },
801 
802     //call back function called widget's state changed to dark.
803 
804     pushDownEvent: function () {
805         if (this._touchEventListener && this._touchEventSelector) {
806             if (this._touchEventSelector) {
807                 this._touchEventSelector.call(this._touchEventListener, this, ccs.TouchEventType.began);
808             }
809         }
810     },
811 
812     moveEvent: function () {
813         if (this._touchEventListener && this._touchEventSelector) {
814             if (this._touchEventSelector) {
815                 this._touchEventSelector.call(this._touchEventListener, this, ccs.TouchEventType.moved);
816             }
817         }
818     },
819 
820     releaseUpEvent: function () {
821         if (this._touchEventListener && this._touchEventSelector) {
822             if (this._touchEventSelector) {
823                 this._touchEventSelector.call(this._touchEventListener, this, ccs.TouchEventType.ended);
824             }
825         }
826     },
827 
828     cancelUpEvent: function () {
829         if (this._touchEventSelector) {
830             this._touchEventSelector.call(this._touchEventListener, this, ccs.TouchEventType.canceled);
831         }
832     },
833 
834     longClickEvent: function () {
835 
836     },
837 
838     /**
839      * Sets the touch event target/selector of the menu item
840      * @param {Function} selector
841      * @param {Object} target
842      */
843     addTouchEventListener: function (selector, target) {
844         this._touchEventSelector = selector;
845         this._touchEventListener = target;
846     },
847 
848     /**
849      * Gets the renderer of widget
850      * @returns {cc.Node}
851      */
852     getRenderer: function () {
853         return this._renderer;
854     },
855 
856     /**
857      * Add a CCNode for rendering.
858      * renderer is a CCNode, it's for drawing
859      * @param {cc.Node} renderer
860      * @param {number} zOrder
861      */
862     addRenderer: function (renderer, zOrder) {
863         this._renderer.addChild(renderer, zOrder);
864     },
865 
866     /**
867      * Remove a CCNode from widget.
868      * @param {cc.Node} renderer
869      * @param {Boolean} cleanup
870      */
871     removeRenderer: function (renderer, cleanup) {
872         this._renderer.removeChild(renderer, cleanup);
873     },
874 
875     /**
876      * Checks a point if is in widget's space
877      * @param {cc.Point} pt
878      * @returns {boolean}
879      */
880     hitTest: function (pt) {
881         var nsp = this._renderer.convertToNodeSpace(pt);
882         var bb = cc.rect(-this._size.width * this._anchorPoint.x, -this._size.height * this._anchorPoint.y, this._size.width, this._size.height);
883         if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) {
884             return true;
885         }
886         return false;
887     },
888 
889     /**
890      * Checks a point if in parent's area.
891      * @param {cc.Point} pt
892      * @returns {Boolean}
893      */
894     clippingParentAreaContainPoint: function (pt) {
895         this._affectByClipping = false;
896         var parent = this.getParent();
897         var clippingParent = null;
898         while (parent) {
899             if (parent instanceof ccs.UILayout) {
900                 if (parent.isClippingEnabled()) {
901                     this._affectByClipping = true;
902                     clippingParent = parent;
903                     break;
904                 }
905             }
906             parent = parent.getParent();
907         }
908 
909         if (!this._affectByClipping) {
910             return true;
911         }
912 
913 
914         if (clippingParent) {
915             var bRet = false;
916             if (clippingParent.hitTest(pt)) {
917                 bRet = true;
918             }
919             if (bRet) {
920                 return clippingParent.clippingParentAreaContainPoint(pt);
921             }
922             return false;
923         }
924         return true;
925     },
926 
927     /**
928      * Sends the touch event to widget's parent
929      * @param {number} handleState
930      * @param {ccs.UIWidget} sender
931      * @param {cc.Point} touchPoint
932      */
933     checkChildInfo: function (handleState, sender, touchPoint) {
934         if (this._widgetParent) {
935             this._widgetParent.checkChildInfo(handleState, sender, touchPoint);
936         }
937     },
938 
939     /**
940      * Changes the position (x,y) of the widget .
941      * @param {cc.Point} pos
942      */
943     setPosition: function (pos) {
944         if (this._isRunning) {
945             this._positionPercent = (this._widgetParent == null) ? cc.PointZero() : cc.p(pos.x / this._widgetParent.getSize().width, pos.y / this._widgetParent.getSize().height);
946         }
947         this._renderer.setPosition(pos);
948     },
949 
950     /**
951      * Changes the position (x,y) of the widget
952      * @param {cc.Point} percent
953      */
954     setPositionPercent: function (percent) {
955         this._positionPercent = percent;
956         if (this._isRunning) {
957             var parentSize = this._widgetParent.getSize();
958             var absPos = cc.p(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y);
959             this._renderer.setPosition(absPos);
960         }
961     },
962 
963     /**
964      * Sets the anchor point in percent.
965      * @param {cc.Point} pt
966      */
967     setAnchorPoint: function (pt) {
968         this._anchorPoint.x = pt.x;
969         this._anchorPoint.y = pt.y;
970         this._renderer.setAnchorPoint(pt);
971     },
972 
973     updateAnchorPoint: function () {
974         this.setAnchorPoint(this._anchorPoint);
975     },
976 
977     /**
978      * Gets the position (x,y) of the widget
979      * @returns {cc.Point}
980      */
981     getPosition: function () {
982         return this._renderer.getPosition();
983     },
984 
985     /**
986      * Gets the percent (x,y) of the widget
987      * @returns {cc.Point}
988      */
989     getPositionPercent: function () {
990         return this._positionPercent;
991     },
992 
993     /**
994      * Changes the position type of the widget
995      * @param {ccs.PositionType} type
996      */
997     setPositionType: function (type) {
998         this._positionType = type;
999     },
1000 
1001     /**
1002      * Gets the position type of the widget
1003      * @returns {cc.pPositionType}
1004      */
1005     getPositionType: function () {
1006         return this._positionType;
1007     },
1008 
1009     /**
1010      * Returns the anchor point in percent.
1011      * @returns {cc.Point}
1012      */
1013     getAnchorPoint: function () {
1014         return this._anchorPoint;
1015     },
1016 
1017     /**
1018      * Changes both X and Y scale factor of the widget.
1019      * 1.0 is the default scale factor. It modifies the X and Y scale at the same time.
1020      * @param {number} scale
1021      */
1022     setScale: function (scale) {
1023         this._renderer.setScale(scale);
1024     },
1025 
1026     /**
1027      * Gets the scale factor of the widget,  when X and Y have the same scale factor.
1028      * @returns {number}
1029      */
1030     getScale: function () {
1031         return this._renderer.getScale();
1032     },
1033 
1034     /**
1035      * Changes the scale factor on X axis of this widget
1036      * @param {number} scaleX
1037      */
1038     setScaleX: function (scaleX) {
1039         this._renderer.setScaleX(scaleX);
1040     },
1041 
1042     /**
1043      * Returns the scale factor on X axis of this widget
1044      * @returns {number}
1045      */
1046     getScaleX: function () {
1047         return this._renderer.getScaleX();
1048     },
1049 
1050     /**
1051      * Changes the scale factor on Y axis of this widget
1052      * @param {number} scaleY
1053      */
1054     setScaleY: function (scaleY) {
1055         this._renderer.setScaleY(scaleY);
1056     },
1057 
1058     /**
1059      * Returns the scale factor on Y axis of this widget
1060      * @returns {number}
1061      */
1062     getScaleY: function () {
1063         return this._renderer.getScaleY();
1064     },
1065 
1066     /**
1067      * Sets the rotation (angle) of the widget in degrees.
1068      * @param {number} rotation
1069      */
1070     setRotation: function (rotation) {
1071         this._renderer.setRotation(rotation);
1072     },
1073 
1074     /**
1075      * Returns the rotation of the widget in degrees.
1076      * @returns {number}
1077      */
1078     getRotation: function () {
1079         return this._renderer.getRotation();
1080     },
1081 
1082     /**
1083      * Sets the X rotation (angle) of the widget in degrees which performs a horizontal rotational skew.
1084      * @param {number} rotationX
1085      */
1086     setRotationX: function (rotationX) {
1087         this._renderer.setRotationX(rotationX);
1088     },
1089 
1090     /**
1091      * Gets the X rotation (angle) of the widget in degrees which performs a horizontal rotation skew.
1092      * @returns {number}
1093      */
1094     getRotationX: function () {
1095         return this._renderer.getRotationX();
1096     },
1097 
1098     /**
1099      * Sets the Y rotation (angle) of the widget in degrees which performs a vertical rotational skew.
1100      * @param {number} rotationY
1101      */
1102     setRotationY: function (rotationY) {
1103         this._renderer.setRotationY(rotationY);
1104     },
1105 
1106     /**
1107      * Gets the Y rotation (angle) of the widget in degrees which performs a vertical rotational skew.
1108      * @returns {number}
1109      */
1110     getRotationY: function () {
1111         return this._renderer.getRotationY();
1112     },
1113 
1114     /**
1115      * Sets whether the widget is visible
1116      * The default value is true, a widget is default to visible
1117      * @param {Boolean} visible
1118      */
1119     setVisible: function (visible) {
1120         this._visible = visible;
1121         this._renderer.setVisible(visible);
1122     },
1123 
1124     /**
1125      * Sets whether the widget should be flipped horizontally or not.
1126      * @param {Boolean} flipX
1127      */
1128     setFlippedX:function(flipX){
1129 
1130     },
1131 
1132     /**
1133      * Returns the flag which indicates whether the widget is flipped horizontally or not.
1134      * It only flips the texture of the widget, and not the texture of the widget's children.
1135      * Also, flipping the texture doesn't alter the anchorPoint.
1136      * If you want to flip the anchorPoint too, and/or to flip the children too use:
1137      * widget.setScaleX(sprite.getScaleX() * -1);
1138      * @return {Boolean} true if the widget is flipped horizaontally, false otherwise.
1139      */
1140     isFlippedX:function(){
1141         false;
1142     },
1143 
1144     /**
1145      * Sets whether the widget should be flipped vertically or not.
1146      * @param {Boolean} flipY
1147      */
1148     setFlippedY:function(flipY){
1149 
1150     },
1151 
1152     /**
1153      * Return the flag which indicates whether the widget is flipped vertically or not.
1154      * It only flips the texture of the widget, and not the texture of the widget's children.
1155      * Also, flipping the texture doesn't alter the anchorPoint.
1156      * If you want to flip the anchorPoint too, and/or to flip the children too use:
1157      * widget.setScaleY(widget.getScaleY() * -1);
1158      * @return {Boolean} true if the widget is flipped vertically, flase otherwise.
1159      */
1160     isFlippedY:function(){
1161         false;
1162     },
1163 
1164     /**
1165      * Determines if the widget is visible
1166      * @returns {boolean}
1167      */
1168     isVisible: function () {
1169         return this._visible;
1170     },
1171 
1172     /**
1173      * Determines if the widget is bright
1174      * @returns {boolean}
1175      */
1176     isBright: function () {
1177         return this._bright;
1178     },
1179 
1180     /**
1181      * Determines if the widget is enabled
1182      * @returns {boolean}
1183      */
1184     isEnabled: function () {
1185         return this._enabled;
1186     },
1187 
1188     /**
1189      * Gets the left boundary position of this widget.
1190      * @returns {number}
1191      */
1192     getLeftInParent: function () {
1193         return this.getPosition().x - this.getAnchorPoint().x * this._size.width;
1194     },
1195 
1196     /**
1197      * Gets the bottom boundary position of this widget.
1198      * @returns {number}
1199      */
1200     getBottomInParent: function () {
1201         return this.getPosition().y - this.getAnchorPoint().y * this._size.height;;
1202     },
1203 
1204     /**
1205      * Gets the right boundary position of this widget.
1206      * @returns {number}
1207      */
1208     getRightInParent: function () {
1209         return this.getLeftInParent() + this._size.width;
1210     },
1211 
1212     /**
1213      * Gets the top boundary position of this widget.
1214      * @returns {number}
1215      */
1216     getTopInParent: function () {
1217         return this.getBottomInParent() + this._size.height;
1218     },
1219 
1220     /**
1221      * Returns a pointer to the parent widget
1222      * @returns {ccs.UIWidget}
1223      */
1224     getParent: function () {
1225         return this._widgetParent;
1226     },
1227 
1228     /**
1229      * Sets the parent widget
1230      * @param {ccs.UIWidget} parent
1231      */
1232     setParent: function (parent) {
1233         this._widgetParent = parent;
1234     },
1235 
1236     /**
1237      * run action
1238      * @param {cc.Action} action
1239      * @returns {*}
1240      */
1241     runAction: function (action) {
1242         this._renderer.runAction(action);
1243     },
1244 
1245     /**
1246      * Sets the CCActionManager object that is used by all actions.
1247      * @param {cc.ActionManager} actionManager
1248      */
1249     setActionManager: function (actionManager) {
1250         this._renderer.setActionManager(actionManager);
1251     },
1252 
1253     /**
1254      * Gets the CCActionManager object that is used by all actions.
1255      * @returns {cc.ActionManager}
1256      */
1257     getActionManager: function () {
1258         return this._renderer.getActionManager();
1259     },
1260 
1261     /**
1262      * Stops and removes all actions from the running action list .
1263      */
1264     stopAllActions: function () {
1265         this._renderer.stopAllActions();
1266     },
1267 
1268     /**
1269      * Stops and removes an action from the running action list.
1270      * @param {cc.Action} action
1271      */
1272     stopAction: function (action) {
1273         this._renderer.stopAction(action);
1274     },
1275 
1276     /**
1277      * Removes an action from the running action list by its tag.
1278      * @param {number} tag
1279      */
1280     stopActionByTag: function (tag) {
1281         this._renderer.stopActionByTag(tag);
1282     },
1283 
1284     /**
1285      * Removes an action from the running action list by its tag.
1286      * @param {number} tag
1287      * @returns {cc.Action}
1288      */
1289     getActionByTag: function (tag) {
1290         return this._renderer.getActionByTag(tag);
1291     },
1292 
1293     /**
1294      * Sets color to widget
1295      * @param {cc.c3b} color
1296      */
1297     setColor: function (color) {
1298         if (this._renderer.RGBAProtocol) {
1299             this._renderer.setColor(color);
1300         }
1301     },
1302 
1303     /**
1304      * Gets color of widget
1305      * @returns {cc.c3b}
1306      */
1307     getColor: function () {
1308         if (this._renderer.RGBAProtocol) {
1309             return this._renderer.getColor();
1310         }
1311         return cc.WHITE;
1312     },
1313 
1314     /**
1315      * Sets opacity to widget
1316      * @param {number} opacity
1317      */
1318     setOpacity: function (opacity) {
1319         if (this._renderer.RGBAProtocol) {
1320             this._renderer.setOpacity(opacity);
1321         }
1322     },
1323 
1324     /**
1325      * Gets opacity of widget
1326      * @returns {number}
1327      */
1328     getOpacity: function () {
1329         if (this._renderer.RGBAProtocol) {
1330             return this._renderer.getOpacity();
1331         }
1332         return 255;
1333     },
1334 
1335     /**
1336      * Gets whether  cascadeOpacity is enabled
1337      * @returns {Boolean}
1338      */
1339     isCascadeOpacityEnabled: function () {
1340         if (this._renderer.RGBAProtocol) {
1341             return this._renderer.isCascadeOpacityEnabled();
1342         }
1343         return false;
1344     },
1345 
1346     /**
1347      * Sets cascade opacity enabled
1348      * @param {Boolean} cascadeOpacityEnabled
1349      */
1350     setCascadeOpacityEnabled: function (cascadeOpacityEnabled) {
1351         if (this._renderer.RGBAProtocol) {
1352             this._renderer.setCascadeOpacityEnabled(cascadeOpacityEnabled);
1353         }
1354     },
1355 
1356     /**
1357      * Gets whether cascadeColor is enabled
1358      * @returns {Boolean}
1359      */
1360     isCascadeColorEnabled: function () {
1361         if (this._renderer.RGBAProtocol) {
1362             return this._renderer.isCascadeColorEnabled();
1363         }
1364         return false;
1365     },
1366 
1367     /**
1368      *  Sets cascade color enabled
1369      * @param {Boolean} cascadeColorEnabled
1370      */
1371     setCascadeColorEnabled: function (cascadeColorEnabled) {
1372         if (this._renderer.RGBAProtocol) {
1373             this._renderer.setCascadeColorEnabled(cascadeColorEnabled);
1374         }
1375     },
1376 
1377     /**
1378      * Sets blendFunc
1379      * @param {cc.BlendFunc} blendFunc
1380      */
1381     setBlendFunc: function (blendFunc) {
1382         if (this._renderer.setBlendFunc) {
1383             this._renderer.setBlendFunc(blendFunc);
1384         }
1385     },
1386 
1387     /**
1388      * Gets touch start position
1389      * @returns {cc.Point}
1390      */
1391     getTouchStartPos: function () {
1392         return this._touchStartPos;
1393     },
1394 
1395     /**
1396      * Gets touch move position
1397      * @returns {cc.Point}
1398      */
1399     getTouchMovePos: function () {
1400         return this._touchMovePos;
1401     },
1402 
1403     /**
1404      * Gets touch end position
1405      * @returns {cc.Point}
1406      */
1407     getTouchEndPos: function () {
1408         return this._touchEndPos;
1409     },
1410 
1411     /**
1412      * Sets widget tag
1413      * @param {Number} tag
1414      */
1415     setTag: function (tag) {
1416         this._widgetTag = tag;
1417     },
1418 
1419     /**
1420      * Gets widget tag
1421      * @returns {Number}
1422      */
1423     getTag: function () {
1424         return this._widgetTag;
1425     },
1426 
1427     /**
1428      * Sets the name of widget
1429      * @param {String} name
1430      */
1431     setName: function (name) {
1432         this._name = name;
1433     },
1434 
1435     /**
1436      * Gets the name of widget
1437      * @returns {string}
1438      */
1439     getName: function () {
1440         return this._name;
1441     },
1442 
1443     /**
1444      * get widget type
1445      * @returns {ccs.WidgetType}
1446      */
1447     getWidgetType: function () {
1448         return this._widgetType;
1449     },
1450 
1451     /**
1452      * Sets layout parameter
1453      * @param {ccs.UILayoutParameter} parameter
1454      */
1455     setLayoutParameter: function (parameter) {
1456         this._layoutParameterDictionary[parameter.getLayoutType()] = parameter;
1457     },
1458 
1459     /**
1460      * Gets layout parameter
1461      * @param {ccs.LayoutParameterType} type
1462      * @returns {ccs.UILayoutParameter}
1463      */
1464     getLayoutParameter: function (type) {
1465         return this._layoutParameterDictionary[type];
1466     },
1467 
1468     /**
1469      * Returns the "class name" of widget.
1470      * @returns {string}
1471      */
1472     getDescription: function () {
1473         return "Widget";
1474     },
1475 
1476     clone: function () {
1477         var clonedWidget = this.createCloneInstance();
1478         clonedWidget.copyProperties(this);
1479         clonedWidget.copyClonedWidgetChildren(this);
1480         return clonedWidget;
1481     },
1482 
1483     createCloneInstance: function () {
1484         return ccs.UIWidget.create();
1485     },
1486 
1487     copyClonedWidgetChildren: function (model) {
1488         var widgetChildren = model.getChildren();
1489         for (var i = 0; i < widgetChildren.length; i++) {
1490             var locChild = widgetChildren[i];
1491             this.addChild(locChild.clone());
1492         }
1493     },
1494 
1495     copySpecialProperties: function (model) {
1496 
1497     },
1498 
1499     copyProperties: function (widget) {
1500         this.setEnabled(widget.isEnabled());
1501         this.setVisible(widget.isVisible());
1502         this.setBright(widget.isBright());
1503         this.setTouchEnabled(widget.isTouchEnabled());
1504         this._touchPassedEnabled = false;
1505         this.setZOrder(widget.getZOrder());
1506         this.setUpdateEnabled(widget.isUpdateEnabled());
1507         this.setTag(widget.getTag());
1508         this.setName(widget.getName());
1509         this.setActionTag(widget.getActionTag());
1510         this._ignoreSize = widget._ignoreSize;
1511         this._size = widget._size;
1512         this._customSize = widget._customSize;
1513         this.copySpecialProperties(widget);
1514         this._sizeType = widget.getSizeType();
1515         this._sizePercent = widget._sizePercent;
1516         this._positionType = widget._positionType;
1517         this._positionPercent = widget._positionPercent;
1518         this.setPosition(widget.getPosition());
1519         this.setAnchorPoint(widget.getAnchorPoint());
1520         this.setScaleX(widget.getScaleX());
1521         this.setScaleY(widget.getScaleY());
1522         this.setRotation(widget.getRotation());
1523         this.setRotationX(widget.getRotationX());
1524         this.setRotationY(widget.getRotationY());
1525         this.setFlippedX(widget.isFlippedX());
1526         this.setFlippedY(widget.isFlippedY());
1527         this.setColor(widget.getColor());
1528         this.setOpacity(widget.getOpacity());
1529         this.setCascadeOpacityEnabled(widget.isCascadeOpacityEnabled());
1530         this.setCascadeColorEnabled(widget.isCascadeColorEnabled());
1531         this.onSizeChanged();
1532     },
1533     
1534     /*temp action*/
1535     setActionTag: function (tag) {
1536         this._actionTag = tag;
1537     },
1538 
1539     getActionTag: function () {
1540         return this._actionTag;
1541     },
1542     setTouchEnable: function (enabled, containChildren) {
1543         containChildren = containChildren || false;
1544         this.setTouchEnabled(enabled);
1545         if (containChildren) {
1546             var childrenArray = this.getChildren();
1547             var length = childrenArray.length;
1548             var child;
1549             for (var i = 0; i < length; ++i) {
1550                 child = childrenArray[i];
1551                 child.setTouchEnable(enabled, true);
1552             }
1553         }
1554     },
1555     disable: function (containChildren) {
1556         containChildren = containChildren || false;
1557         this.setBright(false, containChildren);
1558         this.setTouchEnable(false, containChildren);
1559     },
1560     active: function (containChildren) {
1561         containChildren = containChildren || false;
1562         this.setBright(true, containChildren);
1563         this.setTouchEnable(true, containChildren);
1564     },
1565     isActive: function () {
1566         return this.isBright();
1567     },
1568     setBright: function (bright, containChild) {
1569         this._bright = bright;
1570         if (this._bright) {
1571             this._brightStyle = ccs.BrightStyle.none;
1572             this.setBrightStyle(ccs.BrightStyle.normal);
1573         }
1574         else {
1575             this.onPressStateChangedToDisabled();
1576         }
1577 
1578         if (containChild) {
1579             var childrenArray = this.getChildren();
1580             var length = childrenArray.length;
1581             var child;
1582             for (var i = 0; i < length; ++i) {
1583                 child = childrenArray[i];
1584                 child.setBright(bright, containChild);
1585             }
1586         }
1587     },
1588 
1589     getRect: function () {
1590         var wPos = this.getWorldPosition();
1591         var width = this._size.width;
1592         var height = this._size.height;
1593         var offset_width = this._anchorPoint.x * width;
1594         var offset_height = this._anchorPoint.y * height;
1595         return cc.rect(wPos.x - offset_width, wPos.y - offset_height, width, height);
1596     },
1597     getValidNode: function () {
1598         return this.getVirtualRenderer();
1599     },
1600     setWidgetZOrder: function (z) {
1601         this.setZOrder(z);
1602     },
1603     getWidgetZOrder: function () {
1604         return this.getZOrder();
1605     },
1606     getRelativeLeftPos: function () {
1607         return this.getLeftInParent();
1608     },
1609     getRelativeBottomPos: function () {
1610         return this.getBottomInParent();
1611     },
1612     getRelativeRightPos: function () {
1613         return this.getRightInParent();
1614     },
1615     getRelativeTopPos: function () {
1616         return this.getTopInParent();
1617     },
1618     getContainerNode: function () {
1619         return this.getRenderer();
1620     },
1621     setWidgetParent: function (parent) {
1622         this.setParent(parent);
1623     },
1624     getWidgetParent: function () {
1625         return this.getParent();
1626     },
1627     setWidgetTag: function (tag) {
1628         this.setTag(tag);
1629     },
1630     getWidgetTag: function () {
1631         return this.getTag();
1632     },
1633     addCCNode: function (node) {
1634         this.addRenderer(node, 0);
1635     },
1636     removeCCNode: function (cleanup) {
1637         this.removeRenderer(cleanup);
1638     },
1639     setUserObject:function(userObject){
1640         this._userObject = userObject;
1641     },
1642     getUserObject:function(){
1643         return this._userObject;
1644     }
1645 });
1646 /**
1647  * allocates and initializes a UIWidget.
1648  * @constructs
1649  * @return {ccs.UIWidget}
1650  * @example
1651  * // example
1652  * var uiWidget = ccs.UIWidget.create();
1653  */
1654 ccs.UIWidget.create = function () {
1655     var widget = new ccs.UIWidget();
1656     if (widget && widget.init()) {
1657         return widget;
1658     }
1659     return null;
1660 };
1661 
1662 /**
1663  * Base class for ccs.GUIRenderer
1664  * @class
1665  * @extends ccs.NodeRGBA
1666  */
1667 ccs.GUIRenderer = ccs.NodeRGBA.extend({
1668     _enabled: true,
1669     setEnabled: function (enabled) {
1670         this._enabled = enabled;
1671     },
1672 
1673     isEnabled: function () {
1674         return this._enabled;
1675     },
1676 
1677     visit: function (ctx) {
1678         if (!this._enabled) {
1679             return;
1680         }
1681         cc.NodeRGBA.prototype.visit.call(this, ctx);
1682     }
1683 });
1684 /**
1685  * allocates and initializes a GUIRenderer.
1686  * @constructs
1687  * @return {ccs.GUIRenderer}
1688  * @example
1689  * // example
1690  * var guiRenderer = ccs.GUIRenderer.create();
1691  */
1692 ccs.GUIRenderer.create = function () {
1693     var widget = new ccs.GUIRenderer();
1694     if (widget && widget.init()) {
1695         return widget;
1696     }
1697     return null;
1698 };