285 lines
9.1 KiB
C#
285 lines
9.1 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using UnityEngine;
|
|
using static Animancer.Editor.AnimancerGUI;
|
|
|
|
namespace Animancer.Editor
|
|
{
|
|
/// <summary>An <see cref="TransformTreeWindow{TTarget, TDefinition}"/> for editing spring definitions.</summary>
|
|
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/WeightedMaskLayersDefinitionWindow
|
|
public class WeightedMaskLayersDefinitionWindow :
|
|
TransformTreeWindow<WeightedMaskLayers, WeightedMaskLayersDefinition>
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override IList<Transform> Transforms
|
|
=> Data.Transforms;
|
|
|
|
/// <inheritdoc/>
|
|
public override WeightedMaskLayersDefinition SourceData
|
|
{
|
|
get => SourceObject.Definition;
|
|
set => SourceObject.Definition = value;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
protected override MultiColumnHeaderState.Column[] CreateColumns(float width)
|
|
{
|
|
const float TransformWidth = 300;
|
|
const float GroupWidth = 100;
|
|
|
|
var groupCount = Data.GroupCount;
|
|
var oldColumns = HeaderState?.columns;
|
|
|
|
var newColumns = new MultiColumnHeaderState.Column[groupCount + 2];
|
|
|
|
int index;
|
|
if (oldColumns == null)
|
|
{
|
|
var tooltip = "Select which objects to control the weight of";
|
|
|
|
newColumns[0] = CreateColumn(
|
|
"Transform",
|
|
tooltip,
|
|
TransformWidth);
|
|
|
|
var includedColumn = newColumns[1] = CreateColumn(
|
|
"?",
|
|
tooltip,
|
|
LineHeight + StandardSpacing);
|
|
|
|
includedColumn.minWidth = includedColumn.maxWidth = includedColumn.width;
|
|
|
|
index = 2;
|
|
}
|
|
else
|
|
{
|
|
var copyCount = Math.Min(oldColumns.Length, groupCount + 2);
|
|
for (int i = 0; i < copyCount; i++)
|
|
newColumns[i] = oldColumns[i];
|
|
|
|
index = copyCount;
|
|
}
|
|
|
|
for (int i = index; i < groupCount + 2; i++)
|
|
{
|
|
var groupIndex = i - 2;
|
|
var name = "Group " + groupIndex.ToStringCached();
|
|
var tooltip = "The weights for " + name;
|
|
|
|
if (groupIndex == 0)
|
|
{
|
|
name = "Default " + name;
|
|
tooltip += " (this group will be applied on startup by default)";
|
|
}
|
|
|
|
newColumns[i] = CreateColumn(
|
|
name,
|
|
tooltip,
|
|
GroupWidth);
|
|
}
|
|
|
|
return newColumns;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
protected override Color GetRowColor(TreeViewItem item)
|
|
{
|
|
if (!TreeView.Transforms.TryGetObject(item.id, out var transform))
|
|
return default;
|
|
|
|
if (Transforms.IndexOf(transform) < 0)
|
|
return default;
|
|
|
|
return GetChainColor(transform, Transforms, 0.15f);
|
|
}
|
|
|
|
/// <summary>Returns a color based on the name of the `transform`'s highest included parent.</summary>
|
|
public static Color GetChainColor(Transform transform, IList<Transform> transforms, float alpha)
|
|
{
|
|
transform = GetChainRoot(transform, transforms);
|
|
return GetHashColor(transform.name.GetHashCode(), 1, 1, alpha);
|
|
}
|
|
|
|
/// <summary>Gets the highest parent of `transform` which is included in the `transforms`.</summary>
|
|
public static Transform GetChainRoot(Transform transform, IList<Transform> transforms)
|
|
{
|
|
var parent = transform.parent;
|
|
while (parent != null)
|
|
{
|
|
if (transforms.IndexOf(parent) >= 0)
|
|
transform = parent;
|
|
|
|
parent = parent.parent;
|
|
}
|
|
|
|
return transform;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override void DrawCellGUI(Rect area, int column, int row, TreeViewItem item, ref bool isSelectionClick)
|
|
{
|
|
if (!TreeView.Transforms.TryGetObject(item.id, out var transform))
|
|
return;
|
|
|
|
var definitionIndex = GetDefinitionIndex(item.id);
|
|
|
|
switch (column)
|
|
{
|
|
case 0:// Transform.
|
|
DrawTransformCellGUI(area, transform);
|
|
break;
|
|
|
|
case 1:// Included.
|
|
DrawIsIncludedCellGUI(area, item.id, definitionIndex, ref isSelectionClick);
|
|
break;
|
|
|
|
default:// Groups.
|
|
DrawWeightGUI(area, item.id, column - 2, definitionIndex);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
protected override void SetIncluded(
|
|
int treeItemID,
|
|
int definitionIndex,
|
|
bool isIncluded)
|
|
{
|
|
var data = RecordUndo();
|
|
|
|
if (isIncluded)
|
|
{
|
|
if (definitionIndex < 0 &&
|
|
TreeView.Transforms.TryGetObject(treeItemID, out var transform))
|
|
{
|
|
var groupCount = data.GroupCount;
|
|
|
|
data.AddTransform(transform);
|
|
|
|
if (groupCount != data.GroupCount)
|
|
CreateHeader();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (definitionIndex >= 0)
|
|
{
|
|
data.RemoveTransform(definitionIndex);
|
|
|
|
if (data.GroupCount <= 0)
|
|
CreateHeader();
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void DrawWeightGUI(
|
|
Rect area,
|
|
int treeItemID,
|
|
int groupIndex,
|
|
int transformIndex)
|
|
{
|
|
if (transformIndex < 0)
|
|
return;
|
|
|
|
var weight = Data.GetWeight(groupIndex, transformIndex);
|
|
|
|
if (float.IsNaN(weight))
|
|
return;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
weight = EditorGUI.FloatField(area, weight);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
weight = Mathf.Clamp01(weight);
|
|
|
|
SetValue(treeItemID, i => RecordUndo().SetWeight(groupIndex, i, weight));
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private static readonly GUIContent
|
|
AddGroupLabel = new(
|
|
"Add Group",
|
|
"Add another weight group"),
|
|
RemoveGroupLabel = new(
|
|
"Remove Group",
|
|
"Remove the last weight group");
|
|
|
|
/// <inheritdoc/>
|
|
protected override void DoFooterCenterGUI()
|
|
{
|
|
var hasTransforms = !Data.Transforms.IsNullOrEmpty();
|
|
GUI.enabled = hasTransforms;
|
|
|
|
if (GUILayout.Button(AddGroupLabel))
|
|
{
|
|
RecordUndo().GroupCount++;
|
|
CreateHeader();
|
|
}
|
|
|
|
if (hasTransforms)
|
|
GUI.enabled = Data.GroupCount > 1;
|
|
|
|
if (GUILayout.Button(RemoveGroupLabel))
|
|
{
|
|
RecordUndo().GroupCount--;
|
|
CreateHeader();
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override void Apply()
|
|
{
|
|
base.Apply();
|
|
CreateHeader();
|
|
SceneView.RepaintAll();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void Revert()
|
|
{
|
|
base.Revert();
|
|
CreateHeader();
|
|
SceneView.RepaintAll();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override WeightedMaskLayersDefinition RecordUndo(string name = "Animancer")
|
|
{
|
|
SceneView.RepaintAll();
|
|
return base.RecordUndo(name);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|