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
}