using System; using System.Collections.Generic; using System.Text; using UnityEngine; namespace Unity.Burst.Editor { internal class LongTextArea { private const int kMaxFragment = 2048; private struct Fragment { public int lineCount; public string text; } private string m_Text = ""; private List m_Fragments = null; private Vector2[] m_AreaSizes = null; private bool invalidated = true; private Vector2 finalAreaSize; public string Text { get { return m_Text; } set { if (value != m_Text) { m_Text = value; m_Fragments = RecomputeFragments(m_Text); invalidated = true; m_AreaSizes = new Vector2[m_Fragments.Count]; } } } // Changing the font size doesn't update the text field, so added this to force a recalculation public void Invalidate() { invalidated = true; } public void Render(GUIStyle style, Vector2 scrollPos, Rect workingArea) { // working area will be valid only during repaint, for the layout event we don't draw the labels style.richText = true; if (invalidated) { invalidated = false; int sizeIdx = 0; finalAreaSize = new Vector2(0.0f, 0.0f); foreach (var frag in m_Fragments) { var size = style.CalcSize(new GUIContent(frag.text)); finalAreaSize.x = Math.Max(finalAreaSize.x, size.x); finalAreaSize.y += size.y + style.padding.vertical; m_AreaSizes[sizeIdx++] = size; } } GUILayoutUtility.GetRect(finalAreaSize.x,finalAreaSize.y); // NB we don't use workingArea or scrollPos, but if we find rendering is still too slow at a later date, we can use // these values to decide which chunks to render if (Event.current.type == EventType.Repaint) { float positionY = 0.0f; int sizeIdx = 0; foreach (var fragment in m_Fragments) { var size = m_AreaSizes[sizeIdx++]; GUI.Label(new Rect(0.0f, positionY, finalAreaSize.x, size.y), fragment.text, style); positionY += size.y + style.padding.vertical; } } } private static List RecomputeFragments(string text) { List result = new List(); string[] pieces = text.Split('\n'); StringBuilder b = new StringBuilder(); int lineCount = 0; foreach (var piece in pieces) { if (b.Length >= kMaxFragment) { AddFragment(b, lineCount, result); lineCount = 0; } if (b.Length > 0) b.Append('\n'); b.Append(piece); lineCount++; } AddFragment(b, lineCount, result); return result; } private static void AddFragment(StringBuilder b, int lineCount, List result) { result.Add(new Fragment() { text = b.ToString(), lineCount = lineCount }); b.Length = 0; } } }