com.alicizax.unity.ui.exten.../Runtime/UXComponent/UX/UXGroup.cs

190 lines
4.6 KiB
C#
Raw Normal View History

2025-04-11 17:26:28 +08:00
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;
2025-07-28 13:04:49 +08:00
[ReadOnly, SerializeField] private List<UXButton> m_Buttons = new();
2025-04-11 17:26:28 +08:00
2025-07-28 13:04:49 +08:00
private UXButton _current;
private readonly HashSet<UXButton> _registeredButtons = new();
2025-04-11 17:26:28 +08:00
2025-07-28 13:04:49 +08:00
public UnityEvent<UXButton> onSelectedChanged = new();
2025-04-11 17:26:28 +08:00
public bool allowSwitchOff
{
get => m_AllowSwitchOff;
set
{
m_AllowSwitchOff = value;
ValidateGroupState();
}
}
protected override void OnDestroy()
{
2025-07-28 13:04:49 +08:00
foreach (var button in _registeredButtons)
{
if (button) button.IsSelected = false;
}
2025-08-08 20:56:31 +08:00
2025-04-11 17:26:28 +08:00
m_Buttons.Clear();
2025-07-28 13:04:49 +08:00
_registeredButtons.Clear();
base.OnDestroy();
2025-04-11 17:26:28 +08:00
}
2025-07-28 13:04:49 +08:00
protected override void Awake() => ValidateGroupState();
2025-04-11 17:26:28 +08:00
public void RegisterButton(UXButton button)
{
2025-07-28 13:04:49 +08:00
if (!button || _registeredButtons.Contains(button)) return;
m_Buttons.Add(button);
_registeredButtons.Add(button);
if (button.IsSelected)
2025-04-11 17:26:28 +08:00
{
2025-07-28 13:04:49 +08:00
if (_current && _current != button)
_current.IsSelected = false;
_current = button;
2025-04-11 17:26:28 +08:00
}
2025-07-28 13:04:49 +08:00
ValidateGroupState();
2025-04-11 17:26:28 +08:00
}
public void UnregisterButton(UXButton button)
{
2025-07-28 13:04:49 +08:00
if (!button || !_registeredButtons.Contains(button)) return;
m_Buttons.Remove(button);
_registeredButtons.Remove(button);
button.IsSelected = false;
if (_current == button)
_current = null;
2025-04-11 17:26:28 +08:00
}
internal void NotifyButtonClicked(UXButton clickedButton)
{
2025-07-28 13:04:49 +08:00
if (clickedButton.IsSelected)
2025-04-11 17:26:28 +08:00
{
2025-07-28 13:04:49 +08:00
if (m_AllowSwitchOff)
SetSelectedButton(null);
2025-04-11 17:26:28 +08:00
}
else
{
2025-07-28 13:04:49 +08:00
SetSelectedButton(clickedButton);
2025-04-11 17:26:28 +08:00
}
}
2025-07-28 13:04:49 +08:00
private void SetSelectedButton(UXButton target)
2025-04-11 17:26:28 +08:00
{
2025-07-28 13:04:49 +08:00
var previous = _current;
_current = null;
2025-04-11 17:26:28 +08:00
foreach (var button in m_Buttons)
{
2025-07-28 13:04:49 +08:00
bool shouldSelect = (button == target);
2025-04-11 17:26:28 +08:00
if (button.IsSelected != shouldSelect)
button.IsSelected = shouldSelect;
2025-07-28 13:04:49 +08:00
if (shouldSelect)
_current = button;
2025-04-11 17:26:28 +08:00
}
2025-07-28 13:04:49 +08:00
if (previous != _current)
onSelectedChanged?.Invoke(_current);
2025-04-11 17:26:28 +08:00
}
private void ValidateGroupState()
{
2025-07-28 13:04:49 +08:00
bool hasSelected = _current != null && _current.IsSelected;
if (!hasSelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
2025-04-11 17:26:28 +08:00
SetSelectedButton(m_Buttons[0]);
}
public bool AnyOtherSelected(UXButton exclusion)
{
foreach (var button in m_Buttons)
{
if (button != exclusion && button.IsSelected)
return true;
}
2025-08-08 20:56:31 +08:00
2025-04-11 17:26:28 +08:00
return false;
}
2025-08-08 20:56:31 +08:00
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;
2025-08-11 14:14:01 +08:00
int startIndex = _current ? m_Buttons.IndexOf(_current) : -1;
2025-08-08 20:56:31 +08:00
int newIndex = FindSelectableIndex(startIndex, 1);
if (newIndex != -1)
{
SetSelectedButton(m_Buttons[newIndex]);
}
}
2025-08-11 14:45:27 +08:00
private int FindSelectableIndex(int startIndex, int direction)
{
2025-08-08 20:56:31 +08:00
if (m_Buttons.Count == 0) return -1;
2025-08-11 14:45:27 +08:00
int buttonCount = m_Buttons.Count - 1;
int valueIndex = startIndex == -1 ? 0 : startIndex + direction;
int fallBackIndex = -1;
2025-08-08 20:56:31 +08:00
2025-08-11 14:45:27 +08:00
valueIndex = valueIndex > buttonCount ? 0 : (valueIndex < 0 ? buttonCount : valueIndex);
if (valueIndex > buttonCount)
{
valueIndex = 0;
}
else if (valueIndex < 0)
{
valueIndex = buttonCount;
}
2025-08-08 20:56:31 +08:00
2025-08-11 14:45:27 +08:00
while (valueIndex != startIndex)
{
UXButton btn = m_Buttons[valueIndex];
if (btn.isActiveAndEnabled && btn.Interactable)
{
fallBackIndex = valueIndex;
break;
}
2025-08-08 20:56:31 +08:00
2025-08-11 14:45:27 +08:00
valueIndex += direction;
if (valueIndex > buttonCount)
{
valueIndex = 0;
}
else if (valueIndex < 0)
{
valueIndex = buttonCount;
2025-08-11 14:14:01 +08:00
}
2025-08-08 20:56:31 +08:00
}
2025-08-11 14:45:27 +08:00
return fallBackIndex;
2025-08-08 20:56:31 +08:00
}
2025-04-11 17:26:28 +08:00
}