Procházet zdrojové kódy

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.

Fennel před 8 roky
rodič
revize
e60d67b1bb

+ 7 - 0
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<text.length()-1 && text.charAt(i+1)=='#'){

+ 6 - 2
jme3-core/src/main/java/com/jme3/font/BitmapText.java

@@ -369,7 +369,9 @@ public class BitmapText extends Node {
     }
 
     /**
-     * @param tabs tab positions
+     * Sets the positions at where the text continues after a tab character.<br>
+     * These tab stops need to be sorted from smallest to biggest value.
+     * @param tabs Sorted tab positions. Use <code>null</code> 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}).<br>
+     * This value is also used when no custom tab positions are set.
      * @param width tab size
      */
     public void setTabWidth(float width) {

+ 1 - 10
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();

+ 26 - 15
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;
     }
 }