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 items = new List(); private List callbacks = new List(); [SerializeField] [HideInInspector] public bool DestroyGameObjects = true; [SerializeField] public bool Multiple; [SerializeField] private int selectedIndex = -1; [SerializeField] private List selectedIndicies = new List(); 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 Items { get { return new List(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 SelectedIndicies { get { return new List(selectedIndicies); } set { IEnumerable enumerable = selectedIndicies.Except(value); IEnumerable 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 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 indicies) { selectedIndicies = selectedIndicies.Except(indicies).ToList(); selectedIndex = ((selectedIndicies.Count <= 0) ? (-1) : selectedIndicies[selectedIndicies.Count - 1]); } protected void SilentSelect(List indicies) { if (indicies == null) { indicies = new List(); } 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 func) { items.ForEach(func); } } }