3434* @param {number } [style.strokeThickness=0] - A number that represents the thickness of the stroke. Default is 0 (no stroke).
3535* @param {boolean } [style.wordWrap=false] - Indicates if word wrap should be used.
3636* @param {number } [style.wordWrapWidth=100] - The width in pixels at which text will wrap.
37+ * @param {number } [style.tab=0] - The size (in pixels) of a tab stop, for when text includes tab characters. 0 disables.
3738*/
3839Phaser . Text = function ( game , x , y , text , style ) {
3940
@@ -92,11 +93,8 @@ Phaser.Text = function (game, x, y, text, style) {
9293 */
9394 this . autoRound = false ;
9495
95- this . tab = 0 ;
96-
9796 /**
98- * The resolution of the canvas used for rendering the Text.
99- * @property {number } _res
97+ * @property {number } _res - Internal canvas resolution var.
10098 * @private
10199 */
102100 this . _res = game . renderer . resolution ;
@@ -257,6 +255,7 @@ Phaser.Text.prototype.setShadow = function (x, y, color, blur, shadowStroke, sha
257255* @param {number } [style.strokeThickness=0] - A number that represents the thickness of the stroke. Default is 0 (no stroke).
258256* @param {boolean } [style.wordWrap=false] - Indicates if word wrap should be used.
259257* @param {number } [style.wordWrapWidth=100] - The width in pixels at which text will wrap.
258+ * @param {number } [style.tab=0] - The size (in pixels) of a tab stop, for when text includes tab characters. 0 disables.
260259* @return {Phaser.Text } This Text instance.
261260*/
262261Phaser . Text . prototype . setStyle = function ( style ) {
@@ -276,6 +275,7 @@ Phaser.Text.prototype.setStyle = function (style) {
276275 style . shadowOffsetY = style . shadowOffsetY || 0 ;
277276 style . shadowColor = style . shadowColor || 'rgba(0,0,0,0)' ;
278277 style . shadowBlur = style . shadowBlur || 0 ;
278+ style . tab = style . tab || 0 ;
279279
280280 var components = this . fontToComponents ( style . font ) ;
281281
@@ -337,31 +337,40 @@ Phaser.Text.prototype.updateText = function () {
337337 var lines = outputText . split ( / (?: \r \n | \r | \n ) / ) ;
338338
339339 // Calculate text width
340+ var tab = this . style . tab ;
340341 var lineWidths = [ ] ;
341342 var maxLineWidth = 0 ;
342343 var fontProperties = this . determineFontProperties ( this . style . font ) ;
343344
344345 for ( var i = 0 ; i < lines . length ; i ++ )
345346 {
346- if ( this . tab === 0 )
347+ if ( tab === 0 )
347348 {
348349 // Simple layout (no tabs)
349- var lineWidth = this . context . measureText ( lines [ i ] ) . width + this . padding . x ;
350+ var lineWidth = this . context . measureText ( lines [ i ] ) . width + this . style . strokeThickness + this . padding . x ;
350351 }
351352 else
352353 {
353354 // Complex layout (tabs)
354355 var line = lines [ i ] . split ( / (?: \t ) / ) ;
355- var lineWidth = this . padding . x ;
356+ var lineWidth = this . padding . x + this . style . strokeThickness ;
356357
357358 for ( var c = 0 ; c < line . length ; c ++ )
358359 {
359- lineWidth += this . context . measureText ( line [ c ] ) . width ;
360+ var section = Math . ceil ( this . context . measureText ( line [ c ] ) . width ) ;
361+
362+ // How far to the next tab?
363+ lineWidth += section ;
364+
365+ var snap = this . game . math . snapToCeil ( lineWidth , tab ) ;
366+ var diff = snap - lineWidth ;
367+
368+ lineWidth += diff ;
360369 }
361370 }
362371
363- lineWidths [ i ] = lineWidth ;
364- maxLineWidth = Math . max ( maxLineWidth , lineWidth ) ;
372+ lineWidths [ i ] = Math . ceil ( lineWidth ) ;
373+ maxLineWidth = Math . max ( maxLineWidth , lineWidths [ i ] ) ;
365374 }
366375
367376 var width = maxLineWidth + this . style . strokeThickness ;
@@ -451,13 +460,29 @@ Phaser.Text.prototype.updateText = function () {
451460 if ( this . style . stroke && this . style . strokeThickness )
452461 {
453462 this . updateShadow ( this . style . shadowStroke ) ;
454- this . context . strokeText ( lines [ i ] , linePositionX , linePositionY ) ;
463+
464+ if ( tab === 0 )
465+ {
466+ this . context . strokeText ( lines [ i ] , linePositionX , linePositionY ) ;
467+ }
468+ else
469+ {
470+ this . renderTabLine ( lines [ i ] , linePositionX , linePositionY ) ;
471+ }
455472 }
456473
457474 if ( this . style . fill )
458475 {
459476 this . updateShadow ( this . style . shadowFill ) ;
460- this . context . fillText ( lines [ i ] , linePositionX , linePositionY ) ;
477+
478+ if ( tab === 0 )
479+ {
480+ this . context . fillText ( lines [ i ] , linePositionX , linePositionY ) ;
481+ }
482+ else
483+ {
484+ this . renderTabLine ( lines [ i ] , linePositionX , linePositionY ) ;
485+ }
461486 }
462487 }
463488 }
@@ -466,6 +491,43 @@ Phaser.Text.prototype.updateText = function () {
466491
467492} ;
468493
494+ /**
495+ * Renders a line of text that contains tab characters if Text.tab > 0.
496+ * Called automatically by updateText.
497+ *
498+ * @method Phaser.Text#renderTabLine
499+ * @private
500+ * @param {string } line - The line of text to render.
501+ * @param {integer } x - The x position to start rendering from.
502+ * @param {integer } y - The y position to start rendering from.
503+ */
504+ Phaser . Text . prototype . renderTabLine = function ( line , x , y ) {
505+
506+ // Complex layout (tabs)
507+ var text = line . split ( / (?: \t ) / ) ;
508+ var w = 0 ;
509+
510+ for ( var c = 0 ; c < text . length ; c ++ )
511+ {
512+ var section = Math . ceil ( this . context . measureText ( text [ c ] ) . width ) ;
513+
514+ // How far to the next tab?
515+
516+ console . log ( text [ c ] , '=' , section ) ;
517+
518+ // w += section;
519+
520+ var snap = this . game . math . snapToCeil ( x , this . style . tab ) ;
521+
522+ this . context . fillText ( text [ c ] , snap , y ) ;
523+
524+ console . log ( 'x' , snap ) ;
525+
526+ x = snap + section ;
527+ }
528+
529+ } ;
530+
469531/**
470532* Sets the Shadow on the Text.context based on the Style settings, or disables it if not enabled.
471533* This is called automatically by Text.updateText.
@@ -1301,6 +1363,30 @@ Object.defineProperty(Phaser.Text.prototype, 'resolution', {
13011363
13021364} ) ;
13031365
1366+ /**
1367+ * x
1368+ *
1369+ * @name Phaser.Text#tab
1370+ * @property {integer } tab
1371+ */
1372+ Object . defineProperty ( Phaser . Text . prototype , 'tab' , {
1373+
1374+ get : function ( ) {
1375+ return this . style . tab ;
1376+ } ,
1377+
1378+ set : function ( value ) {
1379+
1380+ if ( value !== this . style . tab )
1381+ {
1382+ this . style . tab = value ;
1383+ this . dirty = true ;
1384+ }
1385+
1386+ }
1387+
1388+ } ) ;
1389+
13041390/**
13051391* Horizontal alignment of the text within the `textBounds`. Can be: 'left', 'center' or 'right'.
13061392* @name Phaser.Text#boundsAlignH
0 commit comments