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

383 lines
8.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using EasyLayout;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace UIWidgets
{
public class TreeViewCustom<TComponent, TItem> : ListViewCustom<TComponent, ListNode<TItem>> where TComponent : ListViewItem
{
[Serializable]
public class NodeEvent : UnityEvent<TreeNode<TItem>>
{
}
[SerializeField]
private IObservableList<TreeNode<TItem>> nodes = new ObservableList<TreeNode<TItem>>();
public NodeEvent NodeToggle = new NodeEvent();
public NodeEvent NodeSelected = new NodeEvent();
public NodeEvent NodeDeselected = new NodeEvent();
protected ObservableList<ListNode<TItem>> NodesList = new ObservableList<ListNode<TItem>>();
[NonSerialized]
private bool isStartedTreeViewCustom;
private TreeNode<TItem> rootNode;
public IObservableList<TreeNode<TItem>> Nodes
{
get
{
return nodes;
}
set
{
if (nodes != null)
{
nodes.OnChange -= NodesChanged;
nodes.OnChange -= CollectionChanged;
}
nodes = value;
RootNode.Nodes = value;
SetScrollValue(0f);
Refresh();
if (nodes != null)
{
nodes.OnChange += NodesChanged;
nodes.OnChange += CollectionChanged;
CollectionChanged();
}
}
}
public TreeNode<TItem> SelectedNode
{
get
{
int count = SelectedNodes.Count;
if (count > 0)
{
return SelectedNodes[count - 1];
}
return null;
}
}
public List<TreeNode<TItem>> SelectedNodes
{
get
{
if (base.SelectedIndex == -1)
{
return new List<TreeNode<TItem>>();
}
return base.SelectedIndicies.Convert((int x) => NodesList[x].Node);
}
set
{
base.SelectedIndicies = Nodes2Indicies(value);
}
}
protected TreeNode<TItem> RootNode
{
get
{
return rootNode;
}
}
protected override void Awake()
{
Start();
}
public override void Start()
{
if (!isStartedTreeViewCustom)
{
isStartedTreeViewCustom = true;
rootNode = new TreeNode<TItem>(default(TItem));
setContentSizeFitter = false;
base.Start();
Refresh();
OnSelect.AddListener(OnSelectNode);
OnDeselect.AddListener(OnDeselectNode);
KeepSelection = true;
base.DataSource = NodesList;
}
}
private void CollectionChanged()
{
if (nodes != null)
{
}
}
private void SetParent(TreeNode<TItem> node)
{
if (node.Parent != RootNode)
{
node.Parent = RootNode;
}
}
protected override bool CanOptimize()
{
bool flag = scrollRect != null;
LayoutGroup layoutGroup = ((!(Container != null)) ? null : (layout ?? Container.GetComponent<LayoutGroup>()));
bool flag2 = layoutGroup is global::EasyLayout.EasyLayout;
return flag && flag2;
}
protected virtual int Nodes2List(IObservableList<TreeNode<TItem>> sourceNodes, int depth, ObservableList<ListNode<TItem>> list)
{
int num = 0;
foreach (TreeNode<TItem> sourceNode in sourceNodes)
{
if (sourceNode.IsVisible)
{
list.Add(new ListNode<TItem>(sourceNode, depth));
if (sourceNode.IsExpanded && sourceNode.Nodes != null && sourceNode.Nodes.Count > 0)
{
int usedNodesCount = Nodes2List(sourceNode.Nodes, depth + 1, list);
sourceNode.UsedNodesCount = usedNodesCount;
}
else
{
sourceNode.UsedNodesCount = 0;
}
num++;
}
}
return num;
}
protected void OnToggleNode(int index)
{
ToggleNode(index);
NodeToggle.Invoke(NodesList[index].Node);
}
protected void OnSelectNode(int index, ListViewItem component)
{
NodeSelected.Invoke(NodesList[index].Node);
}
protected void OnDeselectNode(int index, ListViewItem component)
{
NodeDeselected.Invoke(NodesList[index].Node);
}
protected void ToggleNode(int index)
{
ListNode<TItem> listNode = NodesList[index];
if (listNode.Node.Nodes == null)
{
return;
}
NodesList.BeginUpdate();
if (listNode.Node.IsExpanded)
{
int allUsedNodesCount = listNode.Node.AllUsedNodesCount;
if (allUsedNodesCount > 0)
{
MoveSelectedIndiciesUp(index, allUsedNodesCount);
NodesList.RemoveRange(index + 1, allUsedNodesCount);
}
listNode.Node.PauseObservation = true;
listNode.Node.IsExpanded = false;
listNode.Node.PauseObservation = false;
listNode.Node.UsedNodesCount = 0;
}
else
{
ObservableList<ListNode<TItem>> observableList = new ObservableList<ListNode<TItem>>();
int usedNodesCount = Nodes2List(listNode.Node.Nodes, listNode.Depth + 1, observableList);
MoveSelectedIndiciesDown(index, observableList.Count);
NodesList.InsertRange(index + 1, observableList);
listNode.Node.PauseObservation = true;
listNode.Node.IsExpanded = true;
listNode.Node.PauseObservation = false;
listNode.Node.UsedNodesCount = usedNodesCount;
}
NodesList.EndUpdate();
}
private void MoveSelectedIndiciesUp(int index, int range)
{
int start = index + 1;
int end = start + range;
base.SelectedIndicies.Where((int x) => start <= x && x <= end).ForEach(base.Deselect);
List<int> list = base.SelectedIndicies.Where((int x) => x > end).ToList();
List<int> indicies = list.Select((int x) => x - range).ToList();
SilentDeselect(list);
SilentSelect(indicies);
}
private void MoveSelectedIndiciesDown(int index, int range)
{
int start = index + 1;
int end = start + range;
List<int> list = base.SelectedIndicies.Where((int x) => start <= x && x <= end).ToList();
List<int> indicies = list.Convert((int x) => x + range);
SilentDeselect(list);
SilentSelect(indicies);
}
protected List<int> Nodes2Indicies(IEnumerable<TreeNode<TItem>> targetNodes)
{
return (from x in targetNodes
select NodesList.FindIndex((ListNode<TItem> y) => x == y.Node) into i
where i != -1
select i).ToList();
}
protected virtual void NodesChanged()
{
Refresh();
}
public virtual void Refresh()
{
if (nodes == null)
{
NodesList.Clear();
return;
}
NodesList.BeginUpdate();
List<TreeNode<TItem>> selectedNodes = SelectedNodes;
NodesList.Clear();
Nodes2List(nodes, 0, NodesList);
if (selectedNodes != null)
{
SilentDeselect(base.SelectedIndicies);
List<int> indicies = Nodes2Indicies(selectedNodes);
SilentSelect(indicies);
}
NodesList.EndUpdate();
}
public override void Clear()
{
nodes.Clear();
SetScrollValue(0f);
}
[Obsolete("Not supported for TreeView", true)]
public int Add(TItem item)
{
return -1;
}
[Obsolete("Not supported for TreeView", true)]
public int Remove(TItem item)
{
return -1;
}
public override void Remove(int index)
{
throw new NotSupportedException("Not supported for TreeView.");
}
[Obsolete("Not supported for TreeView", true)]
public int Set(TItem item, bool allowDuplicate = true)
{
return -1;
}
public bool Remove(Predicate<TreeNode<TItem>> match)
{
int num = FindIndex(nodes, match);
if (num != -1)
{
nodes.RemoveAt(num);
return true;
}
foreach (TreeNode<TItem> node in nodes)
{
if (node.Nodes == null || !Remove(node.Nodes, match))
{
continue;
}
return true;
}
return false;
}
private bool Remove(IObservableList<TreeNode<TItem>> nodes, Predicate<TreeNode<TItem>> match)
{
int num = FindIndex(nodes, match);
if (num != -1)
{
nodes.RemoveAt(num);
return true;
}
foreach (TreeNode<TItem> node in nodes)
{
if (node.Nodes == null || !Remove(node.Nodes, match))
{
continue;
}
return true;
}
return false;
}
private int FindIndex(IObservableList<TreeNode<TItem>> nodes, Predicate<TreeNode<TItem>> match)
{
if (nodes is ObservableList<TreeNode<TItem>>)
{
return (nodes as ObservableList<TreeNode<TItem>>).FindIndex(match);
}
for (int i = 0; i < nodes.Count; i++)
{
if (match(nodes[i]))
{
return i;
}
}
return -1;
}
protected override void SetData(TComponent component, ListNode<TItem> item)
{
}
protected override void RemoveCallback(ListViewItem item, int index)
{
if (item != null)
{
(item as TreeViewComponentBase<TItem>).ToggleEvent.RemoveListener(OnToggleNode);
}
base.RemoveCallback(item, index);
}
protected override void AddCallback(ListViewItem item, int index)
{
base.AddCallback(item, index);
(item as TreeViewComponentBase<TItem>).ToggleEvent.AddListener(OnToggleNode);
}
protected override void OnDestroy()
{
OnSelect.RemoveListener(OnSelectNode);
OnDeselect.RemoveListener(OnDeselectNode);
if (Nodes != null)
{
Nodes.Dispose();
}
base.OnDestroy();
}
}
}