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();
}
}
}