A game about forced loneliness, made by TACStudios
1using UnityEditor.U2D.Layout;
2using UnityEngine;
3
4namespace UnityEditor.U2D.Animation
5{
6 internal class SkeletonTool : BaseTool
7 {
8 [SerializeField]
9 SkeletonController m_SkeletonController;
10 SkeletonToolView m_SkeletonToolView;
11 RectBoneSelector m_RectBoneSelector = new RectBoneSelector();
12 RectSelectionTool<BoneCache> m_RectSelectionTool = new RectSelectionTool<BoneCache>();
13 UnselectTool<BoneCache> m_UnselectTool = new UnselectTool<BoneCache>();
14
15 public bool enableBoneInspector { get; set; }
16
17 public SkeletonMode mode
18 {
19 get => m_SkeletonController.view.mode;
20 set => m_SkeletonController.view.mode = value;
21 }
22
23 public bool editBindPose
24 {
25 get => m_SkeletonController.editBindPose;
26 set => m_SkeletonController.editBindPose = value;
27 }
28
29 public ISkeletonStyle skeletonStyle
30 {
31 get => m_SkeletonController.styleOverride;
32 set => m_SkeletonController.styleOverride = value;
33 }
34
35 public override int defaultControlID => 0;
36
37 public BoneCache hoveredBone => m_SkeletonController.hoveredBone;
38
39 public SkeletonCache skeleton
40 {
41 get => m_SkeletonController.skeleton;
42 private set => m_SkeletonController.skeleton = value;
43 }
44
45 internal override void OnCreate()
46 {
47 m_SkeletonController = new SkeletonController();
48 m_SkeletonController.view = new SkeletonView(new GUIWrapper());
49 m_SkeletonController.view.InvalidID = 0;
50 m_SkeletonController.selection = skinningCache.skeletonSelection;
51 m_SkeletonToolView = new SkeletonToolView();
52 m_SkeletonToolView.onBoneNameChanged += BoneNameChanged;
53 m_SkeletonToolView.onBoneDepthChanged += BoneDepthChanged;
54 m_SkeletonToolView.onBonePositionChanged += BonePositionChanged;
55 m_SkeletonToolView.onBoneRotationChanged += BoneRotationChanged;
56 m_SkeletonToolView.onBoneColorChanged += BoneColorChanged;
57 m_RectBoneSelector.selection = skinningCache.skeletonSelection;
58 m_RectSelectionTool.rectSelector = m_RectBoneSelector;
59 m_RectSelectionTool.cacheUndo = skinningCache;
60 m_RectSelectionTool.onSelectionUpdate += () =>
61 {
62 skinningCache.events.boneSelectionChanged.Invoke();
63 };
64 m_UnselectTool.cacheUndo = skinningCache;
65 m_UnselectTool.selection = skinningCache.skeletonSelection;
66 m_UnselectTool.onUnselect += () =>
67 {
68 skinningCache.events.boneSelectionChanged.Invoke();
69 };
70 }
71
72 public override void Initialize(LayoutOverlay layout)
73 {
74 m_SkeletonToolView.Initialize(layout);
75 }
76
77 protected override void OnActivate()
78 {
79 SetupSkeleton(skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite));
80 UpdateBoneInspector();
81 skinningCache.events.skeletonTopologyChanged.AddListener(SkeletonTopologyChanged);
82 skinningCache.events.boneSelectionChanged.AddListener(BoneSelectionChanged);
83 skinningCache.events.selectedSpriteChanged.AddListener(SelectedSpriteChanged);
84 skinningCache.events.skinningModeChanged.AddListener(SkinningModeChanged);
85 skinningCache.events.boneDepthChanged.AddListener(BoneDataChanged);
86 skinningCache.events.boneNameChanged.AddListener(BoneDataChanged);
87 skinningCache.events.boneColorChanged.AddListener(BoneDataChanged);
88 skeletonStyle = null;
89 }
90
91 protected override void OnDeactivate()
92 {
93 m_SkeletonToolView.Hide();
94 m_SkeletonController.Reset();
95 skinningCache.events.skeletonTopologyChanged.RemoveListener(SkeletonTopologyChanged);
96 skinningCache.events.boneSelectionChanged.RemoveListener(BoneSelectionChanged);
97 skinningCache.events.selectedSpriteChanged.RemoveListener(SelectedSpriteChanged);
98 skinningCache.events.skinningModeChanged.RemoveListener(SkinningModeChanged);
99 skinningCache.events.boneDepthChanged.RemoveListener(BoneDataChanged);
100 skinningCache.events.boneNameChanged.RemoveListener(BoneDataChanged);
101 skinningCache.events.boneColorChanged.RemoveListener(BoneDataChanged);
102 skeletonStyle = null;
103 }
104
105 void SkeletonTopologyChanged(SkeletonCache skeletonCache)
106 {
107 if (skeleton == skeletonCache && skeleton != null)
108 m_RectBoneSelector.bones = skeleton.bones;
109 }
110
111 void BoneDataChanged(BoneCache bone)
112 {
113 if (m_SkeletonToolView.target == bone)
114 m_SkeletonToolView.Update(bone.name, Mathf.RoundToInt(bone.depth), bone.position, bone.rotation.eulerAngles.z, bone.bindPoseColor);
115 }
116
117 void SelectedSpriteChanged(SpriteCache sprite)
118 {
119 SetupSkeleton(skinningCache.GetEffectiveSkeleton(sprite));
120 }
121
122 void BoneSelectionChanged()
123 {
124 UpdateBoneInspector();
125 }
126
127 void UpdateBoneInspector()
128 {
129 var selectedBone = skinningCache.skeletonSelection.activeElement;
130 var selectionCount = skinningCache.skeletonSelection.Count;
131
132 m_SkeletonToolView.Hide();
133
134 if (enableBoneInspector && selectedBone != null && selectionCount == 1)
135 {
136 m_SkeletonToolView.Update(selectedBone.name, Mathf.RoundToInt(selectedBone.depth), selectedBone.position, selectedBone.rotation.eulerAngles.z, selectedBone.bindPoseColor);
137 bool isReadOnly = skinningCache.bonesReadOnly;
138 m_SkeletonToolView.Show(selectedBone, isReadOnly);
139 }
140 }
141
142 void SkinningModeChanged(SkinningMode skinningMode)
143 {
144 SetupSkeleton(skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite));
145 }
146
147 void SetupSkeleton(SkeletonCache sk)
148 {
149 m_RectBoneSelector.bones = null;
150 skeleton = sk;
151
152 if (skeleton != null)
153 m_RectBoneSelector.bones = skeleton.bones;
154 }
155
156 protected override void OnGUI()
157 {
158 m_SkeletonController.view.defaultControlID = 0;
159
160 if (skeleton != null && mode != SkeletonMode.Disabled)
161 {
162 m_RectSelectionTool.OnGUI();
163 m_SkeletonController.view.defaultControlID = m_RectSelectionTool.controlID;
164 }
165
166 m_SkeletonController.OnGUI();
167 m_UnselectTool.OnGUI();
168 }
169
170 void BoneColorChanged(BoneCache selectedBone, Color32 color)
171 {
172 if (selectedBone != null)
173 {
174 skinningCache.BeginUndoOperation(TextContent.colorBoneChanged);
175 selectedBone.bindPoseColor = color;
176 skinningCache.events.boneColorChanged.Invoke(selectedBone);
177 }
178 }
179
180 void BonePositionChanged(BoneCache selectedBone, Vector2 position)
181 {
182 if (selectedBone != null)
183 {
184 skinningCache.BeginUndoOperation(TextContent.moveBone);
185 selectedBone.position = position;
186 HandleUtility.Repaint();
187 m_SkeletonController.InvokePoseChanged();
188 }
189 }
190
191 void BoneRotationChanged(BoneCache selectedBone, float rotation)
192 {
193 if (selectedBone != null)
194 {
195 var euler = selectedBone.rotation.eulerAngles;
196 euler.z = rotation;
197 skinningCache.BeginUndoOperation(TextContent.rotateBone);
198 selectedBone.rotation = Quaternion.Euler(euler);
199 HandleUtility.Repaint();
200 m_SkeletonController.InvokePoseChanged();
201 }
202 }
203
204 void BoneNameChanged(BoneCache selectedBone, string name)
205 {
206 if (selectedBone != null)
207 {
208 if (string.Compare(selectedBone.name, name) == 0)
209 return;
210
211 if (string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(name))
212 m_SkeletonToolView.Update(selectedBone.name, Mathf.RoundToInt(selectedBone.depth), selectedBone.position, selectedBone.rotation.eulerAngles.z, selectedBone.bindPoseColor);
213 else
214 {
215 using (skinningCache.UndoScope(TextContent.boneName))
216 {
217 selectedBone.name = name;
218 skinningCache.events.boneNameChanged.Invoke(selectedBone);
219 }
220 }
221 }
222 }
223
224 void BoneDepthChanged(BoneCache selectedBone, int depth)
225 {
226 if (selectedBone != null)
227 {
228 if (Mathf.RoundToInt(selectedBone.depth) == depth)
229 return;
230
231 using (skinningCache.UndoScope(TextContent.boneDepth))
232 {
233 selectedBone.depth = depth;
234 skinningCache.events.boneDepthChanged.Invoke(selectedBone);
235 }
236 }
237 }
238 }
239}