using hedCommon.extension.editor; using hedCommon.extension.runtime; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; namespace hedCommon.saveLastSelection { /// /// This tool permit you to quickly select gameObjects behind others, with only two action: /// - Clic /// - Scroll Up/Down ! /// [InitializeOnLoad] public static class ClickAndScroll { private const int MAX_DEPTH = 40; private static List _underneethGameObjects = new List(MAX_DEPTH); private static MethodInfo _internalPickClosestGameObject; private static int _currentIndex = 0; static ClickAndScroll() { if (EditorApplication.isPlaying) { return; } SceneView.duringSceneGui += OnSceneGUI; FindMethodByReflection(); _currentIndex = 0; } /// /// Save reference of the Internal_PickClosestGO reflection method /// private static void FindMethodByReflection() { Assembly editorAssembly = typeof(Editor).Assembly; System.Type handleUtilityType = editorAssembly.GetType("UnityEditor.HandleUtility"); _internalPickClosestGameObject = handleUtilityType.GetMethod("Internal_PickClosestGO", BindingFlags.Static | BindingFlags.NonPublic); } /// /// pick a gameObject from the sceneView at a given mouse position /// /// current camera /// layer accepted /// mouse position /// ignored gameObjects /// /// /// private static GameObject PickObjectOnPos(Camera cam, int layers, Vector2 position, GameObject[] ignore, GameObject[] filter, out int materialIndex) { materialIndex = -1; return (GameObject)_internalPickClosestGameObject.Invoke(null, new object[] { cam, layers, position, ignore, filter, materialIndex }); } /// /// get the right click on sceneView /// /// private static void OnSceneGUI(SceneView sceneView) { if (ExtEventEditor.IsClickOnSceneView(Event.current)) { SaveAllGameObjectUnderneethMouse(Event.current.mousePosition, sceneView); } else { AttemptToScroll(); } } /// /// attempt to create a contextMenu /// /// /// private static void SaveAllGameObjectUnderneethMouse(Vector2 pos, SceneView sceneView) { _underneethGameObjects.Clear(); Vector2 invertedPos = new Vector2(pos.x, sceneView.position.height - 16 - pos.y); for (int i = 0; i <= MAX_DEPTH; i++) { GameObject clickedGameObject = PickObjectOnPos(sceneView.camera, ~0, invertedPos, _underneethGameObjects.ToArray(), null, out int matIndex); if (clickedGameObject != null) { _underneethGameObjects.AddIfNotContain(clickedGameObject); } } _currentIndex = 0; } private static void AttemptToScroll() { if (_underneethGameObjects.Count <= 1) { return; } bool isScrollingDown = ExtEventEditor.IsScrollingDown(Event.current, out float delta); bool isScrollingUp = ExtEventEditor.IsScrollingUp(Event.current, out delta); if (!isScrollingDown && !isScrollingUp) { return; } bool isShiftHeld = Event.current.shift; bool isControlHeld = Event.current.control; bool isSpecialKeyHeld = isShiftHeld || isControlHeld; if (isSpecialKeyHeld && isScrollingDown) { if (_currentIndex == 0 && Selection.activeGameObject != _underneethGameObjects[0]) { _underneethGameObjects.Insert(0, Selection.activeGameObject); } _currentIndex++; SelectItem(isShiftHeld, isControlHeld); ExtEventEditor.Use(); } else if (isSpecialKeyHeld && isScrollingUp) { if (_currentIndex == 0 && Selection.activeGameObject != _underneethGameObjects[0]) { _underneethGameObjects.Insert(0, Selection.activeGameObject); } else { _currentIndex--; } SelectItem(isShiftHeld, isControlHeld); ExtEventEditor.Use(); } } private static void SelectItem(bool isShiftHeld, bool isControlHeld) { _currentIndex = SetBetween(_currentIndex, 0, _underneethGameObjects.Count - 1); if (isControlHeld) { Selection.activeGameObject = _underneethGameObjects[_currentIndex]; } if (isShiftHeld) { EditorGUIUtility.PingObject(_underneethGameObjects[_currentIndex]); } } private static int SetBetween(int currentValue, int value1, int value2) { if (value1 > value2) { Debug.LogError("value2 can be less than value1"); return (0); } if (currentValue < value1) { currentValue = value1; } if (currentValue > value2) { currentValue = value2; } return (currentValue); } //end of class } }