first commit
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEngine.Splines;
|
||||
#if !UNITY_2022_1_OR_NEWER
|
||||
using UnityEditor.UIElements;
|
||||
#endif
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
sealed class BezierKnotDrawer : ElementDrawer<SelectableKnot>
|
||||
{
|
||||
static readonly string k_PositionTooltip = L10n.Tr("Knot Position");
|
||||
static readonly string k_RotationTooltip = L10n.Tr("Knot Rotation");
|
||||
|
||||
readonly Float3PropertyField<SelectableKnot> m_Position;
|
||||
readonly Float3PropertyField<SelectableKnot> m_Rotation;
|
||||
readonly TangentModePropertyField<SelectableKnot> m_Mode;
|
||||
readonly BezierTangentPropertyField<SelectableKnot> m_BezierMode;
|
||||
readonly TangentPropertyField m_TangentIn;
|
||||
readonly TangentPropertyField m_TangentOut;
|
||||
|
||||
public BezierKnotDrawer()
|
||||
{
|
||||
VisualElement row;
|
||||
Add(row = new VisualElement(){name = "Vector3WithIcon"});
|
||||
row.tooltip = k_PositionTooltip;
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.Add(new VisualElement(){name = "PositionIcon"});
|
||||
row.Add(m_Position = new Float3PropertyField<SelectableKnot>("",
|
||||
(knot) => knot.LocalPosition,
|
||||
(knot, value) => knot.LocalPosition = value)
|
||||
{ name = "Position" });
|
||||
|
||||
m_Position.style.flexGrow = 1;
|
||||
|
||||
Add(row = new VisualElement(){name = "Vector3WithIcon"});
|
||||
row.tooltip = k_RotationTooltip;
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.Add(new VisualElement(){name = "RotationIcon"});
|
||||
row.Add(m_Rotation = new Float3PropertyField<SelectableKnot>("",
|
||||
(knot) => ((Quaternion)knot.LocalRotation).eulerAngles,
|
||||
(knot, value) => knot.LocalRotation = Quaternion.Euler(value))
|
||||
{ name = "Rotation" });
|
||||
|
||||
m_Rotation.style.flexGrow = 1;
|
||||
|
||||
Add(new Separator());
|
||||
|
||||
Add(m_Mode = new TangentModePropertyField<SelectableKnot>());
|
||||
m_Mode.changed += Update;
|
||||
|
||||
Add(m_BezierMode = new BezierTangentPropertyField<SelectableKnot>());
|
||||
m_BezierMode.changed += Update;
|
||||
|
||||
Add(m_TangentIn = new TangentPropertyField("In", "TangentIn", BezierTangent.In));
|
||||
Add(m_TangentOut = new TangentPropertyField("Out", "TangentOut", BezierTangent.Out));
|
||||
|
||||
//Update opposite to take into account some tangent modes
|
||||
m_TangentIn.changed += () => m_TangentOut.Update(targets);
|
||||
m_TangentOut.changed += () => m_TangentIn.Update(targets);
|
||||
}
|
||||
|
||||
public override string GetLabelForTargets()
|
||||
{
|
||||
if (targets.Count > 1)
|
||||
return $"<b>({targets.Count}) Knots</b> selected";
|
||||
|
||||
return $"<b>Knot {target.KnotIndex}</b> (<b>Spline {target.SplineInfo.Index}</b>) selected";
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
m_Position.Update(targets);
|
||||
m_Rotation.Update(targets);
|
||||
|
||||
m_Mode.Update(targets);
|
||||
m_BezierMode.Update(targets);
|
||||
|
||||
m_TangentIn.Update(targets);
|
||||
m_TangentOut.Update(targets);
|
||||
|
||||
//Disabling edition when using linear tangents
|
||||
UpdateTangentsState();
|
||||
}
|
||||
|
||||
void UpdateTangentsState()
|
||||
{
|
||||
bool tangentsModifiable = true;
|
||||
bool tangentsBroken = true;
|
||||
bool tangentInSelectable = false;
|
||||
bool tangentOutSelectable = false;
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
var mode = targets[i].Mode;
|
||||
tangentsModifiable &= SplineUtility.AreTangentsModifiable(mode);
|
||||
tangentsBroken &= mode == TangentMode.Broken;
|
||||
tangentInSelectable |= SplineSelectionUtility.IsSelectable(targets[i].TangentIn);
|
||||
tangentOutSelectable |= SplineSelectionUtility.IsSelectable(targets[i].TangentOut);
|
||||
}
|
||||
|
||||
m_TangentIn.SetEnabled(tangentsModifiable && tangentInSelectable);
|
||||
m_TangentOut.SetEnabled(tangentsModifiable && tangentOutSelectable);
|
||||
|
||||
if(tangentsModifiable)
|
||||
{
|
||||
m_TangentIn.vector3field.SetEnabled(tangentsBroken);
|
||||
m_TangentOut.vector3field.SetEnabled(tangentsBroken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1dec5e4d3c4dd84aab4dfbb3c8e6b48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using UnityEditor.Toolbars;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Splines;
|
||||
#if !UNITY_2022_1_OR_NEWER
|
||||
#endif
|
||||
|
||||
namespace UnityEditor.Splines.Editor.GUI
|
||||
{
|
||||
[EditorToolbarElement("Spline Tool Settings/Default Knot Type")]
|
||||
class DefaultKnotTypeDropdown : EditorToolbarDropdown
|
||||
{
|
||||
const string k_LinearIconPath = "Packages/com.unity.splines/Editor/Resources/Icons/Tangent_Linear.png";
|
||||
const string k_AutoSmoothIconPath = "Packages/com.unity.splines/Editor/Resources/Icons/AutoSmoothKnot.png";
|
||||
readonly GUIContent[] m_OptionContents = new GUIContent[2];
|
||||
|
||||
public DefaultKnotTypeDropdown()
|
||||
{
|
||||
name = "Default Knot Type";
|
||||
|
||||
var content = EditorGUIUtility.TrTextContent("Linear",
|
||||
"Tangents are not used. A linear knot tries to connect to another by a path with no curvature.",
|
||||
k_LinearIconPath);
|
||||
m_OptionContents[0] = content;
|
||||
|
||||
content = EditorGUIUtility.TrTextContent("Auto Smooth",
|
||||
"Tangents are calculated using the previous and next knot positions.",
|
||||
k_AutoSmoothIconPath);
|
||||
m_OptionContents[1] = content;
|
||||
|
||||
clicked += OpenContextMenu;
|
||||
|
||||
RefreshElementContent();
|
||||
}
|
||||
|
||||
void OpenContextMenu()
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(m_OptionContents[0], EditorSplineUtility.DefaultTangentMode == TangentMode.Linear,
|
||||
() => SetTangentModeIfNeeded(TangentMode.Linear));
|
||||
|
||||
menu.AddItem(m_OptionContents[1], EditorSplineUtility.DefaultTangentMode == TangentMode.AutoSmooth,
|
||||
() => SetTangentModeIfNeeded(TangentMode.AutoSmooth));
|
||||
|
||||
menu.DropDown(worldBound);
|
||||
}
|
||||
|
||||
void SetTangentModeIfNeeded(TangentMode tangentMode)
|
||||
{
|
||||
if (EditorSplineUtility.DefaultTangentMode != tangentMode)
|
||||
{
|
||||
EditorSplineUtility.s_DefaultTangentMode.SetValue(tangentMode, true);
|
||||
RefreshElementContent();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshElementContent()
|
||||
{
|
||||
var content = m_OptionContents[EditorSplineUtility.DefaultTangentMode == TangentMode.Linear ? 0 : 1];
|
||||
text = content.text;
|
||||
tooltip = content.tooltip;
|
||||
icon = content.image as Texture2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: facf982a205a4c93830bb62332a75ceb
|
||||
timeCreated: 1649792821
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.UIElements;
|
||||
#if !UNITY_2022_1_OR_NEWER
|
||||
using UnityEditor.UIElements;
|
||||
#endif
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
class Float3PropertyField<T> : Vector3Field
|
||||
where T : ISelectableElement
|
||||
{
|
||||
static readonly List<float3> s_Float3Buffer = new List<float3>();
|
||||
static readonly SplineGUIUtility.EqualityComparer<float3> s_ComparerX = (a, b) => a.x.Equals(b.x);
|
||||
static readonly SplineGUIUtility.EqualityComparer<float3> s_ComparerY = (a, b) => a.y.Equals(b.y);
|
||||
static readonly SplineGUIUtility.EqualityComparer<float3> s_ComparerZ = (a, b) => a.z.Equals(b.z);
|
||||
|
||||
readonly FloatField m_X;
|
||||
readonly FloatField m_Y;
|
||||
readonly FloatField m_Z;
|
||||
|
||||
readonly Func<T, float3> m_Get;
|
||||
readonly Action<T, float3> m_Set;
|
||||
|
||||
IReadOnlyList<T> m_Elements = new List<T>(0);
|
||||
|
||||
public event Action changed;
|
||||
|
||||
public Float3PropertyField(string label, Func<T, float3> get, Action<T, float3> set) : base(label)
|
||||
{
|
||||
m_Get = get;
|
||||
m_Set = set;
|
||||
|
||||
m_X = this.Q<FloatField>("unity-x-input");
|
||||
m_Y = this.Q<FloatField>("unity-y-input");
|
||||
m_Z = this.Q<FloatField>("unity-z-input");
|
||||
|
||||
m_X.RegisterValueChangedCallback(ApplyX);
|
||||
m_Y.RegisterValueChangedCallback(ApplyY);
|
||||
m_Z.RegisterValueChangedCallback(ApplyZ);
|
||||
}
|
||||
|
||||
public void Update(IReadOnlyList<T> elements)
|
||||
{
|
||||
m_Elements = elements;
|
||||
|
||||
s_Float3Buffer.Clear();
|
||||
for (int i = 0; i < elements.Count; ++i)
|
||||
s_Float3Buffer.Add(m_Get.Invoke(elements[i]));
|
||||
|
||||
var value = s_Float3Buffer.Count > 0 ? s_Float3Buffer[0] : 0;
|
||||
m_X.showMixedValue = SplineGUIUtility.HasMultipleValues(s_Float3Buffer, s_ComparerX);
|
||||
if (!m_X.showMixedValue)
|
||||
m_X.SetValueWithoutNotify(value[0]);
|
||||
|
||||
m_Y.showMixedValue = SplineGUIUtility.HasMultipleValues(s_Float3Buffer, s_ComparerY);
|
||||
if (!m_Y.showMixedValue)
|
||||
m_Y.SetValueWithoutNotify(value[1]);
|
||||
|
||||
m_Z.showMixedValue = SplineGUIUtility.HasMultipleValues(s_Float3Buffer, s_ComparerZ);
|
||||
if (!m_Z.showMixedValue)
|
||||
m_Z.SetValueWithoutNotify(value[2]);
|
||||
}
|
||||
|
||||
void ApplyX(ChangeEvent<float> evt)
|
||||
{
|
||||
EditorSplineUtility.RecordObjects(m_Elements, SplineInspectorOverlay.SplineChangeUndoMessage);
|
||||
|
||||
ElementInspector.ignoreKnotCallbacks = true;
|
||||
for (int i = 0; i < m_Elements.Count; ++i)
|
||||
{
|
||||
var value = m_Get.Invoke(m_Elements[i]);
|
||||
value.x = evt.newValue;
|
||||
m_Set.Invoke(m_Elements[i], value);
|
||||
}
|
||||
|
||||
m_X.showMixedValue = false;
|
||||
m_X.SetValueWithoutNotify(evt.newValue);
|
||||
changed?.Invoke();
|
||||
ElementInspector.ignoreKnotCallbacks = false;
|
||||
}
|
||||
|
||||
void ApplyY(ChangeEvent<float> evt)
|
||||
{
|
||||
EditorSplineUtility.RecordObjects(m_Elements, SplineInspectorOverlay.SplineChangeUndoMessage);
|
||||
|
||||
ElementInspector.ignoreKnotCallbacks = true;
|
||||
for (int i = 0; i < m_Elements.Count; ++i)
|
||||
{
|
||||
var value = m_Get.Invoke(m_Elements[i]);
|
||||
value.y = evt.newValue;
|
||||
m_Set.Invoke(m_Elements[i], value);
|
||||
}
|
||||
m_Y.showMixedValue = false;
|
||||
m_Y.SetValueWithoutNotify(evt.newValue);
|
||||
changed?.Invoke();
|
||||
ElementInspector.ignoreKnotCallbacks = false;
|
||||
}
|
||||
|
||||
void ApplyZ(ChangeEvent<float> evt)
|
||||
{
|
||||
EditorSplineUtility.RecordObjects(m_Elements, SplineInspectorOverlay.SplineChangeUndoMessage);
|
||||
|
||||
ElementInspector.ignoreKnotCallbacks = true;
|
||||
for (int i = 0; i < m_Elements.Count; ++i)
|
||||
{
|
||||
var value = m_Get.Invoke(m_Elements[i]);
|
||||
value.z = evt.newValue;
|
||||
m_Set.Invoke(m_Elements[i], value);
|
||||
}
|
||||
m_Z.showMixedValue = false;
|
||||
m_Z.SetValueWithoutNotify(evt.newValue);
|
||||
changed?.Invoke();
|
||||
ElementInspector.ignoreKnotCallbacks = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae3c8f89802f5a242813000e2c3b55a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.Toolbars;
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
[EditorToolbarElement("Spline Tool Settings/Handle Rotation")]
|
||||
class HandleRotationDropdown : EditorToolbarDropdown
|
||||
{
|
||||
const string k_ParentRotationIconPath = "Packages/com.unity.splines/Editor/Resources/Icons/ToolHandleParent.png";
|
||||
const string k_ElementRotationIconPath = "Packages/com.unity.splines/Editor/Resources/Icons/ToolHandleElement.png";
|
||||
|
||||
readonly List<GUIContent> m_OptionContents = new List<GUIContent>();
|
||||
|
||||
public HandleRotationDropdown()
|
||||
{
|
||||
name = "Handle Rotation";
|
||||
|
||||
var content = EditorGUIUtility.TrTextContent("Local",
|
||||
"Toggle Tool Handle Rotation\n\nTool handles are in the active object's rotation.",
|
||||
"ToolHandleLocal");
|
||||
m_OptionContents.Add(content);
|
||||
|
||||
content = EditorGUIUtility.TrTextContent("Global",
|
||||
"Toggle Tool Handle Rotation\n\nTool handles are in global rotation.",
|
||||
"ToolHandleGlobal");
|
||||
m_OptionContents.Add(content);
|
||||
|
||||
content = EditorGUIUtility.TrTextContent("Parent",
|
||||
"Toggle Tool Handle Rotation\n\nTool handles are in active element's parent's rotation.",
|
||||
k_ParentRotationIconPath);
|
||||
m_OptionContents.Add(content);
|
||||
|
||||
content = EditorGUIUtility.TrTextContent("Element",
|
||||
"Toggle Tool Handle Rotation\n\nTool handles are in active element's rotation.",
|
||||
k_ElementRotationIconPath);
|
||||
m_OptionContents.Add(content);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(AttachedToPanel);
|
||||
RegisterCallback<DetachFromPanelEvent>(DetachedFromPanel);
|
||||
|
||||
clicked += OpenContextMenu;
|
||||
|
||||
RefreshElementContent();
|
||||
}
|
||||
|
||||
void OpenContextMenu()
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(m_OptionContents[(int)HandleOrientation.Global], SplineTool.handleOrientation == HandleOrientation.Global,
|
||||
() => SetHandleOrientationIfNeeded(HandleOrientation.Global));
|
||||
|
||||
menu.AddItem(m_OptionContents[(int)HandleOrientation.Local], SplineTool.handleOrientation == HandleOrientation.Local,
|
||||
() => SetHandleOrientationIfNeeded(HandleOrientation.Local));
|
||||
|
||||
menu.AddItem(m_OptionContents[(int)HandleOrientation.Parent], SplineTool.handleOrientation == HandleOrientation.Parent,
|
||||
() => SetHandleOrientationIfNeeded(HandleOrientation.Parent));
|
||||
|
||||
menu.AddItem(m_OptionContents[(int)HandleOrientation.Element], SplineTool.handleOrientation == HandleOrientation.Element,
|
||||
() => SetHandleOrientationIfNeeded(HandleOrientation.Element));
|
||||
|
||||
menu.DropDown(worldBound);
|
||||
}
|
||||
|
||||
void SetHandleOrientationIfNeeded(HandleOrientation handleOrientation)
|
||||
{
|
||||
if (SplineTool.handleOrientation != handleOrientation)
|
||||
{
|
||||
SplineTool.handleOrientation = handleOrientation;
|
||||
RefreshElementContent();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshElementContent()
|
||||
{
|
||||
var content = m_OptionContents[(int)SplineTool.handleOrientation];
|
||||
|
||||
text = content.text;
|
||||
tooltip = content.tooltip;
|
||||
icon = content.image as Texture2D;
|
||||
}
|
||||
|
||||
void AttachedToPanel(AttachToPanelEvent evt)
|
||||
{
|
||||
SplineTool.handleOrientationChanged += RefreshElementContent;
|
||||
}
|
||||
|
||||
void DetachedFromPanel(DetachFromPanelEvent evt)
|
||||
{
|
||||
SplineTool.handleOrientationChanged -= RefreshElementContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29ae16933bbb94210b13408d3f86a072
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
sealed class Separator : VisualElement
|
||||
{
|
||||
public Separator()
|
||||
{
|
||||
AddToClassList("unity-separator");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be6977c835160b643b208844b583a89c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using UnityEditor.EditorTools;
|
||||
using UnityEditor.Toolbars;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
[EditorToolbarElement("Spline Tool Settings/Handle Visuals")]
|
||||
sealed class SplineHandleSettingsDropdown : EditorToolbarDropdown
|
||||
{
|
||||
public SplineHandleSettingsDropdown()
|
||||
{
|
||||
var content = EditorGUIUtility.TrTextContent("Visuals", "Visual settings for handles");
|
||||
|
||||
text = content.text;
|
||||
tooltip = content.tooltip;
|
||||
icon = (Texture2D)content.image;
|
||||
|
||||
clicked += OnClick;
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(AttachToPanel);
|
||||
}
|
||||
|
||||
void OnClick()
|
||||
{
|
||||
SplineHandleSettingsWindow.Show(worldBound);
|
||||
}
|
||||
|
||||
void AttachToPanel(AttachToPanelEvent evt)
|
||||
{
|
||||
var toolType = ToolManager.activeToolType;
|
||||
SetEnabled(toolType != typeof(KnotPlacementTool));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9935a56c1434b7845abe3f2b8f6600f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
sealed class SplineHandleSettingsWindow : EditorWindow
|
||||
{
|
||||
const float k_BorderWidth = 1;
|
||||
|
||||
Toggle m_FlowDirection;
|
||||
Toggle m_AllTangents;
|
||||
Toggle m_KnotIndices;
|
||||
Toggle m_SplineMesh;
|
||||
|
||||
public static void Show(Rect buttonRect)
|
||||
{
|
||||
var window = CreateInstance<SplineHandleSettingsWindow>();
|
||||
window.hideFlags = HideFlags.DontSave;
|
||||
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
var popupWidth = 150;
|
||||
#else
|
||||
var popupWidth = 180;
|
||||
#endif
|
||||
window.ShowAsDropDown(GUIUtility.GUIToScreenRect(buttonRect), new Vector2(popupWidth, 80));
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Color borderColor = EditorGUIUtility.isProSkin ? new Color(0.44f, 0.44f, 0.44f, 1f) : new Color(0.51f, 0.51f, 0.51f);
|
||||
|
||||
rootVisualElement.style.borderLeftWidth = k_BorderWidth;
|
||||
rootVisualElement.style.borderTopWidth = k_BorderWidth;
|
||||
rootVisualElement.style.borderRightWidth = k_BorderWidth;
|
||||
rootVisualElement.style.borderBottomWidth = k_BorderWidth;
|
||||
rootVisualElement.style.borderLeftColor = borderColor;
|
||||
rootVisualElement.style.borderTopColor = borderColor;
|
||||
rootVisualElement.style.borderRightColor = borderColor;
|
||||
rootVisualElement.style.borderBottomColor = borderColor;
|
||||
|
||||
rootVisualElement.Add(m_FlowDirection = new Toggle(L10n.Tr("Flow Direction")));
|
||||
m_FlowDirection.style.flexDirection = FlexDirection.RowReverse;
|
||||
|
||||
rootVisualElement.Add(m_AllTangents = new Toggle(L10n.Tr("All Tangents")));
|
||||
m_AllTangents.style.flexDirection = FlexDirection.RowReverse;
|
||||
|
||||
rootVisualElement.Add(m_KnotIndices = new Toggle(L10n.Tr("Knot Indices")));
|
||||
m_KnotIndices.style.flexDirection = FlexDirection.RowReverse;
|
||||
|
||||
rootVisualElement.Add(m_SplineMesh = new Toggle(L10n.Tr("Show Mesh")));
|
||||
m_SplineMesh.style.flexDirection = FlexDirection.RowReverse;
|
||||
|
||||
|
||||
m_FlowDirection.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
SplineHandleSettings.FlowDirectionEnabled = evt.newValue;
|
||||
SceneView.RepaintAll();
|
||||
});
|
||||
m_AllTangents.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
SplineHandleSettings.ShowAllTangents = evt.newValue;
|
||||
SceneView.RepaintAll();
|
||||
});
|
||||
m_KnotIndices.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
SplineHandleSettings.ShowKnotIndices = evt.newValue;
|
||||
SceneView.RepaintAll();
|
||||
});
|
||||
m_SplineMesh.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
SplineHandleSettings.ShowMesh = evt.newValue;
|
||||
SceneView.RepaintAll();
|
||||
});
|
||||
|
||||
UpdateValues();
|
||||
}
|
||||
|
||||
|
||||
void UpdateValues()
|
||||
{
|
||||
m_FlowDirection.SetValueWithoutNotify(SplineHandleSettings.FlowDirectionEnabled);
|
||||
m_AllTangents.SetValueWithoutNotify(SplineHandleSettings.ShowAllTangents);
|
||||
m_KnotIndices.SetValueWithoutNotify(SplineHandleSettings.ShowKnotIndices);
|
||||
m_SplineMesh.SetValueWithoutNotify(SplineHandleSettings.ShowMesh);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8c433db06b595546b18ebbe3e27c83f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.EditorTools;
|
||||
using UnityEditor.Overlays;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEngine.Splines;
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
[Icon("UnityEditor.InspectorWindow")]
|
||||
[Overlay(typeof(SceneView), "unity-spline-inspector", "Element Inspector", "SplineInspector")]
|
||||
sealed class SplineInspectorOverlay : Overlay, ITransientOverlay
|
||||
{
|
||||
internal static readonly string SplineChangeUndoMessage = L10n.Tr("Apply Changes to Spline");
|
||||
public static void ForceUpdate()
|
||||
{
|
||||
s_ForceUpdateRequested?.Invoke();
|
||||
}
|
||||
|
||||
static event Action s_ForceUpdateRequested;
|
||||
static bool s_FirstUpdateSinceDomainReload = true;
|
||||
static IReadOnlyList<SplineInfo> m_SelectedSplines;
|
||||
internal static void SetSelectedSplines(IReadOnlyList<SplineInfo> splines)
|
||||
{
|
||||
m_SelectedSplines = splines;
|
||||
if (s_FirstUpdateSinceDomainReload)
|
||||
{
|
||||
s_FirstUpdateSinceDomainReload = false;
|
||||
ForceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public bool visible => ToolManager.activeContextType == typeof(SplineToolContext) && ToolManager.activeToolType != typeof(KnotPlacementTool);
|
||||
|
||||
ElementInspector m_ElementInspector;
|
||||
|
||||
public override VisualElement CreatePanelContent()
|
||||
{
|
||||
VisualElement root = new VisualElement();
|
||||
root.Add(m_ElementInspector = new ElementInspector());
|
||||
|
||||
UpdateInspector();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public override void OnCreated()
|
||||
{
|
||||
displayedChanged += OnDisplayedChange;
|
||||
SplineSelection.changed += UpdateInspector;
|
||||
s_ForceUpdateRequested += UpdateInspector;
|
||||
Undo.undoRedoPerformed += OnUndoRedoPerformed;
|
||||
}
|
||||
|
||||
public override void OnWillBeDestroyed()
|
||||
{
|
||||
displayedChanged -= OnDisplayedChange;
|
||||
SplineSelection.changed -= UpdateInspector;
|
||||
s_ForceUpdateRequested -= UpdateInspector;
|
||||
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
|
||||
}
|
||||
|
||||
void OnDisplayedChange(bool displayed)
|
||||
{
|
||||
UpdateInspector();
|
||||
}
|
||||
|
||||
void UpdateInspector()
|
||||
{
|
||||
if (m_SelectedSplines == null)
|
||||
return;
|
||||
|
||||
m_ElementInspector?.UpdateSelection(m_SelectedSplines);
|
||||
}
|
||||
|
||||
void OnUndoRedoPerformed()
|
||||
{
|
||||
ForceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5737da4b5db2be640adcc9bb3360aa91
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Splines;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#if !UNITY_2022_1_OR_NEWER
|
||||
using UnityEditor.UIElements;
|
||||
#endif
|
||||
|
||||
namespace UnityEditor.Splines
|
||||
{
|
||||
sealed class TangentDrawer : ElementDrawer<SelectableTangent>
|
||||
{
|
||||
const string k_TangentDrawerStyle = "tangent-drawer";
|
||||
|
||||
static readonly List<float> s_LengthBuffer = new List<float>(0);
|
||||
static readonly SplineGUIUtility.EqualityComparer<float> s_MagnitudeComparer = (a, b) => a.Equals(b);
|
||||
|
||||
readonly TangentModePropertyField<SelectableTangent> m_Mode;
|
||||
readonly BezierTangentPropertyField<SelectableTangent> m_BezierMode;
|
||||
|
||||
FloatField m_Magnitude;
|
||||
Float3PropertyField<SelectableTangent> m_Direction;
|
||||
|
||||
public TangentDrawer()
|
||||
{
|
||||
AddToClassList(k_TangentDrawerStyle);
|
||||
|
||||
Add(m_Mode = new TangentModePropertyField<SelectableTangent>());
|
||||
m_Mode.changed += () =>
|
||||
{
|
||||
m_BezierMode.Update(targets);
|
||||
EnableElements();
|
||||
};
|
||||
Add(m_BezierMode = new BezierTangentPropertyField<SelectableTangent>());
|
||||
m_BezierMode.changed += () =>
|
||||
{
|
||||
m_Mode.Update(targets);
|
||||
EnableElements();
|
||||
};
|
||||
|
||||
CreateTangentFields();
|
||||
|
||||
m_Magnitude.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
var value = evt.newValue;
|
||||
if (evt.newValue < 0f)
|
||||
{
|
||||
m_Magnitude.SetValueWithoutNotify(0f);
|
||||
value = 0f;
|
||||
}
|
||||
|
||||
Undo.RecordObject(target.SplineInfo.Object, SplineInspectorOverlay.SplineChangeUndoMessage);
|
||||
UpdateTangentMagnitude(value);
|
||||
var tangent = target;
|
||||
m_Direction.SetValueWithoutNotify(tangent.LocalPosition);
|
||||
});
|
||||
}
|
||||
|
||||
public override string GetLabelForTargets()
|
||||
{
|
||||
if (targets.Count > 1)
|
||||
return $"<b>({targets.Count}) Tangents</b> selected";
|
||||
|
||||
var inOutLabel = target.TangentIndex == 0 ? "In" : "Out";
|
||||
return $"Tangent <b>{inOutLabel}</b> selected (<b>Knot {target.KnotIndex}</b>, <b>Spline {target.SplineInfo.Index}</b>)";
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
m_Mode.Update(targets);
|
||||
m_BezierMode.Update(targets);
|
||||
|
||||
UpdateMagnitudeField(targets);
|
||||
m_Direction.Update(targets);
|
||||
|
||||
EnableElements();
|
||||
}
|
||||
|
||||
void CreateTangentFields()
|
||||
{
|
||||
Add(m_Magnitude = new FloatField(L10n.Tr("Length"), 6));
|
||||
|
||||
Add(m_Direction = new Float3PropertyField<SelectableTangent>(L10n.Tr("Direction"),
|
||||
(tangent) => tangent.LocalDirection,
|
||||
(tangent, value) => tangent.LocalDirection = value)
|
||||
{ name = "direction" });
|
||||
m_Direction.changed += () => { UpdateMagnitudeField(targets); };
|
||||
}
|
||||
|
||||
void UpdateMagnitudeField(IReadOnlyList<SelectableTangent> tangents)
|
||||
{
|
||||
s_LengthBuffer.Clear();
|
||||
for (int i = 0; i < tangents.Count; ++i)
|
||||
s_LengthBuffer.Add(math.length(tangents[i].LocalPosition));
|
||||
|
||||
m_Magnitude.showMixedValue = SplineGUIUtility.HasMultipleValues(s_LengthBuffer, s_MagnitudeComparer);
|
||||
if (!m_Magnitude.showMixedValue)
|
||||
m_Magnitude.SetValueWithoutNotify(s_LengthBuffer[0]);
|
||||
}
|
||||
|
||||
void UpdateTangentMagnitude(float value)
|
||||
{
|
||||
ElementInspector.ignoreKnotCallbacks = true;
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
var direction = new float3(0, 0, 1);
|
||||
|
||||
var tangent = targets[i];
|
||||
if (math.length(tangent.LocalPosition) > 0)
|
||||
direction = math.normalize(tangent.LocalPosition);
|
||||
|
||||
tangent.LocalPosition = value * direction;
|
||||
}
|
||||
ElementInspector.ignoreKnotCallbacks = false;
|
||||
}
|
||||
|
||||
void EnableElements()
|
||||
{
|
||||
bool tangentsModifiable = true;
|
||||
bool tangentsBroken = true;
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
var mode = targets[i].Owner.Mode;
|
||||
tangentsModifiable &= SplineUtility.AreTangentsModifiable(mode);
|
||||
tangentsBroken &= mode == TangentMode.Broken;
|
||||
}
|
||||
|
||||
m_Direction.SetEnabled(tangentsModifiable && tangentsBroken);
|
||||
m_Magnitude.SetEnabled(tangentsModifiable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d01d6b9007f24984692322edf5415826
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user