// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using UltimateXR.Core.Components;
using UnityEngine;
namespace UltimateXR.UI.UnityInputModule.Controls
{
///
/// Component that, added to a GameObject, will make all child components behave
/// like a single group where only one selection can be active at a time.
///
public partial class UxrToggleGroup : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private InitState _initialToggleState = InitState.DontChange;
#endregion
#region Public Types & Data
///
/// Event called whenever the currently selected toggle control was changed.
///
public event Action SelectionChanged;
///
/// Gets all the current toggle components.
///
public IList Toggles => _toggles;
///
/// Gets the currently selected toggle component.
///
public UxrToggleControlInput CurrentSelection { get; private set; }
#endregion
#region Public Methods
///
/// 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.
///
public void RefreshToggleChildrenList()
{
_toggles.ForEach(t => t.Toggled -= Toggle_Toggled);
_toggles.Clear();
_toggles = new List();
for (int i = 0; i < transform.childCount; ++i)
{
UxrToggleControlInput toggle = transform.GetChild(i).GetComponent();
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);
}
///
/// Clears the current selection if there is any.
///
public void ClearCurrentSelection()
{
BeginSync();
if (CurrentSelection != null)
{
CurrentSelection.IsSelected = false;
CurrentSelection.CanBeToggled = true;
CurrentSelection = null;
}
EndSyncMethod();
}
#endregion
#region Unity
///
/// Refreshes the toggle list and subscribes to toggle events.
///
protected override void OnEnable()
{
base.OnEnable();
if (!_toggles.Any())
{
RefreshToggleChildrenList();
}
}
///
/// Unsubscribes from toggle events.
///
protected override void OnDisable()
{
base.OnDisable();
_toggles.ForEach(t => t.Toggled -= Toggle_Toggled);
}
///
/// Initializes the current selection if required.
///
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
///
/// Called whenever a toggle component was toggled.
///
/// The toggle component that was toggled
private void Toggle_Toggled(UxrToggleControlInput toggle)
{
NotifyToggle(_toggles.IndexOf(toggle), true);
}
#endregion
#region Private Methods
///
/// Notifies that a toggle component was toggled.
///
/// The index of the toggle
/// Whether the call comes from handling a toggle event
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 _toggles = new List();
#endregion
}
}