From e60d67b1bb1643c3ee2beab071cce1dec812f0cb Mon Sep 17 00:00:00 2001 From: Fennel Date: Tue, 6 Dec 2016 01:12:19 +0100 Subject: [PATCH] Fixes tab stops in BitmapText / BitmapFont. The first explicitely set tab stop was always skipped. For all non-explicitely set tab stops it inserted a fixed spacing. This commit changes the behaviour so tabs are aligned to columns. It also adds handling of tabs to BitmapFont.getLineWidth() which ignored tabs before. --- .../main/java/com/jme3/font/BitmapFont.java | 7 ++++ .../main/java/com/jme3/font/BitmapText.java | 8 +++- .../main/java/com/jme3/font/LetterQuad.java | 11 +---- .../main/java/com/jme3/font/StringBlock.java | 41 ++++++++++++------- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/font/BitmapFont.java b/jme3-core/src/main/java/com/jme3/font/BitmapFont.java index 856268c37..8e58d469d 100644 --- a/jme3-core/src/main/java/com/jme3/font/BitmapFont.java +++ b/jme3-core/src/main/java/com/jme3/font/BitmapFont.java @@ -86,6 +86,8 @@ public class BitmapFont implements Savable { Bottom } + static final float DEFAULT_TAB_WIDTH = 50.0f; + private BitmapCharacterSet charSet; private Material[] pages; @@ -215,6 +217,11 @@ public class BitmapFont implements Savable { firstCharOfLine = true; continue; } + if(theChar == '\t') { + lineWidth = (float)Math.floor(lineWidth / DEFAULT_TAB_WIDTH) * DEFAULT_TAB_WIDTH; + lineWidth += DEFAULT_TAB_WIDTH; + } + BitmapCharacter c = charSet.getCharacter((int) theChar); if (c != null){ if (theChar == '\\' && i + * These tab stops need to be sorted from smallest to biggest value. + * @param tabs Sorted tab positions. Use null to reset tab positions. */ public void setTabPosition(float... tabs) { block.setTabPosition(tabs); @@ -378,7 +380,9 @@ public class BitmapText extends Node { } /** - * used for the tabs over the last tab position. + * Used for all tabs after the last custom tab position + * (see {@link #setTabPosition(float...) setTabPosition}).
+ * This value is also used when no custom tab positions are set. * @param width tab size */ public void setTabWidth(float width) { diff --git a/jme3-core/src/main/java/com/jme3/font/LetterQuad.java b/jme3-core/src/main/java/com/jme3/font/LetterQuad.java index 7977a154e..62e1647e4 100644 --- a/jme3-core/src/main/java/com/jme3/font/LetterQuad.java +++ b/jme3-core/src/main/java/com/jme3/font/LetterQuad.java @@ -306,8 +306,6 @@ class LetterQuad { } void update(StringBlock block) { - final float[] tabs = block.getTabPosition(); - final float tabWidth = block.getTabWidth(); final Rectangle bound = getBound(block); sizeScale = block.getSize() / font.getCharSet().getRenderedSize(); lineY = computeLineY(block); @@ -320,16 +318,9 @@ class LetterQuad { xAdvance = 0; } else if (isTab()) { x0 = previous.getNextX(); - width = tabWidth; + width = block.calcNextTabPosition(x0) - x0; y0 = lineY; height = 0; - if (tabs != null && x0 < tabs[tabs.length-1]) { - for (int i = 0; i < tabs.length-1; i++) { - if (x0 > tabs[i] && x0 < tabs[i+1]) { - width = tabs[i+1] - x0; - } - } - } xAdvance = width; } else if (bitmapChar == null) { x0 = getPrevious().getX1(); diff --git a/jme3-core/src/main/java/com/jme3/font/StringBlock.java b/jme3-core/src/main/java/com/jme3/font/StringBlock.java index 85fc9ab70..7da4cba6c 100644 --- a/jme3-core/src/main/java/com/jme3/font/StringBlock.java +++ b/jme3-core/src/main/java/com/jme3/font/StringBlock.java @@ -53,7 +53,7 @@ class StringBlock implements Cloneable { private int lineCount; private LineWrapMode wrapType = LineWrapMode.Word; private float[] tabPos; - private float tabWidth = 50; + private float tabWidth = BitmapFont.DEFAULT_TAB_WIDTH; private char ellipsisChar = 0x2026; /** @@ -91,6 +91,7 @@ class StringBlock implements Cloneable { clone.color = color.clone(); if (textBox != null) clone.textBox = textBox.clone(); + // tabPos is read-only and replaced on write. return clone; } catch (CloneNotSupportedException ex) { throw new AssertionError(); @@ -172,28 +173,38 @@ class StringBlock implements Cloneable { void setLineWrapMode(LineWrapMode wrap) { this.wrapType = wrap; } + + void setEllipsisChar(char c) { + this.ellipsisChar = c; + } + + int getEllipsisChar() { + return ellipsisChar; + } void setTabWidth(float tabWidth) { this.tabWidth = tabWidth; } void setTabPosition(float[] tabs) { - this.tabPos = tabs; - } - - float getTabWidth() { - return tabWidth; - } - - float[] getTabPosition() { - return tabPos; + if(tabs != null && tabs.length > 0) { + this.tabPos = tabs.clone(); + } else { + this.tabPos = null; + } } - void setEllipsisChar(char c) { - this.ellipsisChar = c; - } + float calcNextTabPosition(float posX) { + // If there is an upcoming user-set tab stop, use that one. + if (tabPos != null && posX < tabPos[tabPos.length-1]) { + for (int i = 0; i < tabPos.length; i++) { + if (posX < tabPos[i]) { + return tabPos[i]; + } + } + } - int getEllipsisChar() { - return ellipsisChar; + // No upcoming tab stops available, use default tab width. + return (float)Math.floor(posX / tabWidth) * tabWidth + tabWidth; } } \ No newline at end of file