BitmapTextUtil useful additions

This patch adds a #toColorCode(ColorRGBA) and #fromColorCode(String) methods to convert to and from colors to display in the BitmapText object. I forget when they added it but BitmapText’s can be different colors like a tooltip in your favorite game.

[java]Index: src/tonegod/gui/core/utils/BitmapTextUtil.java

— src/tonegod/gui/core/utils/BitmapTextUtil.java (revision 448)
+++ src/tonegod/gui/core/utils/BitmapTextUtil.java (working copy)
@@ -2,11 +2,13 @@

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */

package tonegod.gui.core.utils;

import com.jme3.font.BitmapText;
import com.jme3.font.LineWrapMode;
import com.jme3.font.Rectangle;
+import com.jme3.math.ColorRGBA;
import tonegod.gui.core.Element;

/**
@@ -13,70 +15,129 @@
*

  • @author t0neg0d
    */
    -public class BitmapTextUtil {
  • /**
    • Returns the width of the provided text
    • @param ref Element The element the text will be added to (reference for font settings)
    • @param text String the text to be evaluated
    • @return float The width
  • */
  • public static float getTextWidth(Element ref, String text) {
  •   BitmapText eval = new BitmapText(ref.getFont());
    
  •   eval.setSize(ref.getFontSize());
    
  •   eval.setLineWrapMode(LineWrapMode.NoWrap);
    
  •   eval.setBox(null);
    
  •   eval.setText(text);
    
  •   return eval.getLineWidth();
    

+public class BitmapTextUtil
+{
+

  • /**
  • * Returns the width of the provided text
    
  • * <p/>
    
  • * @param ref  Element The element the text will be added to (reference for font settings)
    
  • * @param text String the text to be evaluated
    
  • * @return float The width
    
  • */
    
  • public static float getTextWidth(Element ref, String text)
  • {
  • BitmapText eval = new BitmapText(ref.getFont());
  • eval.setSize(ref.getFontSize());
  • eval.setLineWrapMode(LineWrapMode.NoWrap);
  • eval.setBox(null);
  • eval.setText(text);
  • return eval.getLineWidth();
  • }
  • /**
  • * Returns the width of the provided text or the maxwidth, which ever is less
    
  • * <p/>
    
  • * @param ref      Element The element the text will be added to (reference for font settings)
    
  • * @param text     String the text to be evaluated
    
  • * @param maxWidth The maximum width considered a valid return value
    
  • * @return float The width
    
  • */
    
  • public static float getTextWidth(Element ref, String text, float maxWidth)
  • {
  • BitmapText eval = new BitmapText(ref.getFont());
  • eval.setSize(ref.getFontSize());
  • eval.setText(“Xg”);
  • eval.setText(text);
  • return (eval.getLineWidth() < maxWidth) ? eval.getLineWidth() : maxWidth;
  • }
  • /**
  • * Returns the height value of a single line of text
    
  • * &lt;p/&gt;
    
  • * @param ref  Element The element the text will be added to (reference for font settings)
    
  • * @param text String the text to be evaluated
    
  • * @return float
    
  • */
    
  • public static float getTextLineHeight(Element ref, String text)
  • {
  • BitmapText eval = new BitmapText(ref.getFont());
  • eval.setSize(ref.getFontSize());
  • eval.setLineWrapMode(LineWrapMode.NoWrap);
  • eval.setBox(null);
  • eval.setText(text);
  • return eval.getLineHeight();
  • }
  • /**
  • * Returns the total height of a wrapped text string
    
  • * &lt;p/&gt;
    
  • * @param ref      Element The element the text will be added to (reference for font settings)
    
  • * @param text     String the text to be evaluated
    
  • * @param maxWidth The maximum width considered a valid return value
    
  • * @return float
    
  • */
    
  • public static float getTextTotalHeight(Element ref, String text, float maxWidth)
  • {
  • BitmapText eval = new BitmapText(ref.getFont());
  • eval.setSize(ref.getFontSize());
  • eval.setText(“Xg”);
  • eval.setBox(new Rectangle(0, 0, maxWidth, eval.getLineHeight()));
  • eval.setText(text);
  • return eval.getLineWidth() * eval.getLineCount();
  • }
  • /**
  • * Example usage:
    
  • * &lt;br /&gt;
    
  • * {@code
    
  • * element.setText("Hi! " + toColorCode(ColorRGBA.Blue) + "PC. " + "Do you like " + toColorCode(ColorRGBA.Pink) + "Pink?");}
    
  • * &lt;p/&gt;
    
  • * @param color
    
  • * @return
    
  • */
    
  • public static String toColorCode(ColorRGBA color)
  • {
  • return String.format("\#%02x%02x%02x#", (int) color.r * 255, (int) color.g * 255, (int) color.b * 255);
  • }
  • /**
  • * Example usage:
    
  • * &lt;br /&gt;
    
  • * {@code
    
  • * element.setText("Hi! " + toColorText(ColorRGBA.Blue) + "PC. " + "Do you like " + toColorText(ColorRGBA.Pink) + "Pink?");}
    
  • * &lt;p/&gt;
    
  • * @param color
    
  • * @return
    
  • */
    
  • public static ColorRGBA fromColorCode(String color)
  • {
  • int idxOf = color.indexOf(’#’), lastIdxOf = color.lastIndexOf(’#’);
  • if (idxOf == -1 || lastIdxOf == -1)
  • {
  •   return ColorRGBA.Pink; // :evil grin:
    
    }
  • /**
    • Returns the width of the provided text or the maxwidth, which ever is less
    • @param ref Element The element the text will be added to (reference for font settings)
    • @param text String the text to be evaluated
    • @param maxWidth The maximum width considered a valid return value
    • @return float The width
  • */
  • public static float getTextWidth(Element ref, String text, float maxWidth) {
  •   BitmapText eval = new BitmapText(ref.getFont());
    
  •   eval.setSize(ref.getFontSize());
    
  •   eval.setText("Xg");
    
  •   eval.setText(text);
    
  •   return (eval.getLineWidth() &lt; maxWidth) ? eval.getLineWidth() : maxWidth;
    
  • String colorText = color.substring(idxOf, lastIdxOf);
  • if (colorText != null)
  • {
  •   try
    
  •   {
    
  •   float r = Float.parseFloat(colorText.substring(0, 2));
    
  •   float g = Float.parseFloat(colorText.substring(2, 4));
    
  •   float b = Float.parseFloat(colorText.substring(4, 6));
    
  •   return new ColorRGBA(r, g, b, 1f);
    
  •   } catch (Exception ex)
    
  •   {
    
  •   return ColorRGBA.Pink; // :evil grin:
    
  •   }
    
  • } else
  • {
  •   return ColorRGBA.Pink; // :evil grin:
    
    }
  • /**
    • Returns the height value of a single line of text
    • @param ref Element The element the text will be added to (reference for font settings)
    • @param text String the text to be evaluated
    • @return float
  • */
  • public static float getTextLineHeight(Element ref, String text) {
  •   BitmapText eval = new BitmapText(ref.getFont());
    
  •   eval.setSize(ref.getFontSize());
    
  •   eval.setLineWrapMode(LineWrapMode.NoWrap);
    
  •   eval.setBox(null);
    
  •   eval.setText(text);
    
  •   return eval.getLineHeight();
    
  • }
  • /**
    • Returns the total height of a wrapped text string
    • @param ref Element The element the text will be added to (reference for font settings)
    • @param text String the text to be evaluated
    • @param maxWidth The maximum width considered a valid return value
    • @return float
  • */
  • public static float getTextTotalHeight(Element ref, String text, float maxWidth) {
  •   BitmapText eval = new BitmapText(ref.getFont());
    
  •   eval.setSize(ref.getFontSize());
    
  •   eval.setText("Xg");
    
  •   eval.setBox(new Rectangle(0,0,maxWidth, eval.getLineHeight()));
    
  •   eval.setText(text);
    
  •   return eval.getLineWidth()*eval.getLineCount();
    
  • }
  • }

}
[/java]

1 Like

oOps forgot to update the documentation on those methods…

[java] /**
* Example usage:
* <br />
* {@code
* ColorRGBA color = fromColorCode("\#FF0088#");}
* <p/>
* @param color
* @return
*/[/java]

HAHAHAHA

Return ColorRGBA.PINK… cruel

Wow, this is neat. I didn’t know this was supported.

Completely unrelated, but on the wish list for BitmapText, request… can you start considering how links might be embedded into text… not html links, but in game command type links?

The reason I mention it is… the color change is a positive step in the right direction.

It would be a very complex thing to do… It makes sense to create a LinkLabel (clickable Label with self defined color of underlined text?). Embedding a link into text would require a lot…

  • A new BitmapText class maybe (LinkableBitmapText)
  • Inside the LinkableBitmapText you would have to keep a list of Link text objects
  • These link text objects would need to be able to receive mouse input
  • Finally the renderer for the text would need to be aware of the exact location of each Link text object (sorta like a token in a script parser) and the Link's color
  • I think that is everything
The Link class would look something like... [java]public class Link {
private ColorRGBA color = ColorRGBA.Blue;

private int indexStart, indexEnd;

private boolean underlined = true;

public Link()
{
}

public Link(ColorRGBA color, int indexStart, int indexEnd)
{
this.color = color;
this.indexStart = indexStart;
this.indexEnd = indexEnd;
}

public ColorRGBA getColor()
{
return color;
}

public void setColor(ColorRGBA color)
{
this.color = color;
}

public boolean isUnderlined()
{
return underlined;
}

public void setUnderlined(boolean underlined)
{
this.underlined = underlined;
}

}[/java]

What BitmapText needs is the ability to detect what character (index) is at a particular location. This could be used for a lot of things including hyperlinks.

Embedded colors have pretty much always been supported (for as long as I’ve been messing with BitmapText anyway… almost 3 years). It makes sense to have colors embedded in the mesh somehow because each letter already has its own colors. Might as well provide access. (Note: you can also set colors for particular ranges dynamically through the BitmapText methods… you don’t have to embed.)

If one could detect the character (index) under a particular location then hyperlinks would be pretty trivially supportable externally. As would pop-up tool tips, word highlighting, etc… None of which should actually be embedded into BitmapText itself as there are a dozen different ways to do that.

If BitmapText weren’t such a fragile and convoluted class, I might have added the character location stuff already. I actually need it, too. I go through a certain amount of code-acrobatics to find this out now.

1 Like

That would be pretty neat, can’t wait for that nightly build.

Is there secret deeply embedded code in BitmapText that allows styling text with underlines or strikethroughs?

@squizzle said: That would be pretty neat, can't wait for that nightly build.

Is there secret deeply embedded code in BitmapText that allows styling text with underlines or strikethroughs?

No, unfortunately. A non-trivial addition, too.

Though if we could also get the location of a particular character then it becomes more feasible to at least do externally. What could be interesting is some kind of lower-level text mesh that let us position letter quads exactly where we wanted… then it would just be a matter of overlaying ___ and — in the appropriate places based on the real text’s letter positions.

…the trick is always in the depth buffer. And that wouldn’t change even if we found a way to sandwich it right into BitmapText.

@pspeed said: No, unfortunately. A non-trivial addition, too.

Though if we could also get the location of a particular character then it becomes more feasible to at least do externally. What could be interesting is some kind of lower-level text mesh that let us position letter quads exactly where we wanted… then it would just be a matter of overlaying ___ and — in the appropriate places based on the real text’s letter positions.

…the trick is always in the depth buffer. And that wouldn’t change even if we found a way to sandwich it right into BitmapText.

I’m fairly sure I could get this working… everything needed is in BitmapText right now (for character location that is). It would not be part of BitmapText… that would be super messy. Here is where I would run into issues. Resizing and line wrap changes. Ugh… it would be a nightmare trying to get this functioning properly.

EDIT: Sorry… what I meant was… everything needed to calc the location is there…

I reaaaaalllly need to revisit the AnimText class… it would be a really sweet alternative to BitmapText with just a bit more work.

It’s what I used to do all the animated text in that 2D galaga type game.

Video is better than words… this:

[video]http://youtu.be/t7MViMRzx34[/video]

@squizzle said: That would be pretty neat, can't wait for that nightly build.

Is there secret deeply embedded code in BitmapText that allows styling text with underlines or strikethroughs?

Well… there is multiple character pages, but I don’t think you can use more than one at a time… so yeah… what Paul said.

Actually, I can think of multiple ways of achieving this in the AnimText class mentioned above. It’s Bitmap Font based, but does drop shadowing and few extras… so underline, strikethrough, drop caps, small caps all would be possible.

Heh… and it looks like I have my next pet project.

I need to add text wrap and alignment to the AnimText class.

The coolest part is, it’s based on the AnimElement class which knows everything about every quad added to it’s mesh… each has:

An origin
Rotation
Scale
Location
Parent Linkage
Etc, etc, etc

And you can use TemporalActions to manipulate them as if they were individual objects.

Oh man… it would be the happiest day of my JME life if I could completely ditch BitmapText from the library!! I’m fairly excited about his.

Heh… never added the AnimText class to the library. That wasn’t very nice of me. Guess I’ll be rectifying that soon(ish)