using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using RecrownedAthenaeum.UI.SkinSystem; using RecrownedAthenaeum.UI.SkinSystem.Definitions; using System.Text; namespace RecrownedAthenaeum.UI.Modular.Modules { /// /// Represents text for the UI. /// public class Text : UIModule { private TextSkinDefinition skinDefinition; private SpriteFont font; private float scale; private Vector2 position; private string originalText; private string displayedText; private Vector2 modifiedTextSize; /// /// Whether or not to try and wrap text automatically. Meaning will check and attempt to wrap every update. /// public bool autoWrap; /// /// Whether or not to automatically scale the text every update. Happens after auto wrap if enabled. /// public bool autoScale; /// /// Should this use ellipses? Will perform this operation before auto wrapping or auto scalling. /// public bool useEllipses; /// /// The text to use for the ellipsis. /// public string ellipsis = "..."; private string ModifiedText { get { return displayedText; } set { displayedText = value; modifiedTextSize = font.MeasureString(value); } } /// /// The string to be displayed. /// public string Content { get { return originalText; } set { if (value == null) value = ellipsis; modifiedTextSize = font.MeasureString(value); originalText = value; displayedText = value; } } /// /// Creates a UI text object. /// /// The font to use. /// The string for the text. public Text(SpriteFont font, string content = null) { Content = content; this.font = font; } /// /// Creates a UI text object /// /// The skin to be used. /// The name of the skin's definition to use of a . /// The font to be used. /// The string of text to be displayed. public Text(ISkin skin, SpriteFont font, string skinDefinitionName = null, string content = null) : this(font, content) { skinDefinition = skin.ObtainDefinition(skinDefinitionName, GetType()); color = skin.GetColor(skinDefinition.color); } /// /// Updates the positioning and attempts to perform any operations that were marked automatic. /// /// The game time. public override void Update(GameTime gameTime) { position.X = bounds.X; position.Y = bounds.Y; if (useEllipses) AttemptToApplyEllipsis(); if (autoWrap) AttemptToWrapText(); if (autoScale) AttemptToScaleFont(); base.Update(gameTime); } /// /// Draws the text. /// /// Batch to use. public override void Draw(SpriteBatch batch) { batch.DrawString(font, Content, position, color, 0f, origin, scale, SpriteEffects.None, 0f); base.Draw(batch); } /// /// Attempts to apply ellipsis. Checks of nessecary. /// public void AttemptToApplyEllipsis() { if (modifiedTextSize.X * scale > bounds.Width && ModifiedText.Length > ellipsis.Length + 1) { RemoveLineBreaks(); StringBuilder stringBuilder = new StringBuilder(ModifiedText); do { stringBuilder.Remove(stringBuilder.Length, ellipsis.Length - 1); stringBuilder.Insert(stringBuilder.Length, ellipsis); } while (font.MeasureString(stringBuilder).X * scale > bounds.Width); ModifiedText = stringBuilder.ToString(); } } /// /// Attempts to scale the font. Checks if nessecary. /// public void AttemptToScaleFont() { if (modifiedTextSize.X * scale > bounds.Width || modifiedTextSize.X * scale < bounds.Width - 5) { scale = bounds.Width / modifiedTextSize.X; } if (modifiedTextSize.Y * scale > bounds.Height || modifiedTextSize.Y * scale < bounds.Height - 5) { scale = bounds.Height / modifiedTextSize.Y; } } /// /// Removes line breaks. /// public void RemoveLineBreaks() { ModifiedText = ModifiedText.Replace("\n", " "); } /// /// Resets to original text. /// public void ResetToOriginalText() { ModifiedText = originalText; } /// /// Attempts to wrap text. Checks if nessecary. /// /// If true, will first unwrap text, and the wrap again. This occurs before nessecity check. public void AttemptToWrapText(bool unwrap = false) { if (unwrap) RemoveLineBreaks(); if (modifiedTextSize.X * scale > bounds.Width) { ModifiedText = ModifiedText.Replace("\n", " "); string[] words = ModifiedText.Split(' '); StringBuilder stringBuilder = new StringBuilder(); float currentScaledLineWidth = 0f; for (int w = 0; w < words.Length; w++) { string word = words[w]; float scaledWidth = font.MeasureString(word).X * scale; if (currentScaledLineWidth + scaledWidth <= bounds.Width) { stringBuilder.Append(word); currentScaledLineWidth += scaledWidth; } else { stringBuilder.AppendLine(); currentScaledLineWidth = 0; } } ModifiedText = stringBuilder.ToString(); } } } }