EditorGUIUtils.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. Copyright (c) 2020 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2020.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using UnityEngine;
  14. namespace PluginMaster
  15. {
  16. public static class EditorGUIUtils
  17. {
  18. #region LAYER MASK FIELD
  19. public static LayerMask FieldToLayerMask(int field)
  20. {
  21. LayerMask mask = 0;
  22. var layers = UnityEditorInternal.InternalEditorUtility.layers;
  23. for (int layerIdx = 0; layerIdx < layers.Length; layerIdx++)
  24. {
  25. if ((field & (1 << layerIdx)) == 0) continue;
  26. mask |= 1 << LayerMask.NameToLayer(layers[layerIdx]);
  27. }
  28. return mask;
  29. }
  30. public static int LayerMaskToField(LayerMask mask)
  31. {
  32. int field = 0;
  33. var layers = UnityEditorInternal.InternalEditorUtility.layers;
  34. for (int layerIdx = 0; layerIdx < layers.Length; layerIdx++)
  35. {
  36. if ((mask & (1 << LayerMask.NameToLayer(layers[layerIdx]))) == 0) continue;
  37. field |= 1 << layerIdx;
  38. }
  39. return field;
  40. }
  41. #endregion
  42. #region CUSTOM FIELDS
  43. #region AXIS FIELD
  44. private static Vector3[] directions =
  45. {
  46. Vector3.right, Vector3.left,
  47. Vector3.up, Vector3.down,
  48. Vector3.forward, Vector3.back
  49. };
  50. private static string[] directionNames =
  51. {
  52. "+X", "-X",
  53. "+Y", "-Y",
  54. "+Z", "-Z"
  55. };
  56. public static Vector3 AxisField(string label, Vector3 value)
  57. {
  58. int selectedIndex = System.Array.IndexOf(directions, value);
  59. selectedIndex = UnityEditor.EditorGUILayout.Popup(label, selectedIndex, directionNames);
  60. return directions[selectedIndex];
  61. }
  62. #endregion
  63. #region RANGE FIELD
  64. public static RandomUtils.Range RangeField(string label, RandomUtils.Range value)
  65. {
  66. var result = new RandomUtils.Range();
  67. using (new GUILayout.HorizontalScope())
  68. {
  69. if (label != string.Empty) GUILayout.Label(label);
  70. var prevLabelW = UnityEditor.EditorGUIUtility.labelWidth;
  71. UnityEditor.EditorGUIUtility.labelWidth = 30;
  72. GUILayout.Label("Between:");
  73. result.v1 = UnityEditor.EditorGUILayout.FloatField(value.v1);
  74. result.v2 = UnityEditor.EditorGUILayout.FloatField(value.v2);
  75. UnityEditor.EditorGUIUtility.labelWidth = prevLabelW;
  76. }
  77. return result;
  78. }
  79. public static RandomUtils.Range3 Range3Field(string label, RandomUtils.Range3 value)
  80. {
  81. var result = new RandomUtils.Range3(value);
  82. using (new GUILayout.VerticalScope())
  83. {
  84. if (label != string.Empty) GUILayout.Label(label);
  85. GUILayout.Label("Between:");
  86. result.v1 = UnityEditor.EditorGUILayout.Vector3Field(string.Empty, value.v1);
  87. result.v2 = UnityEditor.EditorGUILayout.Vector3Field(string.Empty, value.v2);
  88. }
  89. return result;
  90. }
  91. #endregion
  92. #region MULTITAG FIELD
  93. public class MultiTagField
  94. {
  95. private const string NOTHING = "Nothing";
  96. private const string EVERYTHING = "Everything";
  97. private const string MIXED = "Mixed ...";
  98. private string _label = null;
  99. private System.Collections.Generic.List<string> _tags = null;
  100. private string _key = null;
  101. public System.Action<System.Collections.Generic.List<string>,
  102. System.Collections.Generic.List<string>, string> OnChange;
  103. private MultiTagField(string label, System.Collections.Generic.List<string> tags, string key)
  104. => (_label, _tags, _key) = (label, tags, key);
  105. private void SelectTag(object obj)
  106. {
  107. var originalList = new System.Collections.Generic.List<string>(_tags);
  108. var originalSet = new System.Collections.Generic.HashSet<string>(_tags);
  109. void CheckChange()
  110. {
  111. var newSet = new System.Collections.Generic.HashSet<string>(_tags);
  112. if (!originalSet.SetEquals(newSet)) OnChange(originalList, _tags, _key);
  113. }
  114. var tag = (string)obj;
  115. if (tag == NOTHING)
  116. {
  117. _tags.Clear();
  118. CheckChange();
  119. return;
  120. }
  121. if (tag == EVERYTHING)
  122. {
  123. _tags.Clear();
  124. _tags.AddRange(UnityEditorInternal.InternalEditorUtility.tags);
  125. CheckChange();
  126. return;
  127. }
  128. if (_tags.Contains(tag)) _tags.Remove(tag);
  129. else _tags.Add(tag);
  130. CheckChange();
  131. }
  132. private void Show()
  133. {
  134. var allTags = UnityEditorInternal.InternalEditorUtility.tags;
  135. var text = _tags.Count == 0
  136. ? NOTHING
  137. : _tags.Count == allTags.Length
  138. ? EVERYTHING
  139. : _tags.Count > 1 ? MIXED : _tags[0];
  140. using (new GUILayout.HorizontalScope())
  141. {
  142. if (_label != null && _label != string.Empty)
  143. GUILayout.Label(_label, GUILayout.Width(UnityEditor.EditorGUIUtility.labelWidth));
  144. if (GUILayout.Button(text, UnityEditor.EditorStyles.popup,
  145. GUILayout.MinWidth(UnityEditor.EditorGUIUtility.fieldWidth)))
  146. {
  147. var menu = new UnityEditor.GenericMenu();
  148. menu.AddItem(new GUIContent(NOTHING), false, SelectTag, NOTHING);
  149. menu.AddItem(new GUIContent(EVERYTHING), false, SelectTag, EVERYTHING);
  150. foreach (var tag in UnityEditorInternal.InternalEditorUtility.tags)
  151. menu.AddItem(new GUIContent(tag), _tags.Contains(tag), SelectTag, tag);
  152. menu.ShowAsContext();
  153. }
  154. }
  155. }
  156. public static MultiTagField Instantiate(string label, System.Collections.Generic.List<string> tags, string key)
  157. {
  158. var field = new MultiTagField(label, tags, key);
  159. field.Show();
  160. return field;
  161. }
  162. }
  163. #endregion
  164. #region OBJECT ARRAY FIELD
  165. public static OBJ_TYPE[] ObjectArrayField<OBJ_TYPE>(string label, OBJ_TYPE[] objArray, ref bool foldout)
  166. where OBJ_TYPE : UnityEngine.Object
  167. {
  168. var size = objArray == null ? 0 : objArray.Length;
  169. OBJ_TYPE[] result = objArray;
  170. foldout = UnityEditor.EditorGUILayout.BeginFoldoutHeaderGroup(foldout, label);
  171. if (!foldout) return result;
  172. using (new GUILayout.HorizontalScope())
  173. {
  174. GUILayout.Space(20);
  175. using (new GUILayout.VerticalScope())
  176. {
  177. UnityEditor.EditorGUIUtility.labelWidth = 40;
  178. size = Mathf.Clamp(UnityEditor.EditorGUILayout.IntField("Size:", size), 0, 10);
  179. result = new OBJ_TYPE[size];
  180. for (int i = 0; i < size; ++i)
  181. {
  182. var obj = i < objArray.Length ? objArray[i] : null;
  183. result[i] = (OBJ_TYPE)UnityEditor.EditorGUILayout.ObjectField(obj, typeof(OBJ_TYPE), true);
  184. }
  185. }
  186. }
  187. UnityEditor.EditorGUILayout.EndFoldoutHeaderGroup();
  188. return result;
  189. }
  190. #endregion
  191. #region OBJECT ARRAY FIELD WITH BUTTONS
  192. public static OBJ_TYPE[] ObjectArrayFieldWithButtons<OBJ_TYPE>(string label, OBJ_TYPE[] objArray,
  193. ref bool foldout, out bool changed)
  194. where OBJ_TYPE : UnityEngine.Object
  195. {
  196. var result = new System.Collections.Generic.List<OBJ_TYPE>();
  197. int removeIdx = -1;
  198. foldout = UnityEditor.EditorGUILayout.BeginFoldoutHeaderGroup(foldout, label);
  199. changed = false;
  200. if (!foldout) return objArray;
  201. using (new GUILayout.HorizontalScope())
  202. {
  203. GUILayout.Space(20);
  204. using (new GUILayout.VerticalScope())
  205. {
  206. if (objArray != null)
  207. {
  208. foreach (var obj in objArray)
  209. {
  210. using (new GUILayout.HorizontalScope())
  211. {
  212. using (var check = new UnityEditor.EditorGUI.ChangeCheckScope())
  213. {
  214. result.Add((OBJ_TYPE)UnityEditor.EditorGUILayout.ObjectField(obj,
  215. typeof(OBJ_TYPE), true));
  216. if(check.changed) changed = true;
  217. }
  218. if (GUILayout.Button("Remove", GUILayout.Width(70)))
  219. {
  220. removeIdx = result.Count - 1;
  221. changed = true;
  222. }
  223. }
  224. }
  225. }
  226. using (new GUILayout.HorizontalScope())
  227. {
  228. GUILayout.FlexibleSpace();
  229. if (GUILayout.Button("Add", GUILayout.Width(70)))
  230. {
  231. result.Add(null);
  232. changed = true;
  233. }
  234. }
  235. }
  236. }
  237. UnityEditor.EditorGUILayout.EndFoldoutHeaderGroup();
  238. if (removeIdx >= 0) result.RemoveAt(removeIdx);
  239. return result.ToArray();
  240. }
  241. #endregion
  242. #endregion
  243. }
  244. }