CoreEditorDrawers.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using UnityEngine;
  6. using UnityEditor.AnimatedValues;
  7. using UnityEngine.Rendering;
  8. namespace UnityEditor.Rendering
  9. {
  10. /// <summary>display options added to the Foldout</summary>
  11. [Flags]
  12. public enum FoldoutOption
  13. {
  14. /// <summary>No Option</summary>
  15. None = 0,
  16. /// <summary>Foldout will be indented</summary>
  17. Indent = 1 << 0,
  18. /// <summary>Foldout will be boxed</summary>
  19. Boxed = 1 << 2,
  20. /// <summary>Foldout will be inside another foldout</summary>
  21. SubFoldout = 1 << 3,
  22. /// <summary>Remove the space at end of the foldout</summary>
  23. NoSpaceAtEnd = 1 << 4
  24. }
  25. /// <summary>display options added to the Group</summary>
  26. [Flags]
  27. public enum GroupOption
  28. {
  29. /// <summary>No Option</summary>
  30. None = 0,
  31. /// <summary>Group will be indented</summary>
  32. Indent = 1 << 0
  33. }
  34. /// <summary>
  35. /// Utility class to draw inspectors
  36. /// </summary>
  37. /// <typeparam name="TData">Type of class containing data needed to draw inspector</typeparam>
  38. public static class CoreEditorDrawer<TData>
  39. {
  40. /// <summary> Abstraction that have the Draw hability </summary>
  41. public interface IDrawer
  42. {
  43. /// <summary>
  44. /// The draw function
  45. /// </summary>
  46. /// <param name="serializedProperty">The SerializedProperty to draw</param>
  47. /// <param name="owner">The editor handling this draw call</param>
  48. void Draw(TData serializedProperty, Editor owner);
  49. }
  50. /// <summary>Delegate that must say if this is enabled for drawing</summary>
  51. /// <param name="data">The data used</param>
  52. /// <param name="owner">The editor rendering</param>
  53. /// <returns>True if this should be drawn</returns>
  54. public delegate bool Enabler(TData data, Editor owner);
  55. /// <summary>Delegate is called when the foldout state is switched</summary>
  56. /// <param name="data">The data used</param>
  57. /// <param name="owner">The editor rendering</param>
  58. public delegate void SwitchEnabler(TData data, Editor owner);
  59. /// <summary>Delegate that must be used to select sub object for data for drawing</summary>
  60. /// <typeparam name="T2Data">The type of the sub object used for data</typeparam>
  61. /// <param name="data">The data used</param>
  62. /// <param name="owner">The editor rendering</param>
  63. /// <returns>Embeded object that will be used as data source for later draw in this Select</returns>
  64. public delegate T2Data DataSelect<T2Data>(TData data, Editor owner);
  65. /// <summary>Delegate type alternative to IDrawer</summary>
  66. /// <param name="data">The data used</param>
  67. /// <param name="owner">The editor rendering</param>
  68. public delegate void ActionDrawer(TData data, Editor owner);
  69. /// <summary> Equivalent to EditorGUILayout.Space that can be put in a drawer group </summary>
  70. public static readonly IDrawer space = Group((data, owner) => EditorGUILayout.Space());
  71. /// <summary> Use it when IDrawer required but no operation should be done </summary>
  72. public static readonly IDrawer noop = Group((data, owner) => { });
  73. /// <summary>
  74. /// Conditioned drawer that will only be drawn if its enabler function is null or return true
  75. /// </summary>
  76. /// <param name="enabler">Enable the drawing if null or return true</param>
  77. /// <param name="contentDrawers">The content of the group</param>
  78. /// <returns>A IDrawer object</returns>
  79. public static IDrawer Conditional(Enabler enabler, params IDrawer[] contentDrawers)
  80. {
  81. return new ConditionalDrawerInternal(enabler, contentDrawers.Draw);
  82. }
  83. /// <summary>
  84. /// Conditioned drawer that will only be drawn if its enabler function is null or return true
  85. /// </summary>
  86. /// <param name="enabler">Enable the drawing if null or return true</param>
  87. /// <param name="contentDrawers">The content of the group</param>
  88. /// <returns>A IDrawer object</returns>
  89. public static IDrawer Conditional(Enabler enabler, params ActionDrawer[] contentDrawers)
  90. {
  91. return new ConditionalDrawerInternal(enabler, contentDrawers);
  92. }
  93. class ConditionalDrawerInternal : IDrawer
  94. {
  95. ActionDrawer[] actionDrawers { get; set; }
  96. Enabler m_Enabler;
  97. public ConditionalDrawerInternal(Enabler enabler = null, params ActionDrawer[] actionDrawers)
  98. {
  99. this.actionDrawers = actionDrawers;
  100. m_Enabler = enabler;
  101. }
  102. void IDrawer.Draw(TData data, Editor owner)
  103. {
  104. if (m_Enabler != null && !m_Enabler(data, owner))
  105. return;
  106. for (var i = 0; i < actionDrawers.Length; i++)
  107. actionDrawers[i](data, owner);
  108. }
  109. }
  110. internal static IDrawer ConditionalWithAdditionalProperties(Enabler enabler, AnimFloat animation, params IDrawer[] contentDrawers)
  111. {
  112. return new ConditionalDrawerWithAdditionalPropertiesInternal(enabler, animation, contentDrawers.Draw);
  113. }
  114. internal static IDrawer ConditionalWithAdditionalProperties(Enabler enabler, AnimFloat animation, params ActionDrawer[] contentDrawers)
  115. {
  116. return new ConditionalDrawerWithAdditionalPropertiesInternal(enabler, animation, contentDrawers);
  117. }
  118. class ConditionalDrawerWithAdditionalPropertiesInternal : IDrawer
  119. {
  120. ActionDrawer[] m_ActionDrawers { get; set; }
  121. Enabler m_Enabler;
  122. AnimFloat m_Anim;
  123. public ConditionalDrawerWithAdditionalPropertiesInternal(Enabler enabler = null, AnimFloat anim = null, params ActionDrawer[] actionDrawers)
  124. {
  125. m_ActionDrawers = actionDrawers;
  126. m_Enabler = enabler;
  127. m_Anim = anim;
  128. }
  129. void IDrawer.Draw(TData data, Editor owner)
  130. {
  131. if (m_Enabler != null && !m_Enabler(data, owner))
  132. return;
  133. if (m_Anim != null)
  134. CoreEditorUtils.BeginAdditionalPropertiesHighlight(m_Anim);
  135. for (var i = 0; i < m_ActionDrawers.Length; i++)
  136. m_ActionDrawers[i](data, owner);
  137. if (m_Anim != null)
  138. {
  139. CoreEditorUtils.EndAdditionalPropertiesHighlight();
  140. // While the highlight is being changed, force the Repaint of the editor
  141. if (m_Anim.value > 0.0f)
  142. owner.Repaint();
  143. }
  144. }
  145. }
  146. /// <summary>
  147. /// Conditioned drawer that will draw something depending of the return of the switch
  148. /// </summary>
  149. /// <param name="switch">Chose witch drawing to use</param>
  150. /// <param name="drawIfTrue">This will be draw if the <see cref="switch"/> is true</param>
  151. /// <param name="drawIfFalse">This will be draw if the <see cref="switch"/> is false</param>
  152. /// <returns>A IDrawer object</returns>
  153. public static IDrawer TernaryConditional(Enabler @switch, IDrawer drawIfTrue, IDrawer drawIfFalse)
  154. => new TernaryConditionalDrawerInternal(@switch, drawIfTrue.Draw, drawIfFalse.Draw);
  155. /// <summary>
  156. /// Conditioned drawer that will draw something depending of the return of the switch
  157. /// </summary>
  158. /// <param name="switch">Chose witch drawing to use</param>
  159. /// <param name="drawIfTrue">This will be draw if the <see cref="switch"/> is true</param>
  160. /// <param name="drawIfFalse">This will be draw if the <see cref="switch"/> is false</param>
  161. /// <returns>A IDrawer object</returns>
  162. public static IDrawer TernaryConditional(Enabler @switch, ActionDrawer drawIfTrue, ActionDrawer drawIfFalse)
  163. => new TernaryConditionalDrawerInternal(@switch, drawIfTrue, drawIfFalse);
  164. class TernaryConditionalDrawerInternal : IDrawer
  165. {
  166. ActionDrawer drawIfTrue;
  167. ActionDrawer drawIfFalse;
  168. Enabler m_Switch;
  169. public TernaryConditionalDrawerInternal(Enabler @switch, ActionDrawer drawIfTrue, ActionDrawer drawIfFalse)
  170. {
  171. this.drawIfTrue = drawIfTrue;
  172. this.drawIfFalse = drawIfFalse;
  173. m_Switch = @switch;
  174. }
  175. void IDrawer.Draw(TData data, Editor owner)
  176. {
  177. if (m_Switch != null && !m_Switch(data, owner))
  178. drawIfFalse?.Invoke(data, owner);
  179. else
  180. drawIfTrue?.Invoke(data, owner);
  181. }
  182. }
  183. /// <summary>
  184. /// Group of drawing function for inspector.
  185. /// They will be drawn one after the other.
  186. /// </summary>
  187. /// <param name="contentDrawers">The content of the group</param>
  188. /// <returns>A IDrawer object</returns>
  189. public static IDrawer Group(params IDrawer[] contentDrawers)
  190. {
  191. return new GroupDrawerInternal(-1f, null, GroupOption.None, contentDrawers.Draw);
  192. }
  193. /// <summary>
  194. /// Group of drawing function for inspector.
  195. /// They will be drawn one after the other.
  196. /// </summary>
  197. /// <param name="contentDrawers">The content of the group</param>
  198. /// <returns>A IDrawer object</returns>
  199. public static IDrawer Group(params ActionDrawer[] contentDrawers)
  200. {
  201. return new GroupDrawerInternal(-1f, null, GroupOption.None, contentDrawers);
  202. }
  203. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  204. /// <param name="labelWidth">Width used for all labels in the group</param>
  205. /// <param name="contentDrawers">The content of the group</param>
  206. /// <returns>A IDrawer object</returns>
  207. public static IDrawer Group(float labelWidth, params IDrawer[] contentDrawers)
  208. {
  209. return new GroupDrawerInternal(labelWidth, null, GroupOption.None, contentDrawers.Draw);
  210. }
  211. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  212. /// <param name="header">Adds a header on top <see cref="GUIContent"/></param>
  213. /// <param name="contentDrawers">The content of the group</param>
  214. /// <returns>A IDrawer object</returns>
  215. public static IDrawer Group(GUIContent header, params IDrawer[] contentDrawers)
  216. {
  217. return new GroupDrawerInternal(-1f, header, GroupOption.None, contentDrawers.Draw);
  218. }
  219. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  220. /// <param name="labelWidth">Width used for all labels in the group</param>
  221. /// <param name="contentDrawers">The content of the group</param>
  222. /// <returns>A IDrawer object</returns>
  223. public static IDrawer Group(float labelWidth, params ActionDrawer[] contentDrawers)
  224. {
  225. return new GroupDrawerInternal(labelWidth, null, GroupOption.None, contentDrawers);
  226. }
  227. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  228. /// <param name="header">Adds a header on top <see cref="GUIContent"/></param>
  229. /// <param name="contentDrawers">The content of the group</param>
  230. /// <returns>A IDrawer object</returns>
  231. public static IDrawer Group(GUIContent header, params ActionDrawer[] contentDrawers)
  232. {
  233. return new GroupDrawerInternal(-1f, header, GroupOption.None, contentDrawers);
  234. }
  235. /// <summary>
  236. /// Group of drawing function for inspector.
  237. /// They will be drawn one after the other.
  238. /// </summary>
  239. /// <param name="options">Allow to add indentation on this group</param>
  240. /// <param name="contentDrawers">The content of the group</param>
  241. /// <returns>A IDrawer object</returns>
  242. public static IDrawer Group(GroupOption options, params IDrawer[] contentDrawers)
  243. {
  244. return new GroupDrawerInternal(-1f, null, options, contentDrawers.Draw);
  245. }
  246. /// <summary>
  247. /// Group of drawing function for inspector.
  248. /// They will be drawn one after the other.
  249. /// </summary>
  250. /// <param name="options">Allow to add indentation on this group</param>
  251. /// <param name="contentDrawers">The content of the group</param>
  252. /// <returns>A IDrawer object</returns>
  253. public static IDrawer Group(GroupOption options, params ActionDrawer[] contentDrawers)
  254. {
  255. return new GroupDrawerInternal(-1f, null, options, contentDrawers);
  256. }
  257. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  258. /// <param name="labelWidth">Width used for all labels in the group</param>
  259. /// <param name="options">Allow to add indentation on this group</param>
  260. /// <param name="contentDrawers">The content of the group</param>
  261. /// <returns>A IDrawer object</returns>
  262. public static IDrawer Group(float labelWidth, GroupOption options, params IDrawer[] contentDrawers)
  263. {
  264. return new GroupDrawerInternal(labelWidth, null, options, contentDrawers.Draw);
  265. }
  266. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  267. /// <param name="header">Adds a header on top <see cref="GUIContent"/></param>
  268. /// <param name="options">Allow to add indentation on this group</param>
  269. /// <param name="contentDrawers">The content of the group</param>
  270. /// <returns>A IDrawer object</returns>
  271. public static IDrawer Group(GUIContent header, GroupOption options, params IDrawer[] contentDrawers)
  272. {
  273. return new GroupDrawerInternal(-1f, header, options, contentDrawers.Draw);
  274. }
  275. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  276. /// <param name="labelWidth">Width used for all labels in the group</param>
  277. /// <param name="options">Allow to add indentation on this group</param>
  278. /// <param name="contentDrawers">The content of the group</param>
  279. /// <returns>A IDrawer object</returns>
  280. public static IDrawer Group(float labelWidth, GroupOption options, params ActionDrawer[] contentDrawers)
  281. {
  282. return new GroupDrawerInternal(labelWidth, null, options, contentDrawers);
  283. }
  284. /// <summary> Group of drawing function for inspector with a set width for labels </summary>
  285. /// <param name="header">Adds a header on top <see cref="GUIContent"/></param>
  286. /// <param name="options">Allow to add indentation on this group</param>
  287. /// <param name="contentDrawers">The content of the group</param>
  288. /// <returns>A IDrawer object</returns>
  289. public static IDrawer Group(GUIContent header, GroupOption options, params ActionDrawer[] contentDrawers)
  290. {
  291. return new GroupDrawerInternal(-1, header, options, contentDrawers);
  292. }
  293. class GroupDrawerInternal : IDrawer
  294. {
  295. ActionDrawer[] actionDrawers { get; set; }
  296. GUIContent header { get; }
  297. float m_LabelWidth;
  298. bool isIndented;
  299. public GroupDrawerInternal(float labelWidth = -1f, GUIContent header = null, GroupOption options = GroupOption.None, params ActionDrawer[] actionDrawers)
  300. {
  301. this.actionDrawers = actionDrawers;
  302. this.header = header;
  303. m_LabelWidth = labelWidth;
  304. isIndented = (options & GroupOption.Indent) != 0;
  305. }
  306. void IDrawer.Draw(TData data, Editor owner)
  307. {
  308. if (isIndented)
  309. ++EditorGUI.indentLevel;
  310. var currentLabelWidth = EditorGUIUtility.labelWidth;
  311. if (m_LabelWidth >= 0f)
  312. {
  313. EditorGUIUtility.labelWidth = m_LabelWidth;
  314. }
  315. if (header != null)
  316. EditorGUILayout.LabelField(header, EditorStyles.boldLabel);
  317. for (var i = 0; i < actionDrawers.Length; i++)
  318. actionDrawers[i](data, owner);
  319. if (m_LabelWidth >= 0f)
  320. {
  321. EditorGUIUtility.labelWidth = currentLabelWidth;
  322. }
  323. if (isIndented)
  324. --EditorGUI.indentLevel;
  325. }
  326. }
  327. class FoldoutGroupDrawerInternal<TEnum, TState> : IDrawer
  328. where TEnum : struct, IConvertible
  329. {
  330. readonly ActionDrawer[] m_ActionDrawers;
  331. readonly bool m_IsBoxed;
  332. readonly bool m_IsSubFoldout;
  333. readonly bool m_NoSpaceAtEnd;
  334. readonly bool m_IsIndented;
  335. readonly GUIContent m_Title;
  336. readonly string m_HelpUrl;
  337. ExpandedState<TEnum, TState> m_State;
  338. readonly TEnum m_Mask;
  339. readonly Enabler m_Enabler;
  340. readonly SwitchEnabler m_SwitchEnabler;
  341. public FoldoutGroupDrawerInternal(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state,
  342. Enabler enabler, SwitchEnabler switchEnabler, FoldoutOption options = FoldoutOption.None, params ActionDrawer[] actionDrawers)
  343. {
  344. m_IsBoxed = (options & FoldoutOption.Boxed) != 0;
  345. m_IsIndented = (options & FoldoutOption.Indent) != 0;
  346. m_IsSubFoldout = (options & FoldoutOption.SubFoldout) != 0;
  347. m_NoSpaceAtEnd = (options & FoldoutOption.NoSpaceAtEnd) != 0;
  348. m_ActionDrawers = actionDrawers;
  349. m_Title = title;
  350. m_State = state;
  351. m_Mask = mask;
  352. m_HelpUrl = DocumentationUtils.GetHelpURL<TEnum>(mask);
  353. m_Enabler = enabler;
  354. m_SwitchEnabler = switchEnabler;
  355. }
  356. void IDrawer.Draw(TData data, Editor owner)
  357. {
  358. bool expended = m_State[m_Mask];
  359. bool newExpended;
  360. if (m_IsSubFoldout)
  361. {
  362. newExpended = CoreEditorUtils.DrawSubHeaderFoldout(m_Title, expended, m_IsBoxed);
  363. }
  364. else
  365. {
  366. CoreEditorUtils.DrawSplitter(m_IsBoxed);
  367. newExpended = CoreEditorUtils.DrawHeaderFoldout(m_Title,
  368. expended,
  369. m_IsBoxed,
  370. m_Enabler == null ? (Func<bool>)null : () => m_Enabler(data, owner),
  371. m_SwitchEnabler == null ? (Action)null : () => m_SwitchEnabler(data, owner),
  372. m_HelpUrl);
  373. }
  374. if (newExpended ^ expended)
  375. m_State[m_Mask] = newExpended;
  376. if (!newExpended)
  377. return;
  378. if (m_IsIndented)
  379. ++EditorGUI.indentLevel;
  380. for (var i = 0; i < m_ActionDrawers.Length; i++)
  381. m_ActionDrawers[i](data, owner);
  382. if (m_IsIndented)
  383. --EditorGUI.indentLevel;
  384. if (!m_NoSpaceAtEnd)
  385. EditorGUILayout.Space();
  386. }
  387. }
  388. /// <summary> Create an IDrawer based on an other data container </summary>
  389. /// <typeparam name="T2Data">Type of selected object containing in the given data containing data needed to draw inspector</typeparam>
  390. /// <param name="dataSelect">The data new source for the inner drawers</param>
  391. /// <param name="otherDrawers">Inner drawers drawed with given data sources</param>
  392. /// <returns>A IDrawer object</returns>
  393. public static IDrawer Select<T2Data>(
  394. DataSelect<T2Data> dataSelect,
  395. params CoreEditorDrawer<T2Data>.IDrawer[] otherDrawers)
  396. {
  397. return new SelectDrawerInternal<T2Data>(dataSelect, otherDrawers.Draw);
  398. }
  399. /// <summary> Create an IDrawer based on an other data container </summary>
  400. /// <typeparam name="T2Data">Type of selected object containing in the given data containing data needed to draw inspector</typeparam>
  401. /// <param name="dataSelect">The data new source for the inner drawers</param>
  402. /// <param name="otherDrawers">Inner drawers drawed with given data sources</param>
  403. /// <returns>A IDrawer object</returns>
  404. public static IDrawer Select<T2Data>(
  405. DataSelect<T2Data> dataSelect,
  406. params CoreEditorDrawer<T2Data>.ActionDrawer[] otherDrawers)
  407. {
  408. return new SelectDrawerInternal<T2Data>(dataSelect, otherDrawers);
  409. }
  410. class SelectDrawerInternal<T2Data> : IDrawer
  411. {
  412. DataSelect<T2Data> m_DataSelect;
  413. CoreEditorDrawer<T2Data>.ActionDrawer[] m_SourceDrawers;
  414. public SelectDrawerInternal(DataSelect<T2Data> dataSelect,
  415. params CoreEditorDrawer<T2Data>.ActionDrawer[] otherDrawers)
  416. {
  417. m_SourceDrawers = otherDrawers;
  418. m_DataSelect = dataSelect;
  419. }
  420. void IDrawer.Draw(TData data, Editor o)
  421. {
  422. var p2 = m_DataSelect(data, o);
  423. for (var i = 0; i < m_SourceDrawers.Length; i++)
  424. m_SourceDrawers[i](p2, o);
  425. }
  426. }
  427. /// <summary>
  428. /// Create an IDrawer foldout header using an ExpandedState.
  429. /// The default option is Indent in this version.
  430. /// </summary>
  431. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  432. /// <typeparam name="TState">Type of the persistent state</typeparam>
  433. /// <param name="title">Title wanted for this foldout header</param>
  434. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  435. /// <param name="state">The ExpandedState describing the component</param>
  436. /// <param name="contentDrawers">The content of the foldout header</param>
  437. /// <returns>A IDrawer object</returns>
  438. public static IDrawer FoldoutGroup<TEnum, TState>(string title, TEnum mask, ExpandedState<TEnum, TState> state, params IDrawer[] contentDrawers)
  439. where TEnum : struct, IConvertible
  440. {
  441. return FoldoutGroup(title, mask, state, contentDrawers.Draw);
  442. }
  443. /// <summary>
  444. /// Create an IDrawer foldout header using an ExpandedState.
  445. /// The default option is Indent in this version.
  446. /// </summary>
  447. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  448. /// <typeparam name="TState">Type of the persistent state</typeparam>
  449. /// <param name="title">Title wanted for this foldout header</param>
  450. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  451. /// <param name="state">The ExpandedState describing the component</param>
  452. /// <param name="contentDrawers">The content of the foldout header</param>
  453. /// <returns>A IDrawer object</returns>
  454. public static IDrawer FoldoutGroup<TEnum, TState>(string title, TEnum mask, ExpandedState<TEnum, TState> state, params ActionDrawer[] contentDrawers)
  455. where TEnum : struct, IConvertible
  456. {
  457. return FoldoutGroup(EditorGUIUtility.TrTextContent(title), mask, state, contentDrawers);
  458. }
  459. /// <summary> Create an IDrawer foldout header using an ExpandedState </summary>
  460. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  461. /// <typeparam name="TState">Type of the persistent state</typeparam>
  462. /// <param name="title">Title wanted for this foldout header</param>
  463. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  464. /// <param name="state">The ExpandedState describing the component</param>
  465. /// <param name="options">Drawing options</param>
  466. /// <param name="contentDrawers">The content of the foldout header</param>
  467. /// <returns>A IDrawer object</returns>
  468. public static IDrawer FoldoutGroup<TEnum, TState>(string title, TEnum mask, ExpandedState<TEnum, TState> state, FoldoutOption options, params IDrawer[] contentDrawers)
  469. where TEnum : struct, IConvertible
  470. {
  471. return FoldoutGroup(title, mask, state, options, contentDrawers.Draw);
  472. }
  473. /// <summary> Create an IDrawer foldout header using an ExpandedState </summary>
  474. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  475. /// <typeparam name="TState">Type of the persistent state</typeparam>
  476. /// <param name="title">Title wanted for this foldout header</param>
  477. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  478. /// <param name="state">The ExpandedState describing the component</param>
  479. /// <param name="options">Drawing options</param>
  480. /// <param name="contentDrawers">The content of the foldout header</param>
  481. /// <returns>A IDrawer object</returns>
  482. public static IDrawer FoldoutGroup<TEnum, TState>(string title, TEnum mask, ExpandedState<TEnum, TState> state, FoldoutOption options, params ActionDrawer[] contentDrawers)
  483. where TEnum : struct, IConvertible
  484. {
  485. return FoldoutGroup(EditorGUIUtility.TrTextContent(title), mask, state, options, contentDrawers);
  486. }
  487. /// <summary>
  488. /// Create an IDrawer foldout header using an ExpandedState.
  489. /// The default option is Indent in this version.
  490. /// </summary>
  491. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  492. /// <typeparam name="TState">Type of the persistent state</typeparam>
  493. /// <param name="title">Title wanted for this foldout header</param>
  494. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  495. /// <param name="state">The ExpandedState describing the component</param>
  496. /// <param name="contentDrawers">The content of the foldout header</param>
  497. /// <returns>A IDrawer object</returns>
  498. public static IDrawer FoldoutGroup<TEnum, TState>(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state, params IDrawer[] contentDrawers)
  499. where TEnum : struct, IConvertible
  500. {
  501. return FoldoutGroup(title, mask, state, contentDrawers.Draw);
  502. }
  503. /// <summary>
  504. /// Create an IDrawer foldout header using an ExpandedState.
  505. /// The default option is Indent in this version.
  506. /// </summary>
  507. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  508. /// <typeparam name="TState">Type of the persistent state</typeparam>
  509. /// <param name="title">Title wanted for this foldout header</param>
  510. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  511. /// <param name="state">The ExpandedState describing the component</param>
  512. /// <param name="contentDrawers">The content of the foldout header</param>
  513. /// <returns>A IDrawer object</returns>
  514. public static IDrawer FoldoutGroup<TEnum, TState>(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state, params ActionDrawer[] contentDrawers)
  515. where TEnum : struct, IConvertible
  516. {
  517. return FoldoutGroup(title, mask, state, FoldoutOption.Indent, contentDrawers);
  518. }
  519. /// <summary> Create an IDrawer foldout header using an ExpandedState </summary>
  520. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  521. /// <typeparam name="TState">Type of the persistent state</typeparam>
  522. /// <param name="title">Title wanted for this foldout header</param>
  523. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  524. /// <param name="state">The ExpandedState describing the component</param>
  525. /// <param name="options">Drawing options</param>
  526. /// <param name="contentDrawers">The content of the foldout header</param>
  527. /// <returns>A IDrawer object</returns>
  528. public static IDrawer FoldoutGroup<TEnum, TState>(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state, FoldoutOption options, params IDrawer[] contentDrawers)
  529. where TEnum : struct, IConvertible
  530. {
  531. return FoldoutGroup(title, mask, state, options, contentDrawers.Draw);
  532. }
  533. /// <summary> Create an IDrawer foldout header using an ExpandedState </summary>
  534. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  535. /// <typeparam name="TState">Type of the persistent state</typeparam>
  536. /// <param name="title">Title wanted for this foldout header</param>
  537. /// <param name="mask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  538. /// <param name="state">The ExpandedState describing the component</param>
  539. /// <param name="options">Drawing options</param>
  540. /// <param name="contentDrawers">The content of the foldout header</param>
  541. /// <returns>A IDrawer object</returns>
  542. public static IDrawer FoldoutGroup<TEnum, TState>(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state, FoldoutOption options, params ActionDrawer[] contentDrawers)
  543. where TEnum : struct, IConvertible
  544. {
  545. return FoldoutGroup(title, mask, state, options, null, null, contentDrawers);
  546. }
  547. // This one is private as we do not want to have unhandled advanced switch. Change it if necessary.
  548. static IDrawer FoldoutGroup<TEnum, TState>(GUIContent title, TEnum mask, ExpandedState<TEnum, TState> state, FoldoutOption options, Enabler showAdditionalProperties, SwitchEnabler switchAdditionalProperties, params ActionDrawer[] contentDrawers)
  549. where TEnum : struct, IConvertible
  550. {
  551. return new FoldoutGroupDrawerInternal<TEnum, TState>(title, mask, state, showAdditionalProperties, switchAdditionalProperties, options, contentDrawers);
  552. }
  553. /// <summary> Helper to draw a foldout with an advanced switch on it. </summary>
  554. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  555. /// <typeparam name="TState">Type of the persistent state</typeparam>
  556. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  557. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  558. /// <param name="foldoutState">The ExpandedState describing the component</param>
  559. /// <param name="isAdvanced"> Delegate allowing to check if advanced mode is active. </param>
  560. /// <param name="switchAdvanced"> Delegate to know what to do when advance is switched. </param>
  561. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  562. /// <param name="advancedContent"> The content of the foldout header only visible if advanced mode is active and if foldout is expended. </param>
  563. /// <param name="options">Drawing options</param>
  564. /// <returns>A IDrawer object</returns>
  565. [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")]
  566. public static IDrawer AdvancedFoldoutGroup<TEnum, TState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, IDrawer normalContent, IDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent)
  567. where TEnum : struct, IConvertible
  568. {
  569. return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent.Draw, advancedContent.Draw, options);
  570. }
  571. /// <summary> Helper to draw a foldout with an advanced switch on it. </summary>
  572. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  573. /// <typeparam name="TState">Type of the persistent state</typeparam>
  574. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  575. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  576. /// <param name="foldoutState">The ExpandedState describing the component</param>
  577. /// <param name="isAdvanced"> Delegate allowing to check if advanced mode is active. </param>
  578. /// <param name="switchAdvanced"> Delegate to know what to do when advance is switched. </param>
  579. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  580. /// <param name="advancedContent"> The content of the foldout header only visible if advanced mode is active and if foldout is expended. </param>
  581. /// <param name="options">Drawing options</param>
  582. /// <returns>A IDrawer object</returns>
  583. [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")]
  584. public static IDrawer AdvancedFoldoutGroup<TEnum, TState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, ActionDrawer normalContent, IDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent)
  585. where TEnum : struct, IConvertible
  586. {
  587. return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent, advancedContent.Draw, options);
  588. }
  589. /// <summary> Helper to draw a foldout with an advanced switch on it. </summary>
  590. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  591. /// <typeparam name="TState">Type of the persistent state</typeparam>
  592. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  593. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  594. /// <param name="foldoutState">The ExpandedState describing the component</param>
  595. /// <param name="isAdvanced"> Delegate allowing to check if advanced mode is active. </param>
  596. /// <param name="switchAdvanced"> Delegate to know what to do when advance is switched. </param>
  597. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  598. /// <param name="advancedContent"> The content of the foldout header only visible if advanced mode is active and if foldout is expended. </param>
  599. /// <param name="options">Drawing options</param>
  600. /// <returns>A IDrawer object</returns>
  601. [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")]
  602. public static IDrawer AdvancedFoldoutGroup<TEnum, TState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, IDrawer normalContent, ActionDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent)
  603. where TEnum : struct, IConvertible
  604. {
  605. return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent.Draw, advancedContent, options);
  606. }
  607. /// <summary> Helper to draw a foldout with an advanced switch on it. </summary>
  608. /// <typeparam name="TEnum">Type of the mask used</typeparam>
  609. /// <typeparam name="TState">Type of the persistent state</typeparam>
  610. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  611. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  612. /// <param name="foldoutState">The ExpandedState describing the component</param>
  613. /// <param name="isAdvanced"> Delegate allowing to check if advanced mode is active. </param>
  614. /// <param name="switchAdvanced"> Delegate to know what to do when advance is switched. </param>
  615. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  616. /// <param name="advancedContent"> The content of the foldout header only visible if advanced mode is active and if foldout is expended. </param>
  617. /// <param name="options">Drawing options</param>
  618. /// <returns>A IDrawer object</returns>
  619. [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")]
  620. public static IDrawer AdvancedFoldoutGroup<TEnum, TState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, ActionDrawer normalContent, ActionDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent)
  621. where TEnum : struct, IConvertible
  622. {
  623. return FoldoutGroup(foldoutTitle, foldoutMask, foldoutState, options, isAdvanced, switchAdvanced, normalContent,
  624. Conditional((serialized, owner) => isAdvanced(serialized, owner) && foldoutState[foldoutMask], advancedContent).Draw);
  625. }
  626. /// <summary>
  627. /// Helper to draw a foldout with additional properties.
  628. /// </summary>
  629. /// <typeparam name="TEnum">Type of the foldout mask used.</typeparam>
  630. /// <typeparam name="TState">Type of the persistent foldout state.</typeparam>
  631. /// <typeparam name="TAPEnum">Type of the additional properties mask used.</typeparam>
  632. /// <typeparam name="TAPState">Type of the persistent additional properties state.</typeparam>
  633. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  634. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  635. /// <param name="foldoutState">The ExpandedState describing the component</param>
  636. /// <param name="additionalPropertiesMask">Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState</param>
  637. /// <param name="additionalPropertiesState">The AdditionalPropertiesState describing the component</param>
  638. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  639. /// <param name="additionalContent">The content of the foldout header only visible if additional properties are shown and if foldout is expanded.</param>
  640. /// <param name="options">Drawing options</param>
  641. /// <returns>A IDrawer object</returns>
  642. public static IDrawer AdditionalPropertiesFoldoutGroup<TEnum, TState, TAPEnum, TAPState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState,
  643. TAPEnum additionalPropertiesMask, AdditionalPropertiesState<TAPEnum, TAPState> additionalPropertiesState, IDrawer normalContent, IDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent)
  644. where TEnum : struct, IConvertible
  645. where TAPEnum : struct, IConvertible
  646. {
  647. return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent.Draw, additionalContent.Draw, options);
  648. }
  649. /// <summary>
  650. /// Helper to draw a foldout with additional properties.
  651. /// </summary>
  652. /// <typeparam name="TEnum">Type of the foldout mask used.</typeparam>
  653. /// <typeparam name="TState">Type of the persistent foldout state.</typeparam>
  654. /// <typeparam name="TAPEnum">Type of the additional properties mask used.</typeparam>
  655. /// <typeparam name="TAPState">Type of the persistent additional properties state.</typeparam>
  656. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  657. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  658. /// <param name="foldoutState">The ExpandedState describing the component</param>
  659. /// <param name="additionalPropertiesMask">Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState</param>
  660. /// <param name="additionalPropertiesState">The AdditionalPropertiesState describing the component</param>
  661. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  662. /// <param name="additionalContent">The content of the foldout header only visible if additional properties are shown and if foldout is expanded.</param>
  663. /// <param name="options">Drawing options</param>
  664. /// <returns>A IDrawer object</returns>
  665. public static IDrawer AdditionalPropertiesFoldoutGroup<TEnum, TState, TAPEnum, TAPState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState,
  666. TAPEnum additionalPropertiesMask, AdditionalPropertiesState<TAPEnum, TAPState> additionalPropertiesState, ActionDrawer normalContent, IDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent)
  667. where TEnum : struct, IConvertible
  668. where TAPEnum : struct, IConvertible
  669. {
  670. return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent, additionalContent.Draw, options);
  671. }
  672. /// <summary>
  673. /// Helper to draw a foldout with additional properties.
  674. /// </summary>
  675. /// <typeparam name="TEnum">Type of the foldout mask used.</typeparam>
  676. /// <typeparam name="TState">Type of the persistent foldout state.</typeparam>
  677. /// <typeparam name="TAPEnum">Type of the additional properties mask used.</typeparam>
  678. /// <typeparam name="TAPState">Type of the persistent additional properties state.</typeparam>
  679. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  680. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  681. /// <param name="foldoutState">The ExpandedState describing the component</param>
  682. /// <param name="additionalPropertiesMask">Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState</param>
  683. /// <param name="additionalPropertiesState">The AdditionalPropertiesState describing the component</param>
  684. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  685. /// <param name="additionalContent">The content of the foldout header only visible if additional properties are shown and if foldout is expanded.</param>
  686. /// <param name="options">Drawing options</param>
  687. /// <returns>A IDrawer object</returns>
  688. public static IDrawer AdditionalPropertiesFoldoutGroup<TEnum, TState, TAPEnum, TAPState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState,
  689. TAPEnum additionalPropertiesMask, AdditionalPropertiesState<TAPEnum, TAPState> additionalPropertiesState, IDrawer normalContent, ActionDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent)
  690. where TEnum : struct, IConvertible
  691. where TAPEnum : struct, IConvertible
  692. {
  693. return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent.Draw, additionalContent, options);
  694. }
  695. /// <summary>
  696. /// Helper to draw a foldout with additional properties.
  697. /// </summary>
  698. /// <typeparam name="TEnum">Type of the foldout mask used.</typeparam>
  699. /// <typeparam name="TState">Type of the persistent foldout state.</typeparam>
  700. /// <typeparam name="TAPEnum">Type of the additional properties mask used.</typeparam>
  701. /// <typeparam name="TAPState">Type of the persistent additional properties state.</typeparam>
  702. /// <param name="foldoutTitle">Title wanted for this foldout header</param>
  703. /// <param name="foldoutMask">Bit mask (enum) used to define the boolean saving the state in ExpandedState</param>
  704. /// <param name="foldoutState">The ExpandedState describing the component</param>
  705. /// <param name="additionalPropertiesMask">Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState</param>
  706. /// <param name="additionalPropertiesState">The AdditionalPropertiesState describing the component</param>
  707. /// <param name="normalContent"> The content of the foldout header always visible if expended. </param>
  708. /// <param name="additionalContent">The content of the foldout header only visible if additional properties are shown and if foldout is expanded.</param>
  709. /// <param name="options">Drawing options</param>
  710. /// <returns>A IDrawer object</returns>
  711. public static IDrawer AdditionalPropertiesFoldoutGroup<TEnum, TState, TAPEnum, TAPState>(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState<TEnum, TState> foldoutState,
  712. TAPEnum additionalPropertiesMask, AdditionalPropertiesState<TAPEnum, TAPState> additionalPropertiesState, ActionDrawer normalContent, ActionDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent)
  713. where TEnum : struct, IConvertible
  714. where TAPEnum : struct, IConvertible
  715. {
  716. bool Enabler(TData data, Editor owner)
  717. {
  718. return additionalPropertiesState[additionalPropertiesMask];
  719. }
  720. void SwitchEnabler(TData data, Editor owner)
  721. {
  722. additionalPropertiesState[additionalPropertiesMask] = !additionalPropertiesState[additionalPropertiesMask];
  723. }
  724. return FoldoutGroup(foldoutTitle, foldoutMask, foldoutState, options, Enabler, SwitchEnabler,
  725. normalContent,
  726. ConditionalWithAdditionalProperties((serialized, owner) => additionalPropertiesState[additionalPropertiesMask] && foldoutState[foldoutMask], additionalPropertiesState.GetAnimation(additionalPropertiesMask), additionalContent).Draw
  727. );
  728. }
  729. }
  730. /// <summary>CoreEditorDrawer extensions</summary>
  731. public static class CoreEditorDrawersExtensions
  732. {
  733. /// <summary> Concatenate a collection of IDrawer as a unique IDrawer </summary>
  734. /// <typeparam name="TData">Type of class containing data needed to draw inspector</typeparam>
  735. /// <param name="drawers">A collection of IDrawers</param>
  736. /// <param name="data">The data source for the inner drawers</param>
  737. /// <param name="owner">The editor drawing</param>
  738. public static void Draw<TData>(this IEnumerable<CoreEditorDrawer<TData>.IDrawer> drawers, TData data, Editor owner)
  739. {
  740. EditorGUILayout.BeginVertical();
  741. foreach (var drawer in drawers)
  742. drawer.Draw(data, owner);
  743. EditorGUILayout.EndVertical();
  744. }
  745. }
  746. }