289 lines
9.9 KiB
C#
289 lines
9.9 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEditor.UIElements;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UIElements;
|
||
|
|
||
|
namespace UnityEditor.U2D.Animation
|
||
|
{
|
||
|
internal class WeightPainterPanel : VisualElement
|
||
|
{
|
||
|
public class WeightPainterPanelFactory : UxmlFactory<WeightPainterPanel, WeightPainterPanelUxmlTraits> {}
|
||
|
public class WeightPainterPanelUxmlTraits : UxmlTraits {}
|
||
|
public static readonly string kNone = "None";
|
||
|
|
||
|
private WeightPainterMode m_PaintMode;
|
||
|
private EnumField m_ModeField;
|
||
|
private Toggle m_NormalizeToggle;
|
||
|
private IntegerField m_HardnessField;
|
||
|
private IntegerField m_StepField;
|
||
|
private IntegerField m_SizeField;
|
||
|
private FloatField m_AmountField;
|
||
|
private Slider m_AmountSlider;
|
||
|
private VisualElement m_BonePopupContainer;
|
||
|
private PopupField<string> m_BonePopup;
|
||
|
private bool m_SliderActive = false;
|
||
|
private WeightInspectorIMGUIPanel m_WeightInspectorPanel;
|
||
|
private UnityEngine.UIElements.PopupWindow m_PopupWindow;
|
||
|
|
||
|
public event Action<int> bonePopupChanged = (s) => {};
|
||
|
public event Action sliderStarted = () => {};
|
||
|
public event Action<float> sliderChanged = (s) => {};
|
||
|
public event Action sliderEnded = () => {};
|
||
|
public event Action weightsChanged = () => {};
|
||
|
|
||
|
public WeightPainterMode paintMode
|
||
|
{
|
||
|
get { return m_PaintMode; }
|
||
|
set
|
||
|
{
|
||
|
if (value == m_PaintMode)
|
||
|
return;
|
||
|
|
||
|
m_PaintMode = value;
|
||
|
if (m_PaintMode == WeightPainterMode.Brush)
|
||
|
{
|
||
|
RemoveFromClassList("SliderMode");
|
||
|
AddToClassList("BrushMode");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RemoveFromClassList("BrushMode");
|
||
|
AddToClassList("SliderMode");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string title
|
||
|
{
|
||
|
set { m_PopupWindow.text = value; }
|
||
|
}
|
||
|
|
||
|
public WeightEditorMode mode
|
||
|
{
|
||
|
get { return (WeightEditorMode)m_ModeField.value; }
|
||
|
set { m_ModeField.value = value; }
|
||
|
}
|
||
|
|
||
|
public int boneIndex
|
||
|
{
|
||
|
get { return m_BonePopup.index - 1; }
|
||
|
}
|
||
|
|
||
|
public int size
|
||
|
{
|
||
|
get { return m_SizeField.value; }
|
||
|
set { m_SizeField.value = value; }
|
||
|
}
|
||
|
|
||
|
public int hardness
|
||
|
{
|
||
|
get { return m_HardnessField.value; }
|
||
|
set { m_HardnessField.value = value; }
|
||
|
}
|
||
|
|
||
|
public int step
|
||
|
{
|
||
|
get { return m_StepField.value; }
|
||
|
set { m_StepField.value = value; }
|
||
|
}
|
||
|
|
||
|
public bool normalize
|
||
|
{
|
||
|
get { return m_NormalizeToggle.value; }
|
||
|
set { m_NormalizeToggle.value = value; }
|
||
|
}
|
||
|
|
||
|
public float amount
|
||
|
{
|
||
|
get { return m_AmountField.value; }
|
||
|
set { m_AmountField.value = value; }
|
||
|
}
|
||
|
|
||
|
public WeightPainterPanel()
|
||
|
{
|
||
|
styleSheets.Add(ResourceLoader.Load<StyleSheet>("SkinningModule/WeightPainterPanelStyle.uss"));
|
||
|
if (EditorGUIUtility.isProSkin)
|
||
|
AddToClassList("Dark");
|
||
|
|
||
|
paintMode = WeightPainterMode.Brush;
|
||
|
AddToClassList("BrushMode");
|
||
|
|
||
|
RegisterCallback<MouseDownEvent>((e) => { e.StopPropagation(); });
|
||
|
RegisterCallback<MouseUpEvent>((e) => { e.StopPropagation(); });
|
||
|
}
|
||
|
|
||
|
public void BindElements()
|
||
|
{
|
||
|
m_ModeField = this.Q<EnumField>("ModeField");
|
||
|
m_BonePopupContainer = this.Q<VisualElement>("BoneEnumPopup");
|
||
|
m_NormalizeToggle = this.Q<Toggle>("NormalizeToggle");
|
||
|
m_SizeField = this.Q<IntegerField>("SizeField");
|
||
|
m_HardnessField = this.Q<IntegerField>("HardnessField");
|
||
|
m_StepField = this.Q<IntegerField>("StepField");
|
||
|
m_AmountSlider = this.Q<Slider>("AmountSlider");
|
||
|
m_AmountField = this.Q<FloatField>("AmountField");
|
||
|
m_AmountField.isDelayed = true;
|
||
|
m_WeightInspectorPanel = this.Q<WeightInspectorIMGUIPanel>("WeightsInspector");
|
||
|
m_PopupWindow = this.Q<UnityEngine.UIElements.PopupWindow>();
|
||
|
|
||
|
LinkSliderToIntegerField(this.Q<Slider>("HardnessSlider"), m_HardnessField);
|
||
|
LinkSliderToIntegerField(this.Q<Slider>("StepSlider"), m_StepField);
|
||
|
|
||
|
m_ModeField.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
SetupMode();
|
||
|
});
|
||
|
|
||
|
m_AmountSlider.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
if (!evt.Equals(m_AmountField.value))
|
||
|
m_AmountField.value = (float)Math.Round((double)evt.newValue, 2);
|
||
|
if (m_SliderActive)
|
||
|
sliderChanged?.Invoke(m_AmountField.value);
|
||
|
});
|
||
|
m_AmountSlider.RegisterCallback<MouseCaptureEvent>(evt =>
|
||
|
{
|
||
|
m_SliderActive = true;
|
||
|
sliderStarted?.Invoke();
|
||
|
}, TrickleDown.TrickleDown);
|
||
|
|
||
|
m_AmountSlider.RegisterCallback<MouseCaptureOutEvent>(evt =>
|
||
|
{
|
||
|
m_SliderActive = false;
|
||
|
sliderEnded?.Invoke();
|
||
|
m_AmountSlider.value = 0;
|
||
|
}, TrickleDown.TrickleDown);
|
||
|
|
||
|
m_AmountField.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
var newValue = Mathf.Clamp(evt.newValue, m_AmountSlider.lowValue, m_AmountSlider.highValue);
|
||
|
|
||
|
if (focusController.focusedElement == m_AmountField && !newValue.Equals(m_AmountSlider.value))
|
||
|
{
|
||
|
sliderStarted();
|
||
|
sliderChanged(newValue);
|
||
|
sliderEnded();
|
||
|
Focus();
|
||
|
m_AmountField.value = 0f;
|
||
|
m_AmountSlider.value = 0f;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
m_WeightInspectorPanel.weightsChanged += () => weightsChanged();
|
||
|
}
|
||
|
|
||
|
public void SetActive(bool active)
|
||
|
{
|
||
|
this.Q("Amount").SetEnabled(active);
|
||
|
}
|
||
|
|
||
|
private void SetupMode()
|
||
|
{
|
||
|
var boneElement = this.Q<VisualElement>("Bone");
|
||
|
boneElement.SetHiddenFromLayout(mode == WeightEditorMode.Smooth);
|
||
|
SetupAmountSlider();
|
||
|
}
|
||
|
|
||
|
private void SetupAmountSlider()
|
||
|
{
|
||
|
if (paintMode == WeightPainterMode.Slider)
|
||
|
{
|
||
|
if (mode == WeightEditorMode.Smooth)
|
||
|
{
|
||
|
m_AmountSlider.lowValue = 0.0f;
|
||
|
m_AmountSlider.highValue = 8.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_AmountSlider.lowValue = -1.0f;
|
||
|
m_AmountSlider.highValue = 1.0f;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void LinkSliderToIntegerField(Slider slider, IntegerField field)
|
||
|
{
|
||
|
slider.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
if (!evt.newValue.Equals(field.value))
|
||
|
field.value = Mathf.RoundToInt(evt.newValue);
|
||
|
});
|
||
|
field.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
if (!evt.newValue.Equals((int)slider.value))
|
||
|
slider.value = evt.newValue;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public void UpdateWeightInspector(BaseSpriteMeshData spriteMeshData, string[] boneNames, ISelection<int> selection, ICacheUndo cacheUndo)
|
||
|
{
|
||
|
m_WeightInspectorPanel.weightInspector.spriteMeshData = spriteMeshData;
|
||
|
m_WeightInspectorPanel.weightInspector.boneNames = ModuleUtility.ToGUIContentArray(boneNames);
|
||
|
m_WeightInspectorPanel.weightInspector.selection = selection;
|
||
|
m_WeightInspectorPanel.weightInspector.cacheUndo = cacheUndo;
|
||
|
}
|
||
|
|
||
|
public void UpdatePanel(string[] boneNames)
|
||
|
{
|
||
|
SetupMode();
|
||
|
UpdateBonePopup(boneNames);
|
||
|
}
|
||
|
|
||
|
private void UpdateBonePopup(string[] names)
|
||
|
{
|
||
|
VisualElement boneElement = null;
|
||
|
if (m_ModeField != null && mode == WeightEditorMode.Smooth)
|
||
|
{
|
||
|
boneElement = this.Q<VisualElement>("Bone");
|
||
|
boneElement.SetHiddenFromLayout(false);
|
||
|
}
|
||
|
|
||
|
if (m_BonePopup != null)
|
||
|
{
|
||
|
m_BonePopupContainer.Remove(m_BonePopup);
|
||
|
}
|
||
|
|
||
|
m_BonePopup = new PopupField<string>(new List<string>(names), 0);
|
||
|
m_BonePopup.name = "BonePopupField";
|
||
|
m_BonePopup.label = TextContent.bone;
|
||
|
m_BonePopup.tooltip = TextContent.boneToolTip;
|
||
|
m_BonePopup.RegisterValueChangedCallback((evt) =>
|
||
|
{
|
||
|
bonePopupChanged(boneIndex);
|
||
|
});
|
||
|
m_BonePopupContainer.Add(m_BonePopup);
|
||
|
|
||
|
if (boneElement != null)
|
||
|
{
|
||
|
boneElement.SetHiddenFromLayout(true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void SetBoneSelectionByName(string boneName)
|
||
|
{
|
||
|
if (m_BonePopup != null)
|
||
|
m_BonePopup.value = boneName;
|
||
|
}
|
||
|
|
||
|
public static WeightPainterPanel GenerateFromUXML()
|
||
|
{
|
||
|
var visualTree = ResourceLoader.Load<VisualTreeAsset>("SkinningModule/WeightPainterPanel.uxml");
|
||
|
var clone = visualTree.CloneTree().Q<WeightPainterPanel>("WeightPainterPanel");
|
||
|
clone.LocalizeTextInChildren();
|
||
|
|
||
|
// EnumField can only get type of Enum from the current running assembly when defined through UXML
|
||
|
// Manually create the EnumField here
|
||
|
var mode = clone.Q<VisualElement>("Mode");
|
||
|
var modeField = new EnumField(WeightEditorMode.AddAndSubtract);
|
||
|
modeField.name = "ModeField";
|
||
|
modeField.label = TextContent.mode;
|
||
|
modeField.tooltip = TextContent.modeTooltip;
|
||
|
mode.Add(modeField);
|
||
|
|
||
|
clone.BindElements();
|
||
|
return clone;
|
||
|
}
|
||
|
}
|
||
|
}
|