254 lines
7.0 KiB
C#
254 lines
7.0 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace AlicizaX.UI
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public sealed class ItemInteractionProxy : MonoBehaviour,
|
|
IPointerClickHandler,
|
|
IPointerEnterHandler,
|
|
IPointerExitHandler,
|
|
ISelectHandler,
|
|
IDeselectHandler,
|
|
IMoveHandler,
|
|
IBeginDragHandler,
|
|
IDragHandler,
|
|
IEndDragHandler,
|
|
ISubmitHandler,
|
|
ICancelHandler
|
|
{
|
|
private IItemInteractionHost host;
|
|
private ItemInteractionFlags flags;
|
|
private Selectable focusAnchor;
|
|
private RecyclerItemSelectable ownedSelectable;
|
|
private Scroller parentScroller;
|
|
|
|
internal void Bind(IItemInteractionHost interactionHost)
|
|
{
|
|
host = interactionHost;
|
|
flags = interactionHost?.InteractionFlags ?? ItemInteractionFlags.None;
|
|
parentScroller = GetComponentInParent<Scroller>();
|
|
EnsureFocusAnchor();
|
|
|
|
if (ownedSelectable != null)
|
|
{
|
|
bool requiresSelection = RequiresSelection(flags);
|
|
ownedSelectable.interactable = requiresSelection;
|
|
ownedSelectable.enabled = requiresSelection;
|
|
}
|
|
|
|
InvalidateNavigationScope();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
host = null;
|
|
flags = ItemInteractionFlags.None;
|
|
parentScroller = null;
|
|
|
|
if (ownedSelectable != null)
|
|
{
|
|
ownedSelectable.interactable = false;
|
|
ownedSelectable.enabled = false;
|
|
}
|
|
|
|
InvalidateNavigationScope();
|
|
}
|
|
|
|
public Selectable GetSelectable()
|
|
{
|
|
EnsureFocusAnchor();
|
|
return focusAnchor;
|
|
}
|
|
|
|
internal bool TryGetFocusTarget(out GameObject target)
|
|
{
|
|
target = null;
|
|
if (!TryGetFocusableSelectable(out Selectable selectable))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
target = selectable.gameObject;
|
|
return target != null;
|
|
}
|
|
|
|
public void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.PointerClick) != 0)
|
|
{
|
|
host?.HandlePointerClick(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.PointerEnter) != 0)
|
|
{
|
|
host?.HandlePointerEnter(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnPointerExit(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.PointerExit) != 0)
|
|
{
|
|
host?.HandlePointerExit(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnSelect(BaseEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Select) != 0)
|
|
{
|
|
host?.HandleSelect(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnDeselect(BaseEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Deselect) != 0)
|
|
{
|
|
host?.HandleDeselect(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnMove(AxisEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Move) != 0)
|
|
{
|
|
host?.HandleMove(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.BeginDrag) != 0)
|
|
{
|
|
host?.HandleBeginDrag(eventData);
|
|
return;
|
|
}
|
|
|
|
parentScroller?.OnBeginDrag(eventData);
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Drag) != 0)
|
|
{
|
|
host?.HandleDrag(eventData);
|
|
return;
|
|
}
|
|
|
|
parentScroller?.OnDrag(eventData);
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.EndDrag) != 0)
|
|
{
|
|
host?.HandleEndDrag(eventData);
|
|
return;
|
|
}
|
|
|
|
parentScroller?.OnEndDrag(eventData);
|
|
}
|
|
|
|
public void OnSubmit(BaseEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Submit) != 0)
|
|
{
|
|
host?.HandleSubmit(eventData);
|
|
}
|
|
}
|
|
|
|
public void OnCancel(BaseEventData eventData)
|
|
{
|
|
if ((flags & ItemInteractionFlags.Cancel) != 0)
|
|
{
|
|
host?.HandleCancel(eventData);
|
|
}
|
|
}
|
|
|
|
private void EnsureFocusAnchor()
|
|
{
|
|
if (focusAnchor != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
focusAnchor = GetComponent<Selectable>();
|
|
if (focusAnchor != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ownedSelectable = GetComponent<RecyclerItemSelectable>();
|
|
if (ownedSelectable == null)
|
|
{
|
|
ownedSelectable = gameObject.AddComponent<RecyclerItemSelectable>();
|
|
}
|
|
|
|
focusAnchor = ownedSelectable;
|
|
}
|
|
|
|
private bool TryGetFocusableSelectable(out Selectable selectable)
|
|
{
|
|
EnsureFocusAnchor();
|
|
if (IsSelectableFocusable(focusAnchor))
|
|
{
|
|
selectable = focusAnchor;
|
|
return true;
|
|
}
|
|
|
|
Selectable[] selectables = GetComponentsInChildren<Selectable>(true);
|
|
for (int i = 0; i < selectables.Length; i++)
|
|
{
|
|
Selectable candidate = selectables[i];
|
|
if (candidate == focusAnchor)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (IsSelectableFocusable(candidate))
|
|
{
|
|
selectable = candidate;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
selectable = null;
|
|
return false;
|
|
}
|
|
|
|
private static bool IsSelectableFocusable(Selectable selectable)
|
|
{
|
|
return selectable != null &&
|
|
selectable.IsActive() &&
|
|
selectable.IsInteractable();
|
|
}
|
|
|
|
private static bool RequiresSelection(ItemInteractionFlags interactionFlags)
|
|
{
|
|
const ItemInteractionFlags selectionFlags =
|
|
ItemInteractionFlags.Select |
|
|
ItemInteractionFlags.Deselect |
|
|
ItemInteractionFlags.Move |
|
|
ItemInteractionFlags.Submit |
|
|
ItemInteractionFlags.Cancel;
|
|
|
|
return (interactionFlags & selectionFlags) != 0;
|
|
}
|
|
|
|
[System.Diagnostics.Conditional("INPUTSYSTEM_SUPPORT")]
|
|
private void InvalidateNavigationScope()
|
|
{
|
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
|
var scope = GetComponentInParent<UnityEngine.UI.UXNavigationScope>(true);
|
|
scope?.InvalidateSelectableCache();
|
|
#endif
|
|
}
|
|
}
|
|
}
|