namespace WallstopStudios.DataVisualizer.Editor.UI
{
using System;
using UnityEngine;
using UnityEngine.UIElements;
/// Catalog row bindings. Existing selection/navigation keys take precedence over boundary keys. Unity buttons retain their platform activation behavior.
[Serializable]
public sealed class CatalogInputSettings
{
// Six logical points ignore small pointer jitter before a drag starts.
public const float DefaultDragThresholdPoints = 6f;
public float DragThresholdPoints
{
get => float.IsNaN(dragThresholdPoints) || float.IsInfinity(dragThresholdPoints) ? DefaultDragThresholdPoints : Math.Max(0, dragThresholdPoints);
set
{
if (value < 0 || float.IsNaN(value) || float.IsInfinity(value))
{
throw new ArgumentOutOfRangeException(nameof(value));
}
dragThresholdPoints = value;
}
}
public KeyCode SelectKey = KeyCode.Return;
public KeyCode AlternateSelectKey = KeyCode.KeypadEnter;
public KeyCode ToggleKey = KeyCode.Space;
public KeyCode PreviousTypeKey = KeyCode.UpArrow;
public KeyCode NextTypeKey = KeyCode.DownArrow;
public KeyCode FirstRowKey = KeyCode.Home;
public KeyCode LastRowKey = KeyCode.End;
public KeyCode PreviousPageKey = KeyCode.PageUp;
public KeyCode NextPageKey = KeyCode.PageDown;
public KeyCode CollapseKey = KeyCode.LeftArrow;
public KeyCode ExpandKey = KeyCode.RightArrow;
public KeyCode CancelDragKey = KeyCode.Escape;
public int PointerButton;
[SerializeField]
[Min(0)]
private float dragThresholdPoints = DefaultDragThresholdPoints;
/// Printable input belongs to the focused text field even when a navigation binding uses that letter.
public static bool IsTextEntry(EventBase evt)
{
return evt is IKeyboardEvent key
&& key.character != '\0'
&& !char.IsControl(key.character)
&& evt.target is VisualElement target
&& (target is TextField || target.GetFirstAncestorOfType() != null);
}
public static bool IsUnitySubmitKey(KeyCode key) => key is KeyCode.Return or KeyCode.KeypadEnter or KeyCode.Space;
public static bool MatchesKey(KeyCode actual, KeyCode configured) => configured != KeyCode.None && actual == configured;
public static bool IsNativeNavigationKey(KeyCode key)
{
return key
is KeyCode.UpArrow
or KeyCode.DownArrow
or KeyCode.Home
or KeyCode.End
or KeyCode.PageUp
or KeyCode.PageDown
or KeyCode.Space
or KeyCode.Return
or KeyCode.KeypadEnter;
}
public KeyCode ToNativeKey(KeyCode key)
{
if (MatchesKey(key, PreviousTypeKey))
{
return KeyCode.UpArrow;
}
if (MatchesKey(key, NextTypeKey))
{
return KeyCode.DownArrow;
}
if (IsConfirmKey(key))
{
return KeyCode.Return;
}
if (MatchesKey(key, ToggleKey))
{
return KeyCode.Space;
}
if (MatchesKey(key, FirstRowKey))
{
return KeyCode.Home;
}
if (MatchesKey(key, LastRowKey))
{
return KeyCode.End;
}
if (MatchesKey(key, PreviousPageKey))
{
return KeyCode.PageUp;
}
if (MatchesKey(key, NextPageKey))
{
return KeyCode.PageDown;
}
return KeyCode.None;
}
public bool IsConfirmKey(KeyCode key) => MatchesKey(key, SelectKey) || MatchesKey(key, AlternateSelectKey);
public bool IsConfirmCharacter(KeyCode key, char character)
{
return key == KeyCode.None && character is '\n' or '\r' && (IsConfirmKey(KeyCode.Return) || IsConfirmKey(KeyCode.KeypadEnter));
}
public bool IsSelectionKey(KeyCode key) => IsConfirmKey(key) || MatchesKey(key, ToggleKey);
public bool IsSelectionKey(IKeyboardEvent evt) => IsSelectionKey(evt.keyCode) && new EditorInputBinding(evt.keyCode).MatchesModifiers(evt.modifiers);
public bool HasPassedDragThreshold(Vector2 start, Vector2 current) => DragThresholdPoints * DragThresholdPoints < (current - start).sqrMagnitude;
}
}