using System; using System.Collections.Generic; using System.Linq; using System.Text; using Unity.UIWidgets.foundation; using Unity.UIWidgets.gestures; using Unity.UIWidgets.ui; using UnityEngine.Assertions; namespace Unity.UIWidgets.painting { public class GestureMock { } public class TextSpan: DiagnosticableTree, IEquatable { public delegate bool Visitor(TextSpan span); public readonly TextStyle style; public readonly string text; public readonly List children; public readonly GestureRecognizer recognizer; public TextSpan(string text = "", TextStyle style = null, List children = null) { this.text = text; this.style = style; this.children = children; } public void build(ParagraphBuilder builder, double textScaleFactor = 1.0) { var hasTyle = style != null; if (hasTyle) { builder.pushStyle(style); } if (!string.IsNullOrEmpty(text)) { builder.addText(text); } if (children != null) { foreach (var child in children) { Assert.IsNotNull(child); child.build(builder, textScaleFactor); } } if (hasTyle) { builder.pop(); } } bool visitTextSpan(Visitor visitor) { if (!string.IsNullOrEmpty(text)) { if (!visitor.Invoke(this)) { return false; } } if (children != null) { foreach (var child in children) { if (!child.visitTextSpan(visitor)) { return false; } } } return true; } TextSpan getSpanForPosition(TextPosition position) { var offset = 0; var targetOffset = position.offset; var affinity = position.affinity; TextSpan result = null; visitTextSpan((span) => { var endOffset = offset + span.text.Length; if ((targetOffset == offset && affinity == TextAffinity.downstream) || (targetOffset > offset && targetOffset < endOffset) || (targetOffset == endOffset && affinity == TextAffinity.upstream)) { result = span; return false; } offset = endOffset; return true; }); return result; } public string toPlainText() { var sb = new StringBuilder(); visitTextSpan((span) => { sb.Append(span.text); return true; }); return sb.ToString(); } public int? codeUnitAt(int index) { if (index < 0) { return null; } var offset = 0; int? result = null; visitTextSpan(span => { if (index - offset < span.text.Length) { result = span.text[index - offset]; return false; } offset += span.text.Length; return true; }); return result; } public RenderComparison compareTo(TextSpan other) { if (Equals(other)) { return RenderComparison.identical; } if (other.text != text || ((children == null) != (other.children == null)) || (children != null && other.children != null && children.Count != other.children.Count) || ((style == null) != (other.style != null)) ) { return RenderComparison.layout; } RenderComparison result = Equals(recognizer, other.recognizer) ? RenderComparison.identical : RenderComparison.metadata; if (style != null) { var candidate = style.compareTo(other.style); if (candidate > result) { result = candidate; } if (result == RenderComparison.layout) { return result; } } if (children != null) { for (var index = 0; index < children.Count; index++) { var candidate = children[index].compareTo(other.children[index]); if (candidate > result) { result = candidate; } if (result == RenderComparison.layout) { return result; } } } return result; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((TextSpan) obj); } public override int GetHashCode() { unchecked { var hashCode = (style != null ? style.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (text != null ? text.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (childHash()); return hashCode; } } public bool Equals(TextSpan other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(style, other.style) && string.Equals(text, other.text) && childEquals(children, other.children); } public static bool operator ==(TextSpan left, TextSpan right) { return Equals(left, right); } public static bool operator !=(TextSpan left, TextSpan right) { return !Equals(left, right); } private int childHash() { unchecked { var hashCode = 0; if (children != null) { foreach (var child in children) { hashCode = (hashCode * 397) ^ (child != null ? child.GetHashCode() : 0); } } return hashCode; } } private static bool childEquals(List left, List right) { if (ReferenceEquals(left, right)) { return true; } if (left == null || right == null) { return false; } return left.SequenceEqual(right); } public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.whitespace; // Properties on style are added as if they were properties directly on // this TextSpan. if (style != null) { style.debugFillProperties(properties); } properties.add(new DiagnosticsProperty( "recognizer", recognizer, description: recognizer == null ? "" : recognizer.GetType().FullName, defaultValue: Diagnostics.kNullDefaultValue )); properties.add(new StringProperty("text", text, showName: false, defaultValue: Diagnostics.kNullDefaultValue)); if (style == null && text == null && children == null) { properties.add(DiagnosticsNode.message("(empty)")); } } public override List debugDescribeChildren() { if (children == null) { return new List(); } return children.Select((child) => { if (child != null) { return child.toDiagnosticsNode(); } else { return DiagnosticsNode.message(""); } }).ToList(); } } }