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

340 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UIWidgets
{
[AddComponentMenu("UI/Combobox", 220)]
[RequireComponent(typeof(InputField))]
public class Combobox : MonoBehaviour, ISubmitHandler, IEventSystemHandler
{
[SerializeField]
private ListView listView;
[SerializeField]
private Button toggleButton;
[SerializeField]
private bool editable = true;
private InputField input;
public ListViewEvent OnSelect = new ListViewEvent();
private Transform _listCanvas;
private Transform listParent;
[NonSerialized]
private bool isStartedCombobox;
protected int? ModalKey;
protected List<SelectListener> childrenDeselect = new List<SelectListener>();
public ListView ListView
{
get
{
return listView;
}
set
{
SetListView(value);
}
}
public Button ToggleButton
{
get
{
return toggleButton;
}
set
{
SetToggleButton(value);
}
}
public bool Editable
{
get
{
return editable;
}
set
{
editable = value;
input.interactable = editable;
}
}
private Transform listCanvas
{
get
{
if (_listCanvas == null)
{
_listCanvas = Utilites.FindCanvas(listView.transform.parent);
}
return _listCanvas;
}
}
private void Awake()
{
Start();
}
public virtual void Start()
{
if (isStartedCombobox)
{
return;
}
isStartedCombobox = true;
input = GetComponent<InputField>();
input.onEndEdit.AddListener(InputItem);
Editable = editable;
SetToggleButton(toggleButton);
SetListView(listView);
if (listView != null)
{
listView.OnSelectString.RemoveListener(SelectItem);
listView.gameObject.SetActive(true);
listView.Start();
if (listView.SelectedIndex != -1)
{
input.text = listView.DataSource[listView.SelectedIndex];
}
listView.gameObject.SetActive(false);
listView.OnSelectString.AddListener(SelectItem);
}
}
protected virtual void SetListView(ListView value)
{
if (listView != null)
{
listParent = null;
listView.OnSelectString.RemoveListener(SelectItem);
listView.OnFocusOut.RemoveListener(onFocusHideList);
listView.onCancel.RemoveListener(OnListViewCancel);
listView.onItemCancel.RemoveListener(OnListViewCancel);
RemoveDeselectCallbacks();
}
listView = value;
if (listView != null)
{
listParent = listView.transform.parent;
listView.OnSelectString.AddListener(SelectItem);
listView.OnFocusOut.AddListener(onFocusHideList);
listView.onCancel.AddListener(OnListViewCancel);
listView.onItemCancel.AddListener(OnListViewCancel);
AddDeselectCallbacks();
}
}
protected virtual void SetToggleButton(Button value)
{
if (toggleButton != null)
{
toggleButton.onClick.RemoveListener(ToggleList);
}
toggleButton = value;
if (toggleButton != null)
{
toggleButton.onClick.AddListener(ToggleList);
}
}
public virtual void Clear()
{
listView.DataSource.Clear();
input.text = string.Empty;
}
public virtual void ToggleList()
{
if (!(listView == null))
{
if (listView.gameObject.activeSelf)
{
HideList();
}
else
{
ShowList();
}
}
}
public virtual void ShowList()
{
if (!(listView == null))
{
if (listCanvas != null)
{
ModalKey = ModalHelper.Open(this, null, new Color(0f, 0f, 0f, 0f), HideList);
listParent = listView.transform.parent;
listView.transform.SetParent(listCanvas);
}
listView.gameObject.SetActive(true);
if (listView.Layout != null)
{
listView.Layout.UpdateLayout();
}
if (listView.SelectComponent())
{
SetChildDeselectListener(EventSystem.current.currentSelectedGameObject);
}
else
{
EventSystem.current.SetSelectedGameObject(listView.gameObject);
}
}
}
public virtual void HideList()
{
int? modalKey = ModalKey;
if (modalKey.HasValue)
{
int? modalKey2 = ModalKey;
ModalHelper.Close(modalKey2.Value);
ModalKey = null;
}
if (!(listView == null))
{
listView.gameObject.SetActive(false);
if (listCanvas != null)
{
listView.transform.SetParent(listParent);
}
}
}
protected void onFocusHideList(BaseEventData eventData)
{
if (eventData.selectedObject == base.gameObject)
{
return;
}
ListViewItemEventData listViewItemEventData = eventData as ListViewItemEventData;
if (listViewItemEventData != null)
{
if (listViewItemEventData.NewSelectedObject != null)
{
SetChildDeselectListener(listViewItemEventData.NewSelectedObject);
}
return;
}
PointerEventData pointerEventData = eventData as PointerEventData;
if (pointerEventData == null)
{
HideList();
return;
}
GameObject gameObject = pointerEventData.pointerPressRaycast.gameObject;
if (!(gameObject == null) && !gameObject.Equals(toggleButton.gameObject))
{
if (gameObject.transform.IsChildOf(listView.transform))
{
SetChildDeselectListener(gameObject);
}
else
{
HideList();
}
}
}
protected void SetChildDeselectListener(GameObject child)
{
SelectListener deselectListener = GetDeselectListener(child);
if (!childrenDeselect.Contains(deselectListener))
{
deselectListener.onDeselect.AddListener(onFocusHideList);
childrenDeselect.Add(deselectListener);
}
}
protected SelectListener GetDeselectListener(GameObject go)
{
return go.GetComponent<SelectListener>() ?? go.AddComponent<SelectListener>();
}
protected void AddDeselectCallbacks()
{
if (!(listView.ScrollRect == null) && !(listView.ScrollRect.verticalScrollbar == null))
{
GameObject go = listView.ScrollRect.verticalScrollbar.gameObject;
SelectListener deselectListener = GetDeselectListener(go);
deselectListener.onDeselect.AddListener(onFocusHideList);
childrenDeselect.Add(deselectListener);
}
}
protected void RemoveDeselectCallbacks()
{
childrenDeselect.ForEach(RemoveDeselectCallback);
childrenDeselect.Clear();
}
protected void RemoveDeselectCallback(SelectListener listener)
{
if (listener != null)
{
listener.onDeselect.RemoveListener(onFocusHideList);
}
}
public virtual int Set(string item, bool allowDuplicate = true)
{
return listView.Set(item, allowDuplicate);
}
protected virtual void SelectItem(int index, string text)
{
input.text = text;
HideList();
if (EventSystem.current != null && !EventSystem.current.alreadySelecting)
{
EventSystem.current.SetSelectedGameObject(toggleButton.gameObject);
}
OnSelect.Invoke(index, text);
}
protected virtual void InputItem(string item)
{
if (editable && !(item == string.Empty) && !listView.DataSource.Contains(item))
{
int index = listView.Add(item);
listView.Select(index);
}
}
protected virtual void OnDestroy()
{
ListView = null;
ToggleButton = null;
if (input != null)
{
input.onEndEdit.RemoveListener(InputItem);
}
}
protected void OnListViewCancel()
{
HideList();
}
public virtual void OnSubmit(BaseEventData eventData)
{
ShowList();
}
}
}