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 text control of Cocos UI.
 28  * @class
 29  * @extends ccui.Widget
 30  *
 31  * @property {Number}   boundingWidth       - Width of the bounding area of label, the real content width is limited by boundingWidth
 32  * @property {Number}   boundingHeight      - Height of the bounding area of label, the real content height is limited by boundingHeight
 33  * @property {String}   string              - The content string of the label
 34  * @property {Number}   stringLength        - <@readonly> The content string length of the label
 35  * @property {String}   font                - The label font with a style string: e.g. "18px Verdana"
 36  * @property {String}   fontName            - The label font name
 37  * @property {Number}   fontSize            - The label font size
 38  * @property {Number}   textAlign           - Horizontal Alignment of label, cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT
 39  * @property {Number}   verticalAlign       - Vertical Alignment of label: cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM
 40  * @property {Boolean}  touchScaleEnabled   - Indicate whether the label will scale when touching
 41  */
 42 ccui.Text = ccui.Widget.extend(/** @lends ccui.Text# */{
 43     _touchScaleChangeEnabled: false,
 44     _normalScaleValueX: 1,
 45     _normalScaleValueY: 1,
 46     _fontName: "Arial",
 47     _fontSize: 16,
 48     _onSelectedScaleOffset:0.5,
 49     _labelRenderer: "",
 50     _textAreaSize: null,
 51     _textVerticalAlignment: 0,
 52     _textHorizontalAlignment: 0,
 53     _className: "Text",
 54     _type: null,
 55     _labelRendererAdaptDirty: true,
 56 
 57     /**
 58      * allocates and initializes a UILabel.
 59      * Constructor of ccui.Text. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
 60      * @param {String} textContent
 61      * @param {String} fontName
 62      * @param {Number} fontSize
 63      * @example
 64      * // example
 65      * var uiLabel = new ccui.Text();
 66      */
 67     ctor: function (textContent, fontName, fontSize) {
 68         this._type = ccui.Text.Type.SYSTEM;
 69         this._textAreaSize = cc.size(0, 0);
 70         ccui.Widget.prototype.ctor.call(this);
 71 
 72         if (fontSize !== undefined) {
 73             this.setFontName(fontName);
 74             this.setFontSize(fontSize);
 75             this.setString(textContent);
 76         } else {
 77             this.setFontName(this._fontName);
 78         }
 79     },
 80 
 81     _initRenderer: function () {
 82         this._labelRenderer = new cc.LabelTTF();
 83         this.addProtectedChild(this._labelRenderer, ccui.Text.RENDERER_ZORDER, -1);
 84     },
 85 
 86     /**
 87      * Changes the  value of ccui.Text.
 88      * @deprecated since v3.0, please use setString() instead.
 89      * @param {String} text
 90      */
 91     setText: function (text) {
 92         cc.log("Please use the setString");
 93         this.setString(text);
 94     },
 95 
 96     /**
 97      * Changes the  value of ccui.Text.
 98      * @param {String} text
 99      */
100     setString: function (text) {
101         if(text === this._labelRenderer.getString())
102             return;
103         this._labelRenderer.setString(text);
104         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
105         this._labelRendererAdaptDirty = true;
106     },
107 
108     /**
109      * Gets the string value of ccui.Text.
110      * @deprecated since v3.0, please use getString instead.
111      * @returns {String}
112      */
113     getStringValue: function () {
114         cc.log("Please use the getString");
115         return this._labelRenderer.getString();
116     },
117 
118     /**
119      * Gets the string value of ccui.Text.
120      * @returns {String}
121      */
122     getString: function () {
123         return this._labelRenderer.getString();
124     },
125 
126     /**
127      * Gets the string length of ccui.Text.
128      * @returns {Number}
129      */
130     getStringLength: function () {
131         return this._labelRenderer.getStringLength();
132     },
133 
134     /**
135      * Sets fontSize
136      * @param {Number} size
137      */
138     setFontSize: function (size) {
139         this._labelRenderer.setFontSize(size);
140         this._fontSize = size;
141         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
142         this._labelRendererAdaptDirty = true;
143     },
144 
145     /**
146      * Returns font Size of ccui.Text
147      * @returns {Number}
148      */
149     getFontSize: function () {
150         return this._fontSize;
151     },
152 
153     /**
154      * Sets font name
155      * @return {String} name
156      */
157     setFontName: function (name) {
158         this._fontName = name;
159         this._labelRenderer.setFontName(name);
160         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
161         this._labelRendererAdaptDirty = true;
162     },
163 
164     /**
165      * Returns font name of ccui.Text.
166      * @returns {string}
167      */
168     getFontName: function () {
169         return this._fontName;
170     },
171 
172     _setFont: function (font) {
173         var res = cc.LabelTTF._fontStyleRE.exec(font);
174         if (res) {
175             this._fontSize = parseInt(res[1]);
176             this._fontName = res[2];
177             this._labelRenderer._setFont(font);
178             this._labelScaleChangedWithSize();
179         }
180     },
181     _getFont: function () {
182         return this._labelRenderer._getFont();
183     },
184 
185     /**
186      * Returns the type of ccui.Text.
187      * @returns {null}
188      */
189     getType: function(){
190         return  this._type;
191     },
192 
193     /**
194      * Sets text Area Size
195      * @param {cc.Size} size
196      */
197     setTextAreaSize: function (size) {
198         this._labelRenderer.setDimensions(size);
199         if (!this._ignoreSize){
200             this._customSize = size;
201         }
202         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
203         this._labelRendererAdaptDirty = true;
204     },
205 
206     /**
207      * Returns renderer's dimension.
208      * @returns {cc.Size}
209      */
210     getTextAreaSize: function(){
211         return this._labelRenderer.getDimensions();
212     },
213 
214     /**
215      * Sets Horizontal Alignment of cc.LabelTTF
216      * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment Horizontal Alignment
217      */
218     setTextHorizontalAlignment: function (alignment) {
219         this._labelRenderer.setHorizontalAlignment(alignment);
220         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
221         this._labelRendererAdaptDirty = true;
222     },
223 
224     /**
225      * Returns Horizontal Alignment of label
226      * @returns {TEXT_ALIGNMENT_LEFT|TEXT_ALIGNMENT_CENTER|TEXT_ALIGNMENT_RIGHT}
227      */
228     getTextHorizontalAlignment: function () {
229         return this._labelRenderer.getHorizontalAlignment();
230     },
231 
232     /**
233      * Sets Vertical Alignment of label
234      * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} alignment
235      */
236     setTextVerticalAlignment: function (alignment) {
237         this._labelRenderer.setVerticalAlignment(alignment);
238         this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize());
239         this._labelRendererAdaptDirty = true;
240     },
241 
242     /**
243      * Gets text vertical alignment.
244      * @returns {VERTICAL_TEXT_ALIGNMENT_TOP|VERTICAL_TEXT_ALIGNMENT_CENTER|VERTICAL_TEXT_ALIGNMENT_BOTTOM}
245      */
246     getTextVerticalAlignment: function () {
247         return this._labelRenderer.getVerticalAlignment();
248     },
249 
250     /**
251      * Sets the touch scale enabled of label.
252      * @param {Boolean} enable
253      */
254     setTouchScaleChangeEnabled: function (enable) {
255         this._touchScaleChangeEnabled = enable;
256     },
257 
258     /**
259      * Gets the touch scale enabled of label.
260      * @returns {Boolean}
261      */
262     isTouchScaleChangeEnabled: function () {
263         return this._touchScaleChangeEnabled;
264     },
265 
266     _onPressStateChangedToNormal: function () {
267         if (!this._touchScaleChangeEnabled)
268             return;
269         this._labelRenderer.setScaleX(this._normalScaleValueX);
270         this._labelRenderer.setScaleY(this._normalScaleValueY);
271     },
272 
273     _onPressStateChangedToPressed: function () {
274         if (!this._touchScaleChangeEnabled)
275             return;
276         this._labelRenderer.setScaleX(this._normalScaleValueX + this._onSelectedScaleOffset);
277         this._labelRenderer.setScaleY(this._normalScaleValueY + this._onSelectedScaleOffset);
278     },
279 
280     _onPressStateChangedToDisabled: function () {
281     },
282 
283     _onSizeChanged: function () {
284         ccui.Widget.prototype._onSizeChanged.call(this);
285         this._labelRendererAdaptDirty = true;
286     },
287 
288     _adaptRenderers: function(){
289         if (this._labelRendererAdaptDirty) {
290             this._labelScaleChangedWithSize();
291             this._labelRendererAdaptDirty = false;
292         }
293     },
294 
295     /**
296      * Returns the renderer's content size.
297      * @override
298      * @returns {cc.Size}
299      */
300     getVirtualRendererSize: function(){
301         return this._labelRenderer.getContentSize();
302     },
303 
304     /**
305      * Returns the renderer of ccui.Text.
306      * @returns {cc.Node}
307      */
308     getVirtualRenderer: function () {
309         return this._labelRenderer;
310     },
311 
312     //@since v3.3
313     getAutoRenderSize: function(){
314         var virtualSize = this._labelRenderer.getContentSize();
315         if (!this._ignoreSize) {
316             this._labelRenderer.setDimensions(0, 0);
317             virtualSize = this._labelRenderer.getContentSize();
318             this._labelRenderer.setDimensions(this._contentSize.width, this._contentSize.height);
319         }
320         return virtualSize;
321     },
322 
323     _labelScaleChangedWithSize: function () {
324         var locContentSize = this._contentSize;
325         if (this._ignoreSize) {
326             this._labelRenderer.setDimensions(0,0);
327             this._labelRenderer.setScale(1.0);
328             this._normalScaleValueX = this._normalScaleValueY = 1;
329         } else {
330             this._labelRenderer.setDimensions(cc.size(locContentSize.width, locContentSize.height));
331             var textureSize = this._labelRenderer.getContentSize();
332             if (textureSize.width <= 0.0 || textureSize.height <= 0.0) {
333                 this._labelRenderer.setScale(1.0);
334                 return;
335             }
336             var scaleX = locContentSize.width / textureSize.width;
337             var scaleY = locContentSize.height / textureSize.height;
338             this._labelRenderer.setScaleX(scaleX);
339             this._labelRenderer.setScaleY(scaleY);
340             this._normalScaleValueX = scaleX;
341             this._normalScaleValueY = scaleY;
342         }
343         this._labelRenderer.setPosition(locContentSize.width / 2.0, locContentSize.height / 2.0);
344     },
345 
346     /**
347      * Returns the "class name" of ccui.Text.
348      * @returns {string}
349      */
350     getDescription: function () {
351         return "Label";
352     },
353 
354     /**
355      * Enables shadow style and sets color, offset and blur radius styles.
356      * @param {cc.Color} shadowColor
357      * @param {cc.Size} offset
358      * @param {Number} blurRadius
359      */
360     enableShadow: function(shadowColor, offset, blurRadius){
361         this._labelRenderer.enableShadow(shadowColor, offset, blurRadius);
362     },
363 
364     /**
365      * Enables outline style and sets outline's color and size.
366      * @param {cc.Color} outlineColor
367      * @param {cc.Size} outlineSize
368      */
369     enableOutline: function(outlineColor, outlineSize){
370         this._labelRenderer.enableStroke(outlineColor, outlineSize);
371     },
372 
373     /**
374      * Enables glow color
375      * @param glowColor
376      */
377     enableGlow: function(glowColor){
378         if (this._type === ccui.Text.Type.TTF)
379             this._labelRenderer.enableGlow(glowColor);
380     },
381 
382     /**
383      * Disables renderer's effect.
384      */
385     disableEffect: function(){
386         if(this._labelRenderer.disableEffect)
387             this._labelRenderer.disableEffect();
388     },
389 
390     _createCloneInstance: function () {
391         return new ccui.Text();
392     },
393 
394     _copySpecialProperties: function (uiLabel) {
395         if(uiLabel instanceof ccui.Text){
396             this.setFontName(uiLabel._fontName);
397             this.setFontSize(uiLabel.getFontSize());
398             this.setString(uiLabel.getString());
399             this.setTouchScaleChangeEnabled(uiLabel.touchScaleEnabled);
400             this.setTextAreaSize(uiLabel._textAreaSize);
401             this.setTextHorizontalAlignment(uiLabel._labelRenderer.getHorizontalAlignment());
402             this.setTextVerticalAlignment(uiLabel._labelRenderer.getVerticalAlignment());
403             this.setContentSize(uiLabel.getContentSize());
404             this.setTextColor(uiLabel.getTextColor());
405         }
406     },
407 
408     _setBoundingWidth: function (value) {
409         this._textAreaSize.width = value;
410         this._labelRenderer._setBoundingWidth(value);
411         this._labelScaleChangedWithSize();
412     },
413     _setBoundingHeight: function (value) {
414         this._textAreaSize.height = value;
415         this._labelRenderer._setBoundingHeight(value);
416         this._labelScaleChangedWithSize();
417     },
418     _getBoundingWidth: function () {
419         return this._textAreaSize.width;
420     },
421     _getBoundingHeight: function () {
422         return this._textAreaSize.height;
423     },
424 
425     _changePosition: function(){
426         this._adaptRenderers();
427     },
428 
429     setColor: function(color){
430         cc.ProtectedNode.prototype.setColor.call(this, color);
431         this._labelRenderer.setColor(color);
432     },
433 
434     setTextColor: function(color){
435         this._labelRenderer.setFontFillColor(color);
436     },
437 
438     getTextColor: function(){
439         return this._labelRenderer._getFillStyle();
440     }
441 });
442 
443 var _p = ccui.Text.prototype;
444 
445 // Extended properties
446 /** @expose */
447 _p.boundingWidth;
448 cc.defineGetterSetter(_p, "boundingWidth", _p._getBoundingWidth, _p._setBoundingWidth);
449 /** @expose */
450 _p.boundingHeight;
451 cc.defineGetterSetter(_p, "boundingHeight", _p._getBoundingHeight, _p._setBoundingHeight);
452 /** @expose */
453 _p.string;
454 cc.defineGetterSetter(_p, "string", _p.getString, _p.setString);
455 /** @expose */
456 _p.stringLength;
457 cc.defineGetterSetter(_p, "stringLength", _p.getStringLength);
458 /** @expose */
459 _p.font;
460 cc.defineGetterSetter(_p, "font", _p._getFont, _p._setFont);
461 /** @expose */
462 _p.fontSize;
463 cc.defineGetterSetter(_p, "fontSize", _p.getFontSize, _p.setFontSize);
464 /** @expose */
465 _p.fontName;
466 cc.defineGetterSetter(_p, "fontName", _p.getFontName, _p.setFontName);
467 /** @expose */
468 _p.textAlign;
469 cc.defineGetterSetter(_p, "textAlign", _p.getTextHorizontalAlignment, _p.setTextHorizontalAlignment);
470 /** @expose */
471 _p.verticalAlign;
472 cc.defineGetterSetter(_p, "verticalAlign", _p.getTextVerticalAlignment, _p.setTextVerticalAlignment);
473 
474 _p = null;
475 
476 /**
477  * allocates and initializes a UILabel.
478  * @deprecated since v3.0, please use new ccui.Text() instead.
479  * @return {ccui.Text}
480  */
481 ccui.Label = ccui.Text.create = function (textContent, fontName, fontSize) {
482     return new ccui.Text(textContent, fontName, fontSize);
483 };
484 
485 /**
486  * The zOrder value of ccui.Text's renderer.
487  * @constant
488  * @type {number}
489  */
490 ccui.Text.RENDERER_ZORDER = -1;
491 
492 /**
493  * @ignore
494  */
495 ccui.Text.Type = {
496     SYSTEM: 0,
497     TTF: 1
498 };