namespace UIWidgets { using System.Collections.Generic; using UIWidgets.Attributes; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Serialization; /// /// Handle for the Rotatable component. /// [DisallowMultipleComponent] [RequireComponent(typeof(Rotatable))] [AddComponentMenu("UI/New UI Widgets/Interactions/Rotatable Handle")] public class RotatableHandle : UIBehaviourConditional { #region Interactable [SerializeField] bool interactable = true; /// /// Is widget interactable. /// /// true if interactable; otherwise, false. public bool Interactable { get { return interactable; } set { if (interactable != value) { interactable = value; InteractableChanged(); } } } /// /// If the canvas groups allow interaction. /// protected bool GroupsAllowInteraction = true; /// /// The CanvasGroup cache. /// protected List CanvasGroupCache = new List(); /// /// Process the CanvasGroupChanged event. /// protected override void OnCanvasGroupChanged() { var groupAllowInteraction = true; var t = transform; while (t != null) { t.GetComponents(CanvasGroupCache); var shouldBreak = false; foreach (var canvas_group in CanvasGroupCache) { if (!canvas_group.interactable) { groupAllowInteraction = false; shouldBreak = true; } shouldBreak |= canvas_group.ignoreParentGroups; } if (shouldBreak) { break; } t = t.parent; } if (groupAllowInteraction != GroupsAllowInteraction) { GroupsAllowInteraction = groupAllowInteraction; InteractableChanged(); } } /// /// Returns true if the GameObject and the Component are active. /// /// true if the GameObject and the Component are active; otherwise false. public override bool IsActive() { return base.IsActive() && GroupsAllowInteraction && Interactable; } /// /// Is instance interactable? /// /// true if instance interactable; otherwise false public bool IsInteractable() { return GroupsAllowInteraction && Interactable; } /// /// Process interactable change. /// protected virtual void InteractableChanged() { if (!base.IsActive()) { return; } OnInteractableChange(GroupsAllowInteraction && Interactable); } /// /// Process interactable change. /// /// Current interactable state. protected virtual void OnInteractableChange(bool interactableState) { } #endregion /// /// Use own handle or handle from the specified source. /// [SerializeField] public bool OwnHandle = true; /// /// Handle source. /// [SerializeField] [EditorConditionBool("OwnHandle", false)] public RotatableHandle HandleSource; /// /// Handle. /// [SerializeField] [FormerlySerializedAs("handler")] [EditorConditionBool("OwnHandle")] protected DragListener handle; /// /// Handle. /// public DragListener Handle { get { return handle; } set { if (handle != null) { handle.OnDragStartEvent.RemoveListener(StartDrag); handle.OnDragEvent.RemoveListener(Drag); handle.OnDragEndEvent.RemoveListener(EndDrag); } handle = value; if (handle != null) { handle.OnDragStartEvent.AddListener(StartDrag); handle.OnDragEvent.AddListener(Drag); handle.OnDragEndEvent.AddListener(EndDrag); } } } /// /// Is currently dragged? /// protected bool IsDrag; /// /// Target. /// protected Rotatable Target; bool isInited; /// /// Start rotation event. /// [SerializeField] public RotatableEvent OnStartRotate = new RotatableEvent(); /// /// During rotation event. /// [SerializeField] public RotatableEvent OnRotate = new RotatableEvent(); /// /// End rotation event. /// [SerializeField] public RotatableEvent OnEndRotate = new RotatableEvent(); /// /// Starts this instance. /// protected override void Start() { base.Start(); Init(); } /// /// Init this instance. /// public virtual void Init() { if (isInited) { return; } isInited = true; Target = GetComponent(); Target.Interactable = false; Handle = handle; } /// /// Interactable state of the handle source. /// protected bool HandleSourceInteractable; /// /// Get source handle. /// public void GetSourceHandle() { HandleSourceInteractable = HandleSource.interactable; HandleSource.interactable = false; SetHandleParent(HandleSource, transform); Handle = HandleSource.Handle; } /// /// Release source handle. /// public void ReleaseSourceHandle() { HandleSource.interactable = HandleSourceInteractable; HandleSource.Init(); SetHandleParent(HandleSource, HandleSource.transform); } /// /// Set new parent to the handle. /// /// Rotatable handle. /// Parent. protected static void SetHandleParent(RotatableHandle rotatableHandle, Transform parent) { if (rotatableHandle.Handle != null) { rotatableHandle.Handle.transform.SetParent(parent, false); } } /// /// Enable handle. /// public void EnableHandle() { Init(); if (Handle != null) { Handle.gameObject.SetActive(true); } } /// /// Disable handle. /// public void DisableHandle() { if (Handle != null) { Handle.gameObject.SetActive(false); } } /// /// Get angle between handle and target. /// /// Angle. protected virtual float GetAngle() { var handle_rt = handle.transform as RectTransform; var rt = transform as RectTransform; var rotation = rt.localRotation; rt.localRotation = Quaternion.Euler(Vector3.zero); var relative = GetCenter(rt) - GetCenter(handle_rt); relative.x *= -1f; var angle = Rotatable.Point2Angle(relative); handle_rt.localRotation = rotation; return angle; } /// /// Process begin drag event. /// /// Event data. protected virtual void StartDrag(PointerEventData eventData) { if (!IsActive()) { return; } IsDrag = true; var angle = GetAngle(); Target.InitRotate(angle); OnStartRotate.Invoke(Target); } /// /// Get center of the specified RectTransform. /// /// RectTransform. /// Center. protected static Vector2 GetCenter(RectTransform rt) { var pos = rt.position; var size = rt.rect.size; var pivot = rt.pivot; var center = new Vector2(pos.x - (size.x * (pivot.x - 0.5f)), pos.y - (size.y * (pivot.y - 0.5f))); return center; } /// /// Process end drag event. /// /// Event data. protected virtual void EndDrag(PointerEventData eventData) { IsDrag = false; OnEndRotate.Invoke(Target); } /// /// Process drag event. /// /// Event data. protected virtual void Drag(PointerEventData eventData) { if (!IsDrag) { return; } Target.Rotate(eventData); OnRotate.Invoke(Target); } /// /// Process destroy event. /// protected override void OnDestroy() { Handle = null; base.OnDestroy(); } } }