Skip to content

Commit ae08b9a

Browse files
committed
Text tab support working. Now to add varying tab sizing.
1 parent b8cc4d9 commit ae08b9a

2 files changed

Lines changed: 100 additions & 13 deletions

File tree

src/gameobjects/Text.js

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
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
*/
3839
Phaser.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
*/
262261
Phaser.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

src/math/Math.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ Phaser.Math = {
173173
/**
174174
* Snap a value to nearest grid slice, using ceil.
175175
*
176-
* Example: if you have an interval gap of 5 and a position of 12... you will snap to 15. As will 14 will snap to 15... but 16 will snap to 20.
176+
* Example: if you have an interval gap of 5 and a position of 12... you will snap to 15.
177+
* As will 14 will snap to 15... but 16 will snap to 20.
177178
*
178179
* @method Phaser.Math#snapToCeil
179180
* @param {number} input - The value to snap.

0 commit comments

Comments
 (0)