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