chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,284 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using static Animancer.Editor.AnimancerGUI;
using static Animancer.Editor.TransitionLibraries.TransitionLibrarySelection;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// A <see cref="TransitionLibraryWindowPage"/> for editing transition aliases.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryAliasesPage
[Serializable]
public class TransitionLibraryAliasesPage : TransitionLibraryWindowPage
{
/************************************************************************************************************************/
[SerializeField]
private Vector2 _ScrollPosition;
[NonSerialized]
private bool _HasSorted;
/************************************************************************************************************************/
/// <inheritdoc/>
public override string DisplayName
=> "Transition Aliases";
/// <inheritdoc/>
public override string HelpTooltip
=> "Aliases are custom names which can be used to refer to transitions instead of direct references.";
/// <inheritdoc/>
public override int Index
=> 2;
/************************************************************************************************************************/
private static readonly List<Rect>
TransitionAreas = new();
private static float ButtonWidth
=> LineHeight * 4;
/************************************************************************************************************************/
/// <inheritdoc/>
public override void OnGUI(Rect area)
{
var definition = Window.Data;
if (!_HasSorted)
{
_HasSorted = true;
definition.SortAliases();
}
var currentEvent = Event.current;
var isRepaint = currentEvent.type == EventType.Repaint;
if (isRepaint)
TransitionAreas.Clear();
area.yMin += StandardSpacing;
area.xMin += StandardSpacing;
area.xMax -= StandardSpacing;
var items = Window.Items;
var aliases = definition.Aliases;
var viewArea = new Rect(
0,
0,
area.width,
CalculateHeight(1 + items.Count + aliases.Length) + StandardSpacing);
if (viewArea.height > area.height)
viewArea.width -= GUI.skin.verticalScrollbar.fixedWidth;
_ScrollPosition = GUI.BeginScrollView(area, _ScrollPosition, viewArea);
viewArea.height = LineHeight;
DoAliasAllGUI(viewArea);
NextVerticalArea(ref viewArea);
for (int i = 0; i < items.Count; i++)
{
if (isRepaint)
TransitionAreas.Add(viewArea);
DoItemGUI(ref viewArea, i, currentEvent);
}
GUI.EndScrollView();
}
/************************************************************************************************************************/
private void DoItemGUI(
ref Rect area,
int itemIndex,
Event currentEvent)
{
var totalTransitionArea = area;
var items = Window.Items;
var item = items.GetItem(itemIndex);
if (item is TransitionAssetBase transition)
{
var hasGroup = items.GetGroup(itemIndex) != null;
if (hasGroup)
area.xMin += IndentSize;
var transitions = Window.Data.Transitions;
var transitionIndex = Array.IndexOf(transitions, transition);
DoTransitionGUI(area, transition, transitionIndex);
NextVerticalArea(ref area);
DoAliasGUI(ref area, transitionIndex);
if (hasGroup)
area.xMin -= IndentSize;
}
else if (item is TransitionGroup group)
{
var groupArea = area;
NextVerticalArea(ref area);
var foldoutArea = StealFromLeft(ref groupArea, LineHeight, StandardSpacing);
TransitionModifierTableGUI.HandleTransitionLabelInput(
ref groupArea,
Window,
group,
SelectionType.Group,
CalculateTarget);
GUI.Label(groupArea, group.Name);
EditorGUI.BeginChangeCheck();
group.IsExpanded = EditorGUI.Foldout(foldoutArea, group.IsExpanded, GUIContent.none);
if (EditorGUI.EndChangeCheck())
Window.Selection.Select(Window, group, group.Index, SelectionType.Group);
}
// Highlights.
totalTransitionArea.yMax = area.yMin - StandardSpacing;
var selected = Window.Selection.Selected == item;
var hover = totalTransitionArea.Contains(currentEvent.mousePosition);
Window.Highlighter.DrawHighlightGUI(totalTransitionArea, selected, hover);
}
/************************************************************************************************************************/
/// <summary>Draws <see cref="TransitionLibraryDefinition.AliasAllTransitions"/>.</summary>
private void DoAliasAllGUI(Rect area)
{
var definition = Window.Data;
using (var label = PooledGUIContent.Acquire(
"Alias All Transitions",
TransitionLibraryDefinition.AliasAllTransitionsTooltip))
definition.AliasAllTransitions = EditorGUI.Toggle(area, label, definition.AliasAllTransitions);
if (TryUseClickEvent(area, 0))
definition.AliasAllTransitions = !definition.AliasAllTransitions;
}
/************************************************************************************************************************/
/// <summary>Draws a `transition`.</summary>
private void DoTransitionGUI(Rect area, TransitionAssetBase transition, int index)
{
var addArea = StealFromLeft(ref area, ButtonWidth, StandardSpacing);
TransitionModifierTableGUI.HandleTransitionLabelInput(
ref area,
Window,
transition,
SelectionType.ToTransition,
CalculateTarget);
var typeArea = StealFromRight(ref area, area.width * 0.5f, StandardSpacing);
var label = transition.GetCachedName();
GUI.Label(area, label);
var wrappedTransition = transition.GetTransition();
var type = wrappedTransition != null
? wrappedTransition.GetType().GetNameCS(false)
: "Null";
GUI.Label(typeArea, type);
if (GUI.Button(addArea, "Add"))
{
var alias = new NamedIndex(null, index);
Window.RecordUndo().AddAlias(alias);
}
}
/************************************************************************************************************************/
/// <summary>Calculates the target index for a drag and drop operation.</summary>
private static ListTargetCalculation CalculateTarget(
Rect area,
int index,
Event currentEvent)
{
var y = currentEvent.mousePosition.y;
for (int i = 0; i < TransitionAreas.Count; i++)
{
area = TransitionAreas[i];
var yMax = area.yMax;
if (y > yMax)
continue;
return new(
i,
Mathf.InverseLerp(area.y, yMax, y));
}
return new(TransitionAreas.Count, 1);
}
/************************************************************************************************************************/
/// <summary>Draws all aliases for the specified `transitionIndex`.</summary>
private void DoAliasGUI(ref Rect area, int transitionIndex)
{
var aliases = Window.Data.Aliases;
for (int i = 0; i < aliases.Length; i++)
{
var alias = aliases[i];
if (alias.Index != transitionIndex)
continue;
DoAliasGUI(area, alias, i);
NextVerticalArea(ref area);
}
}
/// <summary>Draws an `alias`.</summary>
private void DoAliasGUI(Rect area, NamedIndex alias, int aliasIndex)
{
var removeArea = StealFromLeft(ref area, ButtonWidth, StandardSpacing);
EditorGUI.BeginChangeCheck();
var name = StringAssetDrawer.DrawGUI(area, GUIContent.none, alias.Name, Window.SourceObject, out _);
if (EditorGUI.EndChangeCheck())
{
Window.RecordUndo().Aliases[aliasIndex] = alias.With(name as StringAsset);
}
if (GUI.Button(removeArea, "Remove"))
{
Window.RecordUndo().RemoveAlias(aliasIndex);
}
}
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0d5be687cb9b8da4e9c61bfb49ab861d
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,54 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// A <see cref="TransitionLibraryWindowPage"/> for editing
/// <see cref="TransitionModifierDefinition.FadeDuration"/>.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryFadeDurationsPage
[Serializable]
public class TransitionLibraryFadeDurationsPage : TransitionLibraryModifiersPage
{
/************************************************************************************************************************/
/// <inheritdoc/>
public override string DisplayName
=> "Fade Duration Modifiers";
/// <inheritdoc/>
public override string HelpTooltip
=> "Modifiers allow you to replace the usual fade duration for specific combinations of transitions.";
/// <inheritdoc/>
public override int Index
=> 0;
/// <inheritdoc/>
public TransitionLibraryFadeDurationsPage()
: base(Units.AnimationTimeAttribute.Units.Seconds)
{ }
/// <inheritdoc/>
public override float GetValue(ITransition transition)
=> transition.FadeDuration;
/// <inheritdoc/>
public override float GetValue(TransitionModifierDefinition modifier)
=> modifier.FadeDuration;
/// <inheritdoc/>
public override void SetValue(ref TransitionModifierDefinition modifier, float value)
=> modifier = modifier.WithFadeDuration(value);
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: db8c8079cb5b99142af9cbcc29f6c9ef
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using Animancer.Units;
using Animancer.Units.Editor;
using System;
using UnityEngine;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// A <see cref="TransitionLibraryWindowPage"/> for editing transition modifiers.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryModifiersPage
[Serializable]
public abstract class TransitionLibraryModifiersPage : TransitionLibraryWindowPage
{
/************************************************************************************************************************/
[SerializeField]
private TransitionModifierTableGUI _TableGUI;
/************************************************************************************************************************/
/// <summary>The drawer used for time fields on this page.</summary>
public readonly AnimationTimeAttributeDrawer
TimeDrawer = new();
/// <summary>Creates a new <see cref="TransitionLibraryModifiersPage"/>.</summary>
public TransitionLibraryModifiersPage(AnimationTimeAttribute.Units units)
{
TimeDrawer.Initialize(new AnimationTimeAttribute(units));
TimeDrawer.Attribute.Rule = Validate.Value.IsFiniteOrNaN;
TimeDrawer.Attribute.IsOptional = true;
}
/// <summary>Configures this page to display a single field or not.</summary>
public virtual void ConfigureForSingleField(bool singleField, ref float value) { }
/************************************************************************************************************************/
/// <summary>Gets the value controlled by this page.</summary>
public abstract float GetValue(ITransition transition);
/// <summary>Gets the value controlled by this page.</summary>
public abstract float GetValue(TransitionModifierDefinition modifier);
/// <summary>Sets the value controlled by this page.</summary>
public abstract void SetValue(ref TransitionModifierDefinition modifier, float value);
/************************************************************************************************************************/
/// <inheritdoc/>
public override void OnGUI(Rect area)
{
_TableGUI ??= new();
_TableGUI.Page = this;
if (Window.Data.Transitions.Length == 0)
{
area = new Rect(
area.x + AnimancerGUI.StandardSpacing,
area.y + AnimancerGUI.StandardSpacing,
area.width - AnimancerGUI.StandardSpacing * 2,
AnimancerGUI.LineHeight);
GUI.Label(
area,
"Library contains no Transitions." +
" Drag and Drop Transition Assets into this window or use the Create Transition button.");
AnimancerGUI.NextVerticalArea(ref area);
if (GUI.Button(area, "Create Transition"))
TransitionLibraryOperations.CreateTransition(Window);
}
else
{
_TableGUI.DoGUI(area, Window);
}
TransitionLibraryOperations.HandleBackgroundInput(area, Window);
}
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: de81cf7262eb1514894f722e6050eead
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// A <see cref="TransitionLibraryWindowPage"/> for editing
/// <see cref="TransitionModifierDefinition.FadeDuration"/>.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryStartTimesPage
[Serializable]
public class TransitionLibraryStartTimesPage : TransitionLibraryModifiersPage
{
/************************************************************************************************************************/
/// <inheritdoc/>
public override string DisplayName
=> "Start Time Modifiers";
/// <inheritdoc/>
public override string HelpTooltip
=> "Modifiers allow you to replace the usual start time for specific combinations of transitions.";
/// <inheritdoc/>
public override int Index
=> 1;
private readonly string[] ConvertedZeroes;
/// <inheritdoc/>
public TransitionLibraryStartTimesPage()
: base(Units.AnimationTimeAttribute.Units.Normalized)
{
TimeDrawer.Attribute.DisabledText = Strings.Tooltips.StartTimeDisabled;
var converters = TimeDrawer.DisplayConverters;
ConvertedZeroes = new string[converters.Length];
for (int i = 0; i < converters.Length; i++)
ConvertedZeroes[i] = converters[i].ConvertedZero;
}
/// <inheritdoc/>
public override void ConfigureForSingleField(bool singleField, ref float value)
{
var isSingleFieldNaN = singleField && float.IsNaN(value);
if (isSingleFieldNaN)
value = 0;
var converters = TimeDrawer.DisplayConverters;
for (int i = 0; i < converters.Length; i++)
{
var converter = converters[i];
converter.ConvertedZero = isSingleFieldNaN
? Strings.Tooltips.StartTimeDisabled
: ConvertedZeroes[i];
}
}
/// <inheritdoc/>
public override float GetValue(ITransition transition)
=> transition.NormalizedStartTime;
/// <inheritdoc/>
public override float GetValue(TransitionModifierDefinition modifier)
=> modifier.NormalizedStartTime;
/// <inheritdoc/>
public override void SetValue(ref TransitionModifierDefinition modifier, float value)
=> modifier = modifier.WithNormalizedStartTime(value);
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 80fa90c6d42e9064ca6c83b652444790
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using System;
using UnityEngine;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// Manages the selection of pages in the <see cref="TransitionLibraryWindow"/>.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryWindowPage
[Serializable]
public abstract class TransitionLibraryWindowPage : IComparable<TransitionLibraryWindowPage>
{
/************************************************************************************************************************/
/// <summary>The window containing this page.</summary>
public TransitionLibraryWindow Window { get; set; }
/************************************************************************************************************************/
/// <summary>The name of this page.</summary>
public abstract string DisplayName { get; }
/// <summary>The text to use for the tooltip on the help button while this page is visible.</summary>
public abstract string HelpTooltip { get; }
/************************************************************************************************************************/
/// <summary>The sorting index of this page.</summary>
public abstract int Index { get; }
/// <summary>Compares the <see cref="Index"/>.</summary>
public int CompareTo(TransitionLibraryWindowPage other)
=> Index.CompareTo(other.Index);
/************************************************************************************************************************/
/// <summary>Draws the GUI of this page.</summary>
public abstract void OnGUI(Rect area);
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 61210733873388e4e815c6628988b306
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,598 @@
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.Units;
using Animancer.Units.Editor;
using System;
using UnityEditor;
using UnityEngine;
using static Animancer.Editor.AnimancerGUI;
using static Animancer.Editor.TransitionDrawer;
using static Animancer.Editor.TransitionLibraries.TransitionLibrarySelection;
using Object = UnityEngine.Object;
namespace Animancer.Editor.TransitionLibraries
{
/// <summary>[Editor-Only]
/// A <see cref="TableGUI"/> for editing
/// <see cref="Animancer.TransitionLibraries.TransitionLibraryDefinition.Modifiers"/>.
/// </summary>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionModifierTableGUI
[Serializable]
public class TransitionModifierTableGUI : TableGUI
{
/************************************************************************************************************************/
[NonSerialized] private TransitionLibraryWindow _Window;
[NonSerialized] private Vector2Int _SelectedCell;
/// <summary>The page displaying this table.</summary>
[NonSerialized] public TransitionLibraryModifiersPage Page;
/************************************************************************************************************************/
/// <summary>Creates a new <see cref="TransitionModifierTableGUI"/>.</summary>
public TransitionModifierTableGUI()
{
base.DoCellGUI = DoCellGUI;
CalculateWidestLabel = CalculateWidestTransitionLabel;
MinCellSize = new(LineHeight * 2, LineHeight);
MaxCellSize = new(LineHeight * 4, LineHeight);
}
/************************************************************************************************************************/
/// <summary>Draws the table GUI.</summary>
public void DoGUI(
Rect area,
TransitionLibraryWindow window)
{
_Window = window;
_SelectedCell = RecalculateSelectedCell(window.Selection);
DoTableGUI(area, window.Items.Count, window.Items.Count);
}
/************************************************************************************************************************/
/// <summary>Calculates the table coordinates of the `selection`.</summary>
private Vector2Int RecalculateSelectedCell(TransitionLibrarySelection selection)
{
if (selection.Validate())
{
switch (selection.Type)
{
case SelectionType.FromTransition:
case SelectionType.ToTransition:
case SelectionType.Modifier:
var transitions = _Window.Data.Transitions;
transitions.TryGet(selection.FromIndex, out var fromTransition);
transitions.TryGet(selection.ToIndex, out var toTransition);
var cell = new Vector2Int(
_Window.Items.IndexOf(toTransition),
_Window.Items.IndexOf(fromTransition));
if (cell.x < 0)
cell.x = int.MinValue;
if (cell.y < 0)
cell.y = int.MinValue;
return cell;
case SelectionType.Group:
var index = _Window.Items.IndexOf(selection.Selected);
return index >= 0
? new(index, index)
: new(int.MinValue, int.MinValue);
}
}
return new(int.MinValue, int.MinValue);
}
/************************************************************************************************************************/
/// <summary>Draws a table cell.</summary>
private new void DoCellGUI(Rect area, int column, int row)
{
var invertHover = false;
if (column < 0)
{
if (row < 0)
DoCornerGUI(area);
else
DoLabelGUI(
area,
row,
RightLabelStyle,
SelectionType.FromTransition);
}
else if (row < 0)
{
DoLabelGUI(
area,
column,
EditorStyles.label,
SelectionType.ToTransition);
invertHover = true;
}
else
{
DoCellBodyGUI(area, _Window, row, column);
}
DrawHighlightGUI(area, column, row, invertHover);
}
/************************************************************************************************************************/
/// <summary>Draws the header corner.</summary>
private void DoCornerGUI(Rect area)
{
area.xMin += StandardSpacing;
var fromArea = area;
fromArea.y += area.height - LineHeight;
fromArea.height = LineHeight;
var toArea = fromArea;
toArea.y -= toArea.height - Padding;
var deleteTransitionArea = toArea;
deleteTransitionArea.y -= deleteTransitionArea.height - Padding;
var createTransitionArea = deleteTransitionArea;
createTransitionArea.y -= createTransitionArea.height - Padding;
var createGroupArea = createTransitionArea;
createGroupArea.y -= createGroupArea.height - Padding;
fromArea.width -= VerticalScrollBar.fixedWidth + Padding;
var style = RightLabelStyle;
var fontStyle = style.fontStyle;
style.fontStyle = FontStyle.Bold;
GUI.Label(fromArea, "From", style);
GUI.Label(toArea, "To", style);
style.fontStyle = fontStyle;
DoCreateGroupButtonGUI(createGroupArea);
DoCreateTransitionButtonGUI(createTransitionArea);
DoRemoveButtonGUI(deleteTransitionArea);
}
/************************************************************************************************************************/
/// <summary>Draws a button to create a new group.</summary>
private void DoCreateGroupButtonGUI(Rect area)
{
if (GUI.Button(area, "Create Group"))
TransitionLibraryOperations.CreateGroup(_Window, _Window.EditorData);
}
/************************************************************************************************************************/
/// <summary>Draws a button to create a new transition.</summary>
private void DoCreateTransitionButtonGUI(Rect area)
{
if (GUI.Button(area, "Create Transition"))
TransitionLibraryOperations.CreateTransition(_Window);
}
/************************************************************************************************************************/
/// <summary>Draws a button to remove the selected object.</summary>
private void DoRemoveButtonGUI(Rect area)
{
var enabled = GUI.enabled;
var selection = _Window.Selection;
string label = "Remove Selection";
switch (selection.Type)
{
case SelectionType.FromTransition:
GUI.enabled = selection.FromIndex >= 0 && selection.FromIndex < _Window.Data.Transitions.Length;
label = "Remove Transition";
break;
case SelectionType.ToTransition:
GUI.enabled = selection.ToIndex >= 0 && selection.ToIndex < _Window.Data.Transitions.Length;
label = "Remove Transition";
break;
case SelectionType.Modifier:
label = "Remove Modifier";
break;
case SelectionType.Group:
label = "Remove Group";
break;
default:
GUI.enabled = false;
break;
}
using var content = PooledGUIContent.Acquire(label,
"Remove the selected object from this library. [Delete]");
if (GUI.Button(area, content))
{
TransitionLibraryOperations.HandleDelete(_Window);
Deselect();
}
GUI.enabled = enabled;
}
/************************************************************************************************************************/
/// <summary>Draws a row or column label.</summary>
private void DoLabelGUI(
Rect area,
int index,
GUIStyle style,
SelectionType selectionType)
{
if (!_Window.Items.TryGet(index, out var transitionOrGroup))
return;
if (transitionOrGroup is TransitionAssetBase transition)
{
var group = _Window.Items.GetGroup(index);
if (group != null)
StealGroupFoldoutSpace(ref area, style);
HandleTransitionLabelInput(
ref area,
_Window,
transition,
selectionType,
CalculateTarget);
GUI.Label(area, GetTransitionName(transition), style);
}
else if (transitionOrGroup is TransitionGroup group)
{
var foldoutArea = StealGroupFoldoutSpace(ref area, style);
HandleTransitionLabelInput(
ref area,
_Window,
group,
SelectionType.Group,
CalculateTarget);
GUI.Label(area, group.Name, style);
EditorGUI.BeginChangeCheck();
group.IsExpanded = EditorGUI.Foldout(foldoutArea, group.IsExpanded, GUIContent.none);
if (EditorGUI.EndChangeCheck())
_Window.Selection.Select(_Window, group, index, SelectionType.Group);
}
}
/************************************************************************************************************************/
/// <summary>Calculates the area for a group foldout and subtracts it from the appropriate side of the `area`.</summary>
private Rect StealGroupFoldoutSpace(ref Rect area, GUIStyle style)
{
if (style.alignment == TextAnchor.MiddleRight)
{
return StealFromRight(ref area, LineHeight, StandardSpacing);
}
else
{
var space = StealFromLeft(ref area, LineHeight, StandardSpacing);
space.x += StandardSpacing;
return space;
}
}
/************************************************************************************************************************/
/// <summary>Returns the name of the `transition` with a special message for <c>null</c>.</summary>
public static string GetTransitionName(TransitionAssetBase transition)
=> transition != null
? transition.GetCachedName()
: "<Missing Transition>";
/************************************************************************************************************************/
private static readonly int LabelHint = "Label".GetHashCode();
[NonSerialized] private static bool _IsLabelDrag;
/// <summary>Handles input events on transition labels.</summary>
public static void HandleTransitionLabelInput(
ref Rect area,
TransitionLibraryWindow window,
object item,
SelectionType selectionType,
Func<Rect, int, Event, ListTargetCalculation> calculateTarget)
{
var control = new GUIControl(area, LabelHint);
switch (control.EventType)
{
case EventType.MouseDown:
if (control.Event.button == 0 &&
control.TryUseMouseDown())
{
if (control.Event.clickCount == 2)
{
if (item is Object unityObject)
EditorGUIUtility.PingObject(unityObject);
}
else
{
var index = IndexOf(window, item as TransitionAssetBase);
window.Selection.Select(window, item, index, selectionType);
}
_IsLabelDrag = false;
}
break;
case EventType.MouseUp:
if (control.TryUseMouseUp() && _IsLabelDrag)
{
var index = window.Items.IndexOf(item);
var target = calculateTarget(area, index, control.Event);
window.OnDropItem(item, target, selectionType);
}
break;
case EventType.MouseDrag:
if (control.TryUseHotControl())
_IsLabelDrag = true;
break;
}
if (GUIUtility.hotControl == control.ID && _IsLabelDrag)
{
RepaintEverything();
area.y = control.Event.mousePosition.y - area.height * 0.5f;
}
}
/************************************************************************************************************************/
private static int IndexOf(TransitionLibraryWindow window, TransitionAssetBase transition)
=> Array.IndexOf(window.Data.Transitions, transition);
/************************************************************************************************************************/
/// <summary>Calculates the target index for a drag and drop operation.</summary>
private static ListTargetCalculation CalculateTarget(
Rect area,
int index,
Event currentEvent)
{
var target = new ListTargetCalculation(area.y, area.height, currentEvent.mousePosition.y);
target.Index += index;
return target;
}
/************************************************************************************************************************/
private static readonly int GroupHint = "Group".GetHashCode();
/// <summary>
/// Calls <see cref="DoModifierValueGUI"/> if the specified cell
/// contains a transition combination rather than a group.
/// </summary>
public void DoCellBodyGUI(
Rect area,
TransitionLibraryWindow window,
int from,
int to)
{
if (!_Window.Items.TryGet(from, out var fromTransitionOrGroup) ||
!_Window.Items.TryGet(to, out var toTransitionOrGroup))
return;
if (fromTransitionOrGroup is TransitionAssetBase fromTransition &&
toTransitionOrGroup is TransitionAssetBase toTransition)
{
from = IndexOf(window, fromTransition);
to = IndexOf(window, toTransition);
DoModifierValueGUI(area, _Window, Page, from, to, "", true);
}
else
{
var control = new GUIControl(area, GroupHint);
if (control.EventType == EventType.MouseDown &&
control.TryUseMouseDown())
{
var group = fromTransitionOrGroup is TransitionGroup
? fromTransitionOrGroup
: toTransitionOrGroup;
window.Selection.Select(
window,
group,
from,
SelectionType.Group);
}
}
}
/************************************************************************************************************************/
/// <summary>Draws the fade duration for a particular transition combination.</summary>
public static void DoModifierValueGUI(
Rect area,
TransitionLibraryWindow window,
TransitionLibraryModifiersPage page,
int from,
int to,
string label,
bool singleField)
{
var previousHotControl = GUIUtility.hotControl;
var hasModifier = window.Data.TryGetModifier(from, to, out var modifier);
var hasModifierWithValue = hasModifier;
var value = page.GetValue(modifier);
window.Data.Transitions.TryGet(to, out var transition);
if (float.IsNaN(value))
{
hasModifierWithValue = false;
if (transition != null)
value = page.GetValue(transition);
}
var labelStyle = EditorStyles.label.fontStyle;
var numberAlignment = EditorStyles.numberField.alignment;
var numberStyle = EditorStyles.numberField.fontStyle;
var numberSize = EditorStyles.numberField.fontSize;
try
{
EditorStyles.numberField.alignment = TextAnchor.MiddleLeft;
if (hasModifierWithValue)
{
EditorStyles.label.fontStyle = FontStyle.Bold;
EditorStyles.numberField.fontStyle = FontStyle.Bold;
}
else
{
EditorStyles.numberField.fontSize = EditorStyles.numberField.fontSize * 4 / 5;
}
EditorGUI.BeginChangeCheck();
page.ConfigureForSingleField(singleField, ref value);
if (singleField)
transition = null;
using (new DrawerContext(transition))
using (var content = PooledGUIContent.Acquire(label))
page.TimeDrawer.OnGUI(area, content, ref value);
if (TryUseClickEvent(area, 2))
value = float.NaN;
if (EditorGUI.EndChangeCheck())
{
if (EditorGUIUtility.editingTextField &&
!float.TryParse(CurrentFieldText, out value))
value = float.NaN;
if (!hasModifier)
modifier = modifier.WithDetails(float.NaN, float.NaN);
var data = window.RecordUndo();
page.SetValue(ref modifier, value);
data.SetModifier(modifier);
hasModifier = true;
RepaintEverything();
}
}
finally
{
EditorStyles.label.fontStyle = labelStyle;
EditorStyles.numberField.alignment = numberAlignment;
EditorStyles.numberField.fontStyle = numberStyle;
EditorStyles.numberField.fontSize = numberSize;
}
if (previousHotControl != GUIUtility.hotControl)
{
window.Selection.Select(
window,
modifier,
modifier.FromIndex,
SelectionType.Modifier);
}
}
/************************************************************************************************************************/
/// <summary>Draws the selection and hover highlights for a particular cell.</summary>
private void DrawHighlightGUI(Rect area, int column, int row, bool invertHover)
{
if (_Window.Highlighter.EventType != EventType.Repaint)
return;
var selected =
_SelectedCell.x == column ||
_SelectedCell.y == row;
var hover = false;
if (_Window.Highlighter.IsMouseOver)
{
if (invertHover)
(row, column) = (column, row);
var mousePosition = Event.current.mousePosition;
if ((column >= 0 && IsInlineWithX(area, mousePosition.x)) ||
(row >= 0 && IsInlineWithY(area, mousePosition.y)))
{
hover = true;
}
}
_Window.Highlighter.DrawHighlightGUI(area, selected, hover);
}
/************************************************************************************************************************/
/// <summary>Is `x` inside the `area`.</summary>
private static bool IsInlineWithX(Rect area, float x)
=> area.xMin <= x
&& area.xMax > x;
/// <summary>Is `y` inside the `area`.</summary>
private static bool IsInlineWithY(Rect area, float y)
=> area.yMin <= y
&& area.yMax > y;
/************************************************************************************************************************/
/// <summary>Calculates the largest width of all transition labels.</summary>
private float CalculateWidestTransitionLabel()
{
var widest = LineHeight * 2;
var transitions = _Window.Data.Transitions;
for (int i = 0; i < transitions.Length; i++)
{
var transition = transitions[i];
if (transition == null)
continue;
var label = transition.GetCachedName();
var width = CalculateLabelWidth(label);
if (widest < width)
widest = width;
}
return widest;
}
/************************************************************************************************************************/
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 78f4b212f3ad9cd4285498110975c389
timeCreated: 1516751545
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: