popcorn/AnimationValidator/Editor/AnimationValidatorView.cs

204 lines
8.1 KiB
C#
Raw Normal View History

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 <ClipValidationContainer> _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 <AnimationValidatorView>();
_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 <LostProperty> 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;
}
}
}