Files
dungeons/Assets/UltimateXR/Runtime/Scripts/UI/UnityInputModule/Controls/UxrToggleGroup.cs
2024-08-06 21:58:35 +02:00

199 lines
5.9 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrToggleGroup.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using UltimateXR.Core.Components;
using UnityEngine;
namespace UltimateXR.UI.UnityInputModule.Controls
{
/// <summary>
/// Component that, added to a GameObject, will make all child <see cref="UxrToggleControlInput" /> components behave
/// like a single group where only one selection can be active at a time.
/// </summary>
public partial class UxrToggleGroup : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private InitState _initialToggleState = InitState.DontChange;
#endregion
#region Public Types & Data
/// <summary>
/// Event called whenever the currently selected toggle control was changed.
/// </summary>
public event Action<UxrToggleControlInput> SelectionChanged;
/// <summary>
/// Gets all the current toggle components.
/// </summary>
public IList<UxrToggleControlInput> Toggles => _toggles;
/// <summary>
/// Gets the currently selected toggle component.
/// </summary>
public UxrToggleControlInput CurrentSelection { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Refreshes the internal list of children toggle components. This can be used to refresh the list whenever a new
/// child toggle component was added dynamically, or was removed.
/// </summary>
public void RefreshToggleChildrenList()
{
_toggles.ForEach(t => t.Toggled -= Toggle_Toggled);
_toggles.Clear();
_toggles = new List<UxrToggleControlInput>();
for (int i = 0; i < transform.childCount; ++i)
{
UxrToggleControlInput toggle = transform.GetChild(i).GetComponent<UxrToggleControlInput>();
if (toggle != null && !toggle.IsBeingDestroyed && toggle.isActiveAndEnabled)
{
_toggles.Add(toggle);
toggle.Toggled += Toggle_Toggled;
}
}
CurrentSelection = _toggles.FirstOrDefault(t => t.IsSelected);
_toggles.ForEach(t => t.CanBeToggled = t != CurrentSelection);
}
/// <summary>
/// Clears the current selection if there is any.
/// </summary>
public void ClearCurrentSelection()
{
BeginSync();
if (CurrentSelection != null)
{
CurrentSelection.IsSelected = false;
CurrentSelection.CanBeToggled = true;
CurrentSelection = null;
}
EndSyncMethod();
}
#endregion
#region Unity
/// <summary>
/// Refreshes the toggle list and subscribes to toggle events.
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
if (!_toggles.Any())
{
RefreshToggleChildrenList();
}
}
/// <summary>
/// Unsubscribes from toggle events.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
_toggles.ForEach(t => t.Toggled -= Toggle_Toggled);
}
/// <summary>
/// Initializes the current selection if required.
/// </summary>
protected override void Start()
{
base.Start();
switch (_initialToggleState)
{
case InitState.DontChange: break;
case InitState.FirstChild:
if (_toggles.Any())
{
_toggles.First().IsSelected = true;
}
break;
}
}
#endregion
#region Event Handling Methods
/// <summary>
/// Called whenever a toggle component was toggled.
/// </summary>
/// <param name="toggle">The toggle component that was toggled</param>
private void Toggle_Toggled(UxrToggleControlInput toggle)
{
NotifyToggle(_toggles.IndexOf(toggle), true);
}
#endregion
#region Private Methods
/// <summary>
/// Notifies that a toggle component was toggled.
/// </summary>
/// <param name="index">The index of the toggle</param>
/// <param name="isFromEvent">Whether the call comes from handling a toggle event</param>
private void NotifyToggle(int index, bool isFromEvent)
{
BeginSync();
UxrToggleControlInput toggle = index >= 0 && index < _toggles.Count ? _toggles[index] : null;
foreach (UxrToggleControlInput t in _toggles)
{
t.CanBeToggled = t != toggle;
if (t != null && t != toggle)
{
t.SetIsSelected(false, false);
}
}
CurrentSelection = toggle;
if (CurrentSelection != null && !isFromEvent)
{
// Since it doesn't come from an event, we need to update the selection manually.
CurrentSelection.SetIsSelected(true, false);
}
SelectionChanged?.Invoke(toggle);
EndSyncMethod(new object[] { index, false });
}
#endregion
#region Private Types & Data
private List<UxrToggleControlInput> _toggles = new List<UxrToggleControlInput>();
#endregion
}
}