Example #1
0
        // Use picking system to get us ordered list of all visually overlapping gameobjects in screen position from top to bottom
        static IEnumerable <PickingObject> GetAllOverlapping(Vector2 position)
        {
            var allOverlapping = new List <PickingObject>();
            var ignoreList     = new List <PickingObject>();

            while (true)
            {
                PickingObject res = HandleUtility.PickObject(position, false, ignoreList, null);

                if (res.target == null)
                {
                    break;
                }

                if (res.TryGetGameObject(out var go) && SceneVisibilityManager.instance.IsPickingDisabled(go))
                {
                    ignoreList.Add(res);
                    continue;
                }

                // Prevent infinite loop if object cannot be ignored (this needs to be fixed so print an error)
                if (allOverlapping.Count > 0 && res == allOverlapping.Last())
                {
                    Debug.LogError($"GetAllOverlapping failed, could not ignore game object '{res}' when picking");
                    break;
                }

                allOverlapping.Add(res);
                ignoreList.Add(res);

                yield return(res);
            }
        }
Example #2
0
        public void OnGUI()
        {
            Event evt = Event.current;

            Handles.BeginGUI();

            Vector2 mousePos = evt.mousePosition;
            int     id       = s_RectSelectionID;

            switch (evt.GetTypeForControl(id))
            {
            case EventType.Layout:
            case EventType.MouseMove:
                if (!Tools.viewToolActive)
                {
                    HandleUtility.AddDefaultControl(id);
                }

                //Handle the case of the drag being canceled
                if (m_RectSelecting && GUIUtility.hotControl != id)
                {
                    CompleteRectSelection();
                }
                break;

            case EventType.MouseDown:
                if (HandleUtility.nearestControl == id && evt.button == 0)
                {
                    GUIUtility.hotControl = id;
                    m_SelectStartPoint    = mousePos;
                    m_SelectionStart      = Selection.objects;
                    m_RectSelecting       = false;
                }
                break;

            case EventType.MouseDrag:
                if (GUIUtility.hotControl == id)
                {
                    if (!m_RectSelecting && (mousePos - m_SelectStartPoint).magnitude > 6f)
                    {
                        EditorApplication.modifierKeysChanged += SendCommandsOnModifierKeys;
                        m_RectSelecting = true;
                        ActiveEditorTracker.delayFlushDirtyRebuild = true;
                        m_LastSelection    = null;
                        m_CurrentSelection = null;
                        rectSelectionStarting();
                    }
                    if (m_RectSelecting)
                    {
                        m_SelectMousePoint = new Vector2(Mathf.Max(mousePos.x, 0), Mathf.Max(mousePos.y, 0));
                        GameObject[] rectObjs = HandleUtility.PickRectObjects(EditorGUIExt.FromToRect(m_SelectStartPoint, m_SelectMousePoint));
                        m_CurrentSelection = rectObjs;
                        bool setIt = false;
                        if (m_LastSelection == null)
                        {
                            m_LastSelection = new Dictionary <GameObject, bool>();
                            setIt           = true;
                        }
                        setIt |= m_LastSelection.Count != rectObjs.Length;
                        if (!setIt)
                        {
                            Dictionary <GameObject, bool> set = new Dictionary <GameObject, bool>(rectObjs.Length);
                            foreach (GameObject g in rectObjs)
                            {
                                set.Add(g, false);
                            }
                            foreach (GameObject g in m_LastSelection.Keys)
                            {
                                if (!set.ContainsKey(g))
                                {
                                    setIt = true;
                                    break;
                                }
                            }
                        }
                        if (setIt)
                        {
                            m_LastSelection = new Dictionary <GameObject, bool>(rectObjs.Length);
                            foreach (GameObject g in rectObjs)
                            {
                                m_LastSelection.Add(g, false);
                            }
                            if (evt.shift)
                            {
                                UpdateSelection(m_SelectionStart, rectObjs, SelectionType.Additive, m_RectSelecting);
                            }
                            else if (EditorGUI.actionKey)
                            {
                                UpdateSelection(m_SelectionStart, rectObjs, SelectionType.Subtractive, m_RectSelecting);
                            }
                            else
                            {
                                UpdateSelection(m_SelectionStart, rectObjs, SelectionType.Normal, m_RectSelecting);
                            }
                        }
                    }
                    evt.Use();
                }
                break;

            case EventType.Repaint:
                if (GUIUtility.hotControl == id && m_RectSelecting)
                {
                    EditorStyles.selectionRect.Draw(EditorGUIExt.FromToRect(m_SelectStartPoint, m_SelectMousePoint), GUIContent.none, false, false, false, false);
                }
                break;

            case EventType.MouseUp:
                if (GUIUtility.hotControl == id && evt.button == 0)
                {
                    GUIUtility.hotControl = 0;
                    if (m_RectSelecting)
                    {
                        CompleteRectSelection();
                        evt.Use();
                    }
                    else
                    {
                        if (evt.shift || EditorGUI.actionKey)
                        {
                            // For shift, we check if EXACTLY the active GO is hovered by mouse and then subtract. Otherwise additive.
                            // For control/cmd, we check if ANY of the selected GO is hovered by mouse and then subtract. Otherwise additive.
                            // Control/cmd takes priority over shift.
                            var hovered = HandleUtility.PickObject(evt.mousePosition, false);

                            var handledIt = false;
                            // shift-click deselects only if the active GO is exactly what we clicked on
                            if (!EditorGUI.actionKey && Selection.activeObject == hovered.target)
                            {
                                UpdateSelection(m_SelectionStart, hovered.target, SelectionType.Subtractive, m_RectSelecting);
                                handledIt = true;
                            }

                            // ctrl-click deselects everything up to prefab root, that is already selected
                            if (!handledIt && EditorGUI.actionKey)
                            {
                                var selectedObjects = Selection.objects;
                                hovered.TryGetComponent <Transform>(out var hoveredTransform);
                                var hoveredRoot  = HandleUtility.FindSelectionBaseForPicking(hoveredTransform);
                                var deselectList = new List <Object>();

                                while (hovered.target != null)
                                {
                                    if (selectedObjects.Contains(hovered.target))
                                    {
                                        deselectList.Add(hovered.target);
                                    }

                                    if (hovered.target == hoveredRoot)
                                    {
                                        break;
                                    }

                                    if (!hovered.TryGetParent(out var parent))
                                    {
                                        break;
                                    }

                                    hovered = new PickingObject(parent.gameObject);
                                }

                                if (deselectList.Any())
                                {
                                    UpdateSelection(m_SelectionStart, deselectList.ToArray(), SelectionType.Subtractive, m_RectSelecting);
                                    handledIt = true;
                                }
                            }

                            // we did not deselect anything, so add the new thing into selection instead
                            if (!handledIt)
                            {
                                var picked = HandleUtility.PickObject(evt.mousePosition, true);
                                UpdateSelection(m_SelectionStart, picked.target, SelectionType.Additive, m_RectSelecting);
                            }
                        }
                        else     // With no modifier keys, we do the "cycle through overlapped" picking logic in SceneViewPicking.cs
                        {
                            var picked = SceneViewPicking.PickGameObject(evt.mousePosition);
                            UpdateSelection(m_SelectionStart, picked.target, SelectionType.Normal, m_RectSelecting);
                        }

                        evt.Use();
                    }
                }
                break;

            case EventType.ExecuteCommand:
                if (id == GUIUtility.hotControl && evt.commandName == EventCommandNames.ModifierKeysChanged)
                {
                    if (evt.shift)
                    {
                        UpdateSelection(m_SelectionStart, m_CurrentSelection, SelectionType.Additive, m_RectSelecting);
                    }
                    else if (EditorGUI.actionKey)
                    {
                        UpdateSelection(m_SelectionStart, m_CurrentSelection, SelectionType.Subtractive, m_RectSelecting);
                    }
                    else
                    {
                        UpdateSelection(m_SelectionStart, m_CurrentSelection, SelectionType.Normal, m_RectSelecting);
                    }
                    evt.Use();
                }
                break;
            }

            Handles.EndGUI();
        }
Example #3
0
        public static PickingObject PickGameObject(Vector2 mousePosition)
        {
            s_RetainHashes = true;

            var enumerator = GetAllOverlapping(mousePosition).GetEnumerator();

            if (!enumerator.MoveNext())
            {
                return(PickingObject.Empty);
            }

            PickingObject topmost     = enumerator.Current;
            var           pickingBase = topmost.TryGetComponent(out Transform trs)
                ? HandleUtility.FindSelectionBaseForPicking(trs)
                : null;
            // Selection base is only interesting if it's not the topmost
            PickingObject selectionBase = new PickingObject(pickingBase);
            PickingObject first         = selectionBase.target == null ? topmost : selectionBase;
            int           topmostHash   = topmost.GetHashCode();
            int           prefixHash    = topmostHash;

            if (Selection.activeObject == null)
            {
                // Nothing selected
                // Return selection base if it exists, otherwise topmost game object
                s_PreviousTopmostHash = topmostHash;
                s_PreviousPrefixHash  = prefixHash;
                return(first);
            }

            if (topmostHash != s_PreviousTopmostHash)
            {
                // Topmost game object changed
                // Return selection base if exists and is not already selected, otherwise topmost game object
                s_PreviousTopmostHash = topmostHash;
                s_PreviousPrefixHash  = prefixHash;
                return(Selection.activeObject == selectionBase.target ? topmost : first);
            }

            s_PreviousTopmostHash = topmostHash;

            // Pick potential selection base before topmost game object
            if (Selection.activeObject == selectionBase.target)
            {
                if (prefixHash == s_PreviousPrefixHash)
                {
                    return(topmost);
                }
                s_PreviousPrefixHash = prefixHash;
                return(selectionBase);
            }

            s_ActiveObjectFilter.Clear();
            s_ActiveObjectFilter.Add((PickingObject)Selection.activeObject);

            // Check if active game object will appear in selection stack
            PickingObject picked = HandleUtility.PickObject(mousePosition, false, null, s_ActiveObjectFilter);

            if (picked == ((PickingObject)Selection.activeObject))
            {
                // Advance enumerator to active game object
                while (enumerator.Current != ((PickingObject)Selection.activeObject))
                {
                    if (!enumerator.MoveNext())
                    {
                        s_PreviousPrefixHash = topmostHash;
                        return(first); // Should not occur
                    }

                    UpdateHash(ref prefixHash, enumerator.Current);
                }
            }

            if (prefixHash != s_PreviousPrefixHash)
            {
                // Prefix hash changed, start over
                s_PreviousPrefixHash = topmostHash;
                return(first);
            }

            // Move on to next game object
            if (!enumerator.MoveNext())
            {
                s_PreviousPrefixHash = topmostHash;
                return(first); // End reached, start over
            }

            UpdateHash(ref prefixHash, enumerator.Current);

            if (enumerator.Current == selectionBase)
            {
                // Skip selection base
                if (!enumerator.MoveNext())
                {
                    s_PreviousPrefixHash = topmostHash;
                    return(first); // End reached, start over
                }

                UpdateHash(ref prefixHash, enumerator.Current);
            }

            s_PreviousPrefixHash = prefixHash;
            return(enumerator.Current);
        }