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();
}
}
}