1 goog.provide('lime.Label');
  2 goog.provide('lime.Renderer.CANVAS.LABEL');
  3 goog.provide('lime.Renderer.DOM.LABEL');
  4 
  5 
  6 goog.require('lime.Renderer.CANVAS.SPRITE');
  7 goog.require('lime.Renderer.DOM.SPRITE');
  8 goog.require('lime.Sprite');
  9 
 10 /**
 11  * Display object for text
 12  * @param {string} txt Text contents of the label.
 13  * @constructor
 14  * @extends lime.Sprite
 15  */
 16 lime.Label = function(txt) {
 17     lime.Sprite.call(this);
 18 
 19     this.setText(txt);
 20 
 21     this.setFontFamily(lime.Label.defaultFont);
 22     this.setFontSize(14);
 23     this.setFontColor('#000');
 24     this.setAlign('center');
 25     this.setFontWeight('400');
 26 
 27     this.setPadding(0);
 28 
 29     this.setLineHeight(1.15);
 30 
 31     this.setFill(255, 255, 255, 0);
 32 
 33 };
 34 goog.inherits(lime.Label, lime.Sprite);
 35 
 36 /**
 37  * Common name for label objects
 38  * @type {string}
 39  */
 40 lime.Label.prototype.id = 'label';
 41 
 42 /**
 43  * Default Font name for labels
 44  * @type {string}
 45  */
 46 lime.Label.defaultFont = 'Arial';
 47 
 48 /** @inheritDoc */
 49 lime.Label.prototype.supportedRenderers = [
 50     lime.Renderer.DOM.SPRITE.makeSubRenderer(lime.Renderer.DOM.LABEL),
 51     lime.Renderer.CANVAS.SPRITE.makeSubRenderer(lime.Renderer.CANVAS.LABEL)
 52 ];
 53 
 54 (function() {
 55 
 56 var mContext;
 57 
 58 /**
 59  * Measure text contents of the label
 60  * @return {goog.math.Size} size of the text.
 61  */
 62 lime.Label.prototype.measureText = function() {
 63     if (!goog.isDef(mContext)) {
 64         var cvs = document.createElement('canvas');
 65         mContext = cvs.getContext('2d');
 66     }
 67 
 68     var lh = this.getLineHeight();
 69     mContext.font = this.getFontSize() + 'px ' + this.getFontFamily();
 70     var metrics = mContext.measureText(this.text_);
 71     var w = goog.userAgent.WEBKIT ? metrics.width : metrics.width + 1;
 72     var stroke = this.stroke_?this.stroke_.width_:0;
 73     return new goog.math.Size(
 74         this.padding_[1] + this.padding_[3] + w + stroke*2,
 75         this.padding_[0] + this.padding_[2] + lh * this.getFontSize() + stroke*2
 76     );
 77 }
 78 })();
 79 
 80 /** @inheritDoc */
 81 lime.Label.prototype.getSize = function() {
 82     var size = lime.Node.prototype.getSize.call(this);
 83     if (!size || (!size.width && !size.height)) {
 84         return this.measureText();
 85     }
 86     return size;
 87 };
 88 
 89 /**
 90  * Returns label text as stirng
 91  * @return {string} Text contents.
 92  */
 93 lime.Label.prototype.getText = function() {
 94     return this.text_;
 95 };
 96 
 97 /**
 98  * Set label text
 99  * @param {string} txt New text contents.
100  * @return {lime.Label} object itself.
101  */
102 lime.Label.prototype.setText = function(txt) {
103     this.text_ = txt + '';
104     this.setDirty(lime.Dirty.CONTENT);
105     delete this.words_;
106     return this;
107 };
108 
109 /**
110  * Returns font used to draw the label
111  * @return {string} Font name string.
112  */
113 lime.Label.prototype.getFontFamily = function() {
114     return this.fontFamily_;
115 };
116 
117 /**
118  * Set font weight
119  * @param {string} value New font weight value.
120  * @return {lime.Label} object itself.
121  */
122 lime.Label.prototype.setFontWeight = function(value) {
123     this.fontWeight_ = value;
124     this.setDirty(lime.Dirty.FONT);
125     return this;
126 };
127 
128 /**
129  * Returns font used to draw the label
130  * @return {string} Font name string.
131  */
132 lime.Label.prototype.getFontWeight = function() {
133     return this.fontWeight_;
134 };
135 
136 /**
137  * Set font name
138  * @param {string} value New font family string.
139  * @return {lime.Label} object itself.
140  */
141 lime.Label.prototype.setFontFamily = function(value) {
142     this.fontFamily_ = value;
143     this.setDirty(lime.Dirty.FONT);
144     return this;
145 };
146 
147 /**
148  * Returns font size in pixels
149  * @return {number} Font size in px.
150  */
151 lime.Label.prototype.getFontSize = function() {
152     return this.fontSize_;
153 };
154 
155 /**
156  * Set the font size in pixels
157  * @param {number} value New font size in px.
158  * @return {lime.Label} object itself.
159  */
160 lime.Label.prototype.setFontSize = function(value) {
161     this.fontSize_ = value;
162     this.setDirty(lime.Dirty.FONT);
163     return this;
164 };
165 
166 /**
167  * Returns font color as string
168  * @return {string} Font color.
169  */
170 lime.Label.prototype.getFontColor = function() {
171     return this.fontColor_;
172 };
173 
174 /**
175  * Sets the font color. Accepts #hex, rgb(), rgba() or plain color name.
176  * @param {string} value New color.
177  * @return {lime.Label} object itself.
178  */
179 lime.Label.prototype.setFontColor = function(value) {
180     this.fontColor_ = value;
181     this.setDirty(lime.Dirty.FONT);
182     return this;
183 };
184 
185 /**
186  * Return padding box around the text contents
187  * @return {goog.math.Box} padding box.
188  */
189 lime.Label.prototype.getPadding = function() {
190     return this.padding_;
191 };
192 
193 /**
194  * Set new padding box around text contents.
195  * @param {number} top Top padding.
196  * @param {number=} opt_right Right padding.
197  * @param {number=} opt_bottom Bottom padding.
198  * @param {number=} opt_left Left padding.
199  * @return {lime.Label} object itself.
200  */
201 lime.Label.prototype.setPadding = function(top, opt_right,
202         opt_bottom, opt_left) {
203 
204     var val = [top, top, top, top];
205     if (goog.isDef(opt_right)) {
206         val[1] = val[3] = opt_right;
207     }
208     if (goog.isDef(opt_bottom)) {
209         val[2] = opt_bottom;
210     }
211     if (goog.isDef(opt_left)) {
212         val[3] = opt_left;
213     }
214     this.padding_ = val;
215 
216     this.setDirty(lime.Dirty.FONT);
217     return this;
218 };
219 
220 /**
221  * Sets the line height used in multiline strings. Can be in pixels
222  * or factor from font size.
223  * @param {number} value Line height.
224  * @param {boolean=} opt_absolute If height is in pixels.
225  */
226 lime.Label.prototype.setLineHeight = function(value, opt_absolute) {
227     this.lineHeightAbsolute_ = opt_absolute || false;
228     this.lineHeight_ = value;
229 };
230 
231 /**
232  * Return line height as a factor from font size
233  * @return {number} Line height.
234  */
235 lime.Label.prototype.getLineHeight = function() {
236     return this.lineHeightAbsolute_ ?
237         this.lineHeight_ / this.getFontSize() : this.lineHeight_;
238 };
239 
240 /**
241  * Returns alignment value
242  * @return {string} Alignement.
243  */
244 lime.Label.prototype.getAlign = function() {
245     return this.align_;
246 };
247 
248 /**
249  * Sets label alignment. Accepts normal strings as left,center,right
250  * @param {string} value New alignment value.
251  * @return {lime.Label} object itself.
252  */
253 lime.Label.prototype.setAlign = function(value) {
254     this.align_ = value;
255     this.setDirty(lime.Dirty.FONT);
256     return this;
257 };
258 
259 /**
260  * Break text into array of line breakable words
261  * @return {Array.<string>} array of words.
262  */
263 lime.Label.prototype.calcWordsArray = function() {
264   var words = [];
265   var len = this.text_.length;
266   var regexp = goog.userAgent.GECKO ? /[\s\.]+/g : /[\s-\.]+/g;
267   var breaks = this.text_.match(regexp);
268   var st = 0;
269   if (breaks)
270   for (var i = 0; i < breaks.length; i++) {
271       var b = breaks[i];
272       var ibreak = this.text_.indexOf(b, st);
273       var wlen = ibreak + b.length;
274       words.push(this.text_.substring(st, wlen));
275       st = wlen;
276   }
277   if (st != len) {
278       words.push(this.text_.substring(st, len));
279   }
280   return words;
281 };
282 
283 /**
284  * Wrap text on words array to lines based on current
285  * font size and given maximum width.
286  * @param {Object} context Canvas2DContext used to measure.
287  * @param {number} width Maximum line width.
288  * @return {Array.<string>} Lines of text.
289  */
290 lime.Label.prototype.wrapText = function(context, width) {
291     var lines = [], line = '', words = this.words_, metrics;
292     for (var i = 0; i < words.length; i++) {
293         if (line == '') {
294             line = words[i];
295         }
296         else {
297             metrics = context.measureText(goog.string.trim(line + words[i]));
298             if (metrics.width > width) {
299                 lines.push(goog.string.trim(line));
300                 line = words[i];
301             }
302             else {
303                 line += words[i];
304             }
305         }
306     }
307     lines.push(line);
308     return lines;
309 };
310 
311 /** @inheritDoc */
312 lime.Label.prototype.update = function(){
313     
314     if(this.getDirty() & lime.Dirty.CONTENT)
315         delete this.lastDrawnWidth_;
316     
317     lime.Node.prototype.update.apply(this,arguments);
318 }
319 
320 
321 /**
322  * @inheritDoc
323  * @this {lime.Label}
324  */
325 lime.Renderer.DOM.LABEL.draw = function(el) {
326     lime.Renderer.DOM.SPRITE.draw.call(this, el);
327 
328     var style = el.style;
329     if (this.dirty_ & lime.Dirty.CONTENT) {
330         goog.dom.setTextContent(el, this.text_);
331     }
332     if (this.dirty_ & lime.Dirty.FONT) {
333         style['lineHeight'] = this.getLineHeight();
334         style['padding'] = goog.array.map(this.padding_,function(p){return p*this.getRelativeQuality()},this).join('px ') + 'px';
335         style['color'] = this.getFontColor();
336         style['fontFamily'] = this.getFontFamily();
337         style['fontSize'] = this.getFontSize()*this.getRelativeQuality() + 'px';
338         style['fontWeight'] = this.getFontWeight();
339         style['textAlign'] = this.getAlign();
340     }
341 };
342 
343 /**
344  * @inheritDoc
345  * @this {lime.Label}
346  */
347 lime.Renderer.CANVAS.LABEL.draw = function(context) {
348 
349     lime.Renderer.CANVAS.SPRITE.draw.call(this, context);
350 
351     var frame = this.getFrame(),
352         width = -frame.left - this.padding_[3] + frame.right - this.padding_[1],
353         dowrap = 0;
354     
355     if (!this.words_) {
356         this.words_ = this.calcWordsArray();
357         dowrap = 1;
358     }
359     
360     var stroke = this.stroke_?this.stroke_.width_:0;
361 
362     context.save();
363     var align = this.getAlign();
364     if (align == 'left') {
365         context.translate(frame.left + this.padding_[3]+stroke,
366             frame.top + this.padding_[0]+stroke);
367     }
368     else if (align == 'right') {
369         context.translate(frame.right - this.padding_[1]-stroke,
370             frame.top + this.padding_[0]+stroke);
371     }
372     else if (align == 'center') {
373         context.translate(
374             (frame.left + this.padding_[3] +
375                 frame.right - this.padding_[1]) * .5,
376             frame.top + this.padding_[0]+stroke);
377     }
378 
379     var lh = this.getLineHeight();
380 
381     context.fillStyle = this.getFontColor();
382     context.font = this.getFontWeight() + ' ' + this.getFontSize() +
383         'px/' + lh + ' ' + this.getFontFamily();
384     context.textAlign = align;
385     context.textBaseline = 'top';
386     
387     if(dowrap || width!=this.lastDrawnWidth_){
388         this.lines_ = this.wrapText(context, width);
389         this.lastDrawnWidth_ = width;
390     }
391     
392 
393     if (this.lines_) {
394         var lhpx = lh * this.getFontSize();
395         lhpx = goog.userAgent.WEBKIT ? Math.floor(lhpx) : Math.round(lhpx);
396         for (var i = 0; i < this.lines_.length; i++) {
397             context.fillText(this.lines_[i], 0, lhpx * i);
398         }
399     }
400 
401 
402     context.restore();
403 };
404 
405 /**
406  * Helper function to install new font file so you can use
407  * the font name as font-family.
408  * @param {string} name Font name.
409  * @param {string} fileurl Path to font file.
410  * @param {string=} opt_format Font format.
411  */
412 lime.Label.installFont = function(name, fileurl, opt_format) {
413     var format = opt_format || 'truetype';
414     goog.style.installStyles('@font-face{font-family: "' + name +
415         '";src: url(' + fileurl + ') format("' + format + '");})');
416 };
417