139 lines
3.4 KiB
C#
139 lines
3.4 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.EventSystems;
|
|
|
|
|
|
[DisallowMultipleComponent]
|
|
public class UXGroup : UIBehaviour
|
|
{
|
|
[SerializeField] private bool m_AllowSwitchOff;
|
|
[SerializeField] private List<UXButton> m_Buttons = new();
|
|
|
|
private UXButton _current;
|
|
|
|
public UnityEvent<UXButton> onSelectedChanged = new();
|
|
|
|
public bool allowSwitchOff
|
|
{
|
|
get => m_AllowSwitchOff;
|
|
set
|
|
{
|
|
m_AllowSwitchOff = value;
|
|
ValidateGroup();
|
|
}
|
|
}
|
|
|
|
protected override void Awake() => ValidateGroup();
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
foreach (var btn in m_Buttons)
|
|
if (btn)
|
|
btn.InternalTogSelected = false;
|
|
m_Buttons.Clear();
|
|
base.OnDestroy();
|
|
}
|
|
|
|
public void RegisterButton(UXButton button)
|
|
{
|
|
if (!button) return;
|
|
if (m_Buttons.Contains(button)) return;
|
|
m_Buttons.Add(button);
|
|
|
|
if (button.InternalTogSelected)
|
|
{
|
|
if (_current && _current != button)
|
|
_current.InternalTogSelected = false;
|
|
_current = button;
|
|
}
|
|
|
|
ValidateGroup();
|
|
}
|
|
|
|
public void UnregisterButton(UXButton button)
|
|
{
|
|
if (!button) return;
|
|
m_Buttons.Remove(button);
|
|
if (_current == button)
|
|
_current = null;
|
|
button.InternalTogSelected = false;
|
|
}
|
|
|
|
internal void NotifyButtonClicked(UXButton button)
|
|
{
|
|
if (!button) return;
|
|
|
|
if (button.InternalTogSelected)
|
|
{
|
|
if (m_AllowSwitchOff) SetSelected(null);
|
|
}
|
|
else
|
|
{
|
|
SetSelected(button);
|
|
}
|
|
}
|
|
|
|
private void SetSelected(UXButton target)
|
|
{
|
|
if (_current == target) return;
|
|
var previous = _current;
|
|
_current = null;
|
|
|
|
foreach (var btn in m_Buttons)
|
|
{
|
|
bool select = (btn == target);
|
|
if (btn.InternalTogSelected != select)
|
|
btn.InternalTogSelected = select;
|
|
if (select) _current = btn;
|
|
}
|
|
|
|
if (previous != _current)
|
|
onSelectedChanged?.Invoke(_current);
|
|
}
|
|
|
|
private void ValidateGroup()
|
|
{
|
|
if (_current != null && _current.InternalTogSelected) return;
|
|
|
|
if (!m_AllowSwitchOff && m_Buttons.Count > 0)
|
|
SetSelected(m_Buttons[0]);
|
|
}
|
|
|
|
public bool AnyOtherSelected(UXButton exclude)
|
|
{
|
|
foreach (var btn in m_Buttons)
|
|
if (btn != exclude && btn.InternalTogSelected)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public void SelectNext() => SelectRelative(1);
|
|
public void SelectPrevious() => SelectRelative(-1);
|
|
|
|
private void SelectRelative(int dir)
|
|
{
|
|
if (m_Buttons.Count == 0) return;
|
|
int start = _current ? m_Buttons.IndexOf(_current) : -1;
|
|
int next = FindNextSelectable(start, dir);
|
|
if (next >= 0) SetSelected(m_Buttons[next]);
|
|
}
|
|
|
|
private int FindNextSelectable(int startIndex, int dir)
|
|
{
|
|
if (m_Buttons.Count == 0) return -1;
|
|
int count = m_Buttons.Count;
|
|
int index = (startIndex + dir + count) % count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var btn = m_Buttons[index];
|
|
if (btn && btn.isActiveAndEnabled && btn.Interactable)
|
|
return index;
|
|
index = (index + dir + count) % count;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|