aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/font/Letters.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/font/Letters.java')
-rw-r--r--engine/src/core/com/jme3/font/Letters.java331
1 files changed, 331 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/font/Letters.java b/engine/src/core/com/jme3/font/Letters.java
new file mode 100644
index 0000000..dbb9ef9
--- /dev/null
+++ b/engine/src/core/com/jme3/font/Letters.java
@@ -0,0 +1,331 @@
+package com.jme3.font;
+
+import com.jme3.font.BitmapFont.Align;
+import com.jme3.font.BitmapFont.VAlign;
+import com.jme3.font.ColorTags.Range;
+import com.jme3.math.ColorRGBA;
+import java.util.LinkedList;
+
+/**
+ * Manage and align LetterQuads
+ * @author YongHoon
+ */
+class Letters {
+ private final LetterQuad head;
+ private final LetterQuad tail;
+ private final BitmapFont font;
+ private LetterQuad current;
+ private StringBlock block;
+ private float totalWidth;
+ private float totalHeight;
+ private ColorTags colorTags = new ColorTags();
+ private ColorRGBA baseColor = null;
+
+ Letters(BitmapFont font, StringBlock bound, boolean rightToLeft) {
+ final String text = bound.getText();
+ this.block = bound;
+ this.font = font;
+ head = new LetterQuad(font, rightToLeft);
+ tail = new LetterQuad(font, rightToLeft);
+ setText(text);
+ }
+
+ void setText(final String text) {
+ colorTags.setText(text);
+ String plainText = colorTags.getPlainText();
+
+ head.setNext(tail);
+ tail.setPrevious(head);
+ current = head;
+ if (text != null && plainText.length() > 0) {
+ LetterQuad l = head;
+ for (int i = 0; i < plainText.length(); i++) {
+ l = l.addNextCharacter(plainText.charAt(i));
+ if (baseColor != null) {
+ // Give the letter a default color if
+ // one has been provided.
+ l.setColor( baseColor );
+ }
+ }
+ }
+
+ LinkedList<Range> ranges = colorTags.getTags();
+ if (!ranges.isEmpty()) {
+ for (int i = 0; i < ranges.size()-1; i++) {
+ Range start = ranges.get(i);
+ Range end = ranges.get(i+1);
+ setColor(start.start, end.start, start.color);
+ }
+ Range end = ranges.getLast();
+ setColor(end.start, plainText.length(), end.color);
+ }
+
+ invalidate();
+ }
+
+ LetterQuad getHead() {
+ return head;
+ }
+
+ LetterQuad getTail() {
+ return tail;
+ }
+
+ void update() {
+ LetterQuad l = head;
+ int lineCount = 1;
+ BitmapCharacter ellipsis = font.getCharSet().getCharacter(block.getEllipsisChar());
+ float ellipsisWidth = ellipsis!=null? ellipsis.getWidth()*getScale(): 0;
+
+ while (!l.isTail()) {
+ if (l.isInvalid()) {
+ l.update(block);
+
+ if (l.isInvalid(block)) {
+ switch (block.getLineWrapMode()) {
+ case Character:
+ lineWrap(l);
+ lineCount++;
+ break;
+ case Word:
+ if (!l.isBlank()) {
+ // search last blank character before this word
+ LetterQuad blank = l;
+ while (!blank.isBlank()) {
+ if (blank.isLineStart() || blank.isHead()) {
+ lineWrap(l);
+ lineCount++;
+ blank = null;
+ break;
+ }
+ blank = blank.getPrevious();
+ }
+ if (blank != null) {
+ blank.setEndOfLine();
+ lineCount++;
+ while (blank != l) {
+ blank = blank.getNext();
+ blank.invalidate();
+ blank.update(block);
+ }
+ }
+ }
+ break;
+ case NoWrap:
+ // search last blank character before this word
+ LetterQuad cursor = l.getPrevious();
+ while (cursor.isInvalid(block, ellipsisWidth) && !cursor.isLineStart()) {
+ cursor = cursor.getPrevious();
+ }
+ cursor.setBitmapChar(ellipsis);
+ cursor.update(block);
+ cursor = cursor.getNext();
+ while (!cursor.isTail() && !cursor.isLineFeed()) {
+ cursor.setBitmapChar(null);
+ cursor.update(block);
+ cursor = cursor.getNext();
+ }
+ break;
+ }
+ }
+ } else if (current.isInvalid(block)) {
+ invalidate(current);
+ }
+ if (l.isEndOfLine()) {
+ lineCount++;
+ }
+ l = l.getNext();
+ }
+
+ align();
+ block.setLineCount(lineCount);
+ rewind();
+ }
+
+ private void align() {
+ final Align alignment = block.getAlignment();
+ final VAlign valignment = block.getVerticalAlignment();
+ if (block.getTextBox() == null || (alignment == Align.Left && valignment == VAlign.Top))
+ return;
+ LetterQuad cursor = tail.getPrevious();
+ cursor.setEndOfLine();
+ final float width = block.getTextBox().width;
+ final float height = block.getTextBox().height;
+ float lineWidth = 0;
+ float gapX = 0;
+ float gapY = 0;
+ validateSize();
+ if (totalHeight < height) { // align vertically only for no overflow
+ switch (valignment) {
+ case Top:
+ gapY = 0;
+ break;
+ case Center:
+ gapY = (height-totalHeight)*0.5f;
+ break;
+ case Bottom:
+ gapY = height-totalHeight;
+ break;
+ }
+ }
+ while (!cursor.isHead()) {
+ if (cursor.isEndOfLine()) {
+ lineWidth = cursor.getX1()-block.getTextBox().x;
+ if (alignment == Align.Center) {
+ gapX = (width-lineWidth)/2;
+ } else if (alignment == Align.Right) {
+ gapX = width-lineWidth;
+ } else {
+ gapX = 0;
+ }
+ }
+ cursor.setAlignment(gapX, gapY);
+ cursor = cursor.getPrevious();
+ }
+ }
+
+ private void lineWrap(LetterQuad l) {
+ if (l.isHead() || l.isBlank())
+ return;
+ l.getPrevious().setEndOfLine();
+ l.invalidate();
+ l.update(block); // TODO: update from l
+ }
+
+ float getCharacterX0() {
+ return current.getX0();
+ }
+
+ float getCharacterY0() {
+ return current.getY0();
+ }
+
+ float getCharacterX1() {
+ return current.getX1();
+ }
+
+ float getCharacterY1() {
+ return current.getY1();
+ }
+
+ float getCharacterAlignX() {
+ return current.getAlignX();
+ }
+
+ float getCharacterAlignY() {
+ return current.getAlignY();
+ }
+
+ float getCharacterWidth() {
+ return current.getWidth();
+ }
+
+ float getCharacterHeight() {
+ return current.getHeight();
+ }
+
+ public boolean nextCharacter() {
+ if (current.isTail())
+ return false;
+ current = current.getNext();
+ return true;
+ }
+
+ public int getCharacterSetPage() {
+ return current.getBitmapChar().getPage();
+ }
+
+ public LetterQuad getQuad() {
+ return current;
+ }
+
+ public void rewind() {
+ current = head;
+ }
+
+ public void invalidate() {
+ invalidate(head);
+ }
+
+ public void invalidate(LetterQuad cursor) {
+ totalWidth = -1;
+ totalHeight = -1;
+
+ while (!cursor.isTail() && !cursor.isInvalid()) {
+ cursor.invalidate();
+ cursor = cursor.getNext();
+ }
+ }
+
+ float getScale() {
+ return block.getSize() / font.getCharSet().getRenderedSize();
+ }
+
+ public boolean isPrintable() {
+ return current.getBitmapChar() != null;
+ }
+
+ float getTotalWidth() {
+ validateSize();
+ return totalWidth;
+ }
+
+ float getTotalHeight() {
+ validateSize();
+ return totalHeight;
+ }
+
+ void validateSize() {
+ if (totalWidth < 0) {
+ LetterQuad l = head;
+ while (!l.isTail()) {
+ totalWidth = Math.max(totalWidth, l.getX1());
+ l = l.getNext();
+ totalHeight = Math.max(totalHeight, -l.getY1());
+ }
+ }
+ }
+
+ /**
+ * @param start start index to set style. inclusive.
+ * @param end end index to set style. EXCLUSIVE.
+ * @param style
+ */
+ void setStyle(int start, int end, int style) {
+ LetterQuad cursor = head.getNext();
+ while (!cursor.isTail()) {
+ if (cursor.getIndex() >= start && cursor.getIndex() < end) {
+ cursor.setStyle(style);
+ }
+ cursor = cursor.getNext();
+ }
+ }
+
+ /**
+ * Sets the base color for all new letter quads and resets
+ * the color of existing letter quads.
+ */
+ void setColor( ColorRGBA color ) {
+ baseColor = color;
+ setColor( 0, block.getText().length(), color );
+ }
+
+ ColorRGBA getBaseColor() {
+ return baseColor;
+ }
+
+ /**
+ * @param start start index to set style. inclusive.
+ * @param end end index to set style. EXCLUSIVE.
+ * @param color
+ */
+ void setColor(int start, int end, ColorRGBA color) {
+ LetterQuad cursor = head.getNext();
+ while (!cursor.isTail()) {
+ if (cursor.getIndex() >= start && cursor.getIndex() < end) {
+ cursor.setColor(color);
+ }
+ cursor = cursor.getNext();
+ }
+ }
+} \ No newline at end of file