Merge pull request #453 from RobTranquillo/release

Minor enhancements on DropDown
pull/458/head
Simon (Darkside) Jackson 2023-10-05 16:53:52 +01:00 committed by GitHub
commit 322e804f25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 189 additions and 141 deletions

View File

@ -5,25 +5,25 @@ using System.Collections.Generic;
namespace UnityEngine.UI.Extensions namespace UnityEngine.UI.Extensions
{ {
/// <summary> /// <summary>
/// Extension to the UI class which creates a dropdown list /// Extension to the UI class which creates a dropdown list
/// </summary> /// </summary>
[RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/ComboBox/Dropdown List")] [AddComponentMenu("UI/Extensions/ComboBox/Dropdown List")]
public class DropDownList : MonoBehaviour public class DropDownList : MonoBehaviour
{ {
public Color disabledTextColor; public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
[Header("Dropdown List Items")] [Header("Dropdown List Items")]
public List<DropDownListItem> Items; public List<DropDownListItem> Items;
[Header("Properties")] [Header("Properties")]
[SerializeField] [SerializeField]
private bool isActive = true; private bool isActive = true;
public bool OverrideHighlighted = true; public bool OverrideHighlighted = true;
//private bool isInitialized = false; //private bool isInitialized = false;
private bool _isPanelActive = false; private bool _isPanelActive = false;
@ -46,10 +46,13 @@ namespace UnityEngine.UI.Extensions
private List<DropDownListButton> _panelItems = new List<DropDownListButton>(); private List<DropDownListButton> _panelItems = new List<DropDownListButton>();
private GameObject _itemTemplate; private GameObject _itemTemplate;
private bool _initialized; private bool _initialized;
[SerializeField] private string _defaultMainButtonCaption = null;
private Color _defaultNormalColor;
[SerializeField]
private float _scrollBarWidth = 20.0f; private float _scrollBarWidth = 20.0f;
public float ScrollBarWidth public float ScrollBarWidth
{ {
@ -61,7 +64,6 @@ namespace UnityEngine.UI.Extensions
} }
} }
// private int scrollOffset; //offset of the selected item
private int _selectedIndex = -1; private int _selectedIndex = -1;
[SerializeField] [SerializeField]
@ -76,42 +78,42 @@ namespace UnityEngine.UI.Extensions
} }
} }
[SerializeField] [SerializeField]
private float dropdownOffset; private float dropdownOffset;
[SerializeField] [SerializeField]
private bool _displayPanelAbove = false; private bool _displayPanelAbove = false;
public bool SelectFirstItemOnStart = false; public bool SelectFirstItemOnStart = false;
[SerializeField] [SerializeField]
private int selectItemIndexOnStart = 0; private int selectItemIndexOnStart = 0;
private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0; private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;
[System.Serializable] [System.Serializable]
public class SelectionChangedEvent : Events.UnityEvent<int> { } public class SelectionChangedEvent : Events.UnityEvent<int> { }
// fires when item is changed; // fires when item is changed;
[Header("Events")] [Header("Events")]
public SelectionChangedEvent OnSelectionChanged; public SelectionChangedEvent OnSelectionChanged;
[System.Serializable] [System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { } public class ControlDisabledEvent : Events.UnityEvent<bool> { }
// fires when item is changed; // fires when item changes between enabled and disabled;
public ControlDisabledEvent OnControlDisabled; public ControlDisabledEvent OnControlDisabled;
public void Start() public void Start()
{ {
Initialize(); Initialize();
if (shouldSelectItemOnStart && Items.Count > 0) if (shouldSelectItemOnStart && Items.Count > 0)
{ {
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart); SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
} }
RedrawPanel(); RedrawPanel();
} }
private bool Initialize() private bool Initialize()
{ {
if (_initialized) return true; if (_initialized) return true;
@ -121,6 +123,9 @@ namespace UnityEngine.UI.Extensions
_rectTransform = GetComponent<RectTransform>(); _rectTransform = GetComponent<RectTransform>();
_mainButton = new DropDownListButton(_rectTransform.Find("MainButton").gameObject); _mainButton = new DropDownListButton(_rectTransform.Find("MainButton").gameObject);
_defaultMainButtonCaption = _mainButton.txt.text;
_defaultNormalColor = _mainButton.btn.colors.normalColor;
_overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>(); _overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
_overlayRT.gameObject.SetActive(false); _overlayRT.gameObject.SetActive(false);
_scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>(); _scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
@ -147,32 +152,32 @@ namespace UnityEngine.UI.Extensions
Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception"); Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
success = false; success = false;
} }
_initialized = true; _initialized = true;
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
return success; return success;
} }
/// <summary> /// <summary>
/// Update the drop down selection to a specific index /// Update the drop down selection to a specific index
/// </summary> /// </summary>
/// <param name="index"></param> /// <param name="index"></param>
public void SelectItemIndex(int index) public void SelectItemIndex(int index)
{ {
ToggleDropdownPanel(false); ToggleDropdownPanel(false);
OnItemClicked(index); OnItemClicked(index);
} }
// currently just using items in the list instead of being able to add to it. // currently just using items in the list instead of being able to add to it.
/// <summary> /// <summary>
/// Rebuilds the list from a new collection. /// Rebuilds the list from a new collection.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// NOTE, this will clear all existing items /// NOTE, this will clear all existing items
/// </remarks> /// </remarks>
/// <param name="list"></param> /// <param name="list"></param>
public void RefreshItems(params object[] list) public void RefreshItems(params object[] list)
{ {
Items.Clear(); Items.Clear();
List<DropDownListItem> ddItems = new List<DropDownListItem>(); List<DropDownListItem> ddItems = new List<DropDownListItem>();
@ -197,76 +202,94 @@ namespace UnityEngine.UI.Extensions
} }
Items.AddRange(ddItems); Items.AddRange(ddItems);
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Adds an additional item to the drop down list (recommended) /// Adds an additional item to the drop down list (recommended)
/// </summary> /// </summary>
/// <param name="item">Item of type DropDownListItem</param> /// <param name="item">Item of type DropDownListItem</param>
public void AddItem(DropDownListItem item) public void AddItem(DropDownListItem item)
{ {
Items.Add(item); Items.Add(item);
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Adds an additional drop down list item using a string name /// Adds an additional drop down list item using a string name
/// </summary> /// </summary>
/// <param name="item">Item of type String</param> /// <param name="item">Item of type String</param>
public void AddItem(string item) public void AddItem(string item)
{ {
Items.Add(new DropDownListItem(caption: (string)item)); Items.Add(new DropDownListItem(caption: (string)item));
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Adds an additional drop down list item using a sprite image /// Adds an additional drop down list item using a sprite image
/// </summary> /// </summary>
/// <param name="item">Item of type UI Sprite</param> /// <param name="item">Item of type UI Sprite</param>
public void AddItem(Sprite item) public void AddItem(Sprite item)
{ {
Items.Add(new DropDownListItem(image: (Sprite)item)); Items.Add(new DropDownListItem(image: (Sprite)item));
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Removes an item from the drop down list (recommended) /// Removes an item from the drop down list (recommended)
/// </summary> /// </summary>
/// <param name="item">Item of type DropDownListItem</param> /// <param name="item">Item of type DropDownListItem</param>
public void RemoveItem(DropDownListItem item) public void RemoveItem(DropDownListItem item)
{ {
Items.Remove(item); Items.Remove(item);
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Removes an item from the drop down list item using a string name /// Removes an item from the drop down list item using a string name
/// </summary> /// </summary>
/// <param name="item">Item of type String</param> /// <param name="item">Item of type String</param>
public void RemoveItem(string item) public void RemoveItem(string item)
{ {
Items.Remove(new DropDownListItem(caption: (string)item)); Items.Remove(new DropDownListItem(caption: (string)item));
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
/// <summary> /// <summary>
/// Removes an item from the drop down list item using a sprite image /// Removes an item from the drop down list item using a sprite image
/// </summary> /// </summary>
/// <param name="item">Item of type UI Sprite</param> /// <param name="item">Item of type UI Sprite</param>
public void RemoveItem(Sprite item) public void RemoveItem(Sprite item)
{ {
Items.Remove(new DropDownListItem(image: (Sprite)item)); Items.Remove(new DropDownListItem(image: (Sprite)item));
RebuildPanel(); RebuildPanel();
RedrawPanel(); RedrawPanel();
} }
public void ResetItems() public void ResetDropDown()
{
if (!_initialized)
{
return;
}
_mainButton.txt.text = _defaultMainButtonCaption;
for (int i = 0; i < _itemsPanelRT.childCount; i++)
{
_panelItems[i].btnImg.color = _defaultNormalColor;
}
_selectedIndex = -1;
_initialized = false;
Initialize();
}
public void ResetItems()
{ {
Items.Clear(); Items.Clear();
RebuildPanel(); RebuildPanel();
@ -304,7 +327,7 @@ namespace UnityEngine.UI.Extensions
_panelItems[i].txt.text = item.Caption; _panelItems[i].txt.text = item.Caption;
if (item.IsDisabled) _panelItems[i].txt.color = disabledTextColor; if (item.IsDisabled) _panelItems[i].txt.color = disabledTextColor;
if (_panelItems[i].btnImg != null) _panelItems[i].btnImg.sprite = null;//hide the button image if (_panelItems[i].btnImg != null) _panelItems[i].btnImg.sprite = null;//hide the button image
_panelItems[i].img.sprite = item.Image; _panelItems[i].img.sprite = item.Image;
_panelItems[i].img.color = (item.Image == null) ? new Color(1, 1, 1, 0) _panelItems[i].img.color = (item.Image == null) ? new Color(1, 1, 1, 0)
: item.IsDisabled ? new Color(1, 1, 1, .5f) : item.IsDisabled ? new Color(1, 1, 1, .5f)
@ -349,25 +372,25 @@ namespace UnityEngine.UI.Extensions
_mainButton.txt.text = SelectedItem.Caption; _mainButton.txt.text = SelectedItem.Caption;
//update selected index color //update selected index color
if (OverrideHighlighted) if (OverrideHighlighted)
{ {
for (int i = 0; i < _itemsPanelRT.childCount; i++) for (int i = 0; i < _itemsPanelRT.childCount; i++)
{ {
_panelItems[i].btnImg.color = (_selectedIndex == i) ? _mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0); _panelItems[i].btnImg.color = (_selectedIndex == i) ? _mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
} }
} }
} }
private void RedrawPanel() private void RedrawPanel()
{ {
float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
_scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay); _scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
float dropdownHeight = _itemsToDisplay > 0 ? _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) : _rectTransform.sizeDelta.y * _panelItems.Count; float dropdownHeight = _itemsToDisplay > 0 ? _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) : _rectTransform.sizeDelta.y * _panelItems.Count;
dropdownHeight += dropdownOffset; dropdownHeight += dropdownOffset;
if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta) if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta)
{ {
_hasDrawnOnce = true; _hasDrawnOnce = true;
_mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x); _mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
@ -377,12 +400,12 @@ namespace UnityEngine.UI.Extensions
itemsRemaining = itemsRemaining < 0 ? 0 : itemsRemaining; itemsRemaining = itemsRemaining < 0 ? 0 : itemsRemaining;
_scrollPanelRT.SetParent(transform, true); _scrollPanelRT.SetParent(transform, true);
_scrollPanelRT.anchoredPosition = _displayPanelAbove ? _scrollPanelRT.anchoredPosition = _displayPanelAbove ?
new Vector2(0, dropdownOffset + dropdownHeight) : new Vector2(0, dropdownOffset + dropdownHeight) :
new Vector2(0, -(dropdownOffset + _rectTransform.sizeDelta.y)); new Vector2(0, -(dropdownOffset + _rectTransform.sizeDelta.y));
//make the overlay fill the screen //make the overlay fill the screen
_overlayRT.SetParent(_canvas.transform, false); _overlayRT.SetParent(_canvas.transform, false);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x); _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y); _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
@ -392,7 +415,7 @@ namespace UnityEngine.UI.Extensions
if (_panelItems.Count < 1) return; if (_panelItems.Count < 1) return;
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight); _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x); _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
_itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5); _itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
@ -407,38 +430,63 @@ namespace UnityEngine.UI.Extensions
} }
/// <summary> /// <summary>
/// Toggle the drop down list /// Toggle the drop down list if it is active
/// </summary> /// </summary>
/// <param name="directClick"> whether an item was directly clicked on</param> /// <param name="directClick">Retained for backwards compatibility only.</param>
public void ToggleDropdownPanel(bool directClick) [Obsolete("DirectClick Parameter is no longer required")]
public void ToggleDropdownPanel(bool directClick = false)
{ {
if (!isActive) return; ToggleDropdownPanel();
}
/// <summary>
/// Toggle the drop down list if it is active
/// </summary>
public void ToggleDropdownPanel()
{
if (!isActive)
{
return;
}
_overlayRT.transform.localScale = new Vector3(1, 1, 1); _overlayRT.transform.localScale = new Vector3(1, 1, 1);
_scrollBarRT.transform.localScale = new Vector3(1, 1, 1); _scrollBarRT.transform.localScale = new Vector3(1, 1, 1);
_isPanelActive = !_isPanelActive; _isPanelActive = !_isPanelActive;
_overlayRT.gameObject.SetActive(_isPanelActive); _overlayRT.gameObject.SetActive(_isPanelActive);
if (_isPanelActive) if (_isPanelActive)
{ {
transform.SetAsLastSibling(); transform.SetAsLastSibling();
} }
else if (directClick)
{
// scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y);
}
} }
/// <summary> /// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not /// Hides the drop down panel if its visible at the moment
/// </summary> /// </summary>
/// <param name="status"></param> public void HideDropDownPanel()
public void SetActive(bool status) {
{ if (!_isPanelActive)
if (status != isActive) {
{ return;
OnControlDisabled?.Invoke(status); }
}
isActive = status; ToggleDropdownPanel(false);
} }
}
/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// and takes care of the underlying button to follow the status.
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status == isActive)
{
return;
}
isActive = status;
OnControlDisabled?.Invoke(isActive);
_mainButton.btn.enabled = isActive;
}
}
} }