using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System.Collections.Generic; namespace UIWidgets { /// /// Combobox. /// http://ilih.ru/images/unity-assets/UIWidgets/Combobox.png /// [AddComponentMenu("UI/UIWidgets/Combobox")] //[RequireComponent(typeof(InputField))] public class Combobox : MonoBehaviour, ISubmitHandler { [SerializeField] ListView listView; /// /// Gets or sets the ListView. /// /// ListView component. public ListView ListView { get { return listView; } set { SetListView(value); } } [SerializeField] Button toggleButton; /// /// Gets or sets the toggle button. /// /// The toggle button. public Button ToggleButton { get { return toggleButton; } set { SetToggleButton(value); } } [SerializeField] bool editable = true; /// /// Gets or sets a value indicating whether this is editable and user can add new items. /// /// true if editable; otherwise, false. public bool Editable { get { return editable; } set { editable = value; input.interactable = editable; } } protected IInputFieldProxy input; /// /// OnSelect event. /// public ListViewEvent OnSelect = new ListViewEvent(); Transform _listCanvas; Transform listCanvas { get { if (_listCanvas==null) { _listCanvas = Utilites.FindTopmostCanvas(listView.transform.parent); } return _listCanvas; } } Transform listParent; void Awake() { Start(); } [System.NonSerialized] bool isStartedCombobox; /// /// Start this instance. /// public virtual void Start() { if (isStartedCombobox) { return ; } isStartedCombobox = true; InitInputFieldProxy(); input.onEndEdit.AddListener(InputItem); Editable = editable; SetToggleButton(toggleButton); SetListView(listView); if (listView!=null) { listView.gameObject.SetActive(true); listView.Start(); if (listView.SelectedIndex!=-1) { input.text = listView.DataSource[listView.SelectedIndex]; } listView.gameObject.SetActive(false); } } protected virtual void InitInputFieldProxy() { input = new InputFieldProxy(GetComponent()); } /// /// Sets the list view. /// /// Value. 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(); } } /// /// Sets the toggle button. /// /// Value. protected virtual void SetToggleButton(Button value) { if (toggleButton!=null) { toggleButton.onClick.RemoveListener(ToggleList); } toggleButton = value; if (toggleButton!=null) { toggleButton.onClick.AddListener(ToggleList); } } /// /// Clear listview and selected item. /// public virtual void Clear() { listView.DataSource.Clear(); input.text = string.Empty; } /// /// Toggles the list visibility. /// public virtual void ToggleList() { if (listView==null) { return ; } if (listView.gameObject.activeSelf) { HideList(); } else { ShowList(); } } /// /// The modal key. /// protected int? ModalKey; /// /// Shows the list. /// public virtual void ShowList() { if (listView==null) { return ; } listView.gameObject.SetActive(true); ModalKey = ModalHelper.Open(this, null, new Color(0, 0, 0, 0f), HideList); if (listCanvas!=null) { listParent = listView.transform.parent; listView.transform.SetParent(listCanvas); } if (listView.Layout!=null) { listView.Layout.UpdateLayout(); } if (listView.SelectComponent()) { SetChildDeselectListener(EventSystem.current.currentSelectedGameObject); } else { EventSystem.current.SetSelectedGameObject(listView.gameObject); } } /// /// Hides the list. /// public virtual void HideList() { if (ModalKey!=null) { ModalHelper.Close((int)ModalKey); ModalKey = null; } if (listView==null) { return ; } if (listCanvas!=null) { listView.transform.SetParent(listParent); } listView.gameObject.SetActive(false); } /// /// The children deselect. /// protected List childrenDeselect = new List(); /// /// Hide list when focus lost. /// /// Event data. protected void onFocusHideList(BaseEventData eventData) { if (eventData.selectedObject==gameObject) { return ; } var ev_item = eventData as ListViewItemEventData; if (ev_item!=null) { if (ev_item.NewSelectedObject!=null) { SetChildDeselectListener(ev_item.NewSelectedObject); } return ; } var ev = eventData as PointerEventData; if (ev==null) { HideList(); return ; } var go = ev.pointerPressRaycast.gameObject;//ev.pointerEnter if (go==null) { return ; } if (go.Equals(toggleButton.gameObject)) { return ; } if (go.transform.IsChildOf(listView.transform)) { SetChildDeselectListener(go); return ; } HideList(); } /// /// Sets the child deselect listener. /// /// Child. protected void SetChildDeselectListener(GameObject child) { var deselectListener = GetDeselectListener(child); if (!childrenDeselect.Contains(deselectListener)) { deselectListener.onDeselect.AddListener(onFocusHideList); childrenDeselect.Add(deselectListener); } } /// /// Gets the deselect listener. /// /// The deselect listener. /// Go. protected SelectListener GetDeselectListener(GameObject go) { var result = go.GetComponent(); return (result!=null) ? result : go.AddComponent(); } /// /// Adds the deselect callbacks. /// protected void AddDeselectCallbacks() { if (listView.ScrollRect==null) { return ; } if (listView.ScrollRect.verticalScrollbar==null) { return ; } var scrollbar = listView.ScrollRect.verticalScrollbar.gameObject; var deselectListener = GetDeselectListener(scrollbar); deselectListener.onDeselect.AddListener(onFocusHideList); childrenDeselect.Add(deselectListener); } /// /// Removes the deselect callbacks. /// protected void RemoveDeselectCallbacks() { childrenDeselect.ForEach(RemoveDeselectCallback); childrenDeselect.Clear(); } /// /// Removes the deselect callback. /// /// Listener. protected void RemoveDeselectCallback(SelectListener listener) { if (listener!=null) { listener.onDeselect.RemoveListener(onFocusHideList); } } /// /// Set the specified item. /// /// Item. /// If set to true allow duplicate. /// Index of item. public virtual int Set(string item, bool allowDuplicate=true) { return listView.Set(item, allowDuplicate); } /// /// Selects the item. /// /// Index. /// Text. 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); } /// /// Work with input. /// /// Item. protected virtual void InputItem(string item) { if (!editable) { return ; } if (item==string.Empty) { return ; } if (!listView.DataSource.Contains(item)) { var index = listView.Add(item); listView.Select(index); } } /// /// This function is called when the MonoBehaviour will be destroyed. /// protected virtual void OnDestroy() { ListView = null; ToggleButton = null; if (input!=null) { input.onEndEdit.RemoveListener(InputItem); } } /// /// Hide list view. /// protected void OnListViewCancel() { HideList(); } /// /// Called when OnSubmit event occurs. /// /// Event data. public virtual void OnSubmit(BaseEventData eventData) { ShowList(); } } }