using System; using System.IO; namespace Otter { /// /// Graphic used to display simple text. Much faster than RichText, but more limited options. /// public class Text : Graphic { #region Private Fields TextStyle textStyle; #endregion #region Private Properties bool isUsingShadow { get { return ShadowX != 0 || ShadowY != 0; } } bool isUsingOutline { get { return OutlineThickness > 0; } } #endregion #region Public Fields /// /// The color of the text shadow. /// public Color ShadowColor = Color.Black; /// /// The X position of the shadow. /// public int ShadowX; /// /// The Y position of the shadow. /// public int ShadowY; /// /// The Color of the outline. /// public Color OutlineColor = Color.Black; /// /// The thickness of the outline. /// public int OutlineThickness; /// /// The quality of the outline. Higher quality is more rendering passes! /// public TextOutlineQuality OutlineQuality = TextOutlineQuality.Good; #endregion #region Public Properties /// /// The displayed string. /// public string String { get { return text.DisplayedString; } set { text.DisplayedString = value; NeedsUpdate = true; Lines = text.DisplayedString.Split('\n').Length; UpdateDrawable(); } } /// /// The number of lines in the text. /// public int Lines { get; private set; } /// /// The amount of space between each line of text. /// public float LineSpacing { get { return text.Font.GetLineSpacing(text.CharacterSize); } } /// /// The font size. /// public int FontSize { get { return (int)text.CharacterSize; } set { text.CharacterSize = (uint)value; UpdateDrawable(); } } /// /// Set the TextStyle (bold, italic, underline.) /// public TextStyle TextStyle { get { return textStyle; } set { textStyle = value; text.Style = (SFML.Graphics.Text.Styles)TextStyle; NeedsUpdate = true; UpdateDrawable(); } } /// /// Set both ShadowX and ShadowY. /// public int Shadow { set { ShadowX = value; ShadowY = value; } } /// /// Get the actual center Y of the Text. /// public float CenterY { get { return HalfHeight + BoundsTop; } } /// /// The top bounds of the Text. /// public float BoundsTop { get { return text.GetLocalBounds().Top; } } /// /// The left bounds of the Text. /// public float BoundsLeft { get { return text.GetLocalBounds().Left; } } #endregion #region Constructors /// /// Create a new Text object. /// /// The string to display. /// The file path to the font to use. /// The size of the font. public Text(string str, string font = "", int size = 16) : base() { Initialize(str, font, size); } /// /// Create a new Text object. /// /// The string to display. /// The stream to load the font to use. /// The size of the font. public Text(string str, Stream font, int size = 16) : base() { Initialize(str, font, size); } /// /// Create a new Text object. /// /// The string to display. /// The Font to use. /// The size of the font. public Text(string str, Font font, int size = 16) : base() { Initialize(str, font.font, size); } /// /// Create a new Text object. /// /// The string to display. /// The size of the font. public Text(string str, int size = 16) : this(str, "", size) { } /// /// Create a new Text object. /// /// The size of the font. public Text(int size = 16) : this("", "", size) { } #endregion #region Private Methods void Initialize(string str, object font, int size) { if (size < 0) throw new ArgumentException("Font size must be greater than 0."); if (font is string) { this.font = (string)font == "" ? Fonts.DefaultFont : Fonts.Load((string)font); } else if (font is Font) { this.font = ((Font) font).font; } else if (font is SFML.Graphics.Font) { this.font = (SFML.Graphics.Font)font; } else { this.font = Fonts.Load((Stream) font); } text = new SFML.Graphics.Text(str, this.font, (uint)size); String = str; Name = "Text"; SFMLDrawable = text; } protected override void UpdateDrawable() { base.UpdateDrawable(); Width = (int)text.GetLocalBounds().Width; Height = (int)text.GetLocalBounds().Height; } #endregion #region Public Methods /// /// Center the Text's origin. This factors in the Text's local bounds. /// public void CenterTextOrigin() { CenterTextOriginX(); CenterTextOriginY(); } /// /// Center the Text's X origin. This factors in the Text's left bounds. /// public void CenterTextOriginX() { OriginX = HalfWidth + BoundsLeft; } /// /// Center the Text's Y origin. This factors in the Text's top bounds. /// public void CenterTextOriginY() { OriginY = HalfHeight + BoundsTop; } /// /// Draw the Text. /// /// The X position offset. /// The Y position offset. public override void Render(float x = 0, float y = 0) { if (isUsingOutline) { var outlineColor = new Color(OutlineColor); outlineColor.A = Color.A; text.Color = outlineColor.SFMLColor; var angleIncrement = (int)OutlineQuality; for (float o = OutlineThickness * 0.5f; o < OutlineThickness; o += 0.5f) { for (int a = 0; a < 360; a += angleIncrement) { var rx = x + Util.PolarX(a, o); var ry = y + Util.PolarY(a, o); base.Render(rx, ry); } } } if (isUsingShadow) { var shadowColor = new Color(ShadowColor); shadowColor.A = Color.A; text.Color = shadowColor.SFMLColor; base.Render(x + ShadowX, y + ShadowY); } text.Color = Color.SFMLColor; base.Render(x, y); } #endregion #region Internal internal SFML.Graphics.Text text; internal SFML.Graphics.Font font; #endregion } #region Enum [Flags] public enum TextStyle { Regular = 0, Bold = 1, Italic = 2, Underlined = 4, } public enum TextOutlineQuality { Good = 45, Better = 30, Best = 15, Absurd = 10 } #endregion }