using System; using System.Collections.Generic; using System.Linq; using EasyLayout; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; namespace UIWidgets { public class TreeViewCustom : ListViewCustom> where TComponent : ListViewItem { [Serializable] public class NodeEvent : UnityEvent> { } [SerializeField] private IObservableList> nodes = new ObservableList>(); public NodeEvent NodeToggle = new NodeEvent(); public NodeEvent NodeSelected = new NodeEvent(); public NodeEvent NodeDeselected = new NodeEvent(); protected ObservableList> NodesList = new ObservableList>(); [NonSerialized] private bool isStartedTreeViewCustom; private TreeNode rootNode; public IObservableList> 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 SelectedNode { get { int count = SelectedNodes.Count; if (count > 0) { return SelectedNodes[count - 1]; } return null; } } public List> SelectedNodes { get { if (base.SelectedIndex == -1) { return new List>(); } return base.SelectedIndicies.Convert((int x) => NodesList[x].Node); } set { base.SelectedIndicies = Nodes2Indicies(value); } } protected TreeNode RootNode { get { return rootNode; } } protected override void Awake() { Start(); } public override void Start() { if (!isStartedTreeViewCustom) { isStartedTreeViewCustom = true; rootNode = new TreeNode(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 node) { if (node.Parent != RootNode) { node.Parent = RootNode; } } protected override bool CanOptimize() { bool flag = scrollRect != null; LayoutGroup layoutGroup = ((!(Container != null)) ? null : (layout ?? Container.GetComponent())); bool flag2 = layoutGroup is global::EasyLayout.EasyLayout; return flag && flag2; } protected virtual int Nodes2List(IObservableList> sourceNodes, int depth, ObservableList> list) { int num = 0; foreach (TreeNode sourceNode in sourceNodes) { if (sourceNode.IsVisible) { list.Add(new ListNode(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 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> observableList = new ObservableList>(); 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 list = base.SelectedIndicies.Where((int x) => x > end).ToList(); List 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 list = base.SelectedIndicies.Where((int x) => start <= x && x <= end).ToList(); List indicies = list.Convert((int x) => x + range); SilentDeselect(list); SilentSelect(indicies); } protected List Nodes2Indicies(IEnumerable> targetNodes) { return (from x in targetNodes select NodesList.FindIndex((ListNode 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> selectedNodes = SelectedNodes; NodesList.Clear(); Nodes2List(nodes, 0, NodesList); if (selectedNodes != null) { SilentDeselect(base.SelectedIndicies); List 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> match) { int num = FindIndex(nodes, match); if (num != -1) { nodes.RemoveAt(num); return true; } foreach (TreeNode node in nodes) { if (node.Nodes == null || !Remove(node.Nodes, match)) { continue; } return true; } return false; } private bool Remove(IObservableList> nodes, Predicate> match) { int num = FindIndex(nodes, match); if (num != -1) { nodes.RemoveAt(num); return true; } foreach (TreeNode node in nodes) { if (node.Nodes == null || !Remove(node.Nodes, match)) { continue; } return true; } return false; } private int FindIndex(IObservableList> nodes, Predicate> match) { if (nodes is ObservableList>) { return (nodes as ObservableList>).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 item) { } protected override void RemoveCallback(ListViewItem item, int index) { if (item != null) { (item as TreeViewComponentBase).ToggleEvent.RemoveListener(OnToggleNode); } base.RemoveCallback(item, index); } protected override void AddCallback(ListViewItem item, int index) { base.AddCallback(item, index); (item as TreeViewComponentBase).ToggleEvent.AddListener(OnToggleNode); } protected override void OnDestroy() { OnSelect.RemoveListener(OnSelectNode); OnDeselect.RemoveListener(OnDeselectNode); if (Nodes != null) { Nodes.Dispose(); } base.OnDestroy(); } } }