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

500 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
namespace UIWidgets
{
public abstract class ListViewBase : MonoBehaviour, ISelectHandler, IDeselectHandler, ISubmitHandler, ICancelHandler, IEventSystemHandler
{
[SerializeField]
[HideInInspector]
private List<ListViewItem> items = new List<ListViewItem>();
private List<UnityAction> callbacks = new List<UnityAction>();
[SerializeField]
[HideInInspector]
public bool DestroyGameObjects = true;
[SerializeField]
public bool Multiple;
[SerializeField]
private int selectedIndex = -1;
[SerializeField]
private List<int> selectedIndicies = new List<int>();
public ListViewBaseEvent OnSelect = new ListViewBaseEvent();
public ListViewBaseEvent OnDeselect = new ListViewBaseEvent();
public UnityEvent onSubmit = new UnityEvent();
public UnityEvent onCancel = new UnityEvent();
public UnityEvent onItemSelect = new UnityEvent();
public UnityEvent onItemCancel = new UnityEvent();
[SerializeField]
public Transform Container;
public ListViewFocusEvent OnFocusIn = new ListViewFocusEvent();
public ListViewFocusEvent OnFocusOut = new ListViewFocusEvent();
[NonSerialized]
protected bool SetItemIndicies = true;
private GameObject Unused;
[NonSerialized]
private bool isStartedListViewBase;
public List<ListViewItem> Items
{
get
{
return new List<ListViewItem>(items);
}
set
{
UpdateItems(value);
}
}
public int SelectedIndex
{
get
{
return selectedIndex;
}
set
{
if (value == -1)
{
if (selectedIndex != -1)
{
Deselect(selectedIndex);
}
selectedIndex = value;
}
else
{
Select(value);
}
}
}
public List<int> SelectedIndicies
{
get
{
return new List<int>(selectedIndicies);
}
set
{
IEnumerable<int> enumerable = selectedIndicies.Except(value);
IEnumerable<int> enumerable2 = value.Except(selectedIndicies);
enumerable.ForEach(Deselect);
enumerable2.ForEach(Select);
}
}
private void Awake()
{
Start();
}
public virtual void Start()
{
if (!isStartedListViewBase)
{
isStartedListViewBase = true;
Unused = new GameObject("unused base");
Unused.SetActive(false);
Unused.transform.SetParent(base.transform, false);
if (selectedIndex != -1 && selectedIndicies.Count == 0)
{
selectedIndicies.Add(selectedIndex);
}
selectedIndicies.RemoveAll(NotIsValid);
if (selectedIndicies.Count == 0)
{
selectedIndex = -1;
}
}
}
protected bool NotIsValid(int index)
{
return !IsValid(index);
}
public virtual void UpdateItems()
{
UpdateItems(items);
}
private void RemoveCallback(ListViewItem item, int index)
{
if (!(item == null))
{
if (index < callbacks.Count)
{
item.onClick.RemoveListener(callbacks[index]);
}
item.onSubmit.RemoveListener(Toggle);
item.onCancel.RemoveListener(OnItemCancel);
item.onSelect.RemoveListener(HighlightColoring);
item.onDeselect.RemoveListener(Coloring);
item.onMove.RemoveListener(OnItemMove);
}
}
private void OnItemCancel(ListViewItem item)
{
if (!EventSystem.current.alreadySelecting)
{
EventSystem.current.SetSelectedGameObject(base.gameObject);
onItemCancel.Invoke();
}
}
private void RemoveCallbacks()
{
if (callbacks.Count > 0)
{
items.ForEach(RemoveCallback);
}
callbacks.Clear();
}
private void AddCallbacks()
{
items.ForEach(AddCallback);
}
private void AddCallback(ListViewItem item, int index)
{
callbacks.Insert(index, delegate
{
Toggle(item);
});
item.onClick.AddListener(callbacks[index]);
item.onSubmit.AddListener(OnItemSubmit);
item.onCancel.AddListener(OnItemCancel);
item.onSelect.AddListener(HighlightColoring);
item.onDeselect.AddListener(Coloring);
item.onMove.AddListener(OnItemMove);
}
private void OnItemSelect(ListViewItem item)
{
onItemSelect.Invoke();
}
private void OnItemSubmit(ListViewItem item)
{
Toggle(item);
if (!IsSelected(item.Index))
{
HighlightColoring(item);
}
}
protected virtual void OnItemMove(AxisEventData eventData, ListViewItem item)
{
switch (eventData.moveDir)
{
case MoveDirection.Left:
break;
case MoveDirection.Right:
break;
case MoveDirection.Up:
if (item.Index > 0)
{
SelectComponentByIndex(item.Index - 1);
}
break;
case MoveDirection.Down:
if (IsValid(item.Index + 1))
{
SelectComponentByIndex(item.Index + 1);
}
break;
}
}
protected virtual void ScrollTo(int index)
{
}
public virtual int Add(ListViewItem item)
{
item.transform.SetParent(Container, false);
AddCallback(item, items.Count);
items.Add(item);
item.Index = callbacks.Count - 1;
return callbacks.Count - 1;
}
public virtual void Clear()
{
items.Clear();
UpdateItems();
}
protected virtual int Remove(ListViewItem item)
{
RemoveCallbacks();
int index = item.Index;
selectedIndicies = (from x in selectedIndicies
where x != index
select (x <= index) ? x : x--).ToList();
if (selectedIndex == index)
{
Deselect(index);
selectedIndex = ((selectedIndicies.Count <= 0) ? (-1) : selectedIndicies.Last());
}
else if (selectedIndex > index)
{
selectedIndex--;
}
items.Remove(item);
Free(item);
AddCallbacks();
return index;
}
private void Free(Component item)
{
if (item == null)
{
return;
}
if (DestroyGameObjects)
{
if (!(item.gameObject == null))
{
UnityEngine.Object.Destroy(item.gameObject);
}
}
else if (!(item.transform == null) && !(Unused == null) && !(Unused.transform == null))
{
item.transform.SetParent(Unused.transform, false);
}
}
private void UpdateItems(List<ListViewItem> newItems)
{
RemoveCallbacks();
items.Where((ListViewItem item) => item != null && !newItems.Contains(item)).ForEach(Free);
newItems.ForEach(UpdateItem);
items = newItems;
AddCallbacks();
}
private void UpdateItem(ListViewItem item, int index)
{
if (!(item == null))
{
if (SetItemIndicies)
{
item.Index = index;
}
item.transform.SetParent(Container, false);
}
}
public virtual bool IsValid(int index)
{
return index >= 0 && index < items.Count;
}
protected ListViewItem GetItem(int index)
{
return items.Find((ListViewItem x) => x.Index == index);
}
public virtual void Select(int index)
{
if (index == -1)
{
return;
}
if (!IsValid(index))
{
string message = string.Format("Index must be between 0 and Items.Count ({0}). Gameobject {1}.", items.Count - 1, base.name);
throw new IndexOutOfRangeException(message);
}
if (IsSelected(index) && Multiple)
{
return;
}
if (!Multiple)
{
if (selectedIndex != -1 && selectedIndex != index)
{
Deselect(selectedIndex);
}
selectedIndicies.Clear();
}
selectedIndicies.Add(index);
selectedIndex = index;
SelectItem(index);
OnSelect.Invoke(index, GetItem(index));
}
protected void SilentDeselect(List<int> indicies)
{
selectedIndicies = selectedIndicies.Except(indicies).ToList();
selectedIndex = ((selectedIndicies.Count <= 0) ? (-1) : selectedIndicies[selectedIndicies.Count - 1]);
}
protected void SilentSelect(List<int> indicies)
{
if (indicies == null)
{
indicies = new List<int>();
}
selectedIndicies.AddRange(indicies.Except(selectedIndicies));
selectedIndex = ((selectedIndicies.Count <= 0) ? (-1) : selectedIndicies[selectedIndicies.Count - 1]);
}
public void Deselect(int index)
{
if (index != -1 && IsSelected(index))
{
selectedIndicies.Remove(index);
selectedIndex = ((selectedIndicies.Count <= 0) ? (-1) : selectedIndicies.Last());
if (IsValid(index))
{
DeselectItem(index);
OnDeselect.Invoke(index, GetItem(index));
}
}
}
public bool IsSelected(int index)
{
return selectedIndicies.Contains(index);
}
public void Toggle(int index)
{
if (IsSelected(index) && Multiple)
{
Deselect(index);
}
else
{
Select(index);
}
}
private void Toggle(ListViewItem item)
{
bool flag = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
bool flag2 = selectedIndicies.Count > 0;
if (Multiple && flag && flag2 && selectedIndicies[0] != item.Index)
{
selectedIndicies.GetRange(1, selectedIndicies.Count - 1).ForEach(Deselect);
int num = Mathf.Min(selectedIndicies[0], item.Index);
int num2 = Mathf.Max(selectedIndicies[0], item.Index);
Enumerable.Range(num, num2 - num + 1).ForEach(Select);
}
else
{
Toggle(item.Index);
}
}
protected int GetComponentIndex(ListViewItem item)
{
return item.Index;
}
protected void SetComponentAsLastSibling(ListViewItem item)
{
item.transform.SetAsLastSibling();
}
protected virtual void SelectItem(int index)
{
}
protected virtual void DeselectItem(int index)
{
}
protected virtual void Coloring(ListViewItem component)
{
}
protected virtual void HighlightColoring(ListViewItem component)
{
}
protected virtual void OnDestroy()
{
RemoveCallbacks();
items.ForEach(Free);
}
public virtual bool SelectComponent()
{
if (items.Count == 0)
{
return false;
}
int index = ((SelectedIndex != -1) ? SelectedIndex : 0);
SelectComponentByIndex(index);
return true;
}
protected void SelectComponentByIndex(int index)
{
ScrollTo(index);
ListViewItemEventData listViewItemEventData = new ListViewItemEventData(EventSystem.current);
listViewItemEventData.NewSelectedObject = GetItem(index).gameObject;
ListViewItemEventData listViewItemEventData2 = listViewItemEventData;
ExecuteEvents.Execute(listViewItemEventData2.NewSelectedObject, listViewItemEventData2, ExecuteEvents.selectHandler);
}
void ISelectHandler.OnSelect(BaseEventData eventData)
{
if (!EventSystem.current.alreadySelecting)
{
EventSystem.current.SetSelectedGameObject(base.gameObject);
}
OnFocusIn.Invoke(eventData);
}
void IDeselectHandler.OnDeselect(BaseEventData eventData)
{
OnFocusOut.Invoke(eventData);
}
void ISubmitHandler.OnSubmit(BaseEventData eventData)
{
SelectComponent();
onSubmit.Invoke();
}
void ICancelHandler.OnCancel(BaseEventData eventData)
{
onCancel.Invoke();
}
public virtual void ForEachComponent(Action<ListViewItem> func)
{
items.ForEach(func);
}
}
}