using System; using System.ComponentModel; using System.Linq; using UnityEngine; namespace UIWidgets { [Serializable] public class TreeNode : IObservable, IDisposable, INotifyPropertyChanged { public bool PauseObservation; [SerializeField] private bool isVisible = true; [SerializeField] private bool isExpanded; [SerializeField] private TItem item; [SerializeField] private IObservableList> nodes; public int UsedNodesCount; private WeakReference parent; private bool disposed; public bool IsVisible { get { return isVisible; } set { isVisible = value; Changed("IsVisible"); } } public bool IsExpanded { get { return isExpanded; } set { isExpanded = value; Changed("IsExpanded"); } } public TItem Item { get { return item; } set { item = value; Changed("Item"); } } public IObservableList> Nodes { get { return nodes; } set { if (nodes != null) { nodes.OnChange -= Changed; nodes.OnCollectionChange -= CollectionChanged; } nodes = value; if (nodes != null) { nodes.OnChange += Changed; nodes.OnCollectionChange += CollectionChanged; CollectionChanged(); } Changed("Nodes"); } } public int TotalNodesCount { get { if (nodes == null) { return 1; } return nodes.Sum((TreeNode x) => x.TotalNodesCount) + 1; } } public int AllUsedNodesCount { get { if (!isVisible) { return 0; } if (!isExpanded) { return UsedNodesCount; } if (nodes == null) { return UsedNodesCount; } return nodes.Sum((TreeNode x) => x.AllUsedNodesCount) + UsedNodesCount; } } public TreeNode Parent { get { if (parent != null && parent.IsAlive) { return parent.Target as TreeNode; } return null; } set { SetParentValue(value); } } public event OnChange OnChange; public event PropertyChangedEventHandler PropertyChanged; public TreeNode(TItem nodeItem, IObservableList> nodeNodes = null, bool nodeIsExpanded = false, bool nodeIsVisible = true) { item = nodeItem; nodes = nodeNodes; isExpanded = nodeIsExpanded; isVisible = nodeIsVisible; if (nodes != null) { nodes.OnChange += Changed; nodes.OnCollectionChange += CollectionChanged; CollectionChanged(); } } public bool IsParentOfNode(TreeNode node) { TreeNode treeNode = node.Parent; while (treeNode != null) { if (treeNode == this) { return true; } treeNode = treeNode.Parent; } return false; } public bool CanBeParent(TreeNode newParent) { if (this == newParent) { return false; } return !IsParentOfNode(newParent); } private void SetParentValue(TreeNode newParent) { TreeNode treeNode = ((parent == null || !parent.IsAlive) ? null : (parent.Target as TreeNode)); if (treeNode == newParent) { return; } if (newParent != null) { if (newParent == this) { throw new ArgumentException("Node cannot be own parent."); } if (IsParentOfNode(newParent)) { throw new ArgumentException("Own child node cannot be parent node."); } } if (treeNode != null) { treeNode.nodes.OnCollectionChange -= treeNode.CollectionChanged; treeNode.nodes.Remove(this); treeNode.nodes.OnCollectionChange += treeNode.CollectionChanged; } parent = new WeakReference(newParent); if (newParent != null) { if (newParent.nodes == null) { newParent.nodes = new ObservableList>(); newParent.nodes.OnChange += newParent.Changed; newParent.nodes.OnCollectionChange += newParent.CollectionChanged; } newParent.nodes.OnCollectionChange -= newParent.CollectionChanged; newParent.nodes.Add(this); newParent.nodes.OnCollectionChange += newParent.CollectionChanged; } } private void CollectionChanged() { if (nodes != null) { nodes.ForEach(SetParent); } } private void SetParent(TreeNode node) { if (node.Parent != null && node.Parent != this) { node.Parent.nodes.Remove(node); } node.parent = new WeakReference(this); } private void Changed() { Changed("Nodes"); } private void Changed(string propertyName) { if (!PauseObservation) { if (this.OnChange != null) { this.OnChange(); } if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } public override bool Equals(object obj) { TreeNode treeNode = obj as TreeNode; if (treeNode == null) { return this == null; } if (this == null) { return false; } return item.Equals(treeNode.item); } public override int GetHashCode() { return base.GetHashCode(); } public static bool operator ==(TreeNode a, TreeNode b) { bool flag = object.ReferenceEquals(null, a); bool flag2 = object.ReferenceEquals(null, b); if (flag && flag2) { return true; } if (flag != flag2) { return false; } bool flag3 = object.ReferenceEquals(null, a.item); bool flag4 = object.ReferenceEquals(null, b.item); if (flag3 && flag4) { return true; } if (flag3 != flag4) { return false; } return a.item.Equals(b.item); } public static bool operator !=(TreeNode a, TreeNode b) { bool flag = object.ReferenceEquals(null, a); bool flag2 = object.ReferenceEquals(null, b); if (flag && flag2) { return false; } if (flag != flag2) { return true; } bool flag3 = object.ReferenceEquals(null, a.item); bool flag4 = object.ReferenceEquals(null, b.item); if (flag3 && flag4) { return false; } if (flag3 != flag4) { return true; } return !a.item.Equals(b.item); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void DisposeItem(TreeNode node) { node.OnChange -= Changed; node.Dispose(); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { } if (Nodes != null) { Nodes.BeginUpdate(); Nodes.ForEach(DisposeItem); Nodes.EndUpdate(); Nodes = null; } disposed = true; } } ~TreeNode() { Dispose(false); } } }