Forked from yasirkula/SceneViewUIObjectPickerContextWindow.cs
Created
December 11, 2023 05:36
-
-
Save savage69kr/e7f1b9cc9f7f7df751f3f435123a2f9f to your computer and use it in GitHub Desktop.
Revisions
-
yasirkula revised this gist
Dec 9, 2023 . 1 changed file with 5 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -252,6 +252,11 @@ private static bool ShouldCheckRectTransform( RectTransform rectTransform, Vecto if( !culledByCanvasGroup ) { // If the target is a MaskableGraphic that ignores masks (i.e. visible outside masks) and isn't fully transparent, accept it MaskableGraphic maskableGraphic = rectTransform.GetComponent<MaskableGraphic>(); if( maskableGraphic != null && !maskableGraphic.maskable && maskableGraphic.color.a > 0f ) return true; raycastFilters.Clear(); rectTransform.GetComponentsInParent( false, raycastFilters ); foreach( var raycastFilter in raycastFilters ) -
yasirkula revised this gist
Dec 8, 2023 . 1 changed file with 8 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -229,6 +229,14 @@ private static void CheckRectTransformRecursive( RectTransform rectTransform, Ve private static bool ShouldCheckRectTransform( RectTransform rectTransform, Vector2 pointerPos, Camera camera, ref bool culledByCanvasGroup ) { #if UNITY_2019_3_OR_NEWER if( SceneVisibilityManager.instance.IsHidden( rectTransform.gameObject, false ) ) return false; if( SceneVisibilityManager.instance.IsPickingDisabled( rectTransform.gameObject, false ) ) return false; #endif CanvasRenderer canvasRenderer = rectTransform.GetComponent<CanvasRenderer>(); if( canvasRenderer != null && canvasRenderer.cull ) return false; -
yasirkula created this gist
Dec 2, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,258 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Text; using UnityEditor; using UnityEngine; using UnityEngine.UI; #if UNITY_2021_2_OR_NEWER using PrefabStage = UnityEditor.SceneManagement.PrefabStage; using PrefabStageUtility = UnityEditor.SceneManagement.PrefabStageUtility; #elif UNITY_2018_3_OR_NEWER using PrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStage; using PrefabStageUtility = UnityEditor.Experimental.SceneManagement.PrefabStageUtility; #endif public class SceneViewUIObjectPickerContextWindow : EditorWindow { private struct Entry { public readonly RectTransform RectTransform; public readonly List<Entry> Children; public Entry( RectTransform rectTransform ) { RectTransform = rectTransform; Children = new List<Entry>( 2 ); } } private readonly List<RectTransform> uiObjects = new List<RectTransform>( 16 ); private readonly List<string> uiObjectLabels = new List<string>( 16 ); private static RectTransform hoveredUIObject; private static readonly Vector3[] hoveredUIObjectCorners = new Vector3[4]; private static readonly List<ICanvasRaycastFilter> raycastFilters = new List<ICanvasRaycastFilter>( 4 ); private static double lastRightClickTime; private static Vector2 lastRightPos; private static bool blockSceneViewInput; private readonly MethodInfo screenFittedRectGetter = typeof( EditorWindow ).Assembly.GetType( "UnityEditor.ContainerWindow" ).GetMethod( "FitRectToScreen", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ); private const float Padding = 1f; private float RowHeight { get { return EditorGUIUtility.singleLineHeight; } } private GUIStyle RowGUIStyle { get { return "MenuItem"; } } private void ShowContextWindow( List<Entry> results ) { StringBuilder sb = new StringBuilder( 100 ); InitializeUIObjectsRecursive( results, 0, sb ); GUIStyle rowGUIStyle = RowGUIStyle; float preferredWidth = 0f; foreach( string label in uiObjectLabels ) preferredWidth = Mathf.Max( preferredWidth, rowGUIStyle.CalcSize( new GUIContent( label ) ).x ); ShowAsDropDown( new Rect(), new Vector2( preferredWidth + Padding * 2f, uiObjects.Count * RowHeight + Padding * 2f ) ); // Show dropdown above the cursor instead of below the cursor position = (Rect) screenFittedRectGetter.Invoke( null, new object[3] { new Rect( GUIUtility.GUIToScreenPoint( Event.current.mousePosition ) - new Vector2( 0f, position.height ), position.size ), true, true } ); } private void InitializeUIObjectsRecursive( List<Entry> results, int depth, StringBuilder sb ) { foreach( Entry entry in results ) { sb.Length = 0; uiObjects.Add( entry.RectTransform ); uiObjectLabels.Add( sb.Append( ' ', depth * 4 ).Append( entry.RectTransform.name ).ToString() ); if( entry.Children.Count > 0 ) InitializeUIObjectsRecursive( entry.Children, depth + 1, sb ); } } protected void OnEnable() { wantsMouseMove = wantsMouseEnterLeaveWindow = true; #if UNITY_2020_1_OR_NEWER wantsLessLayoutEvents = false; #endif blockSceneViewInput = true; } protected void OnDisable() { hoveredUIObject = null; SceneView.RepaintAll(); } protected void OnGUI() { Event ev = Event.current; float rowWidth = position.width - Padding * 2f, rowHeight = RowHeight; GUIStyle rowGUIStyle = RowGUIStyle; int hoveredRowIndex = -1; for( int i = 0; i < uiObjects.Count; i++ ) { Rect rect = new Rect( Padding, Padding + i * rowHeight, rowWidth, rowHeight ); if( GUI.Button( rect, uiObjectLabels[i], rowGUIStyle ) ) { if( uiObjects[i] != null ) Selection.activeTransform = uiObjects[i]; blockSceneViewInput = false; ev.Use(); Close(); GUIUtility.ExitGUI(); } if( hoveredRowIndex < 0 && ev.type == EventType.MouseMove && rect.Contains( ev.mousePosition ) ) hoveredRowIndex = i; } if( ev.type == EventType.MouseMove || ev.type == EventType.MouseLeaveWindow ) { RectTransform hoveredUIObject = ( hoveredRowIndex >= 0 ) ? uiObjects[hoveredRowIndex] : null; if( hoveredUIObject != SceneViewUIObjectPickerContextWindow.hoveredUIObject ) { SceneViewUIObjectPickerContextWindow.hoveredUIObject = hoveredUIObject; Repaint(); SceneView.RepaintAll(); } } } [InitializeOnLoadMethod] private static void OnSceneViewGUI() { #if UNITY_2019_1_OR_NEWER SceneView.duringSceneGui += ( SceneView sceneView ) => #else SceneView.onSceneGUIDelegate += ( SceneView sceneView ) => #endif { /// Couldn't get <see cref="EventType.ContextClick"/> to work here in Unity 5.6 so implemented context click detection manually Event ev = Event.current; switch( ev.type ) { case EventType.MouseDown: { if( ev.button == 1 ) { lastRightClickTime = EditorApplication.timeSinceStartup; lastRightPos = ev.mousePosition; } else if( blockSceneViewInput ) { // User has clicked outside the context window to close it. Ignore this click in Scene view if it's left click blockSceneViewInput = false; if( ev.button == 0 ) { GUIUtility.hotControl = 0; ev.Use(); } } break; } case EventType.MouseUp: { if( ev.button == 1 && EditorApplication.timeSinceStartup - lastRightClickTime < 0.2 && ( ev.mousePosition - lastRightPos ).magnitude < 2f ) OnSceneViewRightClicked( sceneView ); break; } } if( hoveredUIObject != null ) { hoveredUIObject.GetWorldCorners( hoveredUIObjectCorners ); Handles.DrawSolidRectangleWithOutline( hoveredUIObjectCorners, new Color( 1f, 1f, 0f, 0.25f ), Color.black ); } }; } private static void OnSceneViewRightClicked( SceneView sceneView ) { // Find all UI objects under the cursor Vector2 pointerPos = HandleUtility.GUIPointToScreenPixelCoordinate( Event.current.mousePosition ); Entry rootEntry = new Entry( null ); #if UNITY_2018_3_OR_NEWER PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); if( prefabStage != null && prefabStage.stageHandle.IsValid() && prefabStage.prefabContentsRoot.transform is RectTransform prefabStageRoot ) CheckRectTransformRecursive( prefabStageRoot, pointerPos, sceneView.camera, false, rootEntry.Children ); else #endif { #if UNITY_2022_3_OR_NEWER Canvas[] canvases = FindObjectsByType<Canvas>( FindObjectsSortMode.None ); #else Canvas[] canvases = FindObjectsOfType<Canvas>(); #endif Array.Sort( canvases, ( c1, c2 ) => c1.sortingOrder.CompareTo( c2.sortingOrder ) ); foreach( Canvas canvas in canvases ) { if( canvas != null && canvas.gameObject.activeInHierarchy && canvas.isRootCanvas ) CheckRectTransformRecursive( (RectTransform) canvas.transform, pointerPos, sceneView.camera, false, rootEntry.Children ); } } // Remove non-Graphic root entries with no children from the results rootEntry.Children.RemoveAll( ( canvasEntry ) => canvasEntry.Children.Count == 0 && !canvasEntry.RectTransform.GetComponent<Graphic>() ); // If any results found, show the context window if( rootEntry.Children.Count > 0 ) CreateInstance<SceneViewUIObjectPickerContextWindow>().ShowContextWindow( rootEntry.Children ); } private static void CheckRectTransformRecursive( RectTransform rectTransform, Vector2 pointerPos, Camera camera, bool culledByCanvasGroup, List<Entry> result ) { if( RectTransformUtility.RectangleContainsScreenPoint( rectTransform, pointerPos, camera ) && ShouldCheckRectTransform( rectTransform, pointerPos, camera, ref culledByCanvasGroup ) ) { Entry entry = new Entry( rectTransform ); result.Add( entry ); result = entry.Children; } for( int i = 0, childCount = rectTransform.childCount; i < childCount; i++ ) { RectTransform childRectTransform = rectTransform.GetChild( i ) as RectTransform; if( childRectTransform != null && childRectTransform.gameObject.activeSelf ) CheckRectTransformRecursive( childRectTransform, pointerPos, camera, culledByCanvasGroup, result ); } } private static bool ShouldCheckRectTransform( RectTransform rectTransform, Vector2 pointerPos, Camera camera, ref bool culledByCanvasGroup ) { CanvasRenderer canvasRenderer = rectTransform.GetComponent<CanvasRenderer>(); if( canvasRenderer != null && canvasRenderer.cull ) return false; CanvasGroup canvasGroup = rectTransform.GetComponent<CanvasGroup>(); if( canvasGroup != null ) { if( canvasGroup.ignoreParentGroups ) culledByCanvasGroup = canvasGroup.alpha == 0f; else if( canvasGroup.alpha == 0f ) culledByCanvasGroup = true; } if( !culledByCanvasGroup ) { raycastFilters.Clear(); rectTransform.GetComponentsInParent( false, raycastFilters ); foreach( var raycastFilter in raycastFilters ) { if( !raycastFilter.IsRaycastLocationValid( pointerPos, camera ) ) return false; } } return !culledByCanvasGroup; } }