using Nova;
using UnityEngine;
using UnityEngine.Events;
namespace NovaSamples.UIControls
{
///
/// A UI control which reacts to user input and displays a list of selectable options.
///
public class Dropdown : UIControl
{
[Tooltip("The event fired when a new item is selected from the dropdown list.")]
public UnityEvent OnValueChanged = null;
[SerializeField]
[Tooltip("The data used to populate the list of selectable items in the dropdown.")]
private DropdownData DropdownOptions = new DropdownData();
///
/// The visuals associated with this dropdown control
///
private DropdownVisuals Visuals => View.Visuals as DropdownVisuals;
public void Expand()
{
// Tell the dropdown to expand, showing a list of
// selectable options.
Visuals.Expand(DropdownOptions);
}
public void Collapse()
{
// Collapse the dropdown and stop tracking it
// as the expanded focused object.
Visuals.Collapse();
}
private void OnEnable()
{
if (View.TryGetVisuals(out DropdownVisuals visuals))
{
// Set default state
visuals.UpdateVisualState(VisualState.Default);
}
// Subscribe to desired events
View.UIBlock.AddGestureHandler(DropdownVisuals.HandleHovered);
View.UIBlock.AddGestureHandler(DropdownVisuals.HandleUnhovered);
View.UIBlock.AddGestureHandler(DropdownVisuals.HandlePressed);
View.UIBlock.AddGestureHandler(DropdownVisuals.HandleReleased);
View.UIBlock.AddGestureHandler(DropdownVisuals.HandlePressCanceled);
View.UIBlock.AddGestureHandler(HandleDropdownClicked);
Visuals.OnValueChanged += HandleValueChanged;
InputManager.OnPostClick += HandlePostClick;
// Ensure label is initialized
Visuals.InitSelectionLabel(DropdownOptions.CurrentSelection);
}
private void OnDisable()
{
// Unsubscribe from events
View.UIBlock.RemoveGestureHandler(DropdownVisuals.HandleHovered);
View.UIBlock.RemoveGestureHandler(DropdownVisuals.HandleUnhovered);
View.UIBlock.RemoveGestureHandler(DropdownVisuals.HandlePressed);
View.UIBlock.RemoveGestureHandler(DropdownVisuals.HandleReleased);
View.UIBlock.RemoveGestureHandler(DropdownVisuals.HandlePressCanceled);
View.UIBlock.RemoveGestureHandler(HandleDropdownClicked);
Visuals.OnValueChanged -= HandleValueChanged;
InputManager.OnPostClick -= HandlePostClick;
}
///
/// Fire the Unity event when the selected value changes.
///
/// The string in the list of selectable options.
private void HandleValueChanged(string value)
{
OnValueChanged?.Invoke(value);
}
///
/// Handle a object in the
/// being clicked, and either expand or collapse it accordingly.
///
/// The click event data.
/// The object which was clicked.
private void HandleDropdownClicked(Gesture.OnClick evt, DropdownVisuals dropdownControl)
{
if (evt.Receiver.transform.IsChildOf(dropdownControl.OptionsView.transform))
{
// The clicked object was not the dropdown itself but rather a list item within the dropdown.
// The dropdownControl itself will handle this event, so we don't need to do anything here.
return;
}
// Toggle the expanded state of the dropdown on click
if (dropdownControl.IsExpanded)
{
Collapse();
}
else
{
Expand();
}
}
///
/// Handles unfocusing the if the user clicks somewhere else.
///
private void HandlePostClick(UIBlock clickedUIBlock)
{
if (!Visuals.IsExpanded)
{
return;
}
if (clickedUIBlock == null || !clickedUIBlock.transform.IsChildOf(transform))
{
// Clicked somewhere else, so remove focus.
Collapse();
}
}
}
}