#if UNITY_EDITOR using System.Collections; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; using UnityEditor.UIElements; using System.Reflection; using UnityEditor; using static VInspector.Libs.VUtils; using static VInspector.Libs.VGUI; // using static VTools.VDebug; namespace VInspector { public class VInspectorComponentHeader { void OnGUI() { void masks() { if (!curEvent.isRepaint) return; Color backgroundColor; void set_backgroundColor() { var hovered = EditorGUIUtility.isProSkin ? Greyscale(.28f) : Greyscale(.84f); var normal = EditorGUIUtility.isProSkin ? Greyscale(.244f) : Greyscale(.8f); backgroundColor = normal; if (headerRect.IsHovered() && !mousePressedOnBackground && EditorWindow.mouseOverWindow == window) backgroundColor = hovered; } void set_buttonMaskSize() { buttonsList ??= typeof(EditorGUIUtility).GetMemberValue("s_EditorHeaderItemsMethods"); var buttonsCount = 1 + buttonsList.Count; if (VInspectorMenu.playmodeSaveButtonEnabled && !Application.isPlaying) buttonsCount--; buttonMaskRect = headerRect.AddHeightFromMid(-2).SetXMax(headerRect.xMax - 3).SetWidthFromRight(buttonsCount * 20); } void hideArrow() { if (headerRect.IsHovered()) return; if (!VInspectorMenu.minimalModeEnabled) return; headerRect.SetWidth(17).MoveX(-2).AddHeightFromMid(-2).AddWidthFromRight(-4).Draw(backgroundColor); } void hideButtons() { if (headerRect.IsHovered()) return; if (!VInspectorMenu.minimalModeEnabled) return; buttonMaskRect.Draw(backgroundColor); } void hideScriptText() { if (component is not MonoBehaviour) return; if (!VInspectorMenu.minimalModeEnabled) return; if (imguiContainer.onGUIHandler.Method.DeclaringType.FullName.StartsWith("Sisus")) return; var name = component.GetType().Name.Decamelcase(); var rect = headerRect.AddHeightFromMid(-2).SetWidth(60).MoveX(name.GetLabelWidth(fontSize: 12, isBold: true) + 60 - 3); rect = rect.MoveX(-2); rect.xMax = rect.xMax.Min(buttonMaskRect.x).Max(rect.xMin); rect.Draw(backgroundColor); } void tintScriptIcon() { if (component is not MonoBehaviour) return; if (!mousePressedOnScriptIcon) return; var iconRect = headerRect.MoveX(18).SetWidth(22); iconRect.Draw(backgroundColor.SetAlpha(EditorGUIUtility.isProSkin ? .3f : .45f)); } void nameCurtain() { var rect = headerRect.AddHeightFromMid(-2).SetXMax(buttonMaskRect.x + 2).SetWidthFromRight(18); rect.DrawCurtainLeft(backgroundColor); } set_backgroundColor(); set_buttonMaskSize(); hideArrow(); hideButtons(); hideScriptText(); tintScriptIcon(); nameCurtain(); } void scriptIconClicks() { if (component is not MonoBehaviour) return; if (curEvent.mouseButton != 0) return; if (!VInspectorMenu.hideScriptFieldEnabled) return; var iconRect = headerRect.MoveX(18).SetWidth(22); void mosueDown() { if (!curEvent.isMouseDown) return; if (!iconRect.IsHovered()) return; mousePressedOnScriptIcon = true; mousePressedOnScriptIcon_initPos = curEvent.mousePosition; var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour); // if (curEvent.holdingAlt) if (curEvent.clickCount == 2) AssetDatabase.OpenAsset(script); curEvent.Use(); } void mouseUp() { if (!curEvent.isMouseUp) return; if (!mousePressedOnScriptIcon) return; var script = MonoScript.FromMonoBehaviour(component as MonoBehaviour); if (curEvent.clickCount == 1) EditorUtils.PingObject(script); mousePressedOnScriptIcon = false; window.Repaint(); curEvent.Use(); } void startDrag() { if (!curEvent.isMouseDrag) return; if (!mousePressedOnScriptIcon) return; if ((mousePressedOnScriptIcon_initPos - curEvent.mousePosition).magnitude < 2) return; DragAndDrop.PrepareStartDrag(); DragAndDrop.objectReferences = new[] { component }; DragAndDrop.StartDrag(component.ToString()); mousePressedOnScriptIcon = false; mousePressedOnBackground = false; } mosueDown(); mouseUp(); startDrag(); } void expandWithAnimation() { if (!mousePressedOnBackground) return; if (!curEvent.isMouseUp) return; if (curEvent.mouseButton != 0) return; if (headerRect.SetWidth(16).MoveX(40).IsHovered()) return; // enabled toggle if (buttonMaskRect.IsHovered()) return; // right buttons if (curEvent.holdingShift) VInspector.CollapseOtherComponents(component, window); else if (VInspectorMenu.componentAnimationsEnabled) VInspector.ToggleComponentExpanded(component, window); else return; mousePressedOnBackground = false; curEvent.Use(); EditorGUIUtility.hotControl = 0; } void createComponentWindow() { if (!mousePressedOnBackground) return; if (!curEvent.isMouseDrag) return; if (!curEvent.holdingAlt) return; if (curEvent.mousePosition.DistanceTo(mousePressedOnBackground_initPos) < 2) return; if (!VInspectorMenu.componentWindowsEnabled) return; if (VInspectorComponentWindow.draggedInstance != null) return; var position = EditorGUIUtility.GUIToScreenPoint(headerRect.position + (curEvent.mousePosition - mousePressedOnBackground_initPos)); VInspectorComponentWindow.CreateDraggedInstance(component, position, headerRect.width); EditorGUIUtility.hotControl = 0; mousePressedOnBackground = false; } void set_mousePressedOnBackground() { if (curEvent.isMouseDown && !buttonMaskRect.IsHovered()) { mousePressedOnBackground = true; mousePressedOnBackground_initPos = curEvent.mousePosition; } if (curEvent.isMouseUp || curEvent.isDragUpdate) mousePressedOnBackground = false; if (!imguiContainer.contentRect.IsHovered()) mousePressedOnBackground = false; } void set_hoveredComponentHeader() { if (!curEvent.isRepaint) return; if (component is Transform) VInspector.hoveredComponentHeader = null; if (headerRect.IsHovered()) VInspector.hoveredComponentHeader = this; } void defaultHeaderGUI() { void initOffsets() { if (!VInspectorMenu.minimalModeEnabled) return; if (headerContentStyle != null) return; headerContentStyle = typeof(EditorStyles).GetMemberValue("inspectorTitlebar"); headerFoldoutStyle = typeof(EditorStyles).GetMemberValue("titlebarFoldout"); headerContentStyle_defaultLeftPadding = headerContentStyle.padding.left; headerFoldoutStyle_defaultLeftMargin = headerFoldoutStyle.margin.left; } void setAdjustedOffsets() { if (!VInspectorMenu.minimalModeEnabled) return; headerContentStyle.padding.left = headerContentStyle_defaultLeftPadding - 2; headerFoldoutStyle.margin.left = headerFoldoutStyle_defaultLeftMargin - 1; } void setDefaultOffsets() { if (!VInspectorMenu.minimalModeEnabled) return; headerContentStyle.padding.left = headerContentStyle_defaultLeftPadding; headerFoldoutStyle.margin.left = headerFoldoutStyle_defaultLeftMargin; } initOffsets(); setAdjustedOffsets(); defaultHeaderGUIAction.Invoke(); setDefaultOffsets(); } void preventKeyboardFocus() { if (!curEvent.isUsed) return; if (!headerRect.IsHovered()) return; if (imguiContainer.onGUIHandler.Method.DeclaringType.FullName.StartsWith("Sisus")) return; GUIUtility.keyboardControl = 0; // removes that annoying blue highlight after clicking on header } if (curEvent.isRepaint) defaultHeaderGUI(); masks(); scriptIconClicks(); expandWithAnimation(); createComponentWindow(); set_mousePressedOnBackground(); set_hoveredComponentHeader(); if (!curEvent.isRepaint) defaultHeaderGUI(); preventKeyboardFocus(); } static IList buttonsList; static Rect buttonMaskRect; public bool mousePressedOnBackground; public bool mousePressedOnScriptIcon; public Vector2 mousePressedOnBackground_initPos; public Vector2 mousePressedOnScriptIcon_initPos; public Rect headerRect { get { var contentRect = imguiContainer.contentRect; if (contentRect.height == 42) // with extra lines like "Multi-object editing not supported" return contentRect.SetHeight(22); else return contentRect.SetHeightFromBottom(22); // fixes offset on transform header in 6000 } } static GUIStyle headerContentStyle; static GUIStyle headerFoldoutStyle; static int headerContentStyle_defaultLeftPadding; static int headerFoldoutStyle_defaultLeftMargin; public Vector2 mouseDownPos; public void Update() { if (imguiContainer is VisualElement v && v.panel == null) { imguiContainer.onGUIHandler = defaultHeaderGUIAction; imguiContainer = null; } if (imguiContainer?.onGUIHandler.Method.DeclaringType == typeof(VInspectorComponentHeader)) return; if (imguiContainer?.onGUIHandler.Method.DeclaringType.FullName.StartsWith("Sisus") == true) return; if (typeof(ScriptableObject).IsAssignableFrom(component.GetType())) return; if (editor.GetPropertyValue("propertyViewer") is not EditorWindow window) return; this.window = window; void fixWrongWindow() { if (Application.unityVersion != "2022.3.26f1" && Application.unityVersion != "2023.2.20f1") return; if (!window.hasFocus) window = window.GetMemberValue("m_Parent")?.GetMemberValue>("m_Panes")?.FirstOrDefault(r => r.hasFocus) ?? window; // in some versions wrong inspector may be returned by propertyViewer when there are multiple inspectors // also the same instance of an editor may be used on all inspectors // here we fix it for cases when multiple inspectors are in the same dock area } void findHeader(VisualElement element) { if (element == null) return; if (element.GetType().Name == "EditorElement") { IMGUIContainer curHeaderImguiContainer = null; foreach (var child in element.Children()) { curHeaderImguiContainer ??= new[] { child as IMGUIContainer }.FirstOrDefault(r => r != null && r.name.EndsWith("Header")); if (curHeaderImguiContainer is null) continue; if (child is not InspectorElement) continue; if (child.GetFieldValue("m_Editor") is not Editor editor) continue; if (editor.target != component) continue; imguiContainer = curHeaderImguiContainer; if (editingMultiselection = editor.targets.Count() > 1) multiselectedComponents = editor.targets.Cast().ToList(); return; } } foreach (var r in element.Children()) if (imguiContainer == null) findHeader(r); } void setupGUICallbacks() { if (imguiContainer == null) return; defaultHeaderGUIAction = imguiContainer.onGUIHandler; imguiContainer.onGUIHandler = OnGUI; } fixWrongWindow(); findHeader(window.rootVisualElement); setupGUICallbacks(); } public bool editingMultiselection; public List multiselectedComponents; IMGUIContainer imguiContainer; System.Action defaultHeaderGUIAction; EditorWindow window; public VInspectorComponentHeader(Component component, Editor editor) { this.component = component; this.editor = editor; } public Editor editor; public Component component; } } #endif