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 )
{
2024-04-23 18:25:12 +08:00
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 )
{
2024-04-23 18:25:12 +08:00
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 ;
}
}