using UnityEditor; using UnityEngine; using System.Linq; [InitializeOnLoad] public static class CustomHierarchyDecorator { private static HierarchyDecoratorSettings settings; static CustomHierarchyDecorator() { LoadSettings(); EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyGUI; EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI; } public static void UpdateSettings(HierarchyDecoratorSettings newSettings) { settings = newSettings; EditorApplication.RepaintHierarchyWindow(); } private static void LoadSettings() { settings = AssetDatabase.LoadAssetAtPath("Assets/Scripts/Editor/HierarchyDecoratorSettings.asset"); } private static void OnHierarchyGUI(int instanceID, Rect selectionRect) { if (settings == null) return; // 1. Rysowanie Linii Drzewa (Tree Lines) - DODATKOWY BAJER if (settings.showTreeLines) { DrawTreeLines(selectionRect); } GameObject obj = EditorUtility.InstanceIDToObject(instanceID) as GameObject; if (obj == null) return; // 2. Sprawdzamy typ nagłówka // Typ: "= Clean" (Pusty separator) if (obj.name.Trim().StartsWith("= Clean")) { EditorGUI.DrawRect(selectionRect, settings.cleanBackgroundColor); return; } // Typ: "# Nazwa" (Subtelny nagłówek sekcji) - NOWOŚĆ if (obj.name.Trim().StartsWith("#")) { DrawSectionHeader(selectionRect, obj); PreventRename(selectionRect); return; } // Typ: "1= Nazwa" (Kolorowy nagłówek) if (obj.name.Contains("=")) { DrawColoredHeader(selectionRect, obj); PreventRename(selectionRect); } } // --- NOWOŚĆ: Rysowanie linii hierarchii --- private static void DrawTreeLines(Rect rect) { // Unity wcięcie to zazwyczaj 14 pikseli na poziom float indentWidth = 14f; // Obliczamy poziom zagnieżdżenia na podstawie pozycji X // (To trik, bo nie mamy dostępu do obj.transform.parent w tym miejscu łatwo bez obiektu) // Ale rect.x przesuwa się w prawo. // Rysujemy pionowe linie co 14 pikseli w lewo od rect.x for (float x = rect.x - indentWidth; x > 0; x -= indentWidth) { Rect lineRect = new Rect(x, rect.y, 1f, rect.height); EditorGUI.DrawRect(lineRect, settings.treeLineColor); } } // --- NOWOŚĆ: Rysowanie subtelnego nagłówka --- private static void DrawSectionHeader(Rect rect, GameObject obj) { // Rysujemy tło EditorGUI.DrawRect(rect, settings.sectionBackgroundColor); string text = obj.name.Replace("#", "").Trim(); if (settings.sectionUpperCase) text = text.ToUpper(); GUIStyle style = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter, // Wyśrodkowanie! fontSize = settings.sectionFontSize, fontStyle = FontStyle.Bold, normal = { textColor = settings.sectionTextColor } }; // Dodajemy delikatne kreski obok tekstu (opcjonalnie, wygląda super) // ------- TEKST ------- EditorGUI.LabelField(rect, text, style); } private static void DrawColoredHeader(Rect rect, GameObject obj) { string[] parts = obj.name.Split(new[] { '=' }, System.StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 1) return; string mainText = parts[0].Trim(); string descriptionText = parts.Length > 1 ? parts[1].Trim() : ""; int colorIdentifier; bool hasIdentifier = int.TryParse(parts[0].Trim(), out colorIdentifier); if (hasIdentifier) { mainText = parts.Length > 1 ? parts[1].Trim() : parts[0].Trim(); descriptionText = parts.Length > 2 ? parts[2].Trim() : ""; } Color backgroundColor = obj.activeSelf ? settings.defaultBackgroundColor : settings.defaultInactiveBackgroundColor; Color textColor = obj.activeSelf ? settings.defaultTextColor : settings.defaultInactiveTextColor; Color descriptionTextColor = settings.descriptionTextColor; if (hasIdentifier) { ColorScheme scheme = settings.colorSchemes.FirstOrDefault(s => s.identifier == colorIdentifier); if (scheme != null) { backgroundColor = obj.activeSelf ? scheme.activeBackgroundColor : scheme.inactiveBackgroundColor; textColor = obj.activeSelf ? scheme.activeTextColor : scheme.inactiveTextColor; descriptionTextColor = scheme.activeTextColor; } } EditorGUI.DrawRect(rect, backgroundColor); GUIStyle mainTextStyle = new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleLeft, fontStyle = FontStyle.Bold, normal = { textColor = textColor }, wordWrap = false }; Rect mainTextRect = new Rect(rect.x + settings.mainTextOffset, rect.y, rect.width - 10, rect.height); EditorGUI.LabelField(mainTextRect, new GUIContent(mainText), mainTextStyle); if (!string.IsNullOrEmpty(descriptionText)) { GUIStyle descriptionStyle = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleLeft, fontSize = settings.descriptionFontSize, normal = { textColor = descriptionTextColor }, wordWrap = false }; float descriptionX = rect.x + settings.mainTextOffset + mainTextStyle.CalcSize(new GUIContent(mainText)).x + settings.descriptionOffset; Rect descriptionRect = new Rect(descriptionX, rect.y, rect.width - descriptionX, rect.height); EditorGUI.LabelField(descriptionRect, new GUIContent(descriptionText), descriptionStyle); } } private static void PreventRename(Rect rect) { Event e = Event.current; if (e != null && e.type == EventType.MouseDown && e.clickCount == 2 && rect.Contains(e.mousePosition)) { GUIUtility.keyboardControl = 0; e.Use(); } } }