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;
}
}
}