using UnityEngine.UIElements;
namespace RosettaUI.UIToolkit
{
///
/// AddしたVisualElementの中にフォーカスをループして留めるマニュピレーター
///
public class FocusTrapManipulator : Manipulator
{
private VisualElementFocusRing _focusRing;
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback(OnFocusOut);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback(OnFocusOut);
}
private void OnFocusOut(FocusOutEvent evt)
{
var direction = evt.direction;
if (direction != VisualElementFocusChangeDirection.right &&
direction != VisualElementFocusChangeDirection.left)
{
return;
}
// 自身の外へのフォーカスのみ対応
if (evt.relatedTarget is VisualElement nextFocusTarget && IsChild(nextFocusTarget))
{
return;
}
_focusRing ??= new VisualElementFocusRing(target);
// GetNextFocusable()でcurrentFocusableをnullにすると、最初or最後の要素が返る実装を当て込んでいる
var focusTarget = _focusRing.GetNextFocusable(null, evt.direction);
if (focusTarget == null)
{
return;
}
target.schedule.Execute(()=> focusTarget.Focus());
evt.StopPropagation();
return;
bool IsChild(VisualElement child)
{
while (child != null)
{
if (child == target) return true;
child = child.parent;
}
return false;
}
}
}
}