PageRenderTime 71ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Library/PackageCache/com.unity.shadergraph@7.5.3/Editor/Drawing/Blackboard/BlackboardFieldKeywordView.cs

https://gitlab.com/hieplv.amgame/c0lor-blocks
C# | 285 lines | 223 code | 42 blank | 20 comment | 17 complexity | 8e90589ae49fe44d9ea0b8ff5444db24 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using System.Globalization;
  6. using UnityEditor.Graphing;
  7. using UnityEditor.Graphing.Util;
  8. using UnityEngine;
  9. using UnityEditor.UIElements;
  10. using UnityEngine.UIElements;
  11. using Toggle = UnityEngine.UIElements.Toggle;
  12. using UnityEditor.Experimental.GraphView;
  13. using UnityEditorInternal;
  14. using UnityEditor.ShaderGraph.Internal;
  15. namespace UnityEditor.ShaderGraph.Drawing
  16. {
  17. class BlackboardFieldKeywordView : BlackboardFieldView
  18. {
  19. private ReorderableList m_ReorderableList;
  20. private IMGUIContainer m_Container;
  21. private int m_SelectedIndex;
  22. private ShaderKeyword m_Keyword;
  23. public BlackboardFieldKeywordView(BlackboardField blackboardField, GraphData graph, ShaderInput input)
  24. : base (blackboardField, graph, input)
  25. {
  26. }
  27. public override void BuildCustomFields(ShaderInput input)
  28. {
  29. m_Keyword = input as ShaderKeyword;
  30. if(m_Keyword == null)
  31. return;
  32. // KeywordDefinition
  33. var keywordDefinitionField = new EnumField((Enum)m_Keyword.keywordDefinition);
  34. keywordDefinitionField.RegisterValueChangedCallback(evt =>
  35. {
  36. graph.owner.RegisterCompleteObjectUndo("Change Keyword Type");
  37. if (m_Keyword.keywordDefinition == (KeywordDefinition)evt.newValue)
  38. return;
  39. m_Keyword.keywordDefinition = (KeywordDefinition)evt.newValue;
  40. Rebuild();
  41. });
  42. AddRow("Definition", keywordDefinitionField, m_Keyword.isEditable);
  43. // KeywordScope
  44. if(m_Keyword.keywordDefinition != KeywordDefinition.Predefined)
  45. {
  46. var keywordScopeField = new EnumField((Enum)m_Keyword.keywordScope);
  47. keywordScopeField.RegisterValueChangedCallback(evt =>
  48. {
  49. graph.owner.RegisterCompleteObjectUndo("Change Keyword Type");
  50. if (m_Keyword.keywordScope == (KeywordScope)evt.newValue)
  51. return;
  52. m_Keyword.keywordScope = (KeywordScope)evt.newValue;
  53. });
  54. AddRow("Scope", keywordScopeField, m_Keyword.isEditable);
  55. }
  56. switch(m_Keyword.keywordType)
  57. {
  58. case KeywordType.Boolean:
  59. BuildBooleanKeywordField(m_Keyword);
  60. break;
  61. case KeywordType.Enum:
  62. BuildEnumKeywordField(m_Keyword);
  63. break;
  64. default:
  65. throw new ArgumentOutOfRangeException();
  66. }
  67. }
  68. void BuildBooleanKeywordField(ShaderKeyword keyword)
  69. {
  70. // Default field
  71. var field = new Toggle() { value = keyword.value == 1 };
  72. field.OnToggleChanged(evt =>
  73. {
  74. graph.owner.RegisterCompleteObjectUndo("Change property value");
  75. keyword.value = evt.newValue ? 1 : 0;
  76. DirtyNodes(ModificationScope.Graph);
  77. });
  78. AddRow("Default", field);
  79. }
  80. void BuildEnumKeywordField(ShaderKeyword keyword)
  81. {
  82. // Clamp value between entry list
  83. int value = Mathf.Clamp(keyword.value, 0, keyword.entries.Count - 1);
  84. // Default field
  85. var field = new PopupField<string>(keyword.entries.Select(x => x.displayName).ToList(), value);
  86. field.RegisterValueChangedCallback(evt =>
  87. {
  88. graph.owner.RegisterCompleteObjectUndo("Change Keyword Value");
  89. keyword.value = field.index;
  90. DirtyNodes(ModificationScope.Graph);
  91. });
  92. AddRow("Default", field);
  93. // Entries
  94. m_Container = new IMGUIContainer(() => OnGUIHandler ()) { name = "ListContainer" };
  95. AddRow("Entries", m_Container, keyword.isEditable);
  96. }
  97. private void OnGUIHandler()
  98. {
  99. if(m_ReorderableList == null)
  100. {
  101. RecreateList();
  102. AddCallbacks();
  103. }
  104. m_ReorderableList.index = m_SelectedIndex;
  105. m_ReorderableList.DoLayoutList();
  106. }
  107. internal void RecreateList()
  108. {
  109. // Create reorderable list from entries
  110. m_ReorderableList = new ReorderableList(m_Keyword.entries, typeof(KeywordEntry), true, true, true, true);
  111. }
  112. private void AddCallbacks()
  113. {
  114. // Draw Header
  115. m_ReorderableList.drawHeaderCallback = (Rect rect) =>
  116. {
  117. int indent = 14;
  118. var displayRect = new Rect(rect.x + indent, rect.y, (rect.width - indent) / 2, rect.height);
  119. EditorGUI.LabelField(displayRect, "Display Name");
  120. var referenceRect = new Rect((rect.x + indent) + (rect.width - indent) / 2, rect.y, (rect.width - indent) / 2, rect.height);
  121. EditorGUI.LabelField(referenceRect, "Reference Suffix");
  122. };
  123. // Draw Element
  124. m_ReorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  125. {
  126. KeywordEntry entry = ((KeywordEntry)m_ReorderableList.list[index]);
  127. EditorGUI.BeginChangeCheck();
  128. var displayName = EditorGUI.DelayedTextField( new Rect(rect.x, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), entry.displayName, EditorStyles.label);
  129. var referenceName = EditorGUI.DelayedTextField( new Rect(rect.x + rect.width / 2, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), entry.referenceName, EditorStyles.label);
  130. displayName = GetDuplicateSafeDisplayName(entry.id, displayName);
  131. referenceName = GetDuplicateSafeReferenceName(entry.id, referenceName.ToUpper());
  132. if(EditorGUI.EndChangeCheck())
  133. {
  134. m_Keyword.entries[index] = new KeywordEntry(entry.id, displayName, referenceName);
  135. DirtyNodes();
  136. Rebuild();
  137. }
  138. };
  139. // Element height
  140. m_ReorderableList.elementHeightCallback = (int indexer) =>
  141. {
  142. return m_ReorderableList.elementHeight;
  143. };
  144. // Can add
  145. m_ReorderableList.onCanAddCallback = (ReorderableList list) =>
  146. {
  147. return list.count < KeywordNode.k_MaxEnumEntries;
  148. };
  149. // Can remove
  150. m_ReorderableList.onCanRemoveCallback = (ReorderableList list) =>
  151. {
  152. return list.count > KeywordNode.k_MinEnumEntries;
  153. };
  154. // Add callback delegates
  155. m_ReorderableList.onSelectCallback += SelectEntry;
  156. m_ReorderableList.onAddCallback += AddEntry;
  157. m_ReorderableList.onRemoveCallback += RemoveEntry;
  158. m_ReorderableList.onReorderCallback += ReorderEntries;
  159. }
  160. private void SelectEntry(ReorderableList list)
  161. {
  162. m_SelectedIndex = list.index;
  163. }
  164. private void AddEntry(ReorderableList list)
  165. {
  166. graph.owner.RegisterCompleteObjectUndo("Add Keyword Entry");
  167. int index = GetFirstUnusedID();
  168. if (index <= 0)
  169. return; // Error has already occured, don't attempt to add this entry.
  170. var displayName = GetDuplicateSafeDisplayName(index, "New");
  171. var referenceName = GetDuplicateSafeReferenceName(index, "NEW");
  172. // Add new entry
  173. m_Keyword.entries.Add(new KeywordEntry(index, displayName, referenceName));
  174. // Update Blackboard & Nodes
  175. DirtyNodes();
  176. Rebuild();
  177. graph.OnKeywordChanged();
  178. m_SelectedIndex = list.list.Count - 1;
  179. }
  180. // Allowed indicies are 1-MAX_ENUM_ENTRIES
  181. private int GetFirstUnusedID()
  182. {
  183. List<int> ususedIDs = new List<int>();
  184. foreach (KeywordEntry keywordEntry in m_Keyword.entries)
  185. {
  186. ususedIDs.Add(keywordEntry.id);
  187. }
  188. for (int x = 1; x <= KeywordNode.k_MaxEnumEntries; x++)
  189. {
  190. if (!ususedIDs.Contains(x))
  191. return x;
  192. }
  193. Debug.LogError("GetFirstUnusedID: Attempting to get unused ID when all IDs are used.");
  194. return -1;
  195. }
  196. private void RemoveEntry(ReorderableList list)
  197. {
  198. graph.owner.RegisterCompleteObjectUndo("Remove Keyword Entry");
  199. // Remove entry
  200. m_SelectedIndex = list.index;
  201. var selectedEntry = (KeywordEntry)m_ReorderableList.list[list.index];
  202. m_Keyword.entries.Remove(selectedEntry);
  203. // Clamp value within new entry range
  204. int value = Mathf.Clamp(m_Keyword.value, 0, m_Keyword.entries.Count - 1);
  205. m_Keyword.value = value;
  206. // Update Blackboard & Nodes
  207. DirtyNodes();
  208. Rebuild();
  209. graph.OnKeywordChanged();
  210. m_SelectedIndex = m_SelectedIndex >= list.list.Count - 1 ? list.list.Count - 1 : m_SelectedIndex;
  211. }
  212. private void ReorderEntries(ReorderableList list)
  213. {
  214. DirtyNodes();
  215. }
  216. public string GetDuplicateSafeDisplayName(int id, string name)
  217. {
  218. name = name.Trim();
  219. var entryList = m_ReorderableList.list as List<KeywordEntry>;
  220. return GraphUtil.SanitizeName(entryList.Where(p => p.id != id).Select(p => p.displayName), "{0} ({1})", name);
  221. }
  222. public string GetDuplicateSafeReferenceName(int id, string name)
  223. {
  224. name = name.Trim();
  225. name = Regex.Replace(name, @"(?:[^A-Za-z_0-9])|(?:\s)", "_");
  226. var entryList = m_ReorderableList.list as List<KeywordEntry>;
  227. return GraphUtil.SanitizeName(entryList.Where(p => p.id != id).Select(p => p.referenceName), "{0}_{1}", name);
  228. }
  229. public override void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node)
  230. {
  231. foreach (var node in graph.GetNodes<KeywordNode>())
  232. {
  233. node.UpdateNode();
  234. node.Dirty(modificationScope);
  235. }
  236. // Cant determine if Sub Graphs contain the keyword so just update them
  237. foreach (var node in graph.GetNodes<SubGraphNode>())
  238. {
  239. node.Dirty(modificationScope);
  240. }
  241. }
  242. }
  243. }