using UnityEngine; using System.Collections.Generic; using System.Text; namespace PixelCrushers.DialogueSystem.UnityGUI { /// /// A GUI control that implements GUI.Label to display text and/or a texture. /// [AddComponentMenu("")] // Deprecated public class GUILabel : GUIVisibleControl { /// /// The text style for the text. /// public TextStyle textStyle = TextStyle.None; /// /// The color of the text style's outline or shadow. /// public Color textStyleColor = Color.black; /// /// The color to tint the image. /// public Color imageColor = Color.white; /// /// An image to display (may be unassigned). /// public Texture2D image; /// /// The image animation settings. /// public ImageAnimation imageAnimation = new ImageAnimation(); /// /// The rich text closure tags to apply. This is used by the typewriter effect /// to close rich text tags correctly before the whole line is done. This list /// acts as a stack. /// private List closureTags = new List(); /// /// Gets or sets the length of the current amount of text to display. This is a support /// property for effects like TypewriterEffect. /// /// /// The length of the current substring. /// public int currentLength { get { return substringLength; } set { substringLength = value; useSubstring = !string.IsNullOrEmpty(text) && (substringLength < text.Length); } } /// /// If true use only a substring of the text. /// private bool useSubstring = false; /// /// The length of the substring. /// private int substringLength = 0; /// /// The substring length the last time GetRichTextClosedString() was called. /// We keep track of this so we don't need to build the rich text-closed string /// every OnGUI update. /// private int substringLengthLastGetRichTextClosedString = 0; /// /// The rich text-closed string. /// private string richTextClosedString = string.Empty; public override void Awake() { base.Awake(); ResetClosureTags(); } /// /// Resets the stack of rich text tags to close. /// public void ResetClosureTags() { closureTags.Clear(); } /// /// Adds a closure tag to the stack. /// /// Tag. public void PushClosureTag(string tag) { closureTags.Add(tag); } /// /// Pops the top closure tag from the stack. /// /// Tag. public void PopClosureTag() { if (closureTags.Count > 0) closureTags.RemoveAt(closureTags.Count - 1); } /// /// Sets the control's text and formatting. Also resets the rich text tag count. /// /// Formatted text. public override void SetFormattedText(FormattedText formattedText) { base.SetFormattedText(formattedText); ResetClosureTags(); } /// /// Draws the control, but not its children. /// /// Relative mouse position within the window containing this control. public override void DrawSelf(Vector2 relativeMousePosition) { ApplyAlphaToGUIColor(); if (image != null) { DrawImage(); } if (!string.IsNullOrEmpty(text)) { if (useSubstring) { DrawSubstring(); } else { UnityGUITools.DrawText(rect, text, GuiStyle, textStyle, textStyleColor); } } RestoreGUIColor(); } private void DrawSubstring() { //--- Was: (Used Unity's left align, but caused ugly word backtrace at end of lines) if (IsLeftAligned(GuiStyle.alignment)) { // UnityGUITools.DrawText(rect, GetRichTextClosedText(text.Substring(0, substringLength)), GuiStyle, textStyle, textStyleColor); DrawSubstringLeftAligned(); } else { DrawSubstringNotLeftAligned(); } } private bool IsLeftAligned(TextAnchor textAnchor) { return (textAnchor == TextAnchor.LowerLeft) || (textAnchor == TextAnchor.MiddleLeft) || (textAnchor == TextAnchor.UpperLeft); } private bool IsCenterAligned(TextAnchor textAnchor) { return (textAnchor == TextAnchor.LowerCenter) || (textAnchor == TextAnchor.MiddleCenter) || (textAnchor == TextAnchor.UpperCenter); } private TextAnchor GetLeftAlignedVersion(TextAnchor textAnchor) { switch (textAnchor) { case TextAnchor.LowerCenter: case TextAnchor.LowerRight: return TextAnchor.LowerLeft; case TextAnchor.MiddleCenter: case TextAnchor.MiddleRight: return TextAnchor.MiddleLeft; case TextAnchor.UpperCenter: case TextAnchor.UpperRight: return TextAnchor.UpperLeft; default: return textAnchor; } } private void DrawSubstringLeftAligned() { var currText = string.Empty; int start = 0; int charsLeft = substringLength; while (charsLeft > 0) { string line = GetNextLine(text, start); string subLine = line.Substring(0, Mathf.Min(line.Length, charsLeft)); start += line.Length; charsLeft -= line.Length; if (string.IsNullOrEmpty(currText)) { currText = subLine; } else { currText += "\n" + subLine; } } UnityGUITools.DrawText(rect, GetRichTextClosedText(currText), GuiStyle, textStyle, textStyleColor); } private void DrawSubstringNotLeftAligned() { TextAnchor originalAlignment = GuiStyle.alignment; bool originalWordWrap = GuiStyle.wordWrap; GuiStyle.alignment = GetLeftAlignedVersion(GuiStyle.alignment); GuiStyle.wordWrap = false; float lineHeight = GuiStyle.CalcSize(new GUIContent(text)).y; float y = rect.y; int start = 0; int charsLeft = substringLength; while (charsLeft > 0) { string line = GetNextLine(text, start); string subLine = line.Substring(0, Mathf.Min(line.Length, charsLeft)); start += line.Length; charsLeft -= line.Length; float lineWidth = GuiStyle.CalcSize(new GUIContent(line.Trim())).x; float x = IsCenterAligned(originalAlignment) ? Mathf.Ceil(rect.x + (0.5f * rect.width) - (0.5f * lineWidth)) + 0.5f : rect.x + rect.width - lineWidth; UnityGUITools.DrawText(new Rect(x, y, rect.width, lineHeight), GetRichTextClosedText(subLine.Trim()), GuiStyle, textStyle, textStyleColor); y += GuiStyle.lineHeight; } GuiStyle.alignment = originalAlignment; GuiStyle.wordWrap = originalWordWrap; } private string GetNextLine(string text, int start) { string remainder = text.Substring(start); int lastSpace = 0; if (GuiStyle.CalcSize(new GUIContent(remainder.Trim())).x > rect.width) { int length = 1; while (start + length < text.Length) { string candidate = text.Substring(start, length + 1); if (text[start + length] == ' ') lastSpace = length; float width = GuiStyle.CalcSize(new GUIContent(candidate.Trim())).x; if (width < rect.width) { length++; } else { int maxLength = remainder.Length; if (lastSpace > 0) { return text.Substring(start, Mathf.Max(1, Mathf.Min(lastSpace, maxLength))); } else { return text.Substring(start, Mathf.Max(1, Mathf.Min(length - 1, maxLength))); } } } } return remainder; } /// /// Adds rich text closure tags if necessary. /// /// The rich text closed text. /// The source string. private string GetRichTextClosedText(string s) { if (closureTags.Count == 0) { return s; } else { if (substringLength != substringLengthLastGetRichTextClosedString) { substringLengthLastGetRichTextClosedString = substringLength; StringBuilder sb = new StringBuilder(s); for (int i = closureTags.Count - 1; i >= 0; i--) { sb.Append(closureTags[i]); } richTextClosedString = sb.ToString(); } return richTextClosedString; } } private void DrawImage() { Color originalColor = GUI.color; GUI.color = imageColor; if (imageAnimation.animate) { imageAnimation.DrawAnimation(rect, image); } else { GUI.Label(rect, image, GuiStyle); } GUI.color = originalColor; } public override void Refresh() { base.Refresh(); if (imageAnimation.animate) imageAnimation.RefreshAnimation(image); } } }