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 childrenDeselect = new List(); 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(); 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() ?? go.AddComponent(); } 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(); } } }