using System; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace Cryville.Crtr.Config.UI { public abstract class PVPNumberBase : PropertyValuePanel, IInitializePotentialDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler { [SerializeField] RectTransform m_handleArea; [SerializeField] Image m_handle; [SerializeField] TMP_InputField m_text; protected void Start() { m_text.interactable = SetMapped; m_text.onValueChanged.AddListener(OnTextEdited); m_text.onDeselect.AddListener(OnTextDeselected); OnIdle(); } void OnTextEdited(string value) { if (!m_text.isFocused) return; if (double.TryParse(value, out var result)) { try { MappedValue = result; } catch (Exception) { } } } void OnTextDeselected(string value) { OnValueUpdated(); } protected override void OnValueUpdated() { if (Range != null && Range.Length == 2) { var min = (double)Range[0]; var max = (double)Range[1]; var value = Convert.ToDouble(RawValue); if (value < min) { value = min; RawValue = value; } else if (value > max) { value = max; RawValue = value; } } if (!m_text.isFocused) { m_text.text = MappedValue.ToString(); } } protected virtual void OnIdle() { } protected virtual void Update() { if (use) { SetRatio(GetRatioFromPos(pp)); SetValueFromPos(pp); } } Camera cam; Vector2 pp; bool use, nouse; public void OnInitializePotentialDrag(PointerEventData eventData) { // eventData.useDragThreshold = false; pp = eventData.position; } public void OnDrag(PointerEventData eventData) { if (nouse) return; cam = eventData.pressEventCamera; if (!use) { var delta = eventData.position - pp; float dx = Mathf.Abs(delta.x), dy = Mathf.Abs(delta.y); if (dx > dy) use = true; else if (dx < dy) nouse = true; } if (use) { pp = eventData.position; eventData.Use(); } } public void OnEndDrag(PointerEventData eventData) { if (!nouse) { SetValueFromPos(eventData.position); OnIdle(); eventData.Use(); use = false; } nouse = false; } public void OnPointerClick(PointerEventData eventData) { SetValueFromPos(eventData.position); eventData.Use(); } float GetRatioFromPos(Vector2 pos) { Vector2 lp; if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_handleArea, pos, cam, out lp)) { lp -= m_handleArea.rect.position; return Mathf.Clamp01(lp.x / m_handleArea.rect.width); } return float.NegativeInfinity; } void SetValueFromPos(Vector2 pos) { double min = double.NegativeInfinity, max = double.PositiveInfinity; if (Range != null && Range.Length == 2) { min = (double)Range[0]; max = (double)Range[1]; } double ratio = GetRatioFromPos(pos); double result = GetValue(ratio, Time.deltaTime, min, max); if (result < min) result = min; else if (result > max) result = max; RawValue = result; } protected abstract double GetValue(double ratio, float deltaTime, double min, double max); protected void SetRatio(float ratio) { m_handle.rectTransform.anchorMin = new Vector2(ratio, m_handle.rectTransform.anchorMin.y); m_handle.rectTransform.anchorMax = new Vector2(ratio, m_handle.rectTransform.anchorMax.y); m_handle.rectTransform.anchoredPosition = Vector2.zero; } } }