Ruined Town Sectors

This commit is contained in:
szczuras4
2025-11-27 01:51:39 +01:00
parent 8c28049d38
commit 14c2949ba1
7 changed files with 9925 additions and 2552 deletions

View File

@@ -843,11 +843,17 @@ MonoBehaviour:
- playOnce: 0
delayToStart: 0
customOutput: {fileID: 0}
barks: []
barks:
- barkConversation: CH02/RUINEDTOWN/CH02_ruinedtown_vo_Sidranna_wonderer_01
barkText:
clip: {fileID: 8300000, guid: 5ae21a99ae2a8bd46be39515bdb64e44, type: 3}
- playOnce: 0
delayToStart: 0
customOutput: {fileID: 0}
barks: []
barks:
- barkConversation: CH02/RUINEDTOWN/CH02_vo_bay_wanderer_00
barkText:
clip: {fileID: 8300000, guid: 03230376dca45d6428cd6155236fa94c, type: 3}
- playOnce: 0
delayToStart: 0
customOutput: {fileID: 385000820370598951, guid: 5dd761199ee4b7045a10fd9b79e36026,

File diff suppressed because it is too large Load Diff

View File

@@ -10,82 +10,114 @@ public static class CustomHierarchyDecorator
static CustomHierarchyDecorator()
{
LoadSettings();
// Rejestracja funkcji odpowiedzialnej za rysowanie niestandardowych nag³ówków
EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyGUI;
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
// Monitorowanie zmian w hierarchii
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
// Aktualizacja ustawieñ
public static void UpdateSettings(HierarchyDecoratorSettings newSettings)
{
settings = newSettings;
EditorApplication.RepaintHierarchyWindow();
}
// £adowanie ustawieñ
private static void LoadSettings()
{
settings = AssetDatabase.LoadAssetAtPath<HierarchyDecoratorSettings>("Assets/Scripts/Editor/HierarchyDecoratorSettings.asset");
if (settings == null)
{
Debug.LogWarning("HierarchyDecoratorSettings not found! Please create one in Assets/Scripts/Editor folder or check the path.");
return;
}
//Debug.Log("HierarchyDecoratorSettings loaded successfully.");
}
// Rysowanie nag³ówka
private static void OnHierarchyGUI(int instanceID, Rect selectionRect)
{
if (settings == null) return;
GameObject obj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (obj != null && obj.name.Contains("="))
// 1. Rysowanie Linii Drzewa (Tree Lines) - DODATKOWY BAJER
if (settings.showTreeLines)
{
DrawCustomHeader(selectionRect, obj);
// Ca³kowite zablokowanie zmiany nazwy w Hierarchii
Event e = Event.current;
if (e != null && e.type == EventType.MouseDown && e.clickCount == 2 && selectionRect.Contains(e.mousePosition))
{
// Zapobiegamy aktywacji trybu edycji nazwy
GUIUtility.keyboardControl = 0; // Zapobiegamy edytowaniu nazwy
e.Use();
}
DrawTreeLines(selectionRect);
}
}
// Funkcja rysuj¹ca niestandardowy nag³ówek
private static void DrawCustomHeader(Rect rect, GameObject obj)
{
if (obj.name.Trim().StartsWith("= Clean")) // <-- ZMIANA TUTAJ
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"))
{
// Jeœli nazwa zaczyna siê od "Clean", rysujemy tylko t³o
EditorGUI.DrawRect(rect, settings.cleanBackgroundColor);
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() : ""; // Jeœli istnieje drugi `=`, traktujemy go jako opis
string descriptionText = parts.Length > 1 ? parts[1].Trim() : "";
// Obs³uga identyfikatora koloru
int colorIdentifier;
bool hasIdentifier = int.TryParse(parts[0].Trim(), out colorIdentifier);
if (hasIdentifier)
{
// Jeœli jest identyfikator, przypisujemy g³ówny tekst i opis
mainText = parts.Length > 1 ? parts[1].Trim() : parts[0].Trim();
descriptionText = parts.Length > 2 ? parts[2].Trim() : ""; // Jeœli jest opis, przypisujemy go
descriptionText = parts.Length > 2 ? parts[2].Trim() : "";
}
Color backgroundColor = obj.activeSelf ? settings.defaultBackgroundColor : settings.defaultInactiveBackgroundColor;
@@ -94,7 +126,6 @@ public static class CustomHierarchyDecorator
if (hasIdentifier)
{
// Sprawdzamy identyfikator koloru i przypisujemy odpowiednie kolory
ColorScheme scheme = settings.colorSchemes.FirstOrDefault(s => s.identifier == colorIdentifier);
if (scheme != null)
{
@@ -104,58 +135,42 @@ public static class CustomHierarchyDecorator
}
}
// Rysujemy t³o dla obiektu
EditorGUI.DrawRect(rect, backgroundColor);
// Styl dla g³ównego tekstu (wycentrowany)
GUIStyle mainTextStyle = new GUIStyle(EditorStyles.boldLabel)
{
alignment = TextAnchor.MiddleLeft, // Wyrównanie do lewej strony
alignment = TextAnchor.MiddleLeft,
fontStyle = FontStyle.Bold,
normal = { textColor = textColor },
wordWrap = false // Wy³¹czenie zawijania tekstu
wordWrap = false
};
Rect mainTextRect = new Rect(rect.x + settings.mainTextOffset, rect.y, rect.width - 10, rect.height); // Zmniejszamy szerokoϾ
Rect mainTextRect = new Rect(rect.x + settings.mainTextOffset, rect.y, rect.width - 10, rect.height);
EditorGUI.LabelField(mainTextRect, new GUIContent(mainText), mainTextStyle);
// Jeœli istnieje opis, wyœwietlamy go mniejsz¹ czcionk¹ po prawej stronie
if (!string.IsNullOrEmpty(descriptionText))
{
GUIStyle descriptionStyle = new GUIStyle(EditorStyles.label)
{
alignment = TextAnchor.MiddleLeft, // Zmieniono na wyrównanie do lewej
fontSize = settings.descriptionFontSize, // Sta³a czcionka
alignment = TextAnchor.MiddleLeft,
fontSize = settings.descriptionFontSize,
normal = { textColor = descriptionTextColor },
wordWrap = false // Wy³¹czenie zawijania tekstu
wordWrap = false
};
// Opis wyrównany do koñca g³ównego tekstu, zawsze w tej samej odleg³oœci
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); // Dostosowanie szerokoœci do g³ównego tekstu
Rect descriptionRect = new Rect(descriptionX, rect.y, rect.width - descriptionX, rect.height);
EditorGUI.LabelField(descriptionRect, new GUIContent(descriptionText), descriptionStyle);
}
}
// Funkcja monitoruj¹ca zmiany w hierarchii (np. zablokowanie dodawania dzieci do separatorów)
private static void OnHierarchyChanged()
private static void PreventRename(Rect rect)
{
EditorApplication.delayCall += () =>
Event e = Event.current;
if (e != null && e.type == EventType.MouseDown && e.clickCount == 2 && rect.Contains(e.mousePosition))
{
GameObject[] cleanSeparators = Object.FindObjectsByType<GameObject>(FindObjectsInactive.Include, FindObjectsSortMode.None)
.Where(obj => obj.name.Trim().StartsWith("= Clean")) // <-- ZMIANA TUTAJ
.ToArray();
foreach (var cleanObj in cleanSeparators)
{
for (int i = cleanObj.transform.childCount - 1; i >= 0; i--)
{
Transform child = cleanObj.transform.GetChild(i);
Undo.SetTransformParent(child, null, "Prevent Child to Clean Separator");
Debug.Log($"Blocked child object {child.name} from being added to {cleanObj.name}");
}
}
};
GUIUtility.keyboardControl = 0;
e.Use();
}
}
}
}

View File

@@ -8,6 +8,7 @@ public class HeaderCreatorWindow : EditorWindow
private string objectName = "New GameObject";
private string headerDescription = "";
private int selectedIdentifier = 1;
private bool resetTransform = true;
private static HierarchyDecoratorSettings settings;
private Vector2 scrollPosition;
@@ -18,8 +19,7 @@ public class HeaderCreatorWindow : EditorWindow
public static void ShowWindow()
{
HeaderCreatorWindow window = GetWindow<HeaderCreatorWindow>(true, "Create Object");
// ZMIANA: Zwiêkszamy minimaln¹ wysokoœæ okna, aby zmieœci³ siê nowy przycisk
window.minSize = new Vector2(320, 340);
window.minSize = new Vector2(320, 400); // Jeszcze trochê wiêksze
}
private void OnEnable()
@@ -28,7 +28,7 @@ public class HeaderCreatorWindow : EditorWindow
if (settings == null)
{
Debug.LogError("HierarchyDecoratorSettings not found!");
Debug.LogError("Settings not found!");
Close();
return;
}
@@ -48,118 +48,128 @@ public class HeaderCreatorWindow : EditorWindow
objectName = EditorGUILayout.TextField("Name", objectName);
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("For Custom Header:", EditorStyles.miniBoldLabel);
headerDescription = EditorGUILayout.TextField("Description (Optional)", headerDescription);
if (settings.colorSchemes.Count == 0)
{
EditorGUILayout.HelpBox("No color schemes defined in HierarchyDecoratorSettings. You can only create a simple empty object.", MessageType.Warning);
}
else
{
EditorGUILayout.LabelField("Color Scheme", EditorStyles.boldLabel);
DrawColorSelectionGrid();
}
EditorGUILayout.Space();
GUI.enabled = settings.colorSchemes.Count > 0;
if (GUILayout.Button("Create Custom Header", GUILayout.Height(35)))
{
CreateHeaderObject();
Close();
}
GUI.enabled = true;
EditorGUILayout.LabelField("Description (Optional)", EditorStyles.miniBoldLabel);
headerDescription = EditorGUILayout.TextField(headerDescription);
EditorGUILayout.Space(5);
resetTransform = EditorGUILayout.ToggleLeft("Reset Transform (Pos 0, Scale 1)", resetTransform);
if (GUILayout.Button("Create Simple Empty (using Name only)", GUILayout.Height(30)))
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("Type 1: Colored Header", EditorStyles.boldLabel);
if (settings.colorSchemes.Count > 0)
{
CreateSimpleEmptyObject();
DrawColorSelectionGrid();
EditorGUILayout.Space(2);
if (GUILayout.Button("Create Colored Header", GUILayout.Height(30)))
{
CreateHeaderObject();
Close();
}
}
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("Type 2: Separators", EditorStyles.boldLabel);
// PRZYCISK SEKCJI (SUBTELNY TEKST)
GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f);
if (GUILayout.Button("Create Section Header (Subtle Text)", GUILayout.Height(25)))
{
CreateSectionHeader(); // Nowa funkcja
Close();
}
// ZMIANA: Dodajemy nowy przycisk do tworzenia separatora "= Clean"
EditorGUILayout.Space(10); // Dodajemy trochê wiêcej miejsca
EditorGUILayout.Space(2);
// Ustawiamy inny kolor t³a dla tego specjalnego przycisku, aby siê wyró¿nia³
// PRZYCISK CZYSTEGO SEPARATORA
GUI.backgroundColor = new Color(0.4f, 0.4f, 0.45f);
if (GUILayout.Button("Create Clean Separator", GUILayout.Height(30)))
if (GUILayout.Button("Create Clean Separator (Empty)", GUILayout.Height(25)))
{
CreateCleanSeparator();
Close();
}
// WA¯NE: Resetujemy kolor t³a do domyœlnego, aby nie wp³ywa³ na inne elementy GUI
GUI.backgroundColor = Color.white;
EditorGUILayout.Space(10);
if (GUILayout.Button("Create Simple Empty", GUILayout.Height(20)))
{
CreateSimpleEmptyObject();
Close();
}
}
private void DrawColorSelectionGrid()
{
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(80));
// ... (bez zmian) ...
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(60));
int columns = 5;
int buttonsInRow = 0;
GUILayout.BeginHorizontal();
foreach (var scheme in settings.colorSchemes)
{
GUIStyle buttonStyle = colorStyles[scheme.identifier];
string buttonText = scheme.identifier.ToString();
if (GUILayout.Button(buttonText, buttonStyle, GUILayout.MinWidth(40), GUILayout.Height(30)))
if (GUILayout.Button(scheme.identifier.ToString(), buttonStyle, GUILayout.MinWidth(40), GUILayout.Height(25)))
{
selectedIdentifier = scheme.identifier;
}
if (Event.current.type == EventType.Repaint && scheme.identifier == selectedIdentifier)
{
Rect buttonRect = GUILayoutUtility.GetLastRect();
EditorGUI.DrawRect(buttonRect, new Color(0.5f, 0.5f, 0.5f, 0.4f));
}
buttonsInRow++;
if (buttonsInRow >= columns)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
buttonsInRow = 0;
}
if (buttonsInRow >= columns) { GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); buttonsInRow = 0; }
}
GUILayout.EndHorizontal();
EditorGUILayout.EndScrollView();
}
private void ApplyTransformReset(GameObject obj)
{
if (resetTransform)
{
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
}
}
private void CreateHeaderObject()
{
string finalName = $"{selectedIdentifier}={objectName.Trim()}";
if (!string.IsNullOrEmpty(headerDescription.Trim()))
{
finalName += $"={headerDescription.Trim()}";
}
GameObject header = new GameObject(finalName);
Undo.RegisterCreatedObjectUndo(header, "Create Custom Header");
GameObjectUtility.SetParentAndAlign(header, Selection.activeObject as GameObject);
Selection.activeObject = header;
if (!string.IsNullOrEmpty(headerDescription.Trim())) finalName += $"={headerDescription.Trim()}";
CreateObject(finalName, "Create Custom Header");
}
private void CreateSimpleEmptyObject()
{
GameObject emptyObj = new GameObject(objectName);
Undo.RegisterCreatedObjectUndo(emptyObj, "Create Simple Empty Object");
GameObjectUtility.SetParentAndAlign(emptyObj, Selection.activeObject as GameObject);
Selection.activeObject = emptyObj;
CreateObject(objectName, "Create Simple Empty");
}
// ZMIANA: Nowa funkcja do tworzenia separatora "= Clean"
private void CreateCleanSeparator()
{
// Nazwa jest sta³a i nie zale¿y od pól w oknie
GameObject cleanSeparator = new GameObject("= Clean");
Undo.RegisterCreatedObjectUndo(cleanSeparator, "Create Clean Separator");
GameObjectUtility.SetParentAndAlign(cleanSeparator, Selection.activeObject as GameObject);
Selection.activeObject = cleanSeparator;
CreateObject("= Clean", "Create Clean Separator");
}
// --- NOWA FUNKCJA: TWORZENIE SEKCJI # ---
private void CreateSectionHeader()
{
// Tworzymy nazwê zaczynaj¹c¹ siê od #
string name = objectName.Trim();
if (string.IsNullOrEmpty(name)) name = "SECTION";
string finalName = $"# {name}";
CreateObject(finalName, "Create Section Header");
}
private void CreateObject(string name, string undoName)
{
GameObject obj = new GameObject(name);
Undo.RegisterCreatedObjectUndo(obj, undoName);
GameObjectUtility.SetParentAndAlign(obj, Selection.activeObject as GameObject);
ApplyTransformReset(obj);
Selection.activeObject = obj;
}
private void InitializeButtonStyles()

View File

@@ -12,6 +12,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b2e58b4d6f89b3b4087182494e3cb126, type: 3}
m_Name: HierarchyDecoratorSettings
m_EditorClassIdentifier:
showTreeLines: 1
treeLineColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.2}
defaultBackgroundColor: {r: 0.1, g: 0.1, b: 0.1, a: 1}
defaultInactiveBackgroundColor: {r: 0.19401923, g: 0.2522564, b: 0.3773585, a: 1}
defaultTextColor: {r: 1, g: 1, b: 1, a: 1}
@@ -33,6 +35,10 @@ MonoBehaviour:
activeTextColor: {r: 1, g: 1, b: 1, a: 1}
inactiveTextColor: {r: 0.30588236, g: 0.41568628, b: 0.5568628, a: 0.98039216}
cleanBackgroundColor: {r: 0.21698111, g: 0.21698111, b: 0.21698111, a: 1}
sectionBackgroundColor: {r: 0.21568628, g: 0.21568628, b: 0.21568628, a: 1}
sectionTextColor: {r: 0.7, g: 0.7, b: 0.7, a: 0.6}
sectionFontSize: 11
sectionUpperCase: 1
descriptionTextColor: {r: 0.73344606, g: 0.7648177, b: 0.7735849, a: 1}
descriptionFontSize: 11
mainTextOffset: 50

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
[System.Serializable]
public class ColorScheme
{
public int identifier; // Numer, np. 1, 2, 3 itp.
public int identifier;
public Color activeBackgroundColor = new Color(0.1f, 0.1f, 0.1f, 0.5f);
public Color inactiveBackgroundColor = new Color(0f, 0f, 0f, 0.3f);
public Color activeTextColor = Color.white;
@@ -14,7 +14,11 @@ public class ColorScheme
[CreateAssetMenu(fileName = "HierarchyDecoratorSettings", menuName = "Settings/HierarchyDecoratorSettings")]
public class HierarchyDecoratorSettings : ScriptableObject
{
[Header("Default Background Settings")]
[Header("Global Settings")]
public bool showTreeLines = true; // Czy pokazywać linie drzewa
public Color treeLineColor = new Color(0.5f, 0.5f, 0.5f, 0.2f);
[Header("Default Header Settings")]
public Color defaultBackgroundColor = new Color(0.1f, 0.1f, 0.1f, 0.5f);
public Color defaultInactiveBackgroundColor = new Color(0f, 0f, 0f, 0.3f);
public Color defaultTextColor = Color.green;
@@ -23,21 +27,24 @@ public class HierarchyDecoratorSettings : ScriptableObject
[Header("Custom Color Schemes")]
public List<ColorScheme> colorSchemes = new List<ColorScheme>();
[Header("Clean Separator Settings")]
public Color cleanBackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.5f); // Kolor tła dla separatora Clean
[Header("Separator Styles")]
public Color cleanBackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.5f); // = Clean
[Header("Section Header Settings (# Name)")]
public Color sectionBackgroundColor = new Color(0.15f, 0.15f, 0.15f, 0.8f); // Tło dla #
public Color sectionTextColor = new Color(0.7f, 0.7f, 0.7f, 0.6f); // Subtelny tekst
public int sectionFontSize = 11;
public bool sectionUpperCase = true; // Czy zamieniać na wielkie litery
[Header("Description Settings")]
public Color descriptionTextColor = Color.gray; // Kolor opisu
public int descriptionFontSize = 10; // Rozmiar czcionki opisu
[Header("Position Settings")]
public float mainTextOffset = 0.0f; // Umożliwia dostosowanie przesunięcia głównego tekstu
public float descriptionOffset = 100.0f; // Umożliwia dostosowanie przesunięcia opisu
public Color descriptionTextColor = Color.gray;
public int descriptionFontSize = 10;
public float mainTextOffset = 0.0f;
public float descriptionOffset = 100.0f;
[ContextMenu("Update Hierarchy Display")]
public void UpdateHierarchyDisplay()
{
CustomHierarchyDecorator.UpdateSettings(this);
Debug.Log("Hierarchy display settings updated.");
}
}
}

View File

@@ -6,21 +6,46 @@ using System.Linq;
public class MoveToWindow : EditorWindow
{
// ------------------------------------------------------------------------
// Core Variables
// ------------------------------------------------------------------------
private static List<GameObject> selectedObjects;
private static List<GameObject> topLevelObjects;
private static HierarchyDecoratorSettings settings;
// ------------------------------------------------------------------------
// UI State Variables
// ------------------------------------------------------------------------
private Vector2 scrollPosition;
private string filterText = "";
private bool isPinned = false;
private static HierarchyDecoratorSettings settings;
private Vector2 scrollPosition;
private Dictionary<Color, bool> colorFilters = new Dictionary<Color, bool>();
private static Dictionary<Color, bool> colorFilters = new Dictionary<Color, bool>();
private bool showDefaultColor = true;
// ------------------------------------------------------------------------
// Feature: Shortcut (Spacebar) - GLOBAL STATE
// ------------------------------------------------------------------------
// Must be static to be accessed by SceneView delegate
private static GameObject shortcutTarget = null;
// ------------------------------------------------------------------------
// Feature: Create New Group
// ------------------------------------------------------------------------
private bool showCreationSection = false;
private string newGroupName = "New Group";
private int selectedColorIdForCreation = 1;
private static bool resetPositionOnMove = false;
// ------------------------------------------------------------------------
// Menu Items & Initialization
// ------------------------------------------------------------------------
[MenuItem("Window/Move To...")]
public static void ShowWindow()
{
LoadSettings();
UpdateTopLevelObjects();
MoveToWindow window = GetWindow<MoveToWindow>("Move To...");
LoadSettings();
UpdateSelectedObjects();
window.Show();
}
@@ -28,24 +53,140 @@ public class MoveToWindow : EditorWindow
[MenuItem("GameObject/Move To...", false, -100)]
private static void MoveToContextMenu(MenuCommand command)
{
LoadSettings();
UpdateSelectedObjects();
ShowWindow();
}
private void OnEnable()
{
LoadSettings();
// Subscribe to Scene View updates to handle global shortcuts
SceneView.duringSceneGui -= OnSceneGUI; // Safety unsubscribe
SceneView.duringSceneGui += OnSceneGUI;
}
private void OnDisable()
{
// Unsubscribe to prevent errors when window is closed
SceneView.duringSceneGui -= OnSceneGUI;
}
// ------------------------------------------------------------------------
// Global Shortcut Handling (Scene View)
// ------------------------------------------------------------------------
private static void OnSceneGUI(SceneView sceneView)
{
Event e = Event.current;
// Detect Spacebar press in Scene View
if (e != null && e.type == EventType.KeyDown && e.keyCode == KeyCode.Space)
{
if (shortcutTarget != null)
{
// Refresh selection manually because OnGUI isn't running
UpdateSelectedObjects();
if (selectedObjects != null && selectedObjects.Count > 0)
{
MoveObjectsToTab(selectedObjects, shortcutTarget);
// Consume the event so Unity doesn't do default actions (like maximizing view)
e.Use();
}
}
}
}
// ------------------------------------------------------------------------
// Main GUI Loop (Window View)
// ------------------------------------------------------------------------
private void OnGUI()
{
DrawHeader();
DrawControls();
DrawHideColorsSection();
DrawTabsList();
// Handle shortcut inside the window as well
HandleLocalKeyboardShortcut();
if (settings == null) LoadSettings();
if (topLevelObjects == null) UpdateTopLevelObjects();
EditorGUILayout.BeginHorizontal();
GUILayout.Space(10);
EditorGUILayout.BeginVertical();
{
GUILayout.Space(10);
DrawHeader();
GUILayout.Space(10);
DrawControls();
DrawCreationSection();
DrawHideColorsSection();
// Info Box about Shortcut (Active state)
if (shortcutTarget != null)
{
GUI.backgroundColor = new Color(0.8f, 1f, 0.8f);
EditorGUILayout.HelpBox($"ACTIVE: Press SPACE in Scene View to move objects to: {shortcutTarget.name}", MessageType.Info);
GUI.backgroundColor = Color.white;
}
DrawTabsList();
DrawFooter();
GUILayout.Space(10);
}
EditorGUILayout.EndVertical();
GUILayout.Space(10);
EditorGUILayout.EndHorizontal();
}
// ------------------------------------------------------------------------
// Input Handling (Local Window)
// ------------------------------------------------------------------------
private void HandleLocalKeyboardShortcut()
{
Event e = Event.current;
if (e.type == EventType.KeyDown && e.keyCode == KeyCode.Space)
{
if (shortcutTarget != null)
{
UpdateSelectedObjects(); // Fix: Refresh selection before moving
if (selectedObjects != null && selectedObjects.Count > 0)
{
MoveObjectsToTab(selectedObjects, shortcutTarget);
e.Use();
Repaint();
}
}
}
}
// ------------------------------------------------------------------------
// Draw Methods
// ------------------------------------------------------------------------
private void DrawHeader()
{
GUILayout.Label("Select a tab to move the selected objects:", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter });
EditorGUILayout.BeginHorizontal();
isPinned = EditorGUILayout.Toggle("Pin Window", isPinned);
GUILayout.FlexibleSpace();
if (GUILayout.Button(EditorGUIUtility.IconContent("d_SettingsIcon"), GUILayout.Width(25), GUILayout.Height(19)))
{
Selection.activeObject = settings;
}
EditorGUILayout.EndHorizontal();
filterText = EditorGUILayout.TextField("Filter tabs", filterText);
GUILayout.Space(10);
}
private void DrawControls()
@@ -53,38 +194,35 @@ public class MoveToWindow : EditorWindow
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Enable All", GUILayout.Width(100)))
{
SetAllTabsActiveState(true);
}
if (GUILayout.Button("Disable All", GUILayout.Width(100)))
{
SetAllTabsActiveState(false);
}
if (GUILayout.Button("Collapse All", GUILayout.Width(100)))
{
CollapseAllInHierarchy();
}
if (GUILayout.Button("Enable All", GUILayout.Width(100))) SetAllTabsActiveState(true);
if (GUILayout.Button("Disable All", GUILayout.Width(100))) SetAllTabsActiveState(false);
if (GUILayout.Button("Collapse All", GUILayout.Width(100))) CollapseAllInHierarchy();
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Space(5);
}
private void DrawHideColorsSection()
{
GUILayout.Space(5);
GUILayout.Label("----------------------------------------------------------", EditorStyles.centeredGreyMiniLabel);
GUILayout.Label("Hide Colors", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter });
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
var keys = colorFilters.Keys.ToList();
try
{
showDefaultColor = EditorGUILayout.ToggleLeft(new GUIContent(" ", MakeColorIcon(settings.defaultBackgroundColor)), showDefaultColor, GUILayout.Width(30));
foreach (var colorEntry in colorFilters.Keys.ToList())
if (settings != null)
{
colorFilters[colorEntry] = EditorGUILayout.ToggleLeft(new GUIContent(" ", MakeColorIcon(colorEntry)), colorFilters[colorEntry], GUILayout.Width(30));
GUILayout.Space(5);
showDefaultColor = EditorGUILayout.ToggleLeft(new GUIContent(" ", MakeColorIcon(settings.defaultBackgroundColor)), showDefaultColor, GUILayout.Width(35));
}
foreach (var colorEntry in keys)
{
colorFilters[colorEntry] = EditorGUILayout.ToggleLeft(new GUIContent(" ", MakeColorIcon(colorEntry)), colorFilters[colorEntry], GUILayout.Width(35));
}
}
finally
@@ -94,32 +232,130 @@ public class MoveToWindow : EditorWindow
}
GUILayout.Label("----------------------------------------------------------", EditorStyles.centeredGreyMiniLabel);
// --- NEW HELP TEXT (BLUE) ---
GUIStyle helpStyle = new GUIStyle(EditorStyles.miniLabel);
helpStyle.alignment = TextAnchor.MiddleCenter;
helpStyle.normal.textColor = new Color(0.4f, 0.7f, 1f); // Nice Blue Color
helpStyle.wordWrap = true;
GUILayout.Label("Check the box to set the [SPACE] shortcut target. Press Space to move selected objects.", helpStyle);
// ----------------------------
GUILayout.Space(10);
}
private void DrawCreationSection()
{
EditorGUILayout.BeginVertical(GUI.skin.box);
showCreationSection = EditorGUILayout.Foldout(showCreationSection, "Create New Group", true);
if (showCreationSection)
{
GUILayout.Space(5);
EditorGUILayout.BeginHorizontal();
GUILayout.Label("Name:", GUILayout.Width(45));
newGroupName = EditorGUILayout.TextField(newGroupName);
EditorGUILayout.EndHorizontal();
GUILayout.Space(5);
GUILayout.Label("Pick Color:", EditorStyles.miniBoldLabel);
DrawColorSelectionGrid();
GUILayout.Space(5);
EditorGUILayout.BeginHorizontal();
resetPositionOnMove = EditorGUILayout.ToggleLeft("Reset Position (0,0,0)", resetPositionOnMove, GUILayout.Width(150));
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(5);
Color originalBg = GUI.backgroundColor;
GUI.backgroundColor = new Color(0.6f, 0.9f, 0.6f);
if (GUILayout.Button("Create & Move Objects", GUILayout.Height(25)))
{
CreateAndMove();
}
GUI.backgroundColor = originalBg;
GUILayout.Space(5);
}
EditorGUILayout.EndVertical();
GUILayout.Space(10);
}
private void DrawColorSelectionGrid()
{
if (settings == null || settings.colorSchemes.Count == 0) return;
int columns = 8;
int buttonsInRow = 0;
GUILayout.BeginHorizontal();
foreach (var scheme in settings.colorSchemes)
{
Rect rect = GUILayoutUtility.GetRect(30, 20);
if (GUI.Button(rect, GUIContent.none, GUIStyle.none))
{
selectedColorIdForCreation = scheme.identifier;
}
EditorGUI.DrawRect(rect, scheme.activeBackgroundColor);
if (selectedColorIdForCreation == scheme.identifier)
{
DrawOutline(rect, 2, Color.white);
}
else
{
DrawOutline(rect, 1, new Color(0, 0, 0, 0.3f));
}
buttonsInRow++;
if (buttonsInRow >= columns)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
buttonsInRow = 0;
}
GUILayout.Space(4);
}
GUILayout.EndHorizontal();
}
private void DrawTabsList()
{
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
foreach (var obj in topLevelObjects)
if (topLevelObjects != null)
{
Color tabColor = GetTabColor(obj);
foreach (var obj in topLevelObjects)
{
if (obj == null) continue;
if (!showDefaultColor && tabColor == settings.defaultBackgroundColor)
continue;
Color tabColor = CalculateColorForObject(obj);
if (colorFilters.ContainsKey(tabColor) && colorFilters[tabColor] == false)
continue;
if (!showDefaultColor && settings != null && tabColor == settings.defaultBackgroundColor)
continue;
string cleanName = Regex.Replace(obj.name, @"^\d*=\s*|\s*=.*$", "").Trim();
if (colorFilters.ContainsKey(tabColor) && colorFilters[tabColor] == false)
continue;
if (obj.name.Contains("= Clean"))
continue;
string cleanName = Regex.Replace(obj.name, @"^\d*=\s*|\s*=.*$", "").Trim();
if (!string.IsNullOrEmpty(filterText) && !cleanName.ToLower().Contains(filterText.ToLower()))
continue;
if (obj.name.Contains("= Clean"))
continue;
DrawTabItem(obj, cleanName, tabColor);
if (!string.IsNullOrEmpty(filterText) && !cleanName.ToLower().Contains(filterText.ToLower()))
continue;
DrawTabItem(obj, cleanName, tabColor);
}
}
EditorGUILayout.EndScrollView();
@@ -128,60 +364,195 @@ public class MoveToWindow : EditorWindow
private void DrawTabItem(GameObject obj, string cleanName, Color tabColor)
{
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
// 1. Active Toggle
bool isActive = obj.activeSelf;
bool newActiveState = EditorGUILayout.Toggle(isActive, GUILayout.Width(20));
if (newActiveState != isActive)
{
obj.SetActive(newActiveState);
}
if (newActiveState != isActive) obj.SetActive(newActiveState);
GUILayout.Space(5);
// 2. Color Indicator
GUIStyle colorStyle = new GUIStyle(GUI.skin.box)
{
normal = { background = MakeTex(1, 1, tabColor) },
margin = new RectOffset(0, 5, 4, 4),
margin = new RectOffset(0, 0, 4, 4),
fixedWidth = 15,
fixedHeight = 15
};
GUILayout.Box(GUIContent.none, colorStyle);
GUILayout.Space(10);
// 3. Main Button (Folder Name)
// ZMIANA: Kolor tekstu zale¿ny od aktywnoœci obiektu
GUIStyle tabButtonStyle = new GUIStyle(GUI.skin.button)
{
alignment = TextAnchor.MiddleCenter,
normal = { background = MakeTex(1, 1, obj.activeSelf ? new Color(0.2f, 0.2f, 0.2f) : new Color(0.15f, 0.15f, 0.15f)) }
normal = {
background = MakeTex(1, 1, obj.activeSelf ? new Color(0.25f, 0.25f, 0.25f) : new Color(0.18f, 0.18f, 0.18f)),
textColor = obj.activeSelf ? new Color(0.9f, 0.9f, 0.9f) : new Color(0.5f, 0.5f, 0.5f)
},
hover = {
background = MakeTex(1, 1, new Color(0.3f, 0.3f, 0.3f)),
textColor = Color.white
}
};
if (GUILayout.Button(cleanName, tabButtonStyle, GUILayout.Width(250))) // Zwiêkszono szerokoœæ przycisku do 250
if (GUILayout.Button(cleanName, tabButtonStyle, GUILayout.Height(22), GUILayout.MinWidth(200)))
{
UpdateSelectedObjects(); // Ensure fresh selection
MoveObjectsToTab(selectedObjects, obj);
if (!isPinned)
{
Close();
}
if (!isPinned) Close();
}
GUILayout.Space(20);
GUILayout.Space(10);
// 4. Shortcut Toggle
bool isShortcutTarget = (shortcutTarget == obj);
bool newShortcutState = EditorGUILayout.Toggle(isShortcutTarget, GUILayout.Width(20));
if (newShortcutState != isShortcutTarget)
{
if (newShortcutState) shortcutTarget = obj;
else shortcutTarget = null;
}
if (isShortcutTarget)
{
GUIStyle spaceLabelStyle = new GUIStyle(EditorStyles.miniLabel)
{
// ZMIANA TUTAJ:
// Zamiast Color.green wpisz np. Color.cyan (jasny b³êkit)
// lub w³asny kolor: new Color(0.4f, 0.7f, 1f)
normal = { textColor = new Color(0.4f, 0.7f, 1f) },
fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleLeft
};
GUILayout.Label("[SPACE]", spaceLabelStyle, GUILayout.Width(50));
}
else
{
GUILayout.Space(54);
}
// 5. Show In Hierarchy Button
GUIStyle showInHierarchyStyle = new GUIStyle(GUI.skin.button)
{
alignment = TextAnchor.MiddleCenter,
normal = { textColor = Color.gray, background = MakeTex(1, 1, new Color(0.1f, 0.1f, 0.1f)) },
normal = { textColor = new Color(0.8f, 0.8f, 0.8f) },
hover = { textColor = Color.white },
fontSize = 10,
fontStyle = FontStyle.Italic
};
if (GUILayout.Button("Show in Hierarchy", showInHierarchyStyle, GUILayout.Width(120)))
if (GUILayout.Button("Show", showInHierarchyStyle, GUILayout.Width(45), GUILayout.Height(22)))
{
EditorGUIUtility.PingObject(obj);
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(6);
}
private void DrawFooter()
{
GUILayout.Space(10);
Color oldColor = GUI.backgroundColor;
GUI.backgroundColor = new Color(0.8f, 0.7f, 0.7f);
GUIStyle rootBtnStyle = new GUIStyle(GUI.skin.button);
rootBtnStyle.fontStyle = FontStyle.Bold;
rootBtnStyle.fontSize = 11;
if (GUILayout.Button("Move to Root (Unparent)", rootBtnStyle, GUILayout.Height(25)))
{
MoveToRoot();
}
GUI.backgroundColor = oldColor;
GUILayout.Space(5);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
string status = (selectedObjects != null && selectedObjects.Count > 0)
? $"{selectedObjects.Count} objects selected"
: "No objects selected";
GUILayout.Label(status, EditorStyles.centeredGreyMiniLabel);
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(5);
}
// ------------------------------------------------------------------------
// Logic Methods
// ------------------------------------------------------------------------
private void CreateAndMove()
{
if (string.IsNullOrEmpty(newGroupName)) return;
string finalName = $"{selectedColorIdForCreation}={newGroupName.Trim()}";
GameObject header = new GameObject(finalName);
Undo.RegisterCreatedObjectUndo(header, "Create Group");
if (Selection.activeGameObject != null && !selectedObjects.Contains(Selection.activeGameObject))
{
GameObjectUtility.SetParentAndAlign(header, Selection.activeGameObject);
}
UpdateTopLevelObjects();
UpdateSelectedObjects();
MoveObjectsToTab(selectedObjects, header);
newGroupName = "New Group";
GUI.FocusControl(null);
Repaint();
}
private void MoveToRoot()
{
UpdateSelectedObjects();
if (selectedObjects == null) return;
foreach (var obj in selectedObjects)
{
if (obj != null)
{
Undo.SetTransformParent(obj.transform, null, "Move to Root");
if (resetPositionOnMove)
{
Undo.RecordObject(obj.transform, "Zero Position");
obj.transform.position = Vector3.zero;
}
}
}
}
private static void MoveObjectsToTab(List<GameObject> objects, GameObject targetTab)
{
if (objects == null || targetTab == null) return;
foreach (var obj in objects)
{
if (obj != null)
{
Undo.SetTransformParent(obj.transform, targetTab.transform, "Move objects to folder");
if (resetPositionOnMove)
{
Undo.RecordObject(obj.transform, "Zero Position");
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
}
}
}
}
// ------------------------------------------------------------------------
// Helper Methods & Updating
// ------------------------------------------------------------------------
private void Update()
{
if (isPinned)
@@ -194,10 +565,12 @@ public class MoveToWindow : EditorWindow
private static void LoadSettings()
{
if (settings != null) return;
settings = AssetDatabase.LoadAssetAtPath<HierarchyDecoratorSettings>("Assets/Scripts/Editor/HierarchyDecoratorSettings.asset");
if (settings == null)
{
Debug.LogWarning("HierarchyDecoratorSettings not found! Please create one in Assets/Scripts/Editor folder or check the path.");
settings = ScriptableObject.CreateInstance<HierarchyDecoratorSettings>();
settings.defaultBackgroundColor = Color.gray;
}
}
@@ -208,12 +581,23 @@ public class MoveToWindow : EditorWindow
private static void UpdateTopLevelObjects()
{
if (settings == null) LoadSettings();
topLevelObjects = new List<GameObject>();
foreach (GameObject obj in Resources.FindObjectsOfTypeAll<GameObject>())
{
if (HasColorInHierarchy(obj) && !obj.name.Contains("= Clean"))
if (obj.hideFlags == HideFlags.None && HasColorInHierarchy(obj) && !obj.name.Contains("= Clean"))
{
topLevelObjects.Add(obj);
Color color = CalculateColorForObject(obj);
if (color != settings.defaultBackgroundColor)
{
if (!colorFilters.ContainsKey(color))
{
colorFilters[color] = true;
}
}
}
}
topLevelObjects = topLevelObjects.OrderBy(obj => GetHierarchyDepth(obj)).ThenBy(obj => obj.transform.GetSiblingIndex()).ToList();
@@ -221,6 +605,7 @@ public class MoveToWindow : EditorWindow
private static int GetHierarchyDepth(GameObject obj)
{
if (obj == null) return 0;
int depth = 0;
Transform current = obj.transform;
while (current.parent != null)
@@ -235,7 +620,7 @@ public class MoveToWindow : EditorWindow
{
foreach (var obj in topLevelObjects)
{
obj.SetActive(isActive);
if (obj != null) obj.SetActive(isActive);
}
}
@@ -243,20 +628,21 @@ public class MoveToWindow : EditorWindow
{
foreach (GameObject obj in topLevelObjects)
{
if (PrefabUtility.IsAnyPrefabInstanceRoot(obj) || obj.transform.childCount > 0)
if (obj != null && obj.transform.childCount > 0)
{
bool state = obj.activeSelf;
obj.SetActive(false);
obj.SetActive(true);
obj.SetActive(state);
}
}
}
private static bool HasColorInHierarchy(GameObject obj)
{
return obj.name.Contains("=");
return obj != null && obj.name.Contains("=");
}
private Color GetTabColor(GameObject obj)
private static Color CalculateColorForObject(GameObject obj)
{
Color color = settings != null ? settings.defaultBackgroundColor : Color.gray;
@@ -270,16 +656,20 @@ public class MoveToWindow : EditorWindow
if (scheme != null)
{
color = obj.activeSelf ? scheme.activeBackgroundColor : scheme.inactiveBackgroundColor;
if (!colorFilters.ContainsKey(color))
{
colorFilters[color] = true;
}
}
}
}
return color;
}
private void DrawOutline(Rect rect, float size, Color color)
{
EditorGUI.DrawRect(new Rect(rect.x, rect.y, rect.width, size), color);
EditorGUI.DrawRect(new Rect(rect.x, rect.y + rect.height - size, rect.width, size), color);
EditorGUI.DrawRect(new Rect(rect.x, rect.y, size, rect.height), color);
EditorGUI.DrawRect(new Rect(rect.x + rect.width - size, rect.y, size, rect.height), color);
}
private Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
@@ -295,12 +685,4 @@ public class MoveToWindow : EditorWindow
{
return MakeTex(12, 12, color);
}
private void MoveObjectsToTab(List<GameObject> objects, GameObject targetTab)
{
foreach (var obj in objects)
{
Undo.SetTransformParent(obj.transform, targetTab.transform, "Move objects to folder");
}
}
}
}