190 lines
4.6 KiB
C#
190 lines
4.6 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using System.Collections.Generic;
|
|
using Sirenix.OdinInspector;
|
|
using UnityEngine.EventSystems;
|
|
|
|
[DisallowMultipleComponent]
|
|
public class UXGroup : UIBehaviour
|
|
{
|
|
[SerializeField] private bool m_AllowSwitchOff;
|
|
[ReadOnly, SerializeField] private List<UXButton> m_Buttons = new();
|
|
|
|
private UXButton _current;
|
|
private readonly HashSet<UXButton> _registeredButtons = new();
|
|
|
|
public UnityEvent<UXButton> onSelectedChanged = new();
|
|
|
|
public bool allowSwitchOff
|
|
{
|
|
get => m_AllowSwitchOff;
|
|
set
|
|
{
|
|
m_AllowSwitchOff = value;
|
|
ValidateGroupState();
|
|
}
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
foreach (var button in _registeredButtons)
|
|
{
|
|
if (button) button.IsSelected = false;
|
|
}
|
|
|
|
m_Buttons.Clear();
|
|
_registeredButtons.Clear();
|
|
base.OnDestroy();
|
|
}
|
|
|
|
protected override void Awake() => ValidateGroupState();
|
|
|
|
public void RegisterButton(UXButton button)
|
|
{
|
|
if (!button || _registeredButtons.Contains(button)) return;
|
|
|
|
m_Buttons.Add(button);
|
|
_registeredButtons.Add(button);
|
|
|
|
if (button.IsSelected)
|
|
{
|
|
if (_current && _current != button)
|
|
_current.IsSelected = false;
|
|
_current = button;
|
|
}
|
|
|
|
ValidateGroupState();
|
|
}
|
|
|
|
public void UnregisterButton(UXButton button)
|
|
{
|
|
if (!button || !_registeredButtons.Contains(button)) return;
|
|
|
|
m_Buttons.Remove(button);
|
|
_registeredButtons.Remove(button);
|
|
button.IsSelected = false;
|
|
|
|
if (_current == button)
|
|
_current = null;
|
|
}
|
|
|
|
internal void NotifyButtonClicked(UXButton clickedButton)
|
|
{
|
|
if (clickedButton.IsSelected)
|
|
{
|
|
if (m_AllowSwitchOff)
|
|
SetSelectedButton(null);
|
|
}
|
|
else
|
|
{
|
|
SetSelectedButton(clickedButton);
|
|
}
|
|
}
|
|
|
|
private void SetSelectedButton(UXButton target)
|
|
{
|
|
var previous = _current;
|
|
_current = null;
|
|
|
|
foreach (var button in m_Buttons)
|
|
{
|
|
bool shouldSelect = (button == target);
|
|
if (button.IsSelected != shouldSelect)
|
|
button.IsSelected = shouldSelect;
|
|
|
|
if (shouldSelect)
|
|
_current = button;
|
|
}
|
|
|
|
if (previous != _current)
|
|
onSelectedChanged?.Invoke(_current);
|
|
}
|
|
|
|
private void ValidateGroupState()
|
|
{
|
|
bool hasSelected = _current != null && _current.IsSelected;
|
|
if (!hasSelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
|
SetSelectedButton(m_Buttons[0]);
|
|
}
|
|
|
|
public bool AnyOtherSelected(UXButton exclusion)
|
|
{
|
|
foreach (var button in m_Buttons)
|
|
{
|
|
if (button != exclusion && button.IsSelected)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public void SelectPrevious()
|
|
{
|
|
if (m_Buttons.Count == 0) return;
|
|
|
|
int startIndex = _current ? m_Buttons.IndexOf(_current) : -1;
|
|
int newIndex = FindSelectableIndex(startIndex, -1);
|
|
|
|
if (newIndex != -1)
|
|
{
|
|
SetSelectedButton(m_Buttons[newIndex]);
|
|
}
|
|
}
|
|
|
|
|
|
public void SelectNext()
|
|
{
|
|
if (m_Buttons.Count == 0) return;
|
|
|
|
int startIndex = _current ? m_Buttons.IndexOf(_current) : -1;
|
|
int newIndex = FindSelectableIndex(startIndex, 1);
|
|
|
|
if (newIndex != -1)
|
|
{
|
|
SetSelectedButton(m_Buttons[newIndex]);
|
|
}
|
|
}
|
|
|
|
|
|
private int FindSelectableIndex(int startIndex, int direction)
|
|
{
|
|
if (m_Buttons.Count == 0) return -1;
|
|
int buttonCount = m_Buttons.Count - 1;
|
|
int valueIndex = startIndex == -1 ? 0 : startIndex + direction;
|
|
int fallBackIndex = -1;
|
|
|
|
valueIndex = valueIndex > buttonCount ? 0 : (valueIndex < 0 ? buttonCount : valueIndex);
|
|
if (valueIndex > buttonCount)
|
|
{
|
|
valueIndex = 0;
|
|
}
|
|
else if (valueIndex < 0)
|
|
{
|
|
valueIndex = buttonCount;
|
|
}
|
|
|
|
while (valueIndex != startIndex)
|
|
{
|
|
UXButton btn = m_Buttons[valueIndex];
|
|
if (btn.isActiveAndEnabled && btn.Interactable)
|
|
{
|
|
fallBackIndex = valueIndex;
|
|
break;
|
|
}
|
|
|
|
valueIndex += direction;
|
|
if (valueIndex > buttonCount)
|
|
{
|
|
valueIndex = 0;
|
|
}
|
|
else if (valueIndex < 0)
|
|
{
|
|
valueIndex = buttonCount;
|
|
}
|
|
}
|
|
|
|
return fallBackIndex;
|
|
}
|
|
}
|