1010using UnityHierarchyFolders . Runtime ;
1111using Object = UnityEngine . Object ;
1212
13- namespace Plugins . UnityHierarchyFolders {
13+ namespace UnityHierarchyFolders . Editor
14+ {
1415 public class HierarchyFolderIcon
1516 {
17+ #if UNITY_2020_1_OR_NEWER
18+ private const string OpenedFolderPrefix = "FolderOpened" ;
19+ #else
20+ private const string OpenedFolderPrefix = "OpenedFolder" ;
21+ #endif
22+ private const string ClosedFolderPrefix = "Folder" ;
23+
1624 private static Texture2D openFolderTexture ;
1725 private static Texture2D closedFolderTexture ;
1826 private static Texture2D openFolderSelectedTexture ;
1927 private static Texture2D closedFolderSelectedTexture ;
2028
2129 private static bool isInitialized ;
22- private static bool hasProcessedFrame ;
30+ private static bool hasProcessedFrame = true ;
2331
2432 // Reflected members
2533 private static PropertyInfo prop_sceneHierarchy ;
@@ -32,29 +40,68 @@ public class HierarchyFolderIcon
3240 private static MethodInfo meth_isExpanded ;
3341 private static MethodInfo meth_getAllSceneHierarchyWindows ;
3442
43+ private static ( Texture2D , Texture2D ) [ ] _coloredFolderIcons ;
44+ public static ( Texture2D , Texture2D ) [ ] coloredFolderIcons => _coloredFolderIcons ;
45+
46+ public static int IconColumnCount => IconColors . GetLength ( 0 ) ;
47+ public static int IconRowCount => IconColors . GetLength ( 1 ) ;
48+
49+ public static readonly Color [ , ] IconColors = {
50+ { new Color ( 0.09f , 0.57f , 0.82f ) , new Color ( 0.05f , 0.34f , 0.48f ) , } ,
51+ { new Color ( 0.09f , 0.67f , 0.67f ) , new Color ( 0.05f , 0.42f , 0.42f ) , } ,
52+ { new Color ( 0.23f , 0.73f , 0.36f ) , new Color ( 0.15f , 0.41f , 0.22f ) , } ,
53+ { new Color ( 0.55f , 0.35f , 0.71f ) , new Color ( 0.35f , 0.24f , 0.44f ) , } ,
54+ { new Color ( 0.78f , 0.27f , 0.55f ) , new Color ( 0.52f , 0.15f , 0.35f ) , } ,
55+ { new Color ( 0.80f , 0.66f , 0.10f ) , new Color ( 0.56f , 0.46f , 0.02f ) , } ,
56+ { new Color ( 0.91f , 0.49f , 0.13f ) , new Color ( 0.62f , 0.33f , 0.07f ) , } ,
57+ { new Color ( 0.91f , 0.30f , 0.24f ) , new Color ( 0.77f , 0.15f , 0.09f ) , } ,
58+ { new Color ( 0.35f , 0.49f , 0.63f ) , new Color ( 0.24f , 0.33f , 0.42f ) , } ,
59+ } ;
60+
3561 [ InitializeOnLoadMethod ]
3662 static void Startup ( )
3763 {
38- Initialize ( ) ;
3964 EditorApplication . update += ResetFolderIcons ;
4065 EditorApplication . hierarchyWindowItemOnGUI += RefreshFolderIcons ;
4166 }
4267
43- private static Texture2D GetTintedTexture ( Texture2D original )
68+ private static Texture2D GetTintedTexture ( Texture2D original , Color tint , string name = "" )
69+ {
70+ Color32 TintColor ( Color32 c )
71+ {
72+ return c * tint ;
73+ }
74+
75+ return GetColorizedTexture ( original , TintColor , name ) ;
76+ }
77+
78+ private static Texture2D GetWhiteTexture ( Texture2D original , string name = "" )
79+ {
80+ Color32 MakeColorsWhite ( Color32 c )
81+ {
82+ byte a = c . a ;
83+ c = Color . HSVToRGB ( 0 , 0 , 1 ) ;
84+ c . a = a ;
85+
86+ return c ;
87+ }
88+
89+ return GetColorizedTexture ( original , MakeColorsWhite , name ) ;
90+ }
91+
92+ private static Texture2D GetColorizedTexture ( Texture2D original , Func < Color32 , Color32 > colorManipulator , string name = "" )
4493 {
4594 var tinted = new Texture2D ( original . width , original . height ,
4695 original . graphicsFormat , original . mipmapCount , TextureCreationFlags . MipChain ) ;
96+
97+ tinted . name = name ;
98+
99+ Graphics . CopyTexture ( original , tinted ) ;
47100
48- Graphics . CopyTexture ( original , tinted ) ;
49101 var data = tinted . GetRawTextureData < Color32 > ( ) ;
50102 for ( int index = 0 , len = data . Length ; index < len ; index ++ )
51103 {
52- Color32 c = data [ index ] ;
53- byte a = c . a ;
54- c = Color . HSVToRGB ( 0 , 0 , 1 ) ;
55- c . a = a ;
56-
57- data [ index ] = c ;
104+ data [ index ] = colorManipulator ( data [ index ] ) ;
58105 }
59106
60107 var mipmapSize = tinted . width * tinted . height * 4 ;
@@ -65,20 +112,44 @@ private static Texture2D GetTintedTexture(Texture2D original)
65112 mipmapSize >>= 2 ;
66113 offset += mipmapSize ;
67114 }
115+
116+ tinted . hideFlags = HideFlags . DontSave ;
68117 tinted . Apply ( ) ;
69118
70119 return tinted ;
71120 }
72-
73- private static void Initialize ( )
121+
122+ private static void InitIfNeeded ( )
74123 {
75124 if ( isInitialized ) { return ; }
76-
77- closedFolderTexture = ( Texture2D ) EditorGUIUtility . IconContent ( "Folder Icon" ) . image ;
78- openFolderTexture = ( Texture2D ) EditorGUIUtility . IconContent ( "FolderEmpty Icon" ) . image ;
79-
80- openFolderSelectedTexture = GetTintedTexture ( openFolderTexture ) ;
81- closedFolderSelectedTexture = GetTintedTexture ( closedFolderTexture ) ;
125+
126+ openFolderTexture = ( Texture2D ) EditorGUIUtility . IconContent ( $ "{ OpenedFolderPrefix } Icon") . image ;
127+ closedFolderTexture = ( Texture2D ) EditorGUIUtility . IconContent ( $ "{ ClosedFolderPrefix } Icon") . image ;
128+
129+ // We could use the actual white folder icons but I prefer the look of the tinted folder icon
130+ // so I'm leaving this as a documented alternative.
131+ //openFolderSelectedTexture = (Texture2D) EditorGUIUtility.IconContent($"{OpenedFolderPrefix} On Icon").image;
132+ //closedFolderSelectedTexture = (Texture2D) EditorGUIUtility.IconContent($"{ClosedFolderPrefix} On Icon").image;
133+ openFolderSelectedTexture = GetWhiteTexture ( openFolderTexture , $ "{ OpenedFolderPrefix } Icon White") ;
134+ closedFolderSelectedTexture = GetWhiteTexture ( closedFolderTexture , $ "{ ClosedFolderPrefix } Icon White") ;
135+
136+ _coloredFolderIcons = new ( Texture2D , Texture2D ) [ ] { ( openFolderTexture , closedFolderTexture ) } ;
137+
138+ for ( int row = 0 ; row < IconRowCount ; row ++ )
139+ {
140+ for ( int column = 0 ; column < IconColumnCount ; column ++ )
141+ {
142+ int index = 1 + column + row * IconColumnCount ;
143+ var color = IconColors [ column , row ] ;
144+
145+ var openFolderIcon = GetTintedTexture ( openFolderSelectedTexture ,
146+ color , $ "{ openFolderSelectedTexture . name } { index } ") ;
147+ var closedFolderIcon = GetTintedTexture ( closedFolderSelectedTexture ,
148+ color , $ "{ closedFolderSelectedTexture . name } { index } ") ;
149+
150+ ArrayUtility . Add ( ref _coloredFolderIcons , ( openFolderIcon , closedFolderIcon ) ) ;
151+ }
152+ }
82153
83154 const BindingFlags BindingAll = BindingFlags . Public
84155 | BindingFlags . NonPublic | BindingFlags . Static | BindingFlags . Instance ;
@@ -108,31 +179,37 @@ private static void Initialize()
108179
109180 private static void ResetFolderIcons ( )
110181 {
111- Initialize ( ) ;
182+ InitIfNeeded ( ) ;
112183 hasProcessedFrame = false ;
113184 }
114185
115186 private static void RefreshFolderIcons ( int instanceid , Rect selectionrect )
116187 {
117188 if ( hasProcessedFrame ) { return ; }
189+
118190 hasProcessedFrame = true ;
119191
120192 var windows = ( ( IEnumerable ) meth_getAllSceneHierarchyWindows . Invoke ( null , Array . Empty < object > ( ) ) ) . Cast < EditorWindow > ( ) . ToList ( ) ;
121- foreach ( EditorWindow h in windows )
193+ foreach ( EditorWindow window in windows )
122194 {
123- var sceneHierarchy = prop_sceneHierarchy . GetValue ( h ) ;
195+ var sceneHierarchy = prop_sceneHierarchy . GetValue ( window ) ;
124196 var treeView = prop_treeView . GetValue ( sceneHierarchy ) ;
125197 var data = prop_data . GetValue ( treeView ) ;
126198
127199 var rows = ( IList < TreeViewItem > ) meth_getRows . Invoke ( data , Array . Empty < object > ( ) ) ;
128200 foreach ( TreeViewItem item in rows )
129201 {
130202 var itemObject = ( Object ) prop_objectPPTR . GetValue ( item ) ;
131- if ( ! itemObject || ! Folder . IsFolder ( itemObject ) ) { continue ; }
203+ if ( ! Folder . TryGetIconIndex ( itemObject , out int colorIndex ) ) { continue ; }
132204
205+
133206 var isExpanded = ( bool ) meth_isExpanded . Invoke ( data , new object [ ] { item } ) ;
134207
135- item . icon = isExpanded ? openFolderTexture : closedFolderTexture ;
208+ Texture2D open , closed ;
209+ var count = _coloredFolderIcons . Length ;
210+ ( open , closed ) = coloredFolderIcons [ Mathf . Clamp ( colorIndex , 0 , count ) % count ] ;
211+ item . icon = isExpanded ? open : closed ;
212+
136213 prop_selectedIcon . SetValue ( item , isExpanded ? openFolderSelectedTexture : closedFolderSelectedTexture ) ;
137214 }
138215 }
0 commit comments