public void AddTooltipViews()
            {
                var allViews = new List <GUIViewProxy>();

                GUIViewDebuggerHelperProxy.GetViews(allViews);

                foreach (var tooltipView in allViews.Where(v => v.IsGUIViewAssignableTo(GUIViewProxy.TooltipViewType)))
                {
                    m_MaskData[tooltipView] = MaskViewData.CreateEmpty(MaskType.FullyUnmasked);
                }
            }
        static bool FindAncestorPropertyRegion(string propertyPath, string targetTypeName,
                                               List <IMGUIDrawInstructionProxy> drawInstructions, List <IMGUIPropertyInstructionProxy> propertyInstructions,
                                               ref Rect regionRect)
        {
            while (true)
            {
                // Remove last component of property path
                var lastIndexOfDelimiter = propertyPath.LastIndexOf(".");
                if (lastIndexOfDelimiter < 1)
                {
                    // No components left, give up
                    return(false);
                }
                propertyPath = propertyPath.Substring(0, lastIndexOfDelimiter);

                foreach (var instruction in propertyInstructions)
                {
                    if (instruction.targetTypeName == targetTypeName &&
                        instruction.path == propertyPath)
                    {
                        regionRect = instruction.rect;

                        // The property rect itself does not contain the foldout arrow
                        // Expand region to include all draw instructions for this property
                        var unifiedInstructions = new List <IMGUIInstructionProxy>(128);
                        GUIViewDebuggerHelperProxy.GetUnifiedInstructions(unifiedInstructions);
                        var collectDrawInstructions = false;
                        var propertyBeginLevel      = 0;
                        foreach (var unifiedInstruction in unifiedInstructions)
                        {
                            if (collectDrawInstructions)
                            {
                                if (unifiedInstruction.level <= propertyBeginLevel)
                                {
                                    break;
                                }

                                if (unifiedInstruction.type == InstructionTypeProxy.StyleDraw)
                                {
                                    var drawRect = drawInstructions[unifiedInstruction.typeInstructionIndex].rect;
                                    if (drawRect.xMin < regionRect.xMin)
                                    {
                                        regionRect.xMin = drawRect.xMin;
                                    }
                                    if (drawRect.yMin < regionRect.yMin)
                                    {
                                        regionRect.yMin = drawRect.yMin;
                                    }
                                    if (drawRect.xMax > regionRect.xMax)
                                    {
                                        regionRect.xMax = drawRect.xMax;
                                    }
                                    if (drawRect.yMax > regionRect.yMax)
                                    {
                                        regionRect.yMax = drawRect.yMax;
                                    }
                                }
                            }
                            else
                            {
                                if (unifiedInstruction.type == InstructionTypeProxy.PropertyBegin)
                                {
                                    var propertyInstruction = propertyInstructions[unifiedInstruction.typeInstructionIndex];
                                    if (propertyInstruction.targetTypeName == targetTypeName &&
                                        propertyInstruction.path == propertyPath)
                                    {
                                        collectDrawInstructions = true;
                                        propertyBeginLevel      = unifiedInstruction.level;
                                    }
                                }
                            }
                        }

                        return(true);
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Applies masking.
        /// </summary>
        /// <param name="unmaskedViewsAndRegionsMaskData"></param>
        /// <param name="maskColor"></param>
        /// <param name="highlightedRegionsMaskData"></param>
        /// <param name="highlightColor"></param>
        /// <param name="blockedInteractionsColor"></param>
        /// <param name="highlightThickness"></param>
        public static void Mask(
            UnmaskedView.MaskData unmaskedViewsAndRegionsMaskData, Color maskColor,
            UnmaskedView.MaskData highlightedRegionsMaskData, Color highlightColor, Color blockedInteractionsColor, float highlightThickness
            )
        {
            Unmask();

            CopyMaskData(unmaskedViewsAndRegionsMaskData, s_UnmaskedViews);
            CopyMaskData(highlightedRegionsMaskData, s_HighlightedViews);

            List <GUIViewProxy> views = new List <GUIViewProxy>();

            GUIViewDebuggerHelperProxy.GetViews(views);

            foreach (var view in views)
            {
                if (!view.IsValid)
                {
                    continue;
                }

                MaskViewData maskViewData;

                var viewRect = new Rect(0, 0, view.Position.width, view.Position.height);

                // mask everything except the unmasked view rects
                if (s_UnmaskedViews.TryGetValue(view, out maskViewData))
                {
                    // Beginning from 2021.2 the layout of floating/undocked EditorWindows has changed a bit and now contains
                    // an offset caused by the tab area which we need to take into account.
                    EditorWindow parentWindow = null;
                    if (maskViewData.EditorWindowType != null)
                    {
                        parentWindow = FindOpenEditorWindowInstance(maskViewData.EditorWindowType);
                    }

                    List <Rect> rects       = maskViewData.rects;
                    var         maskedRects = GetNegativeSpaceRects(viewRect, rects);
                    for (var i = 0; i < maskedRects.Count; ++i)
                    {
                        var rect = maskedRects[i];
                        if (parentWindow != null && !parentWindow.IsDocked())
                        {
                            // In theory we could have an X offset also but it seems highgly unlikely.
                            rect.y -= parentWindow.rootVisualElement.layout.y;
                        }
                        var mask = new VisualElement();
                        mask.style.backgroundColor = maskColor;
                        mask.SetLayout(rect);
                        AddMaskToView(view, mask);
                        s_Masks.Add(mask);
                    }

                    if (maskViewData.maskType == MaskType.BlockInteractions)
                    {
                        foreach (var rect in rects)
                        {
                            var mask = new VisualElement();
                            mask.style.backgroundColor = blockedInteractionsColor;
                            mask.SetLayout(rect);
                            AddMaskToView(view, mask);
                            s_Masks.Add(mask);
                        }
                    }
                }
                else // mask the whole view
                {
                    var mask = new VisualElement();
                    mask.style.backgroundColor = maskColor;
                    mask.SetLayout(viewRect);
                    AddMaskToView(view, mask);
                    s_Masks.Add(mask);
                }

                if (s_HighlightedViews.TryGetValue(view, out maskViewData))
                {
                    var rects = maskViewData.rects;
                    // unclip highlight to apply as "outer stroke" if it is being applied to some control(s) in the view
                    var unclip       = rects.Count > 1 || rects[0] != viewRect;
                    var borderRadius = 5.0f;
                    foreach (var rect in rects)
                    {
                        var highlighter = new VisualElement();
#if UNITY_2019_3_OR_NEWER
                        highlighter.style.borderLeftColor   = highlightColor;
                        highlighter.style.borderRightColor  = highlightColor;
                        highlighter.style.borderTopColor    = highlightColor;
                        highlighter.style.borderBottomColor = highlightColor;
#else
                        highlighter.style.borderColor = highlightColor;
#endif
                        highlighter.style.borderLeftWidth   = highlightThickness;
                        highlighter.style.borderRightWidth  = highlightThickness;
                        highlighter.style.borderTopWidth    = highlightThickness;
                        highlighter.style.borderBottomWidth = highlightThickness;

                        highlighter.style.borderBottomLeftRadius  = borderRadius;
                        highlighter.style.borderTopLeftRadius     = borderRadius;
                        highlighter.style.borderBottomRightRadius = borderRadius;
                        highlighter.style.borderTopRightRadius    = borderRadius;

                        highlighter.pickingMode = PickingMode.Ignore;
                        var layout = rect;
                        if (unclip)
                        {
                            layout.xMin -= highlightThickness;
                            layout.xMax += highlightThickness;
                            layout.yMin -= highlightThickness;
                            layout.yMax += highlightThickness;
                        }
                        highlighter.SetLayout(layout);
                        UIElementsHelper.GetVisualTree(view).Add(highlighter);
                        s_Highlighters.Add(highlighter);
                    }
                }
            }

            s_LastHighlightTime = EditorApplication.timeSinceStartup;
        }
        public static MaskData GetViewsAndRects(IEnumerable <UnmaskedView> unmaskedViews, out bool foundAncestorProperty)
        {
            foundAncestorProperty = false;

            var allViews = new List <GUIViewProxy>();

            GUIViewDebuggerHelperProxy.GetViews(allViews);

            // initialize result
            var result           = new Dictionary <GUIViewProxy, MaskViewData>();
            var unmaskedControls = new Dictionary <GUIViewProxy, List <GuiControlSelector> >();
            var viewsWithWindows = new Dictionary <GUIViewProxy, HashSet <EditorWindow> >();

            foreach (var unmaskedView in unmaskedViews)
            {
                foreach (var view in GetMatchingViews(unmaskedView, allViews, viewsWithWindows))
                {
                    MaskViewData maskViewData;
                    if (!result.TryGetValue(view, out maskViewData))
                    {
                        result[view] = new MaskViewData()
                        {
                            rects = new List <Rect>(8), maskType = unmaskedView.m_MaskType, maskSizeModifier = unmaskedView.m_MaskSizeModifier
                        };
                    }

                    List <GuiControlSelector> controls;
                    if (!unmaskedControls.TryGetValue(view, out controls))
                    {
                        unmaskedControls[view] = controls = new List <GuiControlSelector>();
                    }

                    controls.AddRange(unmaskedView.m_UnmaskedControls);
                }
            }

            // validate input
            foreach (var viewWithWindow in viewsWithWindows)
            {
                if (viewWithWindow.Value.Count > 1)
                {
                    throw new ArgumentException(
                              string.Format(
                                  "Tried to get controls from multiple EditorWindows docked in the same location: {0}",
                                  string.Join(", ", viewWithWindow.Value.Select(w => w.GetType().Name).ToArray())
                                  ),
                              "unmaskedViews"
                              );
                }
            }

            // populate result
            var drawInstructions         = new List <IMGUIDrawInstructionProxy>(32);
            var namedControlInstructions = new List <IMGUINamedControlInstructionProxy>(32);
            var propertyInstructions     = new List <IMGUIPropertyInstructionProxy>(32);

            foreach (var viewRects in result)
            {
                // prevents null exception when repainting in case e.g., user has accidentally maximized view
                if (!viewRects.Key.IsWindowAndRootViewValid)
                {
                    continue;
                }

                var unmaskedControlSelectors = unmaskedControls[viewRects.Key];
                if (unmaskedControlSelectors.Count == 0)
                {
                    continue;
                }

                // if the view refers to an InspectorWindow, flush the optimized GUI blocks so that Editor control rects will be updated
                HashSet <EditorWindow> windows;
                if (viewsWithWindows.TryGetValue(viewRects.Key, out windows) && windows.Count > 0)
                {
                    InspectorWindowProxy.DirtyAllEditors(windows.First());
                }

                // TODO: use actual selectors when API is in place
                GUIViewDebuggerHelperProxy.DebugWindow(viewRects.Key);

                viewRects.Key.RepaintImmediately();

                GUIViewDebuggerHelperProxy.GetDrawInstructions(drawInstructions);
                GUIViewDebuggerHelperProxy.GetNamedControlInstructions(namedControlInstructions);
                GUIViewDebuggerHelperProxy.GetPropertyInstructions(propertyInstructions);

                foreach (var controlSelector in unmaskedControls[viewRects.Key])
                {
                    Rect regionRect  = Rect.zero;
                    bool regionFound = false;
                    switch (controlSelector.SelectorMode)
                    {
                    case GuiControlSelector.Mode.GuiContent:
                        var selectorContent = controlSelector.GuiContent;
                        foreach (var instruction in drawInstructions)
                        {
                            if (AreEquivalent(instruction.usedGUIContent, selectorContent))
                            {
                                regionFound = true;
                                regionRect  = instruction.rect;
                            }
                        }
                        break;

                    case GuiControlSelector.Mode.GuiStyleName:
                        foreach (var instruction in drawInstructions)
                        {
                            if (instruction.usedGUIStyleName == controlSelector.GuiStyleName)
                            {
                                regionFound = true;
                                regionRect  = instruction.rect;
                            }
                        }
                        break;

                    case GuiControlSelector.Mode.NamedControl:
                        foreach (var instruction in namedControlInstructions)
                        {
                            if (instruction.name == controlSelector.ControlName)
                            {
                                regionFound = true;
                                regionRect  = instruction.rect;
                            }
                        }
                        break;

                    case GuiControlSelector.Mode.Property:
                        if (controlSelector.TargetType == null)
                        {
                            continue;
                        }
                        var targetTypeName = controlSelector.TargetType.AssemblyQualifiedName;
                        foreach (var instruction in propertyInstructions)
                        {
                            if (
                                instruction.targetTypeName == targetTypeName &&
                                instruction.path == controlSelector.PropertyPath
                                )
                            {
                                regionFound = true;
                                regionRect  = instruction.rect;
                            }
                        }

                        if (!regionFound)
                        {
                            // Property instruction not found
                            // Let's see if we can find any of the ancestor instructions to allow the user to unfold
                            regionFound = FindAncestorPropertyRegion(controlSelector.PropertyPath, targetTypeName,
                                                                     drawInstructions, propertyInstructions,
                                                                     ref regionRect);
                            foundAncestorProperty = regionFound;
                        }
                        break;

                    case GuiControlSelector.Mode.ObjectReference:
                        if (controlSelector.ObjectReference == null)
                        {
                            continue;
                        }

                        var referencedObject = controlSelector.ObjectReference.SceneObjectReference.ReferencedObject;
                        if (referencedObject == null)
                        {
                            continue;
                        }

                        foreach (var instruction in drawInstructions)
                        {
                            if (instruction.usedGUIContent.text != referencedObject.name)
                            {
                                continue;
                            }

                            regionFound = true;
                            regionRect  = instruction.rect;
                            break;
                        }
                        break;

                    default:
                        Debug.LogErrorFormat(
                            "No method currently implemented for selecting using specified mode: {0}",
                            controlSelector.SelectorMode
                            );
                        break;
                    }

                    if (regionFound)
                    {
                        if (viewRects.Value.maskSizeModifier == MaskSizeModifier.ExpandWidthToWholeWindow)
                        {
                            const int padding = 5;
                            regionRect.x     = padding;
                            regionRect.width = viewRects.Key.Position.width - padding * 2;
                        }
                        viewRects.Value.rects.Add(regionRect);
                    }
                }

                GUIViewDebuggerHelperProxy.StopDebugging();
            }

            return(new MaskData(result));
        }
        /// <summary>
        /// Applies masking.
        /// </summary>
        /// <param name="unmaskedViewsAndRegionsMaskData"></param>
        /// <param name="maskColor"></param>
        /// <param name="highlightedRegionsMaskData"></param>
        /// <param name="highlightColor"></param>
        /// <param name="blockedInteractionsColor"></param>
        /// <param name="highlightThickness"></param>
        public static void Mask(
            UnmaskedView.MaskData unmaskedViewsAndRegionsMaskData, Color maskColor,
            UnmaskedView.MaskData highlightedRegionsMaskData, Color highlightColor, Color blockedInteractionsColor, float highlightThickness
            )
        {
            Unmask();

            CopyMaskData(unmaskedViewsAndRegionsMaskData, s_UnmaskedViews);
            CopyMaskData(highlightedRegionsMaskData, s_HighlightedViews);

            List <GUIViewProxy> views = new List <GUIViewProxy>();

            GUIViewDebuggerHelperProxy.GetViews(views);

            foreach (var view in views)
            {
                if (!view.IsValid)
                {
                    continue;
                }

                MaskViewData maskViewData;

                var viewRect = new Rect(0, 0, view.Position.width, view.Position.height);

                // mask everything except the unmasked view rects
                if (s_UnmaskedViews.TryGetValue(view, out maskViewData))
                {
                    List <Rect> rects       = maskViewData.rects;
                    var         maskedRects = GetNegativeSpaceRects(viewRect, rects);
                    foreach (var rect in maskedRects)
                    {
                        var mask = new VisualElement();
                        mask.style.backgroundColor = maskColor;
                        mask.SetLayout(rect);
                        AddMaskToView(view, mask);
                        s_Masks.Add(mask);
                    }

                    if (maskViewData.maskType == MaskType.BlockInteractions)
                    {
                        foreach (var rect in rects)
                        {
                            var mask = new VisualElement();
                            mask.style.backgroundColor = blockedInteractionsColor;
                            mask.SetLayout(rect);
                            AddMaskToView(view, mask);
                            s_Masks.Add(mask);
                        }
                    }
                }
                // mask the whole view
                else
                {
                    var mask = new VisualElement();
                    mask.style.backgroundColor = maskColor;
                    mask.SetLayout(viewRect);
                    AddMaskToView(view, mask);
                    s_Masks.Add(mask);
                }

                if (s_HighlightedViews.TryGetValue(view, out maskViewData))
                {
                    var rects = maskViewData.rects;
                    // unclip highlight to apply as "outer stroke" if it is being applied to some control(s) in the view
                    var unclip       = rects.Count > 1 || rects[0] != viewRect;
                    var borderRadius = 5.0f;
                    foreach (var rect in rects)
                    {
                        var highlighter = new VisualElement();
#if UNITY_2019_3_OR_NEWER
                        highlighter.style.borderLeftColor   = highlightColor;
                        highlighter.style.borderRightColor  = highlightColor;
                        highlighter.style.borderTopColor    = highlightColor;
                        highlighter.style.borderBottomColor = highlightColor;
#else
                        highlighter.style.borderColor = highlightColor;
#endif
                        highlighter.style.borderLeftWidth   = highlightThickness;
                        highlighter.style.borderRightWidth  = highlightThickness;
                        highlighter.style.borderTopWidth    = highlightThickness;
                        highlighter.style.borderBottomWidth = highlightThickness;

                        highlighter.style.borderBottomLeftRadius  = borderRadius;
                        highlighter.style.borderTopLeftRadius     = borderRadius;
                        highlighter.style.borderBottomRightRadius = borderRadius;
                        highlighter.style.borderTopRightRadius    = borderRadius;

                        highlighter.pickingMode = PickingMode.Ignore;
                        var layout = rect;
                        if (unclip)
                        {
                            layout.xMin -= highlightThickness;
                            layout.xMax += highlightThickness;
                            layout.yMin -= highlightThickness;
                            layout.yMax += highlightThickness;
                        }
                        highlighter.SetLayout(layout);
                        UIElementsHelper.GetVisualTree(view).Add(highlighter);
                        s_Highlighters.Add(highlighter);
                    }
                }
            }

            s_LastHighlightTime = EditorApplication.timeSinceStartup;
        }