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