• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.font;
33 
34 import com.jme3.font.BitmapFont.Align;
35 import com.jme3.font.BitmapFont.VAlign;
36 import com.jme3.material.Material;
37 import com.jme3.math.ColorRGBA;
38 import com.jme3.renderer.RenderManager;
39 import com.jme3.scene.Node;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42 
43 /**
44  * @author YongHoon
45  */
46 public class BitmapText extends Node {
47     private BitmapFont font;
48     private StringBlock block;
49     private boolean needRefresh = true;
50     private final BitmapTextPage[] textPages;
51     private Letters letters;
52 
BitmapText(BitmapFont font)53     public BitmapText(BitmapFont font) {
54         this(font, false, false);
55     }
56 
BitmapText(BitmapFont font, boolean rightToLeft)57     public BitmapText(BitmapFont font, boolean rightToLeft) {
58         this(font, rightToLeft, false);
59     }
60 
BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased)61     public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
62         textPages = new BitmapTextPage[font.getPageSize()];
63         for (int page = 0; page < textPages.length; page++) {
64             textPages[page] = new BitmapTextPage(font, arrayBased, page);
65             attachChild(textPages[page]);
66         }
67 
68         this.font = font;
69         this.block = new StringBlock();
70         block.setSize(font.getPreferredSize());
71         letters = new Letters(font, block, rightToLeft);
72     }
73 
74     @Override
clone()75     public BitmapText clone() {
76         BitmapText clone = (BitmapText) super.clone();
77         for (int i = 0; i < textPages.length; i++) {
78             clone.textPages[i] = textPages[i].clone();
79         }
80         clone.block = block.clone();
81         clone.needRefresh = true;
82         return clone;
83     }
84 
getFont()85     public BitmapFont getFont() {
86         return font;
87     }
88 
89     /**
90      * Changes text size
91      * @param size text size
92      */
setSize(float size)93     public void setSize(float size) {
94         block.setSize(size);
95         needRefresh = true;
96         letters.invalidate();
97     }
98 
99     /**
100      *
101      * @param text charsequence to change text to
102      */
setText(CharSequence text)103     public void setText(CharSequence text) {
104         // note: text.toString() is free if text is already a java.lang.String.
105         setText( text != null ? text.toString() : null );
106     }
107 
108     /**
109      *
110      * @param text String to change text to
111      */
setText(String text)112     public void setText(String text) {
113         text = text == null ? "" : text;
114         if (text == block.getText() || block.getText().equals(text)) {
115             return;
116         }
117 
118         block.setText(text);
119         letters.setText(text);
120         needRefresh = true;
121     }
122 
123     /**
124      * @return returns text
125      */
getText()126     public String getText() {
127         return block.getText();
128     }
129 
130     /**
131      * @return color of the text
132      */
getColor()133     public ColorRGBA getColor() {
134         return letters.getBaseColor();
135     }
136 
137     /**
138      * changes text color. all substring colors are deleted.
139      * @param color new color of text
140      */
setColor(ColorRGBA color)141     public void setColor(ColorRGBA color) {
142         letters.setColor(color);
143         letters.invalidate(); // TODO: Don't have to align.
144         needRefresh = true;
145     }
146 
147     /**
148      * Define area where bitmaptext will be rendered
149      * @param rect position and size box where text is rendered
150      */
setBox(Rectangle rect)151     public void setBox(Rectangle rect) {
152         block.setTextBox(rect);
153         letters.invalidate();
154         needRefresh = true;
155     }
156 
157     /**
158      * @return height of the line
159      */
getLineHeight()160     public float getLineHeight() {
161         return font.getLineHeight(block);
162     }
163 
164     /**
165      * @return height of whole textblock
166      */
getHeight()167     public float getHeight() {
168         if (needRefresh) {
169             assemble();
170         }
171         float height = getLineHeight()*block.getLineCount();
172         Rectangle textBox = block.getTextBox();
173         if (textBox != null) {
174             return Math.max(height, textBox.height);
175         }
176         return height;
177     }
178 
179     /**
180      * @return width of line
181      */
getLineWidth()182     public float getLineWidth() {
183         if (needRefresh) {
184             assemble();
185         }
186         Rectangle textBox = block.getTextBox();
187         if (textBox != null) {
188             return Math.max(letters.getTotalWidth(), textBox.width);
189         }
190         return letters.getTotalWidth();
191     }
192 
193     /**
194      * @return line count
195      */
getLineCount()196     public int getLineCount() {
197         if (needRefresh) {
198             assemble();
199         }
200         return block.getLineCount();
201     }
202 
getLineWrapMode()203     public LineWrapMode getLineWrapMode() {
204         return block.getLineWrapMode();
205     }
206 
207     /**
208      * Set horizontal alignment. Applicable only when text bound is set.
209      * @param align
210      */
setAlignment(BitmapFont.Align align)211     public void setAlignment(BitmapFont.Align align) {
212         if (block.getTextBox() == null && align != Align.Left) {
213             throw new RuntimeException("Bound is not set");
214         }
215         block.setAlignment(align);
216         letters.invalidate();
217         needRefresh = true;
218     }
219 
220     /**
221      * Set vertical alignment. Applicable only when text bound is set.
222      * @param align
223      */
setVerticalAlignment(BitmapFont.VAlign align)224     public void setVerticalAlignment(BitmapFont.VAlign align) {
225         if (block.getTextBox() == null && align != VAlign.Top) {
226             throw new RuntimeException("Bound is not set");
227         }
228         block.setVerticalAlignment(align);
229         letters.invalidate();
230         needRefresh = true;
231     }
232 
getAlignment()233     public BitmapFont.Align getAlignment() {
234         return block.getAlignment();
235     }
236 
getVerticalAlignment()237     public BitmapFont.VAlign getVerticalAlignment() {
238         return block.getVerticalAlignment();
239     }
240 
241     /**
242      * Set the font style of substring. If font doesn't contain style, default style is used
243      * @param start start index to set style. inclusive.
244      * @param end   end index to set style. EXCLUSIVE.
245      * @param style
246      */
setStyle(int start, int end, int style)247     public void setStyle(int start, int end, int style) {
248         letters.setStyle(start, end, style);
249     }
250 
251     /**
252      * Set the font style of substring. If font doesn't contain style, default style is applied
253      * @param regexp regular expression
254      * @param style
255      */
setStyle(String regexp, int style)256     public void setStyle(String regexp, int style) {
257         Pattern p = Pattern.compile(regexp);
258         Matcher m = p.matcher(block.getText());
259         while (m.find()) {
260             setStyle(m.start(), m.end(), style);
261         }
262     }
263 
264     /**
265      * Set the color of substring.
266      * @param start start index to set style. inclusive.
267      * @param end   end index to set style. EXCLUSIVE.
268      * @param color
269      */
setColor(int start, int end, ColorRGBA color)270     public void setColor(int start, int end, ColorRGBA color) {
271         letters.setColor(start, end, color);
272         letters.invalidate();
273         needRefresh = true;
274     }
275 
276     /**
277      * Set the color of substring.
278      * @param regexp regular expression
279      * @param color
280      */
setColor(String regexp, ColorRGBA color)281     public void setColor(String regexp, ColorRGBA color) {
282         Pattern p = Pattern.compile(regexp);
283         Matcher m = p.matcher(block.getText());
284         while (m.find()) {
285             letters.setColor(m.start(), m.end(), color);
286         }
287         letters.invalidate();
288         needRefresh = true;
289     }
290 
291     /**
292      * @param tabs tab positions
293      */
setTabPosition(float... tabs)294     public void setTabPosition(float... tabs) {
295         block.setTabPosition(tabs);
296         letters.invalidate();
297         needRefresh = false;
298     }
299 
300     /**
301      * used for the tabs over the last tab position.
302      * @param width tab size
303      */
setTabWidth(float width)304     public void setTabWidth(float width) {
305         block.setTabWidth(width);
306         letters.invalidate();
307         needRefresh = false;
308     }
309 
310     /**
311      * for setLineWrapType(LineWrapType.NoWrap),
312      * set the last character when the text exceeds the bound.
313      * @param c
314      */
setEllipsisChar(char c)315     public void setEllipsisChar(char c) {
316         block.setEllipsisChar(c);
317         letters.invalidate();
318         needRefresh = false;
319     }
320 
321     /**
322      * Available only when bounding is set. <code>setBox()</code> method call is needed in advance.
323      * true when
324      * @param wrap NoWrap   : Letters over the text bound is not shown. the last character is set to '...'(0x2026)
325      *             Character: Character is split at the end of the line.
326      *             Word     : Word is split at the end of the line.
327      */
setLineWrapMode(LineWrapMode wrap)328     public void setLineWrapMode(LineWrapMode wrap) {
329         if (block.getLineWrapMode() != wrap) {
330             block.setLineWrapMode(wrap);
331             letters.invalidate();
332             needRefresh = true;
333         }
334     }
335 
336     @Override
updateLogicalState(float tpf)337     public void updateLogicalState(float tpf) {
338         super.updateLogicalState(tpf);
339         if (needRefresh) {
340             assemble();
341         }
342     }
343 
assemble()344     private void assemble() {
345         // first generate quadlist
346         letters.update();
347 
348         for (int i = 0; i < textPages.length; i++) {
349             textPages[i].assemble(letters);
350         }
351         needRefresh = false;
352     }
353 
render(RenderManager rm)354     public void render(RenderManager rm) {
355         for (BitmapTextPage page : textPages) {
356             Material mat = page.getMaterial();
357             mat.setTexture("Texture", page.getTexture());
358             mat.render(page, rm);
359         }
360     }
361 }
362