A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using UnityEditor.U2D.Common;
4using UnityEngine;
5using UnityEngine.UIElements;
6
7namespace UnityEditor.U2D.Animation
8{
9#if ENABLE_UXML_SERIALIZED_DATA
10 [UxmlElement]
11#endif
12 internal partial class WeightPainterPanel : VisualElement
13 {
14#if ENABLE_UXML_TRAITS
15 public class WeightPainterPanelFactory : UxmlFactory<WeightPainterPanel, WeightPainterPanelUxmlTraits> {}
16 public class WeightPainterPanelUxmlTraits : UxmlTraits {}
17#endif
18 public static readonly string kNone = "None";
19
20 private WeightPainterMode m_PaintMode;
21 private EnumField m_ModeField;
22 private Toggle m_NormalizeToggle;
23 private IntegerField m_HardnessField;
24 private IntegerField m_StepField;
25 private IntegerField m_SizeField;
26 private FloatField m_AmountField;
27 private Slider m_AmountSlider;
28 private VisualElement m_BonePopupContainer;
29 private PopupField<string> m_BonePopup;
30 private bool m_SliderActive = false;
31 private WeightInspectorIMGUIPanel m_WeightInspectorPanel;
32 private UnityEngine.UIElements.PopupWindow m_PopupWindow;
33
34 public event Action<int> bonePopupChanged = (s) => {};
35 public event Action sliderStarted = () => {};
36 public event Action<float> sliderChanged = (s) => {};
37 public event Action sliderEnded = () => {};
38 public event Action weightsChanged = () => {};
39
40 public WeightPainterMode paintMode
41 {
42 get { return m_PaintMode; }
43 set
44 {
45 if (value == m_PaintMode)
46 return;
47
48 m_PaintMode = value;
49 if (m_PaintMode == WeightPainterMode.Brush)
50 {
51 RemoveFromClassList("SliderMode");
52 AddToClassList("BrushMode");
53 }
54 else
55 {
56 RemoveFromClassList("BrushMode");
57 AddToClassList("SliderMode");
58 }
59 }
60 }
61
62 public string title
63 {
64 set { m_PopupWindow.text = value; }
65 }
66
67 public WeightEditorMode mode
68 {
69 get { return (WeightEditorMode)m_ModeField.value; }
70 set { m_ModeField.value = value; }
71 }
72
73 public int boneIndex
74 {
75 get { return m_BonePopup.index - 1; }
76 }
77
78 public int size
79 {
80 get { return m_SizeField.value; }
81 set { m_SizeField.value = value; }
82 }
83
84 public int hardness
85 {
86 get { return m_HardnessField.value; }
87 set { m_HardnessField.value = value; }
88 }
89
90 public int step
91 {
92 get { return m_StepField.value; }
93 set { m_StepField.value = value; }
94 }
95
96 public bool normalize
97 {
98 get { return m_NormalizeToggle.value; }
99 set { m_NormalizeToggle.value = value; }
100 }
101
102 public float amount
103 {
104 get { return m_AmountField.value; }
105 set { m_AmountField.value = value; }
106 }
107
108 public WeightPainterPanel()
109 {
110 styleSheets.Add(ResourceLoader.Load<StyleSheet>("SkinningModule/WeightPainterPanelStyle.uss"));
111 if (EditorGUIUtility.isProSkin)
112 AddToClassList("Dark");
113
114 paintMode = WeightPainterMode.Brush;
115 AddToClassList("BrushMode");
116
117 RegisterCallback<MouseDownEvent>((e) => { e.StopPropagation(); });
118 RegisterCallback<MouseUpEvent>((e) => { e.StopPropagation(); });
119 }
120
121 public void BindElements()
122 {
123 m_ModeField = this.Q<EnumField>("ModeField");
124 m_BonePopupContainer = this.Q<VisualElement>("BoneEnumPopup");
125 m_NormalizeToggle = this.Q<Toggle>("NormalizeToggle");
126 m_SizeField = this.Q<IntegerField>("SizeField");
127 m_HardnessField = this.Q<IntegerField>("HardnessField");
128 m_StepField = this.Q<IntegerField>("StepField");
129 m_AmountSlider = this.Q<Slider>("AmountSlider");
130 m_AmountField = this.Q<FloatField>("AmountField");
131 m_AmountField.isDelayed = true;
132 m_WeightInspectorPanel = this.Q<WeightInspectorIMGUIPanel>("WeightsInspector");
133 m_PopupWindow = this.Q<UnityEngine.UIElements.PopupWindow>();
134
135 LinkSliderToIntegerField(this.Q<Slider>("HardnessSlider"), m_HardnessField);
136 LinkSliderToIntegerField(this.Q<Slider>("StepSlider"), m_StepField);
137
138 m_ModeField.RegisterValueChangedCallback((evt) =>
139 {
140 SetupMode();
141 });
142
143 m_AmountSlider.RegisterValueChangedCallback((evt) =>
144 {
145 if (!evt.Equals(m_AmountField.value))
146 m_AmountField.value = (float)Math.Round((double)evt.newValue, 2);
147 if (m_SliderActive)
148 sliderChanged?.Invoke(m_AmountField.value);
149 });
150 m_AmountSlider.RegisterCallback<MouseCaptureEvent>(evt =>
151 {
152 m_SliderActive = true;
153 sliderStarted?.Invoke();
154 }, TrickleDown.TrickleDown);
155
156 m_AmountSlider.RegisterCallback<MouseCaptureOutEvent>(evt =>
157 {
158 m_SliderActive = false;
159 sliderEnded?.Invoke();
160 m_AmountSlider.value = 0;
161 }, TrickleDown.TrickleDown);
162
163 m_AmountField.RegisterValueChangedCallback((evt) =>
164 {
165 var newValue = Mathf.Clamp(evt.newValue, m_AmountSlider.lowValue, m_AmountSlider.highValue);
166
167 if (focusController.focusedElement == m_AmountField && !newValue.Equals(m_AmountSlider.value))
168 {
169 sliderStarted();
170 sliderChanged(newValue);
171 sliderEnded();
172 Focus();
173 m_AmountField.value = 0f;
174 m_AmountSlider.value = 0f;
175 }
176 });
177
178 m_WeightInspectorPanel.weightsChanged += () => weightsChanged();
179 }
180
181 public void SetActive(bool active)
182 {
183 this.Q("Amount").SetEnabled(active);
184 }
185
186 private void SetupMode()
187 {
188 var boneElement = this.Q<VisualElement>("Bone");
189 boneElement.SetHiddenFromLayout(mode == WeightEditorMode.Smooth);
190 SetupAmountSlider();
191 }
192
193 private void SetupAmountSlider()
194 {
195 if (paintMode == WeightPainterMode.Slider)
196 {
197 if (mode == WeightEditorMode.Smooth)
198 {
199 m_AmountSlider.lowValue = 0.0f;
200 m_AmountSlider.highValue = 8.0f;
201 }
202 else
203 {
204 m_AmountSlider.lowValue = -1.0f;
205 m_AmountSlider.highValue = 1.0f;
206 }
207 }
208 }
209
210 private void LinkSliderToIntegerField(Slider slider, IntegerField field)
211 {
212 slider.RegisterValueChangedCallback((evt) =>
213 {
214 if (!evt.newValue.Equals(field.value))
215 field.value = Mathf.RoundToInt(evt.newValue);
216 });
217 field.RegisterValueChangedCallback((evt) =>
218 {
219 if (!evt.newValue.Equals((int)slider.value))
220 slider.value = evt.newValue;
221 });
222 }
223
224 public void UpdateWeightInspector(BaseSpriteMeshData spriteMeshData, string[] boneNames, ISelection<int> selection, ICacheUndo cacheUndo)
225 {
226 m_WeightInspectorPanel.weightInspector.spriteMeshData = spriteMeshData;
227 m_WeightInspectorPanel.weightInspector.boneNames = ModuleUtility.ToGUIContentArray(boneNames);
228 m_WeightInspectorPanel.weightInspector.selection = selection;
229 m_WeightInspectorPanel.weightInspector.cacheUndo = cacheUndo;
230 }
231
232 public void UpdatePanel(string[] boneNames)
233 {
234 SetupMode();
235 UpdateBonePopup(boneNames);
236 }
237
238 private void UpdateBonePopup(string[] names)
239 {
240 VisualElement boneElement = null;
241 if (m_ModeField != null && mode == WeightEditorMode.Smooth)
242 {
243 boneElement = this.Q<VisualElement>("Bone");
244 boneElement.SetHiddenFromLayout(false);
245 }
246
247 if (m_BonePopup != null)
248 {
249 m_BonePopupContainer.Remove(m_BonePopup);
250 }
251
252 m_BonePopup = new PopupField<string>(new List<string>(names), 0);
253 m_BonePopup.name = "BonePopupField";
254 m_BonePopup.label = TextContent.bone;
255 m_BonePopup.tooltip = TextContent.boneToolTip;
256 m_BonePopup.RegisterValueChangedCallback((evt) =>
257 {
258 bonePopupChanged(boneIndex);
259 });
260 m_BonePopupContainer.Add(m_BonePopup);
261
262 if (boneElement != null)
263 {
264 boneElement.SetHiddenFromLayout(true);
265 }
266 }
267
268 internal void SetBoneSelectionByName(string boneName)
269 {
270 if (m_BonePopup != null)
271 m_BonePopup.value = boneName;
272 }
273
274 public static WeightPainterPanel GenerateFromUXML()
275 {
276 var visualTree = ResourceLoader.Load<VisualTreeAsset>("SkinningModule/WeightPainterPanel.uxml");
277 var clone = visualTree.CloneTree().Q<WeightPainterPanel>("WeightPainterPanel");
278 clone.LocalizeTextInChildren();
279
280 // EnumField can only get type of Enum from the current running assembly when defined through UXML
281 // Manually create the EnumField here
282 var mode = clone.Q<VisualElement>("Mode");
283 var modeField = new EnumField(WeightEditorMode.AddAndSubtract);
284 modeField.name = "ModeField";
285 modeField.label = TextContent.mode;
286 modeField.tooltip = TextContent.modeTooltip;
287 mode.Add(modeField);
288
289 clone.BindElements();
290 return clone;
291 }
292 }
293}