UniversalViewer/Assets/Scripts/ModelViewerBase/UI/Handles/UIHandle.cs

278 lines
8.6 KiB
C#
Raw Permalink Normal View History

2024-04-21 22:38:26 +08:00
using UnityEngine;
using UnityEngine.UI;
public class UIHandle : MonoBehaviour
{
/// <summary> Object that "owns" the handle </summary>
public ObjectContainer Owner;
/// <summary> Object that the handle refers to. Cast in inheriting class </summary>
public Transform Target;
/// <summary> Display object on the UI </summary>
public GameObject Handle;
/// <summary> Collider for selecting the handle on UI </summary>
public SphereCollider Collider;
/// <summary> Object that appears when right-clicking the handle </summary>
public UIPopupPanel Popup;
public LineRenderer LineRenderer;
protected SerializableTransform _defaultTransform;
protected float _baseScale = 1;
protected bool _forceDisplayOff = false;
protected ModelViewerMain Main => ModelViewerMain.GetInstance();
public static T CreateAsChild<T>(Transform parent) where T : UIHandle
{
var handle = new GameObject(parent.name + "_Handle").AddComponent<T>();
handle.transform.parent = parent.transform;
handle.transform.localPosition = Vector3.zero;
handle.transform.localScale = Vector3.one;
handle.transform.rotation = parent.rotation;
handle.Target = parent.transform;
return handle;
}
public virtual UIHandle Init(ObjectContainer owner, Transform target)
{
Target = target;
return Init(owner);
}
public virtual UIHandle Init(ObjectContainer owner)
{
HandleManager.RegisterHandle(this);
gameObject.layer = LayerMask.NameToLayer("UIHandle");
Target = Target == null? owner.transform : Target;
Owner = owner;
Owner.Handles.Add(this);
Handle = Instantiate(HandleManager.Instance.Pfb_HandleDisplay, HandleManager.Instance.HandlesPanel.transform);
Handle.transform.SetAsFirstSibling();
Popup = Instantiate(HandleManager.Instance.Pfb_Popup, HandleManager.Instance.HandlesPanel.transform).Init(this);
Popup.gameObject.SetActive(false);
_defaultTransform = new SerializableTransform(Target, Space.Self);
var collider = gameObject.AddComponent<SphereCollider>();
collider.center = Vector3.zero;
Collider = collider;
return this;
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position + Collider.center, transform.lossyScale.x * Collider.radius);
}
public virtual void UpdateManual(Camera camera, bool linesEnabled)
{
if (Handle != null && camera != null && transform != null)
{
Handle.transform.localScale = Vector3.one * Mathf.Clamp(_baseScale / Vector3.Distance(camera.transform.position, transform.position), 0.1f, 1);
if (Collider.transform.localScale.x != 0 && transform.lossyScale.x != 0)
{
Collider.radius = Mathf.Abs(35 /* magic number */ * (1 / transform.lossyScale.x) * GetRadiusOnScreen(camera, Collider.transform.position, Handle.transform.localScale.x));
2024-04-21 22:38:26 +08:00
Collider.radius = Mathf.Clamp(Collider.radius, 0.001f, 2);
}
Handle.transform.position = camera.WorldToScreenPoint(Collider.transform.TransformPoint(Collider.center));
if (ShouldBeHidden())
{
if (Handle.activeSelf == true)
{
ToggleActive(false);
}
}
else
{
bool isOnScreen =
!(Handle.transform.position.x < 0 || Handle.transform.position.y < 0 || Handle.transform.position.z < 0
|| Handle.transform.position.x > Screen.width || Handle.transform.position.y > Screen.height);
if (Handle.activeSelf != isOnScreen)
{
ToggleActive(!Handle.activeSelf);
}
}
}
if(Handle.activeSelf && LineRenderer != null)
{
if (LineRenderer.enabled != linesEnabled)
{
LineRenderer.enabled = linesEnabled;
}
if (linesEnabled)
{
LineRenderer.SetPositions(new Vector3[] { (Target).position, (Target).parent.position });
}
}
}
protected virtual bool ShouldBeHidden()
{
return _forceDisplayOff;
}
/// <summary> For future, `offset` param will allow popups to be spaced out when selecting more than 1 handle at a time. </summary>
public void TogglePopup(int offset = 0)
{
Popup.Offset = offset * (Popup.transform as RectTransform).sizeDelta.x * ModelViewerInterface.GetInstance().MainCanvas.scaleFactor;
2024-04-21 22:38:26 +08:00
ModelViewerInterface.ToggleVisible(Popup.gameObject);
}
public UIHandle SetDefaults(Vector3 localPos, Vector3 localRot, Vector3 localScale)
{
_defaultTransform.Position = localPos;
_defaultTransform.Rotation = localRot;
_defaultTransform.Scale = localScale;
return this;
}
public UIHandle SetColor(Color color)
{
color.a = Handle.GetComponent<Image>().color.a;
Handle.GetComponent<Image>().color = color;
return this;
}
public UIHandle SetScale(float scale)
{
this._baseScale = scale;
return this;
}
public UIHandle SetName(string name)
{
Handle.gameObject.name = name;
Popup.NameLabel.text = name;
return this;
}
public UIHandle SetOffset(Vector3 offset)
{
Collider.center = offset;
return this;
}
public UIHandle SetContainer(ObjectContainer container)
{
Owner = container;
return this;
}
public float GetRadiusOnScreen(Camera cam, Vector3 position, float screenSize)
{
Vector3 a = cam.WorldToScreenPoint(position);
Vector3 b = new Vector3(a.x, a.y + screenSize, a.z);
Vector3 aa = cam.ScreenToWorldPoint(a);
Vector3 bb = cam.ScreenToWorldPoint(b);
return (aa - bb).magnitude;
}
public UIHandle WithLineRenderer()
{
LineRenderer = Handle.gameObject.AddComponent<LineRenderer>();
LineRenderer.positionCount = 2;
LineRenderer.startWidth = LineRenderer.endWidth = 0.005f;
LineRenderer.material = HandleManager.Instance.LineRendererMaterial;
LineRenderer.startColor = LineRenderer.endColor = Handle.GetComponent<Image>().color;
return this;
}
private void OnDestroy()
{
if (Popup)
{
Destroy(Popup.gameObject);
}
if (Handle)
{
Destroy(Handle);
}
HandleManager.UnregisterHandle(this);
}
private void TransformReset(PoseLoadOptions options = null)
{
if(options == null)
{
options = PoseLoadOptions.All();
}
_defaultTransform.ApplyTo(Target, options);
}
public void TransformResetAll()
{
var HandleUndoData = new HandleUndoData(this);
HandleUndoData.OldPosition = new SerializableTransform(Target, Space.World);
TransformReset();
HandleUndoData.NewPosition = Target;
HandleManager.RegisterRuntimeGizmoUndoAction.Invoke(HandleUndoData);
Owner.SetKeyframe();
}
public void TransformResetPosition()
{
var HandleUndoData = new HandleUndoData(this);
HandleUndoData.OldPosition = new SerializableTransform(Target, Space.World);
TransformReset(new PoseLoadOptions(false) { Position = true });
HandleUndoData.NewPosition = Target;
HandleManager.RegisterRuntimeGizmoUndoAction.Invoke(HandleUndoData);
Owner.SetKeyframe();
}
public void TransformResetRotation()
{
var HandleUndoData = new HandleUndoData(this);
HandleUndoData.OldPosition = new SerializableTransform(Target, Space.World);
TransformReset(new PoseLoadOptions(false) { Rotation = true });
HandleUndoData.NewPosition = Target;
HandleManager.RegisterRuntimeGizmoUndoAction.Invoke(HandleUndoData);
Owner.SetKeyframe();
}
public void TransformResetScale()
{
var HandleUndoData = new HandleUndoData(this);
HandleUndoData.OldPosition = new SerializableTransform(Target, Space.World);
TransformReset(new PoseLoadOptions(false) { Scale = true });
HandleUndoData.NewPosition = Target;
HandleManager.RegisterRuntimeGizmoUndoAction.Invoke(HandleUndoData);
Owner.SetKeyframe();
}
public void ToggleActive(bool value)
{
Handle.SetActive(value);
Collider.enabled = value;
Popup.gameObject.SetActive(false);
}
public void ForceDisplayOff(bool value)
{
_forceDisplayOff = value;
}
}