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); } } } }
/// <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; }