In-line Button Glyphs
From XNAWiki
This class can be used to render button glyphs in-line with normal text. To make use of this component you need the button glyphs font found on the XNA website. It can also do text wrapping and clipping.
Tags
[A] [B] [X] [Y] [START] [BACK] [GUIDE] [RT] [LT] [LB] [RB] [LTHUMB] [RTHUMB]
[NL] - adds a new line in place of \\n
Usage
//in game.LoadContent() TextElement text = new TextElement(); text.LoadContent(Content, GraphicsDevice); //in game.Draw() text.Draw(spriteBatch);
Code
/// <summary>
/// Represents formatted text with inline button glyphs, clipping and new lines.
/// </summary>
public class TextElement
{
private SpriteFont font, buttonFont;
private Dictionary<string, string> buttonGlyphs = new Dictionary<string, string>();
private float lineHeight = 0;
public TextElement()
{
ButtonScale = 0.6f;
Position = Vector2.Zero;
Text = "Here is some example text. Press [A] or [START] to continue.";
Color = Color.Black;
Size = Vector2.Zero;
ButtonScale = 0.6f;
ClipText = false;
}
#region Properties
private string text;
public string Text
{
get { return text; }
set
{
text = value;
if (size != Vector2.Zero)
WrapText();
}
}
public bool ClipText
{
get;
set;
}
public Vector2 Position
{
get;
set;
}
public Color Color
{
get;
set;
}
private Vector2 size;
public Vector2 Size
{
get { return size; }
set
{
size = value;
if (size != Vector2.Zero)
WrapText();
}
}
public float ButtonScale
{
get;
set;
}
#endregion
public void LoadContent(ContentManager content, GraphicsDevice device)
{
buttonGlyphs = new Dictionary<string, string>();
buttonGlyphs.Add("[LTHUMB]", " ");
buttonGlyphs.Add("[RTHUMB]", "\"");
buttonGlyphs.Add("[DPAD]", "!");
buttonGlyphs.Add("[BACK]", "#");
buttonGlyphs.Add("[GUIDE]", "$");
buttonGlyphs.Add("[START]", "%");
buttonGlyphs.Add("[X]", "&");
buttonGlyphs.Add("[Y]", "(");
buttonGlyphs.Add("[A]", "'");
buttonGlyphs.Add("[B]", ")");
buttonGlyphs.Add("[LB]", "-");
buttonGlyphs.Add("[RB]", "*");
buttonGlyphs.Add("[RT]", "+");
buttonGlyphs.Add("[LT]", ",");
font = content.Load<SpriteFont>("Font");
buttonFont = content.Load<SpriteFont>("xboxControllerSpriteFont");
WrapText();
}
public void Draw(SpriteBatch sb)
{
lineHeight = font.LineSpacing;
if (ClipText)
{
sb.GraphicsDevice.RenderState.ScissorTestEnable = true;
sb.GraphicsDevice.ScissorRectangle = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
}
DrawText(Text, sb, Position);
if (ClipText)
{
sb.End();
sb.Begin();
sb.GraphicsDevice.RenderState.ScissorTestEnable = false;
}
}
private void DrawText(string text, SpriteBatch sb, Vector2 position)
{
int tagStart = text.IndexOf('[');
int tagEnd = text.IndexOf(']', tagStart != -1 ? tagStart : 0);
if (tagStart > 0)
position += DrawString(text.Substring(0, tagStart), sb, position);
if (tagStart != -1 && tagEnd != -1)
position += DrawButton(text.Substring(tagStart, tagEnd - tagStart + 1), sb, position);
if (tagEnd != -1)
DrawText(text.Substring(tagEnd+1), sb, position);
else
DrawString(text, sb, position);
}
private Vector2 DrawString(string text, SpriteBatch sb, Vector2 position)
{
sb.DrawString(font, text, position, Color);
return new Vector2(font.MeasureString(text).X, 0);
}
private Vector2 DrawButton(string tag, SpriteBatch sb, Vector2 position)
{
//Convert tag into button font text
if (buttonGlyphs.ContainsKey(tag))
tag = buttonGlyphs[tag];
else if (tag == "[NL]")
{
Vector2 r = new Vector2(Position.X - position.X, lineHeight);
lineHeight = font.LineSpacing;
return r;
}
else
return DrawString(tag, sb, position);
Vector2 size = buttonFont.MeasureString(tag) * ButtonScale;
if (lineHeight < size.Y * 0.5f) lineHeight = size.Y * 0.4f;
//Draw string
sb.DrawString(buttonFont, tag, position, Color.White, 0f, new Vector2(0, size.Y / 2), ButtonScale, SpriteEffects.None, 0);
return new Vector2(size.X, 0);
}
private void WrapText()
{
if (font == null || Size == Vector2.Zero) return;
string[] words = Text.Split(' ');
StringBuilder sb = new StringBuilder();
float lineWidth = 0f;
float spaceWidth = font.MeasureString(" ").X;
foreach (string word in words)
{
float size = MeasureWord(word);
if (lineWidth + size > Size.X)
{
sb.Append(word + "[NL]");
lineWidth = 0f;
}
else
{
sb.Append(word);
lineWidth += size;
}
}
text = sb.ToString();
}
private float MeasureWord(string text)
{
float length = 0f;
int startIndex = text.IndexOf('[');
int endIndex = text.IndexOf(']', startIndex != -1 ? startIndex : 0);
if (startIndex > 0)
length = font.MeasureString(text.Substring(0, startIndex)).X;
if (startIndex != -1 && endIndex != -1)
length += MeasureTag(text.Substring(startIndex, endIndex - startIndex + 1));
if (endIndex != -1)
length += MeasureWord(text.Substring(endIndex+1));
else
return font.MeasureString(text).X;
if (length < 0) length = 0;
return length;
}
private float MeasureTag(string tag)
{
if (buttonGlyphs.ContainsKey(tag))
return buttonFont.MeasureString(buttonGlyphs[tag]).X;
else if (tag == "[NL]")
return float.NegativeInfinity;
else
return font.MeasureString(tag).X;
}
}