Files
aibis-dream/Assets/Editor/FrameAnimation/FrameAnimationEditorDialogs.cs
T

308 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace AibisDream.FrameAnimation.Editor
{
internal sealed class FrameAnimationTextInputWindow : EditorWindow
{
private string label;
private string value;
private string warning;
private Func<string, string> validate;
private Action<string> confirm;
private Vector2 scroll;
public static void Show(
string title,
string label,
string initialValue,
string warning,
Func<string, string> validate,
Action<string> confirm)
{
var window = CreateInstance<FrameAnimationTextInputWindow>();
window.titleContent = new GUIContent(title);
window.label = label;
window.value = initialValue ?? string.Empty;
window.warning = warning ?? string.Empty;
window.validate = validate;
window.confirm = confirm;
window.minSize = new Vector2(460f, 220f);
window.maxSize = new Vector2(700f, 420f);
window.ShowUtility();
}
private void OnGUI()
{
scroll = EditorGUILayout.BeginScrollView(scroll);
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
GUI.SetNextControlName("FrameAnimationTextInput");
value = EditorGUILayout.TextField(value);
if (!string.IsNullOrEmpty(warning))
{
EditorGUILayout.HelpBox(warning, MessageType.Warning);
}
var error = validate?.Invoke(value) ?? string.Empty;
if (!string.IsNullOrEmpty(error))
{
EditorGUILayout.HelpBox(error, MessageType.Error);
}
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("取消", GUILayout.Width(90f)))
{
Close();
}
using (new EditorGUI.DisabledScope(!string.IsNullOrEmpty(error)))
{
if (GUILayout.Button("确认", GUILayout.Width(90f)))
{
var callback = confirm;
var result = value;
Close();
callback?.Invoke(result);
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndScrollView();
}
private void OnEnable()
{
EditorApplication.delayCall += FocusInput;
}
private void FocusInput()
{
if (this != null)
{
Focus();
EditorGUI.FocusTextInControl("FrameAnimationTextInput");
}
}
}
internal sealed class FrameAnimationManualClipWindow : EditorWindow
{
private FrameAnimationGraph graph;
private FrameClip source;
private string id = "NewClip";
private string displayName = "New Clip";
private bool external;
private Action<FrameClip> completed;
public static void Show(
FrameAnimationGraph graph,
FrameClip source,
Action<FrameClip> completed)
{
var window = CreateInstance<FrameAnimationManualClipWindow>();
window.titleContent = new GUIContent(source == null ? "Create Manual Clip" : "Copy As Manual Clip");
window.graph = graph;
window.source = source;
window.completed = completed;
var baseId = source != null ? source.Id + "_Manual" : "NewClip";
window.id = MakeUniqueId(graph, baseId);
window.displayName = source != null ? source.DisplayName + " Manual" : window.id;
window.minSize = new Vector2(460f, 260f);
window.maxSize = new Vector2(700f, 420f);
window.ShowUtility();
}
private void OnGUI()
{
EditorGUILayout.LabelField(source == null ? "创建 Manual Clip" : "复制为 Manual Clip", EditorStyles.boldLabel);
id = EditorGUILayout.TextField("ID", id);
displayName = EditorGUILayout.TextField("Display Name", displayName);
external = EditorGUILayout.ToggleLeft("保存为外部独立 .asset(默认保存为 Graph sub-asset", external);
var error = FrameAnimationAssetOperations.IsPlayableIdAvailable(graph, id)
? string.Empty
: "ID 为空或与当前 Graph 的 Clip / Flow 冲突。";
if (!string.IsNullOrEmpty(error))
{
EditorGUILayout.HelpBox(error, MessageType.Error);
}
if (source != null)
{
EditorGUILayout.HelpBox(
"帧表将深拷贝,但 Sprite 仍复用原资源;ImportSource 关联会被清除。",
MessageType.Info);
}
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("取消", GUILayout.Width(90f)))
{
Close();
}
using (new EditorGUI.DisabledScope(!string.IsNullOrEmpty(error)))
{
if (GUILayout.Button("创建", GUILayout.Width(90f)))
{
Create();
}
}
EditorGUILayout.EndHorizontal();
}
private void Create()
{
var path = string.Empty;
if (external)
{
path = EditorUtility.SaveFilePanelInProject(
"保存外部 Manual Clip",
id,
"asset",
"请选择 Assets 下的保存位置。");
if (string.IsNullOrEmpty(path))
{
return;
}
}
var succeeded = source == null
? FrameAnimationAssetOperations.CreateManualClip(graph, id, displayName, path, out var result, out var error)
: FrameAnimationAssetOperations.CopyToManual(graph, source, id, displayName, path, out result, out error);
if (!succeeded)
{
EditorUtility.DisplayDialog("操作失败", error, "确定");
return;
}
var callback = completed;
Close();
callback?.Invoke(result);
}
private static string MakeUniqueId(FrameAnimationGraph graph, string baseId)
{
var candidate = baseId;
var suffix = 2;
while (!FrameAnimationAssetOperations.IsPlayableIdAvailable(graph, candidate))
{
candidate = baseId + suffix++;
}
return candidate;
}
}
internal sealed class FrameAnimationExistingClipWindow : EditorWindow
{
private FrameAnimationGraph graph;
private FrameClip clip;
private Action<FrameClip> completed;
public static void Show(FrameAnimationGraph graph, Action<FrameClip> completed)
{
var window = CreateInstance<FrameAnimationExistingClipWindow>();
window.titleContent = new GUIContent("Add Existing Manual Clip");
window.graph = graph;
window.completed = completed;
window.minSize = new Vector2(460f, 180f);
window.maxSize = new Vector2(640f, 260f);
window.ShowUtility();
}
private void OnGUI()
{
EditorGUILayout.LabelField("添加外部 Manual Clip", EditorStyles.boldLabel);
clip = (FrameClip)EditorGUILayout.ObjectField("FrameClip", clip, typeof(FrameClip), false);
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("取消", GUILayout.Width(90f)))
{
Close();
}
using (new EditorGUI.DisabledScope(clip == null))
{
if (GUILayout.Button("添加", GUILayout.Width(90f)))
{
if (!FrameAnimationAssetOperations.AddExistingManualClip(graph, clip, out var error))
{
EditorUtility.DisplayDialog("添加失败", error, "确定");
return;
}
var callback = completed;
var result = clip;
Close();
callback?.Invoke(result);
}
}
EditorGUILayout.EndHorizontal();
}
}
internal sealed class FrameAnimationFlowWindow : EditorWindow
{
private FrameAnimationGraph graph;
private AnimationNode entry;
private string id;
private string displayName;
private Action<AnimationFlow> completed;
internal static void Show(
FrameAnimationGraph graph,
AnimationNode entry,
Action<AnimationFlow> completed)
{
var window = CreateInstance<FrameAnimationFlowWindow>();
window.titleContent = new GUIContent("Create Animation Flow");
window.graph = graph;
window.entry = entry;
window.id = FrameAnimationGraphMutationService.MakeUniqueFlowId(graph, entry);
window.displayName = window.id;
window.completed = completed;
window.minSize = new Vector2(460f, 230f);
window.maxSize = new Vector2(700f, 360f);
window.ShowUtility();
}
private void OnGUI()
{
EditorGUILayout.LabelField("从选中节点创建 Flow", EditorStyles.boldLabel);
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.TextField("Entry Node", entry?.DisplayName ?? string.Empty);
}
id = EditorGUILayout.TextField("ID", id);
displayName = EditorGUILayout.TextField("Display Name", displayName);
var idError = FrameAnimationAssetOperations.IsPlayableIdAvailable(graph, id)
? string.Empty
: "ID 为空或与当前 Graph 中的 Clip / Flow 冲突。";
var owner = graph?.Flows.FirstOrDefault(flow => flow != null && flow.EntryNodeId == entry?.InternalId);
if (owner != null)
{
idError = $"该节点已是 Flow '{owner.Id}' 的入口。";
}
if (!string.IsNullOrEmpty(idError))
{
EditorGUILayout.HelpBox(idError, MessageType.Error);
}
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("取消", GUILayout.Width(90f))) Close();
using (new EditorGUI.DisabledScope(!string.IsNullOrEmpty(idError)))
{
if (GUILayout.Button("创建", GUILayout.Width(90f)))
{
if (!FrameAnimationGraphMutationService.CreateFlow(
graph, entry, id, displayName, out var flow, out var error))
{
EditorUtility.DisplayDialog("创建 Flow 失败", error, "确定");
return;
}
var callback = completed;
Close();
callback?.Invoke(flow);
}
}
EditorGUILayout.EndHorizontal();
}
}
}