using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace StaTech.AnimationValidator { public class AnimationValidatorView : EditorWindow { private Texture2D _successIcon; private Texture2D SuccessIcon { get{ if(_successIcon == null){ _successIcon = GetBuiltInIcon("testpassed.png"); } return _successIcon; } } private Texture2D _errorIcon; private Texture2D ErrorIcon { get{ if(_errorIcon == null){ _errorIcon = GetBuiltInIcon("testfailed.png"); } return _errorIcon; } } private const float DetailSpace = 30f; private const float RightPadding = 30f; private static List _clipValidations; private static GameObject _selectedObject; private static AnimationValidatorView _window; private static Vector2 _scrollPos; [MenuItem("GameObject/アニメーションクリップ修正", false, -1)] public static void Open(){ _clipValidations = AnimationValidator.ValidateAnimation(); if(_clipValidations == null){ return; } _window = GetWindow (); _window.titleContent = new GUIContent("anim修正"); _selectedObject = Selection.activeGameObject; } private void OnGUI(){ if(_clipValidations == null || _clipValidations.Count == 0){ GUILayout.Label("AnimationClipがありません"); return; } _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, true, true); GUILayout.Label("====================================="); GUILayout.Label("Animationでmissingになっているものを表示します"); GUILayout.Label("オブジェクトの名前が他と被っていなれば自動で修正します"); GUILayout.Label("====================================="); if(_clipValidations.Count > 1){ foreach(var result in _clipValidations){ if(!result.HasNoError){ DrawButton("全部まとめて修正", () => { AnimationValidator.ExecuteAllRecovery(_selectedObject, _clipValidations, ShowProgress); _window.Repaint(); EditorApplication.RepaintAnimationWindow(); }); break; } } } foreach(var result in _clipValidations){ DrawResult(result); } DrawButton("閉じる", () => _window.Close()); EditorGUILayout.EndScrollView(); } private void DrawResult(ClipValidationContainer result){ if(result.HasNoError){ using(new EditorGUILayout.VerticalScope("box", GUILayout.Width(position.width - RightPadding))){ DrawOnSuccess(result); } }else{ using(new EditorGUILayout.VerticalScope("box", GUILayout.Width(position.width - RightPadding))){ DrawOnError(result); } } } private void DrawOnSuccess(ClipValidationContainer result){ DrawIconAndLabel(SuccessIcon, result.ClipName, "→正常です"); DrawDetail(result.LostProperties); } private void DrawOnError(ClipValidationContainer result){ DrawIconAndLabel(ErrorIcon, result.ClipName); DrawDetail(result.LostProperties); DrawButton("自動修正", () => { AnimationValidator.ExecuteUnitRecovery(_selectedObject, result, ShowProgress); _window.Repaint(); EditorApplication.RepaintAnimationWindow(); }); } private void ShowProgress(string content, float progress){ EditorUtility.DisplayProgressBar("実行中", content, progress); } private void DrawDetail(List Props){ using(new GUILayout.VerticalScope()){ foreach(var prop in Props){ var icon = prop.State == FixState.Fixed ? SuccessIcon : ErrorIcon; DrawSpaceAndText(DetailSpace, prop.PropPath + " : " + prop.AttributeName, icon, prop.State); } } } private void DrawIconAndLabel(Texture image, string content, string detail = ""){ using(new GUILayout.HorizontalScope()){ GUILayout.Label(image, GUILayout.Height(18f), GUILayout.Width(20f)); GUILayout.Label(content); if(!string.IsNullOrEmpty(detail)){ GUIStyle s = new GUIStyle(EditorStyles.label){ normal = { textColor = Color.green } }; GUILayout.Label(detail, s); GUILayout.FlexibleSpace(); } } } private void DrawSpaceAndText(float space, string content, Texture headIcon, FixState state = FixState.None){ using(new GUILayout.HorizontalScope()){ GUILayout.Space(space); if(headIcon){ GUILayout.Label(headIcon, GUILayout.Height(18f), GUILayout.Width(20f)); } GUILayout.Label(content); var detail = GetDetail(state); if(!string.IsNullOrEmpty(detail)){ // 黄色文字で足す var color = GetColor(state); if(color != Color.white){ GUIStyle s = new GUIStyle(EditorStyles.label){ normal = { textColor = color } }; GUILayout.Label(detail, s); GUILayout.FlexibleSpace(); } } } } private static Color GetColor(FixState state){ switch(state){ case FixState.ErrorDuplicate: case FixState.ErrorNoSameName: return Color.yellow; case FixState.Fixed: return Color.green; default: return Color.white; } } private static string GetDetail(FixState state){ switch(state){ case FixState.ErrorDuplicate: return "→同じ名前のオブジェクトが子階層上に複数あります"; case FixState.ErrorNoSameName: return "→同じ名前のオブジェクトが見つかりませんでした"; case FixState.Lost: return " "; case FixState.Fixed: return "→Animationのパスを変更しました"; default: return ""; } } private void DrawButton(string buttonName, System.Action callback = null){ if(GUILayout.Button(buttonName, GUILayout.Width(200f))){ if(callback != null){ callback.Invoke(); } } } private void OnDestroy(){ if(_clipValidations != null){ _clipValidations.Clear(); _clipValidations = null; } } private static Texture2D GetBuiltInIcon(string name){ System.Reflection.MethodInfo mi = typeof(EditorGUIUtility).GetMethod("IconContent", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public, null, new System.Type[] { typeof(string) }, null); if(mi == null){ mi = typeof(EditorGUIUtility).GetMethod("IconContent", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new System.Type[] { typeof(string) }, null); } return (Texture2D)((GUIContent) mi.Invoke(null, new object[] { name })).image; } } }