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  * The button controls of Cocos UI.
 28  * @class
 29  * @extends ccui.Widget
 30  *
 31  * @property {String}   titleText               - The content string of the button title
 32  * @property {String}   titleFont               - The content string font of the button title
 33  * @property {Number}   titleFontSize           - The content string font size of the button title
 34  * @property {String}   titleFontName           - The content string font name of the button title
 35  * @property {cc.Color} titleFontColor          - The content string font color of the button title
 36  * @property {Boolean}  pressedActionEnabled    - Indicate whether button has zoom effect when clicked
 37  */
 38 ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{
 39     _buttonNormalRenderer: null,
 40     _buttonClickedRenderer: null,
 41     _buttonDisableRenderer: null,
 42     _titleRenderer: null,
 43 
 44     _normalFileName: "",
 45     _clickedFileName: "",
 46     _disabledFileName: "",
 47 
 48     _prevIgnoreSize: true,
 49     _scale9Enabled: false,
 50 
 51     _capInsetsNormal: null,
 52     _capInsetsPressed: null,
 53     _capInsetsDisabled: null,
 54 
 55     _normalTexType: ccui.Widget.LOCAL_TEXTURE,
 56     _pressedTexType: ccui.Widget.LOCAL_TEXTURE,
 57     _disabledTexType: ccui.Widget.LOCAL_TEXTURE,
 58 
 59     _normalTextureSize: null,
 60     _pressedTextureSize: null,
 61     _disabledTextureSize: null,
 62 
 63     pressedActionEnabled: false,
 64     _titleColor: null,
 65     _normalTextureScaleXInSize: 1,
 66     _normalTextureScaleYInSize: 1,
 67     _pressedTextureScaleXInSize: 1,
 68     _pressedTextureScaleYInSize: 1,
 69 
 70     _zoomScale: 0.1,
 71 
 72     _normalTextureLoaded: false,
 73     _pressedTextureLoaded: false,
 74     _disabledTextureLoaded: false,
 75 
 76     _className: "Button",
 77     _normalTextureAdaptDirty: true,
 78     _pressedTextureAdaptDirty: true,
 79     _disabledTextureAdaptDirty: true,
 80 
 81     _fontName: "Thonburi",
 82     _fontSize: 12,
 83     _type: 0,
 84 
 85     /**
 86      * Allocates and initializes a UIButton.
 87      * Constructor of ccui.Button. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
 88      * @param {String} normalImage
 89      * @param {String} [selectedImage=""]
 90      * @param {String} [disableImage=""]
 91      * @param {Number} [texType=ccui.Widget.LOCAL_TEXTURE]
 92      * @example
 93      * // example
 94      * var uiButton = new ccui.Button();
 95      */
 96     ctor: function (normalImage, selectedImage, disableImage, texType) {
 97         this._capInsetsNormal = cc.rect(0, 0, 0, 0);
 98         this._capInsetsPressed = cc.rect(0, 0, 0, 0);
 99         this._capInsetsDisabled = cc.rect(0, 0, 0, 0);
100         this._normalTextureSize = cc.size(0, 0);
101         this._pressedTextureSize = cc.size(0, 0);
102         this._disabledTextureSize = cc.size(0, 0);
103         this._titleColor = cc.color.WHITE;
104         ccui.Widget.prototype.ctor.call(this);
105         this.setTouchEnabled(true);
106 
107         if (normalImage) {
108             this.loadTextures(normalImage, selectedImage,disableImage, texType);
109         }
110     },
111 
112     _initRenderer: function () {
113         //todo create Scale9Sprite
114         this._buttonNormalRenderer = new cc.Sprite();
115         this._buttonClickedRenderer = new cc.Sprite();
116         this._buttonDisableRenderer = new cc.Sprite();
117         this._titleRenderer = new cc.LabelTTF("");
118         this._titleRenderer.setAnchorPoint(0.5, 0.5);
119 
120         this.addProtectedChild(this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER, -1);
121         this.addProtectedChild(this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER, -1);
122         this.addProtectedChild(this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER, -1);
123         this.addProtectedChild(this._titleRenderer, ccui.Button.TITLE_RENDERER_ZORDER, -1);
124     },
125 
126     /**
127      * Sets if button is using scale9 renderer.
128      * @param {Boolean} able true that using scale9 renderer, false otherwise.
129      */
130     setScale9Enabled: function (able) {
131         //todo create Scale9Sprite
132         if (this._scale9Enabled === able)
133             return;
134 
135         this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE;
136         this._scale9Enabled = able;
137 
138         this.removeProtectedChild(this._buttonNormalRenderer);
139         this.removeProtectedChild(this._buttonClickedRenderer);
140         this.removeProtectedChild(this._buttonDisableRenderer);
141 
142         if (this._scale9Enabled) {
143             this._buttonNormalRenderer = new ccui.Scale9Sprite();
144             this._buttonClickedRenderer = new ccui.Scale9Sprite();
145             this._buttonDisableRenderer = new ccui.Scale9Sprite();
146         } else {
147             this._buttonNormalRenderer = new cc.Sprite();
148             this._buttonClickedRenderer = new cc.Sprite();
149             this._buttonDisableRenderer = new cc.Sprite();
150         }
151 
152         this._buttonClickedRenderer.setVisible(false);
153         this._buttonDisableRenderer.setVisible(false);
154 
155         this.loadTextureNormal(this._normalFileName, this._normalTexType);
156         this.loadTexturePressed(this._clickedFileName, this._pressedTexType);
157         this.loadTextureDisabled(this._disabledFileName, this._disabledTexType);
158 
159         this.addProtectedChild(this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER, -1);
160         this.addProtectedChild(this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER, -1);
161         this.addProtectedChild(this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER, -1);
162         if (this._scale9Enabled) {
163             var ignoreBefore = this._ignoreSize;
164             this.ignoreContentAdaptWithSize(false);
165             this._prevIgnoreSize = ignoreBefore;
166         } else {
167             this.ignoreContentAdaptWithSize(this._prevIgnoreSize);
168         }
169         this.setCapInsetsNormalRenderer(this._capInsetsNormal);
170         this.setCapInsetsPressedRenderer(this._capInsetsPressed);
171         this.setCapInsetsDisabledRenderer(this._capInsetsDisabled);
172         this.setBright(this._bright);
173 
174         this._normalTextureAdaptDirty = true;
175         this._pressedTextureAdaptDirty = true;
176         this._disabledTextureAdaptDirty = true;
177     },
178 
179     /**
180      *  Returns button is using scale9 renderer or not.
181      * @returns {Boolean}
182      */
183     isScale9Enabled: function () {
184         return this._scale9Enabled;
185     },
186 
187     /**
188      * Sets whether ignore the widget size
189      * @param {Boolean} ignore true that widget will ignore it's size, use texture size, false otherwise. Default value is true.
190      * @override
191      */
192     ignoreContentAdaptWithSize: function (ignore) {
193         if(this._unifySize){
194             this._updateContentSize();
195             return;
196         }
197         if (!this._scale9Enabled || (this._scale9Enabled && !ignore)) {
198             ccui.Widget.prototype.ignoreContentAdaptWithSize.call(this, ignore);
199             this._prevIgnoreSize = ignore;
200         }
201     },
202 
203     /**
204      * Returns the renderer size.
205      * @returns {cc.Size}
206      */
207     getVirtualRendererSize: function(){
208         if (this._unifySize)
209             return this._getNormalSize();
210 
211         if (!this._normalTextureLoaded && this._titleRenderer.getString().length > 0) {
212             return this._titleRenderer.getContentSize();
213         }
214         return cc.size(this._normalTextureSize);
215     },
216 
217     /**
218      * Load textures for button.
219      * @param {String} normal normal state of texture's filename.
220      * @param {String} selected  selected state of texture's filename.
221      * @param {String} disabled  disabled state of texture's filename.
222      * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType
223      */
224     loadTextures: function (normal, selected, disabled, texType) {
225         this.loadTextureNormal(normal, texType);
226         this.loadTexturePressed(selected, texType);
227         this.loadTextureDisabled(disabled, texType);
228     },
229 
230     /**
231      * Load normal state texture for button.
232      * @param {String} normal normal state of texture's filename.
233      * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType
234      */
235     loadTextureNormal: function (normal, texType) {
236         if (!normal)
237             return;
238         texType = texType || ccui.Widget.LOCAL_TEXTURE;
239         this._normalFileName = normal;
240         this._normalTexType = texType;
241 
242         var self = this;
243         var normalRenderer = this._buttonNormalRenderer;
244         if(!normalRenderer._textureLoaded){
245             normalRenderer.addEventListener("load", function(){
246                 self.loadTextureNormal(self._normalFileName, self._normalTexType);
247             });
248         }
249         switch (this._normalTexType){
250             case ccui.Widget.LOCAL_TEXTURE:
251                 //SetTexture cannot load resource
252                 normalRenderer.initWithFile(normal);
253                 break;
254             case ccui.Widget.PLIST_TEXTURE:
255                 //SetTexture cannot load resource
256                 normalRenderer.initWithSpriteFrameName(normal);
257                 break;
258             default:
259                 break;
260         }
261 
262         this._normalTextureLoaded = normalRenderer._textureLoaded;
263 
264         this._normalTextureSize = this._buttonNormalRenderer.getContentSize();
265         this._updateChildrenDisplayedRGBA();
266         if (this._unifySize){
267             if (this._scale9Enabled){
268                 normalRenderer.setCapInsets(this._capInsetsNormal);
269                 this._updateContentSizeWithTextureSize(this._getNormalSize());
270             }
271         }else
272             this._updateContentSizeWithTextureSize(this._normalTextureSize);
273 
274         this._normalTextureAdaptDirty = true;
275         this._findLayout();
276     },
277 
278     /**
279      * Load selected state texture for button.
280      * @param {String} selected selected state of texture's filename.
281      * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType
282      */
283     loadTexturePressed: function (selected, texType) {
284         if (!selected)
285             return;
286         texType = texType || ccui.Widget.LOCAL_TEXTURE;
287         this._clickedFileName = selected;
288         this._pressedTexType = texType;
289 
290         var self = this;
291         var clickedRenderer = this._buttonClickedRenderer;
292         if(!clickedRenderer._textureLoaded){
293             clickedRenderer.addEventListener("load", function(){
294                 self.loadTexturePressed(self._clickedFileName, self._pressedTexType);
295             });
296         }
297 
298         switch (this._pressedTexType) {
299             case ccui.Widget.LOCAL_TEXTURE:
300                 //SetTexture cannot load resource
301                 clickedRenderer.initWithFile(selected);
302                 break;
303             case ccui.Widget.PLIST_TEXTURE:
304                 //SetTexture cannot load resource
305                 clickedRenderer.initWithSpriteFrameName(selected);
306                 break;
307             default:
308                 break;
309         }
310 
311         if (this._scale9Enabled)
312             clickedRenderer.setCapInsets(this._capInsetsPressed);
313 
314         this._pressedTextureSize = this._buttonClickedRenderer.getContentSize();
315         this._updateChildrenDisplayedRGBA();
316 
317         this._pressedTextureLoaded = true;
318         this._pressedTextureAdaptDirty = true;
319         this._findLayout();
320     },
321 
322     /**
323      * Load dark state texture for button.
324      * @param {String} disabled disabled state of texture's filename.
325      * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType
326      */
327     loadTextureDisabled: function (disabled, texType) {
328         if (!disabled)
329             return;
330 
331         texType = texType || ccui.Widget.LOCAL_TEXTURE;
332         this._disabledFileName = disabled;
333         this._disabledTexType = texType;
334 
335         var self = this;
336         var disabledRenderer = this._buttonDisableRenderer;
337         if(!disabledRenderer._textureLoaded){
338             disabledRenderer.addEventListener("load", function() {
339                 self.loadTextureDisabled(self._disabledFileName, self._disabledTexType);
340             });
341         }
342 
343         switch (this._disabledTexType) {
344             case ccui.Widget.LOCAL_TEXTURE:
345                 //SetTexture cannot load resource
346                 disabledRenderer.initWithFile(disabled);
347                 break;
348             case ccui.Widget.PLIST_TEXTURE:
349                 //SetTexture cannot load resource
350                 disabledRenderer.initWithSpriteFrameName(disabled);
351                 break;
352             default:
353                 break;
354         }
355 
356         if (this._scale9Enabled)
357             disabledRenderer.setCapInsets(this._capInsetsDisabled);
358 
359         this._disabledTextureSize = this._buttonDisableRenderer.getContentSize();
360         this._updateChildrenDisplayedRGBA();
361 
362         this._disabledTextureLoaded = true;
363         this._disabledTextureAdaptDirty = true;
364         this._findLayout();
365     },
366 
367     /**
368      * Sets capinsets for button, if button is using scale9 renderer.
369      * @param {cc.Rect} capInsets
370      */
371     setCapInsets: function (capInsets) {
372         this.setCapInsetsNormalRenderer(capInsets);
373         this.setCapInsetsPressedRenderer(capInsets);
374         this.setCapInsetsDisabledRenderer(capInsets);
375     },
376 
377     /**
378      * Sets capinsets for button, if button is using scale9 renderer.
379      * @param {cc.Rect} capInsets
380      */
381     setCapInsetsNormalRenderer: function (capInsets) {
382         if(!capInsets)
383             return;
384 
385         var x = capInsets.x, y = capInsets.y;
386         var width = capInsets.width, height = capInsets.height;
387         if (this._normalTextureSize.width < width){
388             x = 0;
389             width = 0;
390         }
391         if (this._normalTextureSize.height < height){
392             y = 0;
393             height = 0;
394         }
395 
396         var locInsets = this._capInsetsNormal;
397         locInsets.x = x;
398         locInsets.y = y;
399         locInsets.width = width;
400         locInsets.height = height;
401 
402         if (!this._scale9Enabled)
403             return;
404         this._buttonNormalRenderer.setCapInsets(locInsets);
405     },
406 
407     /**
408      *  Returns normal renderer cap insets.
409      * @returns {cc.Rect}
410      */
411     getCapInsetsNormalRenderer:function(){
412         return cc.rect(this._capInsetsNormal);
413     },
414 
415     /**
416      * Sets capinsets for button, if button is using scale9 renderer.
417      * @param {cc.Rect} capInsets
418      */
419     setCapInsetsPressedRenderer: function (capInsets) {
420         if(!capInsets || !this._scale9Enabled)
421             return;
422 
423         var x = capInsets.x, y = capInsets.y;
424         var width = capInsets.width, height = capInsets.height;
425 
426         if (this._pressedTextureSize.width < width) {
427             x = 0;
428             width = 0;
429         }
430         if (this._pressedTextureSize.height < height) {
431             y = 0;
432             height = 0;
433         }
434 
435         var locInsets = this._capInsetsPressed;
436         locInsets.x = x;
437         locInsets.y = y;
438         locInsets.width = width;
439         locInsets.height = height;
440 
441         this._buttonClickedRenderer.setCapInsets(locInsets);
442     },
443 
444     /**
445      *  Returns pressed renderer cap insets.
446      * @returns {cc.Rect}
447      */
448     getCapInsetsPressedRenderer: function () {
449         return cc.rect(this._capInsetsPressed);
450     },
451 
452     /**
453      * Sets capinsets for button, if button is using scale9 renderer.
454      * @param {cc.Rect} capInsets
455      */
456     setCapInsetsDisabledRenderer: function (capInsets) {
457         if(!capInsets || !this._scale9Enabled)
458             return;
459 
460         var x = capInsets.x, y = capInsets.y;
461         var width = capInsets.width, height = capInsets.height;
462 
463         if (this._disabledTextureSize.width < width) {
464             x = 0;
465             width = 0;
466         }
467         if (this._disabledTextureSize.height < height) {
468             y = 0;
469             height = 0;
470         }
471 
472         var locInsets = this._capInsetsDisabled;
473         locInsets.x = x;
474         locInsets.y = y;
475         locInsets.width = width;
476         locInsets.height = height;
477 
478         this._buttonDisableRenderer.setCapInsets(locInsets);
479     },
480 
481     /**
482      * Returns disable renderer cap insets.
483      * @returns {cc.Rect}
484      */
485     getCapInsetsDisabledRenderer: function () {
486         return cc.rect(this._capInsetsDisabled);
487     },
488 
489     _onPressStateChangedToNormal: function () {
490         this._buttonNormalRenderer.setVisible(true);
491         this._buttonClickedRenderer.setVisible(false);
492         this._buttonDisableRenderer.setVisible(false);
493         if (this._scale9Enabled)
494             this._buttonNormalRenderer.setState( ccui.Scale9Sprite.state.NORMAL);
495         if (this._pressedTextureLoaded) {
496             if (this.pressedActionEnabled){
497                 this._buttonNormalRenderer.stopAllActions();
498                 this._buttonClickedRenderer.stopAllActions();
499                 //var zoomAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, this._normalTextureScaleXInSize, this._normalTextureScaleYInSize);
500                 //fixme: the zoomAction will run in the next frame which will cause the _buttonNormalRenderer to a wrong scale
501                 //this._buttonNormalRenderer.runAction(zoomAction);
502                 this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize);
503                 this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize);
504 
505                 this._titleRenderer.stopAllActions();
506                 if (this._unifySize){
507                     var zoomTitleAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, 1, 1);
508                     this._titleRenderer.runAction(zoomTitleAction);
509                 }else{
510                     this._titleRenderer.setScaleX(1);
511                     this._titleRenderer.setScaleY(1);
512                 }
513             }
514         } else {
515             this._buttonNormalRenderer.stopAllActions();
516             this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize);
517 
518             this._titleRenderer.stopAllActions();
519             if (this._scale9Enabled)
520                 this._buttonNormalRenderer.setColor(cc.color.WHITE);
521 
522             this._titleRenderer.setScaleX(1);
523             this._titleRenderer.setScaleY(1);
524         }
525     },
526 
527     _onPressStateChangedToPressed: function () {
528         var locNormalRenderer = this._buttonNormalRenderer;
529         if (this._scale9Enabled)
530             locNormalRenderer.setState(ccui.Scale9Sprite.state.NORMAL);
531 
532         if (this._pressedTextureLoaded) {
533             locNormalRenderer.setVisible(false);
534             this._buttonClickedRenderer.setVisible(true);
535             this._buttonDisableRenderer.setVisible(false);
536             if (this.pressedActionEnabled) {
537                 locNormalRenderer.stopAllActions();
538                 this._buttonClickedRenderer.stopAllActions();
539                 var zoomAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, this._pressedTextureScaleXInSize + this._zoomScale,
540                         this._pressedTextureScaleYInSize + this._zoomScale);
541                 this._buttonClickedRenderer.runAction(zoomAction);
542                 locNormalRenderer.setScale(this._pressedTextureScaleXInSize + this._zoomScale, this._pressedTextureScaleYInSize + this._zoomScale);
543 
544                 this._titleRenderer.stopAllActions();
545                 this._titleRenderer.runAction(cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, 1 + this._zoomScale, 1 + this._zoomScale));
546             }
547         } else {
548             locNormalRenderer.setVisible(true);
549             this._buttonClickedRenderer.setVisible(true);
550             this._buttonDisableRenderer.setVisible(false);
551             locNormalRenderer.stopAllActions();
552             locNormalRenderer.setScale(this._normalTextureScaleXInSize + this._zoomScale, this._normalTextureScaleYInSize + this._zoomScale);
553 
554             this._titleRenderer.stopAllActions();
555             this._titleRenderer.setScaleX(1 + this._zoomScale);
556             this._titleRenderer.setScaleY(1 + this._zoomScale);
557         }
558     },
559 
560     _onPressStateChangedToDisabled: function () {
561         //if disable resource is null
562         if (!this._disabledTextureLoaded){
563             if (this._normalTextureLoaded && this._scale9Enabled)
564                 this._buttonNormalRenderer.setState(ccui.Scale9Sprite.state.GRAY);
565         }else{
566             this._buttonNormalRenderer.setVisible(false);
567             this._buttonDisableRenderer.setVisible(true);
568         }
569 
570         this._buttonClickedRenderer.setVisible(false);
571         this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize);
572         this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize);
573     },
574 
575     _updateContentSize: function(){
576         if (this._unifySize){
577             if (this._scale9Enabled)
578                 ccui.ProtectedNode.setContentSize(this._customSize);
579             else{
580                 var s = this._getNormalSize();
581                 ccui.ProtectedNode.setContentSize(s);
582             }
583             this._onSizeChanged();
584             return;
585         }
586 
587         if (this._ignoreSize)
588             this.setContentSize(this.getVirtualRendererSize());
589     },
590 
591     _onSizeChanged: function () {
592         ccui.Widget.prototype._onSizeChanged.call(this);
593         this._updateTitleLocation();
594         this._normalTextureAdaptDirty = true;
595         this._pressedTextureAdaptDirty = true;
596         this._disabledTextureAdaptDirty = true;
597     },
598 
599     /**
600      * Gets the Virtual Renderer of widget.
601      * @returns {cc.Node}
602      */
603     getVirtualRenderer: function () {
604         if (this._bright) {
605             switch (this._brightStyle) {
606                 case ccui.Widget.BRIGHT_STYLE_NORMAL:
607                     return this._buttonNormalRenderer;
608                 case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT:
609                     return this._buttonClickedRenderer;
610                 default:
611                     return null;
612             }
613         } else
614             return this._buttonDisableRenderer;
615     },
616 
617     _normalTextureScaleChangedWithSize: function () {
618         if(this._ignoreSize && !this._unifySize){
619             if(!this._scale9Enabled){
620                 this._buttonNormalRenderer.setScale(1);
621                 this._normalTextureScaleXInSize = this._normalTextureScaleYInSize = 1;
622             }
623         }else{
624             if (this._scale9Enabled){
625                 this._buttonNormalRenderer.setPreferredSize(this._contentSize);
626                 this._normalTextureScaleXInSize = this._normalTextureScaleYInSize = 1;
627                 this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize);
628             }else{
629                 var textureSize = this._normalTextureSize;
630                 if (textureSize.width <= 0 || textureSize.height <= 0)
631                 {
632                     this._buttonNormalRenderer.setScale(1);
633                     return;
634                 }
635                 var scaleX = this._contentSize.width / textureSize.width;
636                 var scaleY = this._contentSize.height / textureSize.height;
637                 this._buttonNormalRenderer.setScaleX(scaleX);
638                 this._buttonNormalRenderer.setScaleY(scaleY);
639                 this._normalTextureScaleXInSize = scaleX;
640                 this._normalTextureScaleYInSize = scaleY;
641             }
642         }
643         this._buttonNormalRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2);
644     },
645 
646     _pressedTextureScaleChangedWithSize: function () {
647         if (this._ignoreSize && !this._unifySize) {
648             if (!this._scale9Enabled) {
649                 this._buttonClickedRenderer.setScale(1);
650                 this._pressedTextureScaleXInSize = this._pressedTextureScaleYInSize = 1;
651             }
652         } else {
653             if (this._scale9Enabled) {
654                 this._buttonClickedRenderer.setPreferredSize(this._contentSize);
655                 this._pressedTextureScaleXInSize = this._pressedTextureScaleYInSize = 1;
656                 this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize);
657             } else {
658                 var textureSize = this._pressedTextureSize;
659                 if (textureSize.width <= 0 || textureSize.height <= 0) {
660                     this._buttonClickedRenderer.setScale(1);
661                     return;
662                 }
663                 var scaleX = this._contentSize.width / textureSize.width;
664                 var scaleY = this._contentSize.height / textureSize.height;
665                 this._buttonClickedRenderer.setScaleX(scaleX);
666                 this._buttonClickedRenderer.setScaleY(scaleY);
667                 this._pressedTextureScaleXInSize = scaleX;
668                 this._pressedTextureScaleYInSize = scaleY;
669             }
670         }
671         this._buttonClickedRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2);
672     },
673 
674     _disabledTextureScaleChangedWithSize: function () {
675         if(this._ignoreSize && !this._unifySize){
676             if (this._scale9Enabled)
677                 this._buttonDisableRenderer.setScale(1);
678         }else {
679             if (this._scale9Enabled){
680                 this._buttonDisableRenderer.setScale(1);
681                 this._buttonDisableRenderer.setPreferredSize(this._contentSize);
682             }else{
683                 var textureSize = this._disabledTextureSize;
684                 if (textureSize.width <= 0 || textureSize.height <= 0) {
685                     this._buttonDisableRenderer.setScale(1);
686                     return;
687                 }
688                 var scaleX = this._contentSize.width / textureSize.width;
689                 var scaleY = this._contentSize.height / textureSize.height;
690                 this._buttonDisableRenderer.setScaleX(scaleX);
691                 this._buttonDisableRenderer.setScaleY(scaleY);
692             }
693         }
694         this._buttonDisableRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2);
695     },
696 
697     _adaptRenderers: function(){
698         if (this._normalTextureAdaptDirty) {
699             this._normalTextureScaleChangedWithSize();
700             this._normalTextureAdaptDirty = false;
701         }
702         if (this._pressedTextureAdaptDirty) {
703             this._pressedTextureScaleChangedWithSize();
704             this._pressedTextureAdaptDirty = false;
705         }
706         if (this._disabledTextureAdaptDirty) {
707             this._disabledTextureScaleChangedWithSize();
708             this._disabledTextureAdaptDirty = false;
709         }
710     },
711 
712     _updateTitleLocation: function(){
713         this._titleRenderer.setPosition(this._contentSize.width * 0.5, this._contentSize.height * 0.5);
714     },
715 
716     /**
717      * Changes if button can be clicked zoom effect.
718      * @param {Boolean} enabled
719      */
720     setPressedActionEnabled: function (enabled) {
721         this.pressedActionEnabled = enabled;
722     },
723 
724     /**
725      * Sets title text to ccui.Button
726      * @param {String} text
727      */
728     setTitleText: function (text) {
729         if(text === this.getTitleText())
730             return;
731         this._titleRenderer.setString(text);
732         if (this._ignoreSize){
733             var s = this.getVirtualRendererSize();
734             this.setContentSize(s);
735         }else{
736             this._titleRenderer._renderCmd._updateTTF();
737         }
738     },
739 
740     /**
741      * Returns title text of ccui.Button
742      * @returns {String} text
743      */
744     getTitleText: function () {
745         return this._titleRenderer.getString();
746     },
747 
748     /**
749      * Sets title color to ccui.Button.
750      * @param {cc.Color} color
751      */
752     setTitleColor: function (color) {
753         this._titleRenderer.setFontFillColor(color);
754     },
755 
756     /**
757      * Returns title color of ccui.Button
758      * @returns {cc.Color}
759      */
760     getTitleColor: function () {
761         return this._titleRenderer._getFillStyle();
762     },
763 
764     /**
765      * Sets title fontSize to ccui.Button
766      * @param {cc.Size} size
767      */
768     setTitleFontSize: function (size) {
769         this._titleRenderer.setFontSize(size);
770         this._fontSize = size;
771     },
772 
773     /**
774      * Returns title fontSize of ccui.Button.
775      * @returns {Number}
776      */
777     getTitleFontSize: function () {
778         return this._titleRenderer.getFontSize();
779     },
780 
781     /**
782      * When user pressed the button, the button will zoom to a scale.
783      * The final scale of the button  equals (button original scale + _zoomScale)
784      * @since v3.2
785      * @param scale
786      */
787     setZoomScale: function(scale){
788         this._zoomScale = scale;
789     },
790 
791     /**
792      * Returns a zoom scale
793      * @since v3.2
794      * @returns {number}
795      */
796     getZoomScale: function(){
797         return this._zoomScale;
798     },
799 
800     /**
801      * Returns the normalize of texture size
802      * @since v3.3
803      * @returns {cc.Size}
804      */
805     getNormalTextureSize: function(){
806         return this._normalTextureSize;
807     },
808 
809     /**
810      * Sets title fontName to ccui.Button.
811      * @param {String} fontName
812      */
813     setTitleFontName: function (fontName) {
814         this._titleRenderer.setFontName(fontName);
815         this._fontName = fontName;
816     },
817 
818     /**
819      * Get the title renderer.
820      * title ttf object.
821      * @returns {cc.LabelTTF}
822      */
823     getTitleRenderer: function(){
824         return this._titleRenderer;
825     },
826 
827     /**
828      * Gets title fontName of ccui.Button.
829      * @returns {String}
830      */
831     getTitleFontName: function () {
832         return this._titleRenderer.getFontName();
833     },
834 
835     _setTitleFont: function (font) {
836         this._titleRenderer.font = font;
837     },
838     _getTitleFont: function () {
839         return this._titleRenderer.font;
840     },
841 
842     /**
843      * Returns the "class name" of widget.
844      * @override
845      * @returns {string}
846      */
847     getDescription: function () {
848         return "Button";
849     },
850 
851     _createCloneInstance: function () {
852         return new ccui.Button();
853     },
854 
855     _copySpecialProperties: function (uiButton) {
856         this._prevIgnoreSize = uiButton._prevIgnoreSize;
857         this.setScale9Enabled(uiButton._scale9Enabled);
858         this.loadTextureNormal(uiButton._normalFileName, uiButton._normalTexType);
859         this.loadTexturePressed(uiButton._clickedFileName, uiButton._pressedTexType);
860         this.loadTextureDisabled(uiButton._disabledFileName, uiButton._disabledTexType);
861         this.setCapInsetsNormalRenderer(uiButton._capInsetsNormal);
862         this.setCapInsetsPressedRenderer(uiButton._capInsetsPressed);
863         this.setCapInsetsDisabledRenderer(uiButton._capInsetsDisabled);
864         this.setTitleText(uiButton.getTitleText());
865         this.setTitleFontName(uiButton.getTitleFontName());
866         this.setTitleFontSize(uiButton.getTitleFontSize());
867         this.setTitleColor(uiButton.getTitleColor());
868         this.setPressedActionEnabled(uiButton.pressedActionEnabled);
869         this.setZoomScale(uiButton._zoomScale);
870     },
871 
872     _getNormalSize: function(){
873         var titleSize;
874         if (this._titleRenderer !== null)
875             titleSize = this._titleRenderer.getContentSize();
876 
877         var imageSize;
878         if (this._buttonNormalRenderer !== null)
879             imageSize = this._buttonNormalRenderer.getContentSize();
880         var width = titleSize.width > imageSize.width ? titleSize.width : imageSize.width;
881         var height = titleSize.height > imageSize.height ? titleSize.height : imageSize.height;
882 
883         return cc.size(width,height);
884     }
885 });
886 
887 var _p = ccui.Button.prototype;
888 
889 // Extended properties
890 /** @expose */
891 _p.titleText;
892 cc.defineGetterSetter(_p, "titleText", _p.getTitleText, _p.setTitleText);
893 /** @expose */
894 _p.titleFont;
895 cc.defineGetterSetter(_p, "titleFont", _p._getTitleFont, _p._setTitleFont);
896 /** @expose */
897 _p.titleFontSize;
898 cc.defineGetterSetter(_p, "titleFontSize", _p.getTitleFontSize, _p.setTitleFontSize);
899 /** @expose */
900 _p.titleFontName;
901 cc.defineGetterSetter(_p, "titleFontName", _p.getTitleFontName, _p.setTitleFontName);
902 /** @expose */
903 _p.titleColor;
904 cc.defineGetterSetter(_p, "titleColor", _p.getTitleColor, _p.setTitleColor);
905 
906 _p = null;
907 
908 /**
909  * allocates and initializes a UIButton.
910  * @deprecated since v3.0, please use new ccui.Button() instead.
911  * @param {string} [normalImage]    normal state texture name
912  * @param {string} [selectedImage]  selected state texture name
913  * @param {string} [disableImage]   disabled state texture name
914  * @param {string} [texType]
915  * @return {ccui.Button}
916  */
917 ccui.Button.create = function (normalImage, selectedImage, disableImage, texType) {
918     return new ccui.Button(normalImage, selectedImage, disableImage, texType);
919 };
920 
921 // Constants
922 /**
923  * The normal renderer's zOrder value of ccui.Button.
924  * @constant
925  * @type {number}
926  */
927 ccui.Button.NORMAL_RENDERER_ZORDER = -2;
928 /**
929  * The pressed renderer's zOrder value ccui.Button.
930  * @constant
931  * @type {number}
932  */
933 ccui.Button.PRESSED_RENDERER_ZORDER = -2;
934 /**
935  * The disabled renderer's zOrder value of ccui.Button.
936  * @constant
937  * @type {number}
938  */
939 ccui.Button.DISABLED_RENDERER_ZORDER = -2;
940 /**
941  * The title renderer's zOrder value of ccui.Button.
942  * @constant
943  * @type {number}
944  */
945 ccui.Button.TITLE_RENDERER_ZORDER = -1;
946 
947 /**
948  * the zoom action time step of ccui.Button
949  * @constant
950  * @type {number}
951  */
952 ccui.Button.ZOOM_ACTION_TIME_STEP = 0.05;
953 
954 /**
955  * @ignore
956  */
957 ccui.Button.SYSTEM = 0;
958 ccui.Button.TTF = 1;
959