using AssetBank.Editor.Tools; using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace AssetBank.Settings { /// /// Hosts the Component Stats UI within the Project Settings window. /// internal class ComponentStatsSettingsProvider : SettingsProvider { private ComponentStatsController _controller; private ComponentStatsController.ScanSource _scanSource = ComponentStatsController.ScanSource.Both; private Dictionary _stats = new(); private Vector2 _scrollPosition; private GUIStyle _alternatingRowStyle; private ComponentStatsSettings _statsSettings; const string k_SettingsPath = "Project/Project AssetDatabase/Component Stats"; public ComponentStatsSettingsProvider(string path, SettingsScope scope = SettingsScope.Project) : base(path, scope) {} public override void OnActivate(string searchContext, UnityEngine.UIElements.VisualElement rootElement) { _controller = new ComponentStatsController(); _statsSettings = ComponentStatsSettings.GetOrCreateSettings(); LoadStatsFromSettings(); // Create a style for alternating row colors _alternatingRowStyle = new GUIStyle(); var texture = new Texture2D(1, 1); var color = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.05f) : new Color(0f, 0f, 0f, 0.05f); texture.SetPixel(0, 0, color); texture.Apply(); _alternatingRowStyle.normal.background = texture; } public override void OnGUI(string searchContext) { EditorGUILayout.LabelField("Component Stats Generator", EditorStyles.boldLabel); EditorGUILayout.Space(); EditorGUILayout.HelpBox("Scan project assets to find all unique component types and their statistics.", MessageType.Info); if (!string.IsNullOrEmpty(_statsSettings.LastScanTime)) { EditorGUILayout.HelpBox($"Last Scan: {_statsSettings.LastScanTime}", MessageType.None); } _scanSource = (ComponentStatsController.ScanSource)EditorGUILayout.EnumPopup("Asset Source to Scan", _scanSource); if (GUILayout.Button("Scan Project for Components")) { var newStats = _controller.ScanProject(_scanSource); _stats = newStats; // Immediately save the new scan results and update the timestamp _controller.UpdateAndSaveScanResults(_stats); } EditorGUILayout.Space(); DrawHeader(); DrawComponentList(); EditorGUILayout.Space(); if (GUILayout.Button("Save Stats")) { _controller.SaveStats(_stats); } if (GUI.changed) { EditorUtility.SetDirty(_statsSettings); AssetDatabase.SaveAssets(); } } private void DrawHeader() { EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.Label("Component Name", GUILayout.MinWidth(150), GUILayout.ExpandWidth(true)); GUILayout.Label("Occurrences", GUILayout.Width(80)); GUILayout.Label("Max Props", GUILayout.Width(70)); GUILayout.Label("Total Props", GUILayout.Width(80)); EditorGUILayout.EndHorizontal(); } private void DrawComponentList() { _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.ExpandHeight(true)); if (_stats.Count == 0) { EditorGUILayout.LabelField("No components found. Please run a scan.", EditorStyles.centeredGreyMiniLabel); } else { var sortedStats = _stats.Values.OrderBy(s => s.Name).ToList(); int i = 0; foreach (var stat in sortedStats) { var style = (i++ % 2 == 0) ? GUIStyle.none : _alternatingRowStyle; EditorGUILayout.BeginHorizontal(style); EditorGUILayout.LabelField(stat.Name, GUILayout.MinWidth(150), GUILayout.ExpandWidth(true)); EditorGUILayout.LabelField(stat.TotalOccurrences.ToString(), GUILayout.Width(80)); EditorGUILayout.LabelField(stat.MaxProperties.ToString(), GUILayout.Width(70)); EditorGUILayout.LabelField(stat.TotalProperties.ToString(), GUILayout.Width(80)); EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndScrollView(); } private void LoadStatsFromSettings() { _stats = _statsSettings.ComponentStats.ToDictionary(s => s.Name, s => s); } [SettingsProvider] public static SettingsProvider CreateSettingsProvider() { var provider = new ComponentStatsSettingsProvider(k_SettingsPath, SettingsScope.Project); return provider; } } }