Files
2026-02-21 16:45:37 +08:00

364 lines
6.5 KiB
C#

using System;
using System.ComponentModel;
using System.Linq;
using UnityEngine;
namespace UIWidgets
{
[Serializable]
public class TreeNode<TItem> : IObservable, IDisposable, INotifyPropertyChanged
{
public bool PauseObservation;
[SerializeField]
private bool isVisible = true;
[SerializeField]
private bool isExpanded;
[SerializeField]
private TItem item;
[SerializeField]
private IObservableList<TreeNode<TItem>> 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<TreeNode<TItem>> 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<TItem> 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<TItem> x) => x.AllUsedNodesCount) + UsedNodesCount;
}
}
public TreeNode<TItem> Parent
{
get
{
if (parent != null && parent.IsAlive)
{
return parent.Target as TreeNode<TItem>;
}
return null;
}
set
{
SetParentValue(value);
}
}
public event OnChange OnChange;
public event PropertyChangedEventHandler PropertyChanged;
public TreeNode(TItem nodeItem, IObservableList<TreeNode<TItem>> 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<TItem> node)
{
TreeNode<TItem> treeNode = node.Parent;
while (treeNode != null)
{
if (treeNode == this)
{
return true;
}
treeNode = treeNode.Parent;
}
return false;
}
public bool CanBeParent(TreeNode<TItem> newParent)
{
if (this == newParent)
{
return false;
}
return !IsParentOfNode(newParent);
}
private void SetParentValue(TreeNode<TItem> newParent)
{
TreeNode<TItem> treeNode = ((parent == null || !parent.IsAlive) ? null : (parent.Target as TreeNode<TItem>));
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<TreeNode<TItem>>();
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<TItem> 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<TItem> treeNode = obj as TreeNode<TItem>;
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<TItem> a, TreeNode<TItem> 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<TItem> a, TreeNode<TItem> 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<TItem> 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);
}
}
}