using System; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Plex.Engine.GraphicsSubsystem; using Microsoft.Xna.Framework.Graphics; namespace Plex.Engine { public enum WrapMode { None, Words, Letters } /// /// A class for rendering text. /// public static class TextRenderer { private static string WrapLine(SpriteFont font, string text, float maxLineWidth) { if (string.IsNullOrEmpty(text)) return text; if (font.MeasureString(text).X <= maxLineWidth) return text; text = text.Trim(); var sb = new StringBuilder(); return sb.ToString().TrimEnd(); } /// /// Perform text wrapping on a string of text using the specified . /// /// The representing the font to measure the text in. /// The text to wrap. /// The maximum width (in pixels) that a line of text can be. /// The type of text wrapping to apply. /// The resulting wrapped text. public static string WrapText(SpriteFont font, string text, float maxLineWidth, WrapMode mode) { if (string.IsNullOrEmpty(text)) return text; if (font.MeasureString(text).X <= maxLineWidth) return text; if (mode == WrapMode.Words) { float spacewidth = font.MeasureString(" ").X; if (maxLineWidth < spacewidth) return text; text = text.Trim().Replace("\r", ""); string[] lines = text.Split('\n'); float lineWidth = 0; var sb = new StringBuilder(); foreach (var line in lines) { lineWidth = 0; if (sb.Length>0) sb.Append("\n"); var words = line.Split(' ').ToList(); for (int i = 0; i < words.Count; i++) { string word = words[i]; Vector2 size = font.MeasureString(word); if (lineWidth + size.X <= maxLineWidth) { sb.Append(word + " "); lineWidth += size.X + spacewidth; } else { if (size.X >= maxLineWidth) { if (sb.Length>0) sb.Append("\n"); int half = word.Length / 2; string first = word.Substring(0, half); string second = word.Substring(half); words[i] = first; words.Insert(i + 1, second); i--; continue; } else { sb.Append("\n" + word + " "); lineWidth = size.X + spacewidth; } } } } return sb.ToString().TrimEnd(); } else { float lineWidth = 0; string newstr = ""; foreach (char c in text) { var measure = font.MeasureString(c.ToString()); if(lineWidth + measure.X > maxLineWidth) { newstr += "\n"; lineWidth = 0; } else { if (c == '\n') { lineWidth = 0; } else lineWidth += measure.X; } newstr += c; } return newstr; } } /// /// Measure a string of text to get its width and height in pixels. /// /// The text to measure /// The font to measure with /// The maximum width text can be before it is wrapped /// The wrap mode to use /// The size in pixels of the text. public static Vector2 MeasureText(string text, SpriteFont font, int maxwidth, WrapMode wrapMode) { if (string.IsNullOrEmpty(text)) return Vector2.Zero; switch (wrapMode) { case WrapMode.None: return font.MeasureString(text); default: return font.MeasureString(WrapText(font, text, maxwidth, wrapMode)); } } /// /// Render a string of text. /// /// The graphics context to render the text to. /// The text to render. /// The X coordinate of the text. /// The Y coordinate of the text. /// The font to render the text in. /// The maximum width text can be before it is wrapped. /// The alignment of the text. /// The type of text wrapping to use. /// The color of the text to render public static void DrawText(GraphicsContext gfx, int x, int y, string text, SpriteFont font, Color color, int maxwidth, TextAlignment alignment, WrapMode wrapMode) { if (string.IsNullOrEmpty(text)) return; string measured = (wrapMode == WrapMode.None) ? text : WrapText(font, text, maxwidth, wrapMode); string[] lines = measured.Split('\n'); for (int i = 0; i < lines.Length; i++) { var line = lines[i]; var measure = font.MeasureString(line); switch (alignment) { case TextAlignment.Left: gfx.Batch.DrawString(font, line, new Vector2(x, y + (measure.Y * i)), color); break; case TextAlignment.Center: gfx.Batch.DrawString(font, line, new Vector2(x + ((maxwidth-measure.X)/2), y + (measure.Y * i)), color); break; case TextAlignment.Right: gfx.Batch.DrawString(font, line, new Vector2(x + (maxwidth - measure.X), y + (measure.Y * i)), color); break; } } } } /// /// Describes how text should be aligned when rendered. /// public enum TextAlignment { /// /// Text should be aligned to the centre of the render bounds. /// Center = 0, /// /// Text should be aligned to the left. /// Left = 1, /// /// Text should be rendered to the right. /// Right = 2, } /// /// Indicates that this should be the default renderer for the game. /// [Obsolete("GDI fonts no longer supported.")] public class DefaultRenderer : Attribute { } /// /// Indicates that this should be the fallback renderer for the game. /// [Obsolete("GDI fonts no longer supported.")] public class FallbackRenderer : Attribute { } }