#if UNITY_EDITOR && UNITY_2021_3_OR_NEWER using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using UnityEngine.Windows; [InitializeOnLoad] public class ZFolderIcons : EditorWindow { private static GUIStyle DirectoryLabelStyle; private static GUIStyle MonoScriptLabelStyle; private const float maxHeight = 18f; private static Texture2D scriptIconTexture; private static Dictionary PreDefinedFolderLabels = new Dictionary { { new Regex(@"^Script(s)?$", RegexOptions.IgnoreCase), "C#" }, { new Regex(@"^Plugin(s)?$", RegexOptions.IgnoreCase), "Plug" }, { new Regex(@"^Resource(s)?$", RegexOptions.IgnoreCase), "Res" }, { new Regex(@"^Editor$", RegexOptions.IgnoreCase), "Edit" }, { new Regex(@"^Prefab(s)?$", RegexOptions.IgnoreCase), "PF" }, { new Regex(@"^Tile(s)?Palette(s)?$", RegexOptions.IgnoreCase), "Tile" }, }; static ZFolderIcons() { EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI; } private static void OnProjectWindowItemGUI(string guid, Rect selectionRect) { if (selectionRect.height < maxHeight) return; // Get the asset path based on the GUID string assetPath = AssetDatabase.GUIDToAssetPath(guid); // Check if the asset is a folder and not in the base project folder // Use "&& assetPath.Count(c => c == '/') >= 2" to ignore base assets folder // TODO: Impliment AssetDatabase.GetMainAssetTypeFromGUID(new GUID(guid)).IsSubclassOf(typeof(ScriptableObject)) Type objectType = null; if (AssetDatabase.IsValidFolder(assetPath)) { DoFolderIcons(assetPath, selectionRect); } else { objectType = AssetDatabase.GetMainAssetTypeFromGUID(new GUID(guid)); } if (objectType == null) return; if (objectType == typeof(MonoScript)) // Is script object { DoMonoScriptIcon(assetPath, selectionRect); } } static void DoFolderIcons(string folderPath, Rect selectionRect) { // Calculate the position for the custom label Rect labelRect = new Rect(selectionRect.x + selectionRect.width * 0.15f, selectionRect.y + selectionRect.width * 0.4f, selectionRect.width, selectionRect.height); string folderName = Path.GetFileName(folderPath); // Create GUIStyle if it hasn't been created yet if (DirectoryLabelStyle == null) { DirectoryLabelStyle = new GUIStyle(EditorStyles.miniLabel); DirectoryLabelStyle.alignment = TextAnchor.UpperLeft; // Adjust the font size as desired DirectoryLabelStyle.normal.textColor = Color.black; // Set the text color TryAssignFont(ref DirectoryLabelStyle); } DirectoryLabelStyle.fontSize = (int)(selectionRect.width * 0.35f); // Adjust the font size as desired string labelText; if (TryGetPreDefinedLabel(folderName, out string label)) { labelText = label; } else if (folderName.Count(char.IsUpper) >= 2) { labelText = new string(folderName.Where(x => char.IsUpper(x)).Take(4).ToArray()); } else { labelText = new(folderName.Take(4).ToArray()); } // Draw the custom label with black color var previousColor = GUI.color; GUI.color = Color.black; EditorGUI.LabelField(labelRect, labelText, DirectoryLabelStyle); GUI.color = previousColor; DrawFolderColorStrip(folderName, selectionRect); } static void DrawFolderColorStrip(string seedString, Rect selectionRect) { Color stripColor = GetRandomColor(seedString); // Calculate the position for the strip Rect stripRect = new Rect( x: selectionRect.x + selectionRect.width * 0.175f, y: selectionRect.y + selectionRect.width * 0.725f, width: selectionRect.width * 0.64f, height: selectionRect.height * 0.05f); // Draw the custom label with black color var previousColor = GUI.color; EditorGUI.DrawRect(stripRect, stripColor); GUI.color = previousColor; } static void DoMonoScriptIcon(string scriptPath, Rect selectionRect) { // Calculate the position for the white overlay Rect overwriteOverlayRect = new Rect(selectionRect.x + selectionRect.width * 0.25f, selectionRect.y + selectionRect.width * 0.20f, selectionRect.width*0.5f, selectionRect.height*0.5f); var previousColor = GUI.color; if (!Application.isPlaying) { // Draw the custom rect with white color previousColor = GUI.color; float shadeOfWhite = 247; GUI.color = new Color(shadeOfWhite / 255f, shadeOfWhite / 255f, shadeOfWhite / 255f); EditorGUI.DrawRect(overwriteOverlayRect, GUI.color); GUI.color = previousColor; } else { //Did not work //// Gets playmode tint color //string prefPlaymodeTint = EditorPrefs.GetString("Playmode tint", "").Replace("Playmode tint;", ""); //string[] rgba = prefPlaymodeTint.Split(";"); //Color color = new Color(float.Parse(rgba[0]), float.Parse(rgba[1]), float.Parse(rgba[2]), float.Parse(rgba[3])); //// Draw the custom rect with play color tint //previousColor = GUI.color; //GUI.color = color; //EditorGUI.DrawRect(overwriteOverlayRect, GUI.color); //GUI.color = previousColor; // Draw the custom rect with white color previousColor = GUI.color; float shadeOfWhite = 247; GUI.color = new Color(shadeOfWhite / 255f, shadeOfWhite / 255f, shadeOfWhite / 255f); EditorGUI.DrawRect(overwriteOverlayRect, GUI.color); GUI.color = previousColor; } string scriptName = Path.GetFileName(scriptPath); const int maxLength = 8; string labelText; { // Use LINQ to iterate through each character and insert a line break before uppercase letters labelText = new string(scriptName.SelectMany(c => char.IsUpper(c) ? new char[] { '\n', c } : new[] { c }).ToArray()); labelText = labelText.TrimStart('\n').Replace(".cs", ""); labelText = string.Join('\n', MergeLooseCapitalStrings(labelText.Split('\n'))); labelText = string.Join('\n', labelText.Split('\n').Select(x => x.Length > 6 ? new string(x.Take(maxLength).ToArray()) + "…" : x)); } // Calculate the position for the custom label Rect labelRect = new Rect(selectionRect.x + selectionRect.width * 0.15f, selectionRect.y + selectionRect.width * 0.1f, selectionRect.width, selectionRect.height); // Create GUIStyle if it hasn't been created yet if (MonoScriptLabelStyle == null) { MonoScriptLabelStyle = new GUIStyle(EditorStyles.miniLabel); MonoScriptLabelStyle.alignment = TextAnchor.UpperLeft; // Adjust the font size as desired MonoScriptLabelStyle.normal.textColor = Color.black; // Set the text color TryAssignFont(ref MonoScriptLabelStyle); } MonoScriptLabelStyle.fontSize = (int)(selectionRect.width * 0.2f); // Adjust the font size as desired // Draw the custom label with black color previousColor = GUI.color; GUI.color = Color.black; EditorGUI.LabelField(labelRect, labelText, MonoScriptLabelStyle); GUI.color = previousColor; // Custom icon rect Rect customIconRect = new Rect(selectionRect.x + selectionRect.width * 0.62f, selectionRect.y + selectionRect.width * 0.645f, selectionRect.width * 0.25f, selectionRect.height * 0.25f); // Load texture if null if (scriptIconTexture == null) { if (TryGetScriptIcon(out Texture2D icon)) { scriptIconTexture = icon; } else { return; // Couldn't get icon, so don't draw it } } // Draw the custom icon GUI.DrawTexture(customIconRect, scriptIconTexture); } public static bool TryGetPreDefinedLabel(string folderName, out string label) { foreach (var regex in PreDefinedFolderLabels.Keys) { if (regex.IsMatch(folderName)) { label = PreDefinedFolderLabels[regex]; return true; } } label = "Error"; return false; } static bool TryGetScriptIcon(out Texture2D icon) { if (FindFolder("ExtraIcons", out string path)) { icon = AssetDatabase.LoadAssetAtPath(path + "/ScriptHashtag.png"); return true; } else { icon = null; return false; } } static bool FindFolder(string folderName, out string path) { string[] guids = AssetDatabase.FindAssets("t:Folder " + folderName); if (guids.Length > 0) { path = AssetDatabase.GUIDToAssetPath(guids[0]); return true; } else { path = null; return false; } } static string[] MergeLooseCapitalStrings(string[] arr) { List result = new List(); string currentString = ""; foreach (string s in arr) { if (IsUpperCase(s)) { currentString += s; } else if (!string.IsNullOrEmpty(currentString)) { result.Add(currentString + s); currentString = ""; } else { result.Add(s); } } if (!string.IsNullOrEmpty(currentString)) { result.Add(currentString); } return result.ToArray(); } static Func IsUpperCase = s => !string.IsNullOrEmpty(s) && s.All(char.IsUpper); /// /// Generates a semi random color out of a seed /// /// Used to generate the color /// A semi random color public static Color GetRandomColor(string seed) { int intSeed = seed.Select(c=>(int)c).Sum(); System.Random random = new System.Random(intSeed); // Generate random values for R, G, and B components between 0 and 1. float r = (float)random.NextDouble(); float g = (float)random.NextDouble(); float b = (float)random.NextDouble(); // Create and return the color. return new Color(r, g, b); } private static void TryAssignFont(ref GUIStyle guiFont) { string[] guids = AssetDatabase.FindAssets("t:Font CozetteVector", new[] { "Assets/Plugins/ZFolderIcons" }); if (guids.Length <= 0) { return; // Couldn't find font asset } string path = AssetDatabase.GUIDToAssetPath(guids[0]); guiFont.font = AssetDatabase.LoadAssetAtPath(path); } } #endif