Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/LapinerTools/uMyGUI/uMyGUI_TreeBrowser.cs
2026-02-21 16:45:37 +08:00

595 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace LapinerTools.uMyGUI
{
public class uMyGUI_TreeBrowser : MonoBehaviour
{
public class Node
{
public readonly object SendMessageData;
public readonly Node[] Children;
public Node(object p_sendMessageData, Node[] p_children)
{
SendMessageData = p_sendMessageData;
Children = p_children;
}
}
public class NodeClickEventArgs : EventArgs
{
public readonly Node ClickedNode;
public NodeClickEventArgs(Node p_clickedNode)
{
ClickedNode = p_clickedNode;
}
}
public class NodeInstantiateEventArgs : EventArgs
{
public readonly Node Node;
public readonly GameObject Instance;
public NodeInstantiateEventArgs(Node p_node, GameObject p_instance)
{
Node = p_node;
Instance = p_instance;
}
}
private class InternalNode
{
public readonly Node m_node;
public GameObject m_instance;
public int m_indentLevel;
public RectTransform m_transform;
public bool m_isFoldout;
public float m_minY;
public InternalNode(Node p_node, GameObject p_instance, int p_indentLevel)
{
m_node = p_node;
m_instance = p_instance;
m_indentLevel = p_indentLevel;
m_transform = m_instance.GetComponent<RectTransform>();
}
}
[SerializeField]
private GameObject m_innerNodePrefab;
[SerializeField]
private GameObject m_leafNodePrefab;
[SerializeField]
private float m_offsetStart;
[SerializeField]
private float m_offsetEnd;
[SerializeField]
private float m_padding = 4f;
[SerializeField]
private float m_indentSize = 20f;
[SerializeField]
private float m_forcedEntryHeight;
[SerializeField]
private bool m_useExplicitNavigation;
[SerializeField]
private float m_navScrollSpeed = 200f;
[SerializeField]
private float m_navScrollSmooth = 20f;
private ScrollRect m_parentScroller;
public EventHandler<NodeClickEventArgs> OnInnerNodeClick;
public EventHandler<NodeClickEventArgs> OnLeafNodeClick;
public EventHandler<NodeClickEventArgs> OnLeafNodePointerDown;
public EventHandler<NodeInstantiateEventArgs> OnNodeInstantiate;
private RectTransform m_rectTransform;
private List<InternalNode> m_nodes = new List<InternalNode>();
private GameObject m_lastSelectedGO;
public GameObject InnerNodePrefab
{
get
{
return m_innerNodePrefab;
}
set
{
m_innerNodePrefab = value;
}
}
public GameObject LeafNodePrefab
{
get
{
return m_leafNodePrefab;
}
set
{
m_leafNodePrefab = value;
}
}
public float OffsetStart
{
get
{
return m_offsetStart;
}
set
{
m_offsetStart = value;
}
}
public float OffsetEnd
{
get
{
return m_offsetEnd;
}
set
{
m_offsetEnd = value;
}
}
public float Padding
{
get
{
return m_padding;
}
set
{
m_padding = value;
}
}
public float IndentSize
{
get
{
return m_indentSize;
}
set
{
m_indentSize = value;
}
}
public float ForcedEntryHeight
{
get
{
return m_forcedEntryHeight;
}
set
{
m_forcedEntryHeight = value;
}
}
public bool UseExplicitNavigation
{
get
{
return m_useExplicitNavigation;
}
set
{
m_useExplicitNavigation = value;
}
}
public float NavScrollSpeed
{
get
{
return m_navScrollSpeed;
}
set
{
m_navScrollSpeed = value;
}
}
public float NavScrollSmooth
{
get
{
return m_navScrollSmooth;
}
set
{
m_navScrollSmooth = value;
}
}
public ScrollRect ParentScroller
{
get
{
return m_parentScroller;
}
}
private RectTransform RTransform
{
get
{
return (!(m_rectTransform != null)) ? (m_rectTransform = GetComponent<RectTransform>()) : m_rectTransform;
}
}
public void BuildTree(Node[] p_rootNodes)
{
BuildTree(p_rootNodes, 0, 0);
}
public void BuildTree(Node[] p_rootNodes, int p_insertAt, int p_indentLevel)
{
if (m_innerNodePrefab != null && m_leafNodePrefab != null)
{
List<InternalNode> list = new List<InternalNode>();
float num = 0f;
float p_currY = ((m_nodes.Count < p_insertAt || p_insertAt <= 0) ? (0f - m_offsetStart) : m_nodes[p_insertAt - 1].m_minY);
for (int i = 0; i < p_rootNodes.Length; i++)
{
if (p_rootNodes[i] == null)
{
continue;
}
bool flag = p_rootNodes[i].Children != null && p_rootNodes[i].Children.Length > 0;
GameObject gameObject = ((!flag) ? UnityEngine.Object.Instantiate(m_leafNodePrefab) : UnityEngine.Object.Instantiate(m_innerNodePrefab));
RectTransform component = gameObject.GetComponent<RectTransform>();
if (m_forcedEntryHeight != 0f)
{
component.sizeDelta = new Vector2(component.sizeDelta.x, m_forcedEntryHeight);
}
float height = component.rect.height;
if (p_rootNodes[i].SendMessageData != null)
{
if (!gameObject.activeInHierarchy)
{
Debug.LogError("uMyGUI_TreeBrowser: BuildTree: node has SendMessageData set, but instance is inactive! SendMessage call will fail! Make your prefab active!");
}
gameObject.SendMessage("uMyGUI_TreeBrowser_InitNode", p_rootNodes[i].SendMessageData);
}
InternalNode internalNode = new InternalNode(p_rootNodes[i], gameObject, p_indentLevel);
list.Add(internalNode);
if (flag)
{
SetupInnerNode(internalNode);
}
else
{
SetupLeafNode(internalNode);
}
p_currY = SetRectTransformPosition(component, p_currY, height, p_indentLevel);
internalNode.m_minY = component.anchoredPosition.y - height;
num = internalNode.m_minY;
if (OnNodeInstantiate != null)
{
OnNodeInstantiate(this, new NodeInstantiateEventArgs(p_rootNodes[i], gameObject));
}
}
if (p_insertAt < m_nodes.Count)
{
float p_moveDist = ((p_insertAt != 0) ? (num - m_nodes[p_insertAt - 1].m_minY) : num);
UpdateNodePosition(p_insertAt, p_moveDist);
}
if (p_insertAt < m_nodes.Count)
{
m_nodes.InsertRange(p_insertAt, list);
}
else
{
m_nodes.AddRange(list);
}
if (m_nodes.Count > 0)
{
RTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, Mathf.Abs(m_nodes[m_nodes.Count - 1].m_minY - RTransform.rect.yMax - m_offsetEnd));
}
if (m_useExplicitNavigation)
{
SetExplicitNavigationTargets();
}
}
else
{
Debug.LogError("uMyGUI_TreeBrowser: BuildTree: you must provide the InnerNodePrefab and LeafNodePrefab in the inspector or via script!");
}
}
public void Clear()
{
for (int i = 0; i < m_nodes.Count; i++)
{
UnityEngine.Object.Destroy(m_nodes[i].m_instance);
}
m_nodes.Clear();
}
private void Start()
{
m_parentScroller = GetComponentInParent<ScrollRect>();
}
private void LateUpdate()
{
if (m_parentScroller == null)
{
return;
}
EventSystem current = EventSystem.current;
GameObject currentSelectedGameObject;
if (current != null && (currentSelectedGameObject = current.currentSelectedGameObject) != null && currentSelectedGameObject.transform.IsChildOf(base.transform))
{
if (!(currentSelectedGameObject != m_lastSelectedGO))
{
return;
}
m_lastSelectedGO = currentSelectedGameObject;
Transform parent = currentSelectedGameObject.transform;
while (parent.parent != base.transform && parent.parent != null)
{
parent = parent.parent;
}
RectTransform component = parent.GetComponent<RectTransform>();
if (component == null)
{
return;
}
Vector3[] array = new Vector3[4];
component.GetWorldCorners(array);
for (int i = 0; i < array.Length; i++)
{
array[i] = m_parentScroller.transform.InverseTransformPoint(array[i]);
}
Vector3 vector = Vector3.Min(Vector3.Min(array[0], array[1]), Vector3.Min(array[2], array[3]));
Vector3 vector2 = Vector3.Max(Vector3.Max(array[0], array[1]), Vector3.Max(array[2], array[3]));
m_parentScroller.GetComponent<RectTransform>().GetLocalCorners(array);
Vector3 vector3 = Vector3.Min(Vector3.Min(array[0], array[1]), Vector3.Min(array[2], array[3]));
Vector3 vector4 = Vector3.Max(Vector3.Max(array[0], array[1]), Vector3.Max(array[2], array[3]));
if (vector.y < vector3.y)
{
if (m_parentScroller.verticalNormalizedPosition >= 1f)
{
m_parentScroller.verticalNormalizedPosition = 0.999f;
}
m_parentScroller.velocity = Vector3.up * Mathf.Max(5f, m_navScrollSpeed * ((m_navScrollSmooth == 0f) ? 1f : ((vector3.y - vector.y) / m_navScrollSmooth)));
m_lastSelectedGO = null;
}
else if (vector2.y > vector4.y)
{
if (m_parentScroller.verticalNormalizedPosition <= 0f)
{
m_parentScroller.verticalNormalizedPosition = 0.001f;
}
m_parentScroller.velocity = Vector3.down * Mathf.Max(5f, m_navScrollSpeed * ((m_navScrollSmooth == 0f) ? 1f : ((vector2.y - vector4.y) / m_navScrollSmooth)));
m_lastSelectedGO = null;
}
}
else
{
m_lastSelectedGO = null;
}
}
private void OnDestroy()
{
OnInnerNodeClick = null;
OnLeafNodeClick = null;
OnNodeInstantiate = null;
}
private void SetExplicitNavigationTargets()
{
if (m_nodes.Count <= 2)
{
return;
}
RectTransform rectTransform = m_nodes[0].m_transform;
RectTransform rectTransform2 = m_nodes[1].m_transform;
Selectable[] array = rectTransform.GetComponentsInChildren<Selectable>();
Selectable[] componentsInChildren = rectTransform2.GetComponentsInChildren<Selectable>();
SetAutomaticNavigation(m_nodes[0].m_transform);
SetAutomaticNavigation(m_nodes[m_nodes.Count - 1].m_transform);
for (int i = 1; i < m_nodes.Count - 1; i++)
{
RectTransform rectTransform3 = rectTransform;
rectTransform = rectTransform2;
rectTransform2 = m_nodes[i + 1].m_transform;
Selectable[] array2 = array;
array = componentsInChildren;
componentsInChildren = rectTransform2.GetComponentsInChildren<Selectable>();
if (rectTransform3 != null && rectTransform != null && rectTransform2 != null && array2.Length == array.Length && componentsInChildren.Length == array.Length)
{
for (int j = 0; j < array.Length; j++)
{
Navigation navigation = array[j].navigation;
navigation.mode = Navigation.Mode.Explicit;
navigation.selectOnUp = array2[j];
navigation.selectOnDown = componentsInChildren[j];
array[j].navigation = navigation;
}
}
}
}
private void SetAutomaticNavigation(RectTransform p_nodeTransform)
{
if (p_nodeTransform != null)
{
Selectable[] componentsInChildren = p_nodeTransform.GetComponentsInChildren<Selectable>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
Navigation navigation = componentsInChildren[i].navigation;
navigation.mode = Navigation.Mode.Automatic;
componentsInChildren[i].navigation = navigation;
}
}
}
private float SetRectTransformPosition(RectTransform p_transform, float p_currY, float p_size, int p_indentLevel)
{
p_transform.SetParent(RTransform, false);
Vector2 anchoredPosition = p_transform.anchoredPosition;
anchoredPosition.x += (float)p_indentLevel * m_indentSize;
anchoredPosition.y += p_currY;
p_currY -= m_padding + p_size;
p_transform.anchoredPosition = anchoredPosition;
return p_currY;
}
private void UpdateNodePosition(int p_startIndex, float p_moveDist)
{
for (int i = p_startIndex; i < m_nodes.Count; i++)
{
Vector2 anchoredPosition = m_nodes[i].m_transform.anchoredPosition;
anchoredPosition.y += p_moveDist;
m_nodes[i].m_transform.anchoredPosition = anchoredPosition;
m_nodes[i].m_minY = anchoredPosition.y - m_nodes[i].m_transform.rect.height;
}
}
private void SetupInnerNode(InternalNode p_node)
{
if (p_node.m_instance.GetComponent<Button>() != null)
{
p_node.m_instance.GetComponent<Button>().onClick.AddListener(delegate
{
ToggleInnerNodeFoldout(p_node);
});
}
else if (p_node.m_instance.GetComponent<Toggle>() != null)
{
p_node.m_instance.GetComponent<Toggle>().onValueChanged.AddListener(delegate
{
ToggleInnerNodeFoldout(p_node);
});
}
else
{
Debug.LogError("uMyGUI_TreeBrowser: BuildTree: the inner node prefabs must have either a Button or a Toggle script attached to the root. Otherwise they cannot fold out!");
}
}
private void SetupLeafNode(InternalNode p_node)
{
if (p_node.m_instance.GetComponent<Button>() != null)
{
p_node.m_instance.GetComponent<Button>().onClick.AddListener(delegate
{
SafeCallOnLeafNodeClick(p_node);
});
}
else if (p_node.m_instance.GetComponent<Toggle>() != null)
{
p_node.m_instance.GetComponent<Toggle>().onValueChanged.AddListener(delegate
{
SafeCallOnLeafNodeClick(p_node);
});
}
EventTrigger eventTrigger = p_node.m_instance.GetComponent<EventTrigger>();
if (eventTrigger == null)
{
eventTrigger = p_node.m_instance.AddComponent<EventTrigger>();
}
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerDown;
EventTrigger.TriggerEvent triggerEvent = new EventTrigger.TriggerEvent();
triggerEvent.AddListener(delegate
{
SafeCallOnLeafNodePointerDown(p_node);
});
entry.callback = triggerEvent;
if (eventTrigger.triggers == null)
{
eventTrigger.triggers = new List<EventTrigger.Entry>();
}
eventTrigger.triggers.Add(entry);
}
private void ToggleInnerNodeFoldout(InternalNode p_node)
{
int num = m_nodes.IndexOf(p_node);
p_node.m_isFoldout = !p_node.m_isFoldout;
if (p_node.m_isFoldout)
{
BuildTree(p_node.m_node.Children, num + 1, p_node.m_indentLevel + 1);
}
else
{
float num2 = 0f;
for (int i = 0; i < p_node.m_node.Children.Length; i++)
{
int index = num + p_node.m_node.Children.Length - i;
InternalNode internalNode = m_nodes[index];
num2 += internalNode.m_transform.rect.height;
if (i + 1 < p_node.m_node.Children.Length)
{
num2 += m_padding;
}
if (internalNode.m_isFoldout)
{
ToggleInnerNodeFoldout(internalNode);
}
m_nodes.RemoveAt(index);
UnityEngine.Object.Destroy(internalNode.m_instance);
}
UpdateNodePosition(num + 1, num2);
RTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, RTransform.sizeDelta.y - num2);
}
if (OnInnerNodeClick != null)
{
OnInnerNodeClick(this, new NodeClickEventArgs(p_node.m_node));
}
}
private void SafeCallOnLeafNodePointerDown(InternalNode p_node)
{
if (OnLeafNodePointerDown != null)
{
OnLeafNodePointerDown(this, new NodeClickEventArgs(p_node.m_node));
}
}
private void SafeCallOnLeafNodeClick(InternalNode p_node)
{
if (OnLeafNodeClick != null)
{
OnLeafNodeClick(this, new NodeClickEventArgs(p_node.m_node));
}
}
}
}