UIAnimationEditor.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using UnityEditor.AnimatedValues;
  6. [CustomEditor(typeof(UIAnimation))]
  7. public class UIAnimationEditor : Editor
  8. {
  9. SerializedProperty loop;
  10. SerializedProperty restartOnVisible;
  11. SerializedProperty startAnimationAfter;
  12. SerializedProperty animationFrames;
  13. AnimBool showMovementProps;
  14. AnimBool showRotationProps;
  15. AnimBool showScaleProps;
  16. AnimBool showOpacityProps;
  17. AnimBool showSliceProps;
  18. private static bool movementFoldout = true;
  19. private static bool rotationFoldout;
  20. private static bool scaleFoldout;
  21. private static bool opacityFoldout;
  22. private static bool sliceFoldout;
  23. static int chosenFrame = -1;
  24. int lastAddedFrame = -1;
  25. private bool recordingPosition;
  26. private bool lastRecordingState;
  27. public Vector2 originalPosition;
  28. void OnEnable()
  29. {
  30. loop = serializedObject.FindProperty("Loop");
  31. restartOnVisible = serializedObject.FindProperty("RestartOnVisible");
  32. startAnimationAfter = serializedObject.FindProperty("StartAnimationAfter");
  33. animationFrames = serializedObject.FindProperty("AnimationFrames");
  34. showMovementProps = new AnimBool();
  35. showRotationProps = new AnimBool();
  36. showScaleProps = new AnimBool();
  37. showOpacityProps = new AnimBool();
  38. showSliceProps = new AnimBool();
  39. showMovementProps.valueChanged.AddListener(Repaint);
  40. showRotationProps.valueChanged.AddListener(Repaint);
  41. showScaleProps.valueChanged.AddListener(Repaint);
  42. showOpacityProps.valueChanged.AddListener(Repaint);
  43. showSliceProps.valueChanged.AddListener(Repaint);
  44. }
  45. public override void OnInspectorGUI()
  46. {
  47. serializedObject.Update();
  48. EditorGUILayout.Space();
  49. EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
  50. EditorGUILayout.PropertyField(startAnimationAfter);
  51. EditorGUILayout.PropertyField(loop);
  52. EditorGUILayout.PropertyField(restartOnVisible);
  53. EditorGUILayout.LabelField("Frames", EditorStyles.boldLabel);
  54. GUILayout.BeginHorizontal();
  55. GUILayout.FlexibleSpace();
  56. GUI.color = Color.green;
  57. if (GUILayout.Button("Add", GUILayout.Width(60)))
  58. {
  59. InsertFrame(0);
  60. }
  61. GUI.color = Color.white;
  62. GUILayout.FlexibleSpace();
  63. GUILayout.EndHorizontal();
  64. for (int i = 0; i < animationFrames.arraySize; i++)
  65. {
  66. EditorGUILayout.BeginHorizontal();
  67. if (GUILayout.Button("Frame " + (i + 1) + (lastAddedFrame == i ? " (Newest)" : ""), GUILayout.Height(30)))
  68. {
  69. chosenFrame = chosenFrame != i ? i : -1;
  70. }
  71. #region Delete Button
  72. GUI.color = Color.red;
  73. if (GUILayout.Button("X", GUILayout.Width(20), GUILayout.Height(20)))
  74. {
  75. animationFrames.DeleteArrayElementAtIndex(i);
  76. if (i == lastAddedFrame)
  77. lastAddedFrame = -1;
  78. i--;
  79. continue;
  80. }
  81. GUI.color = Color.white;
  82. #endregion
  83. EditorGUILayout.EndHorizontal();
  84. #region Frame Details
  85. //If this frame is selected
  86. if (chosenFrame == i)
  87. {
  88. SerializedProperty curFrame = animationFrames.GetArrayElementAtIndex(i);
  89. #region Properties
  90. SerializedProperty startAfter = curFrame.FindPropertyRelative("StartAfter");
  91. SerializedProperty duration = curFrame.FindPropertyRelative("Duration");
  92. SerializedProperty movementSection = curFrame.FindPropertyRelative("MovementSection");
  93. SerializedProperty rotationSection = curFrame.FindPropertyRelative("RotationSection");
  94. SerializedProperty scaleSection = curFrame.FindPropertyRelative("ScaleSection");
  95. SerializedProperty opacitySection = curFrame.FindPropertyRelative("OpacitySection");
  96. SerializedProperty sliceSection = curFrame.FindPropertyRelative("SliceSection");
  97. SerializedProperty audioClip = curFrame.FindPropertyRelative("AudioClip");
  98. SerializedProperty onPlay = curFrame.FindPropertyRelative("OnPlay");
  99. #endregion
  100. EditorGUILayout.PropertyField(startAfter);
  101. EditorGUILayout.PropertyField(duration);
  102. EditorGUILayout.Space();
  103. //Movement
  104. DrawAnimationSection(movementSection, ref movementFoldout, ref showMovementProps);
  105. EditorGUILayout.Space();
  106. //Rotation
  107. DrawAnimationSection(rotationSection, ref rotationFoldout, ref showRotationProps);
  108. EditorGUILayout.Space();
  109. //Scale
  110. DrawAnimationSection(scaleSection, ref scaleFoldout, ref showScaleProps);
  111. EditorGUILayout.Space();
  112. //Opacity
  113. DrawAnimationSection(opacitySection, ref opacityFoldout, ref showOpacityProps);
  114. EditorGUILayout.Space();
  115. //Slice
  116. DrawAnimationSection(sliceSection, ref sliceFoldout, ref showSliceProps);
  117. EditorGUILayout.Space();
  118. #region Sound
  119. EditorGUILayout.LabelField("Sound", EditorStyles.boldLabel);
  120. EditorGUILayout.PropertyField(audioClip, new GUIContent("Clip"));
  121. #endregion
  122. #region Event
  123. EditorGUILayout.LabelField("Events", EditorStyles.boldLabel);
  124. EditorGUILayout.PropertyField(onPlay, new GUIContent("On Play"));
  125. #endregion
  126. EditorGUILayout.Space();
  127. }
  128. #endregion
  129. #region Add Button
  130. GUILayout.BeginHorizontal();
  131. GUILayout.FlexibleSpace();
  132. GUI.color = Color.green;
  133. if (GUILayout.Button("Add", GUILayout.Width(60)))
  134. {
  135. InsertFrame(i + 1);
  136. }
  137. GUILayout.FlexibleSpace();
  138. GUILayout.EndHorizontal();
  139. #endregion
  140. GUI.color = Color.white;
  141. }
  142. serializedObject.ApplyModifiedProperties();
  143. }
  144. void InsertFrame(int index)
  145. {
  146. UIAnimation anim = ((UIAnimation)target);
  147. anim.AnimationFrames.Insert(index, new UIAnimation.AnimationFrame(0.3f, 0.5f, -1, -1, -1, -1, -1));
  148. lastAddedFrame = index;
  149. }
  150. void EndRecording()
  151. {
  152. UIAnimation uiAnimation = target as UIAnimation;
  153. UIElement element = uiAnimation.GetComponent<UIElement>();
  154. RectTransform elementRT = element.GetComponent<RectTransform>();
  155. RectTransform parentCanvas = element.GetComponentInParent<Canvas>().GetComponent<RectTransform>();
  156. Undo.RecordObject(element, "Record Hiding Position");
  157. float canvasWidth = parentCanvas.lossyScale.x * parentCanvas.rect.width;
  158. float canvasHeight = parentCanvas.lossyScale.y * parentCanvas.rect.height;
  159. float canvasStartX = parentCanvas.position.x - canvasWidth / 2;
  160. float canvasStartY = parentCanvas.position.y - canvasHeight / 2;
  161. uiAnimation.AnimationFrames[chosenFrame].MovementSection.WantedVectorValue = new Vector3((elementRT.position.x - canvasStartX) / canvasWidth,
  162. (elementRT.position.y - canvasStartY) / canvasHeight, elementRT.position.z);
  163. elementRT.position = element.MovementSection.startVectorValue;
  164. }
  165. void DiscardRecording()
  166. {
  167. UIAnimation uiAnimation = target as UIAnimation;
  168. UIElement element = uiAnimation.GetComponent<UIElement>();
  169. RectTransform elementRT = element.GetComponent<RectTransform>();
  170. elementRT.position = element.MovementSection.startVectorValue;
  171. lastRecordingState = recordingPosition = false;
  172. }
  173. void DrawAnimationSection(SerializedProperty section, ref bool foldout, ref AnimBool animBool)
  174. {
  175. #region Properties Initialization
  176. SerializedProperty useSection = section.FindPropertyRelative("UseSection");
  177. SerializedProperty type = section.FindPropertyRelative("Type");
  178. SerializedProperty wantedVectorValue = section.FindPropertyRelative("WantedVectorValue");
  179. SerializedProperty wantedFloatValue = section.FindPropertyRelative("WantedFloatValue");
  180. SerializedProperty startAfter = section.FindPropertyRelative("StartAfter");
  181. SerializedProperty duration = section.FindPropertyRelative("Duration");
  182. SerializedProperty easingParams = section.FindPropertyRelative("easingParams");
  183. SerializedProperty curFrame = animationFrames.GetArrayElementAtIndex(chosenFrame);
  184. SerializedProperty goToStartValue = curFrame.FindPropertyRelative("Start" + section.name.Substring(0, section.name.Length - 7));
  185. SerializedProperty movementHidingPosition = curFrame.FindPropertyRelative("MovementHidingPosition");
  186. SerializedProperty edgeGap = curFrame.FindPropertyRelative("EdgeGap");
  187. SerializedProperty direction = curFrame.FindPropertyRelative("Direction");
  188. #endregion
  189. string sectionName = section.displayName.Substring(0, section.displayName.Length - 8);
  190. #region Header
  191. EditorStyles.foldout.fontStyle = FontStyle.Bold;
  192. string chosenType = useSection.boolValue ? type.enumDisplayNames[type.enumValueIndex] : "None";
  193. foldout = EditorGUILayout.Foldout(foldout, sectionName + " (" + chosenType + ")", true);
  194. EditorStyles.foldout.fontStyle = FontStyle.Normal;
  195. #endregion
  196. if (foldout)
  197. {
  198. EditorGUILayout.PropertyField(useSection, new GUIContent("Use " + sectionName + "*"));
  199. animBool.target = useSection.boolValue;
  200. if (EditorGUILayout.BeginFadeGroup(animBool.faded))
  201. {
  202. EditorGUILayout.PropertyField(type);
  203. EditorGUILayout.PropertyField(goToStartValue, new GUIContent("Go To Normal?"));
  204. if (!goToStartValue.boolValue)
  205. {
  206. #region Wanted Values
  207. if (sectionName == "Movement")
  208. {
  209. EditorGUILayout.PropertyField(movementHidingPosition, new GUIContent("Hiding Position"));
  210. if (movementHidingPosition.enumValueIndex == 8) //Custom position
  211. {
  212. #region Discard Button
  213. if (recordingPosition)
  214. {
  215. EditorGUILayout.BeginHorizontal();
  216. GUILayout.FlexibleSpace();
  217. if (GUILayout.Button("X", GUILayout.Width(50), GUILayout.Height(15)))
  218. DiscardRecording();
  219. EditorGUILayout.EndHorizontal();
  220. }
  221. #endregion
  222. #region Record Button
  223. EditorGUILayout.BeginHorizontal();
  224. GUILayout.FlexibleSpace();
  225. if (recordingPosition)
  226. GUI.color = Color.red;
  227. recordingPosition = GUILayout.Toggle(recordingPosition, !recordingPosition ? "Record Position" : "Finish Recording", EditorStyles.miniButton);
  228. GUI.color = Color.white;
  229. EditorGUILayout.EndHorizontal();
  230. if (lastRecordingState != recordingPosition)
  231. {
  232. //If recording start
  233. if (recordingPosition)
  234. {
  235. for (int i = 0; i < targets.Length; i++)
  236. {
  237. UIAnimation uiAnimation = target as UIAnimation;
  238. UIElement element = uiAnimation.GetComponent<UIElement>();
  239. RectTransform elementRT = element.GetComponent<RectTransform>();
  240. RectTransform parentCanvas = element.GetComponentInParent<Canvas>().GetComponent<RectTransform>();
  241. float canvasWidth = parentCanvas.lossyScale.x * parentCanvas.rect.width;
  242. float canvasHeight = parentCanvas.lossyScale.y * parentCanvas.rect.height;
  243. if (wantedVectorValue.vector3Value == new Vector3(9999, 9999))
  244. {
  245. float canvasStartX = parentCanvas.position.x - canvasWidth / 2;
  246. float canvasStartY = parentCanvas.position.y - canvasHeight / 2;
  247. Undo.RecordObject(uiAnimation, "Position");
  248. wantedVectorValue.vector3Value = new Vector3((elementRT.position.x - canvasStartX) / canvasWidth,
  249. (elementRT.position.y - canvasStartY) / canvasHeight, elementRT.position.z);
  250. }
  251. element.MovementSection.startVectorValue = elementRT.position;
  252. Vector3 chp = wantedVectorValue.vector3Value;
  253. elementRT.position = new Vector3(
  254. parentCanvas.position.x + (chp.x - 0.5f) * canvasWidth,
  255. parentCanvas.position.y + (chp.y - 0.5f) * canvasHeight, elementRT.position.z);
  256. }
  257. }
  258. //If recording end
  259. if (!recordingPosition)
  260. {
  261. EndRecording();
  262. }
  263. }
  264. lastRecordingState = recordingPosition;
  265. #endregion
  266. Vector2 customVec = wantedVectorValue.vector3Value;
  267. wantedVectorValue.vector3Value = EditorGUILayout.Vector2Field(new GUIContent("Wanted Position", "Custom position as percentage of the screen."), customVec);
  268. }
  269. else
  270. {
  271. EditorGUILayout.PropertyField(edgeGap);
  272. }
  273. }
  274. if (sectionName == "Rotation")
  275. {
  276. EditorGUILayout.PropertyField(wantedVectorValue, new GUIContent("Wanted Rotation", "The rotation this element should change to."));
  277. EditorGUILayout.PropertyField(direction);
  278. }
  279. if (sectionName == "Scale")
  280. EditorGUILayout.PropertyField(wantedVectorValue, new GUIContent("Wanted Scale", "The scale this element should change to."));
  281. if (sectionName == "Opacity")
  282. EditorGUILayout.Slider(wantedFloatValue, 0, 1, new GUIContent("Wanted Opacity", "The opacity this element should fade to."));
  283. if (sectionName == "Slice")
  284. EditorGUILayout.Slider(wantedFloatValue, 0, 1, new GUIContent("Wanted Fill Amount", "The fill amount this element's image should change to."));
  285. #endregion
  286. //Ease Function Parameters Drawing
  287. DrawEasingParams(type.enumNames[type.enumValueIndex], easingParams);
  288. }
  289. #region Custom Properties
  290. #region Custom Properties Drawing
  291. if (startAfter.floatValue >= 0)
  292. {
  293. EditorGUILayout.BeginHorizontal();
  294. EditorGUILayout.PropertyField(startAfter);
  295. if (GUILayout.Button("Delete", EditorStyles.miniButtonRight))
  296. {
  297. Undo.RecordObject(target, "Delete Custom " + startAfter.displayName);
  298. UIAnimation.AnimationSection s = GetFrameAnimationSection(section);
  299. s.StartAfter = -1;
  300. }
  301. EditorGUILayout.EndHorizontal();
  302. }
  303. if (duration.floatValue >= 0)
  304. {
  305. EditorGUILayout.BeginHorizontal();
  306. EditorGUILayout.PropertyField(duration);
  307. if (GUILayout.Button("Delete", EditorStyles.miniButtonRight))
  308. {
  309. Undo.RecordObject(target, "Delete Custom Duration");
  310. UIAnimation.AnimationSection s = GetFrameAnimationSection(section);
  311. s.Duration = -1;
  312. }
  313. EditorGUILayout.EndHorizontal();
  314. }
  315. #endregion
  316. //Seperate in case there an option to add custom property
  317. if (startAfter.floatValue < 0 || duration.floatValue < 0)
  318. EditorGUILayout.Space();
  319. #region Custom Properties Adding
  320. if (startAfter.floatValue < 0)
  321. {
  322. string txt = targets.Length == 1 ? "Add custom \"" + startAfter.displayName + "\"" : "Add custom \"" + startAfter.displayName + "\" to all";
  323. string tooltip = "Add a custom \"" + startAfter.displayName + "\" for this animation section, meaning this section will ignore general \"" + startAfter.displayName + "\".";
  324. EditorGUILayout.BeginHorizontal();
  325. GUILayout.FlexibleSpace();
  326. if (GUILayout.Button(new GUIContent(txt, tooltip), EditorStyles.miniButtonRight, GUILayout.Width(EditorGUIUtility.currentViewWidth / 2)))
  327. {
  328. Undo.RecordObject(target, "Add Custom " + startAfter.displayName);
  329. UIAnimation anim = target as UIAnimation;
  330. UIAnimation.AnimationSection s = GetFrameAnimationSection(section);
  331. s.StartAfter = anim.AnimationFrames[chosenFrame].StartAfter;
  332. }
  333. EditorGUILayout.EndHorizontal();
  334. }
  335. if (duration.floatValue < 0)
  336. {
  337. string txt = targets.Length == 1 ? "Add custom \"" + duration.displayName + "\"" : "Add custom \"" + duration.displayName + "\" to all";
  338. string tooltip = "Add a custom \"" + duration.displayName + "\" for this animation section, meaning this section will ignore general \"" + duration.displayName + "\".";
  339. EditorGUILayout.BeginHorizontal();
  340. GUILayout.FlexibleSpace();
  341. if (GUILayout.Button(new GUIContent(txt, tooltip), EditorStyles.miniButtonRight, GUILayout.Width(EditorGUIUtility.currentViewWidth / 2)))
  342. {
  343. Undo.RecordObject(target, "Add Custom Duration");
  344. UIAnimation anim = target as UIAnimation;
  345. UIAnimation.AnimationSection s = GetFrameAnimationSection(section);
  346. s.Duration = anim.AnimationFrames[chosenFrame].Duration;
  347. }
  348. EditorGUILayout.EndHorizontal();
  349. }
  350. #endregion
  351. #endregion
  352. EditorGUILayout.EndFadeGroup();
  353. }
  354. }
  355. }
  356. void DrawEasingParams(string equationName, SerializedProperty easingParams)
  357. {
  358. SerializedProperty property = easingParams.FindPropertyRelative(equationName);
  359. if (property != null)
  360. {
  361. SerializedProperty endProp = property.Copy();
  362. endProp.Next(false);
  363. SerializedProperty c = property.Copy();
  364. c.Next(true);
  365. while (true)
  366. {
  367. EditorGUILayout.PropertyField(c, new GUIContent(c.displayName), true);
  368. c.Next(true);
  369. if (SerializedProperty.EqualContents(c, endProp))
  370. break;
  371. }
  372. }
  373. }
  374. void OnDisable()
  375. {
  376. if (recordingPosition)
  377. {
  378. if (EditorUtility.DisplayDialog("Recording", "You are recording a position, would you like to apply it?", "Apply", "No"))
  379. EndRecording();
  380. else
  381. DiscardRecording();
  382. }
  383. }
  384. UIAnimation.AnimationSection GetFrameAnimationSection(SerializedProperty section)
  385. {
  386. UIAnimation anim = target as UIAnimation;
  387. System.Reflection.PropertyInfo frameListPropInfo = anim.GetType().GetProperty("_AnimationFrames");
  388. IList frameListI = frameListPropInfo.GetValue(anim, null) as IList;
  389. System.Reflection.PropertyInfo sectionProp = frameListPropInfo.PropertyType.GetGenericArguments()[0].GetProperty("_" + section.name);
  390. foreach (var listItem in frameListI)
  391. {
  392. if (frameListI.IndexOf(listItem) == chosenFrame)
  393. {
  394. UIAnimation.AnimationSection s = sectionProp.GetValue(listItem, null) as UIAnimation.AnimationSection;
  395. return s;
  396. }
  397. }
  398. return null;
  399. }
  400. }