Skip to content

Commit

Permalink
Several lifetime feature updates for the ComboBox controls:
Browse files Browse the repository at this point in the history
- Resolves startup issue that prevented the control being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes
- Added the ability to set a specific item on start and not just the first
- Added the ability to disable the dropdown to make a read-only dropdown

Resolves:
- #426
- #425
  • Loading branch information
Simon Jackson committed Feb 5, 2023
1 parent 9ce7661 commit 33cd5a9
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 51 deletions.
66 changes: 59 additions & 7 deletions Runtime/Scripts/Controls/ComboBox/AutoCompleteComboBox.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
///Credit perchik
///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/

using System;
using System.Collections.Generic;
using System.Linq;

Expand All @@ -16,14 +17,14 @@ public enum AutoCompleteSearchType
[AddComponentMenu("UI/Extensions/ComboBox/AutoComplete ComboBox")]
public class AutoCompleteComboBox : MonoBehaviour
{
public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it

/// <summary>
/// Contains the included items. To add and remove items to/from this list, use the <see cref="AddItem(string)"/>,
/// <see cref="RemoveItem(string)"/> and <see cref="SetAvailableOptions(List{string})"/> methods as these also execute
/// the required methods to update to the current collection.
/// </summary>
[Header("AutoComplete Box Items")]
public List<string> AvailableOptions;

private bool _isPanelActive = false;
Expand Down Expand Up @@ -51,11 +52,13 @@ public class AutoCompleteComboBox : MonoBehaviour
private Dictionary<string, GameObject> panelObjects;

private GameObject itemTemplate;
private bool _initialized;

public string Text { get; private set; }

[Header("Properties")]
[SerializeField]
private float dropdownOffset;
private bool isActive = true;

[SerializeField]
private float _scrollBarWidth = 20.0f;
Expand All @@ -81,8 +84,6 @@ public int ItemsToDisplay
}
}

public bool SelectFirstItemOnStart = false;

[SerializeField]
[Tooltip("Change input text color based on matching items")]
private bool _ChangeInputTextColorBasedOnMatchingItems = false;
Expand All @@ -107,9 +108,19 @@ public bool InputColorMatching

public AutoCompleteSearchType autocompleteSearchType = AutoCompleteSearchType.Linq;

[SerializeField]
private float dropdownOffset;

[SerializeField]
private bool _displayPanelAbove = false;

public bool SelectFirstItemOnStart = false;

[SerializeField]
private int selectItemIndexOnStart = 0;

private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;

private bool _selectionIsValid = false;

[System.Serializable]
Expand All @@ -121,12 +132,18 @@ public class SelectionTextChangedEvent : Events.UnityEvent<string> { }
[System.Serializable]
public class SelectionValidityChangedEvent : Events.UnityEvent<bool> { }

[System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { }

// fires when input text is changed;
[Header("Events")]
public SelectionTextChangedEvent OnSelectionTextChanged;
// fires when an Item gets selected / deselected (including when items are added/removed once this is possible)
public SelectionValidityChangedEvent OnSelectionValidityChanged;
// fires in both cases
public SelectionChangedEvent OnSelectionChanged;
// fires when item is changed;
public ControlDisabledEvent OnControlDisabled;

public void Awake()
{
Expand All @@ -135,16 +152,17 @@ public void Awake()

public void Start()
{
if (SelectFirstItemOnStart && AvailableOptions.Count > 0)
if (shouldSelectItemOnStart && AvailableOptions.Count > 0)
{
ToggleDropdownPanel(false);
OnItemClicked(AvailableOptions[0]);
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}

private bool Initialize()
{
if (_initialized) return true;

bool success = true;
try
{
Expand Down Expand Up @@ -184,6 +202,8 @@ private bool Initialize()
_prunedPanelItems = new List<string>();
_panelItems = new List<string>();

_initialized = true;

RebuildPanel();
return success;
}
Expand Down Expand Up @@ -218,6 +238,17 @@ public void RemoveItem(string item)
}
}


/// <summary>
/// Update the drop down selection to a specific index
/// </summary>
/// <param name="index"></param>
public void SelectItemIndex(int index)
{
ToggleDropdownPanel(false);
OnItemClicked(AvailableOptions[index]);
}

/// <summary>
/// Sets the given items as new content for the comboBox. Previous entries will be cleared.
/// </summary>
Expand Down Expand Up @@ -263,6 +294,11 @@ public void ResetItems()
/// </summary>
private void RebuildPanel()
{
if (!_initialized)
{
Start();
}

if (_isPanelActive) ToggleDropdownPanel();

//panel starts with all options
Expand Down Expand Up @@ -427,6 +463,8 @@ private void SetInputTextColor()
/// <param name="directClick"> whether an item was directly clicked on</param>
public void ToggleDropdownPanel(bool directClick = false)
{
if (!isActive) return;

_isPanelActive = !_isPanelActive;

_overlayRT.gameObject.SetActive(_isPanelActive);
Expand All @@ -440,6 +478,20 @@ public void ToggleDropdownPanel(bool directClick = false)
}
}


/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status != isActive)
{
OnControlDisabled?.Invoke(status);
}
isActive = status;
}

private void PruneItems(string currText)
{
if (autocompleteSearchType == AutoCompleteSearchType.Linq)
Expand Down
69 changes: 59 additions & 10 deletions Runtime/Scripts/Controls/ComboBox/ComboBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@

using System.Collections.Generic;
using System.Linq;
using static UnityEditor.Progress;

namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/ComboBox/ComboBox")]
public class ComboBox : MonoBehaviour
{
public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; }

[Header("Combo Box Items")]
public List<string> AvailableOptions;

[Header("Properties")]
[SerializeField]
private bool isActive = true;

[SerializeField]
private float _scrollBarWidth = 20.0f;

Expand All @@ -27,22 +32,32 @@ public class ComboBox : MonoBehaviour
[SerializeField]
private bool _displayPanelAbove = false;

public bool SelectFirstItemOnStart = false;

[SerializeField]
private int selectItemIndexOnStart = 0;

private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;

[System.Serializable]
public class SelectionChangedEvent : Events.UnityEvent<string> { }

[Header("Events")]
// fires when item is changed;
public SelectionChangedEvent OnSelectionChanged;

[System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { }

// fires when item is changed;
public ControlDisabledEvent OnControlDisabled;

//private bool isInitialized = false;
private bool _isPanelActive = false;
private bool _hasDrawnOnce = false;

private InputField _mainInput;
private RectTransform _inputRT;


private RectTransform _rectTransform;

private RectTransform _overlayRT;
private RectTransform _scrollPanelRT;
private RectTransform _scrollBarRT;
Expand All @@ -51,14 +66,11 @@ public class SelectionChangedEvent : Events.UnityEvent<string> { }
private RectTransform _itemsPanelRT;
private Canvas _canvas;
private RectTransform _canvasRT;

private ScrollRect _scrollRect;

private List<string> _panelItems; //items that will get shown in the drop-down

private Dictionary<string, GameObject> panelObjects;

private GameObject itemTemplate;
private bool _initialized;

public string Text { get; private set; }

Expand Down Expand Up @@ -89,11 +101,17 @@ public void Awake()

public void Start()
{
if (shouldSelectItemOnStart && AvailableOptions.Count > 0)
{
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}

private bool Initialize()
{
if (_initialized) return true;

bool success = true;
try
{
Expand Down Expand Up @@ -133,11 +151,22 @@ private bool Initialize()

_panelItems = AvailableOptions.ToList();

_initialized = true;

RebuildPanel();
//RedrawPanel(); - causes an initialisation failure in U5
return success;
}

/// <summary>
/// Update the drop down selection to a specific index
/// </summary>
/// <param name="index"></param>
public void SelectItemIndex(int index)
{
ToggleDropdownPanel(false);
OnItemClicked(AvailableOptions[index]);
}

public void AddItem(string item)
{
AvailableOptions.Add(item);
Expand Down Expand Up @@ -187,6 +216,11 @@ public void ResetItems()
/// </summary>
private void RebuildPanel()
{
if (!_initialized)
{
Start();
}

//panel starts with all options
_panelItems.Clear();
foreach (string option in AvailableOptions)
Expand Down Expand Up @@ -310,6 +344,8 @@ public void OnValueChanged(string currText)
/// <param name="directClick"> whether an item was directly clicked on</param>
public void ToggleDropdownPanel(bool directClick)
{
if (!isActive) return;

_isPanelActive = !_isPanelActive;

_overlayRT.gameObject.SetActive(_isPanelActive);
Expand All @@ -322,5 +358,18 @@ public void ToggleDropdownPanel(bool directClick)
// scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y);
}
}

/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status != isActive)
{
OnControlDisabled?.Invoke(status);
}
isActive = status;
}
}
}
Loading

0 comments on commit 33cd5a9

Please sign in to comment.