PageRenderTime 72ms CodeModel.GetById 39ms RepoModel.GetById 1ms app.codeStats 0ms

/Library/PackageCache/com.unity.shadergraph@10.8.1/Editor/Drawing/Views/ReorderableSlotListView.cs

https://gitlab.com/shashank_makam/dissolve-shader
C# | 274 lines | 203 code | 49 blank | 22 comment | 17 complexity | c7f2d8b3187b9465c7fd0c88d32defb8 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.UIElements;
  6. using UnityEditor.Graphing;
  7. using UnityEditorInternal;
  8. namespace UnityEditor.ShaderGraph.Drawing
  9. {
  10. internal class ReorderableSlotListView : VisualElement
  11. {
  12. int m_SelectedIndex = -1;
  13. SlotType m_SlotType;
  14. GUIStyle m_LabelStyle;
  15. IMGUIContainer m_Container;
  16. AbstractMaterialNode m_Node;
  17. ReorderableList m_ReorderableList;
  18. bool m_AllowBareResources;
  19. internal delegate void ListRecreatedDelegate();
  20. ListRecreatedDelegate m_OnListRecreatedCallback = new ListRecreatedDelegate(() => { });
  21. string label => string.Format("{0}s", m_SlotType.ToString());
  22. public ReorderableList.AddCallbackDelegate OnAddCallback
  23. {
  24. get => m_ReorderableList?.onAddCallback;
  25. set => m_ReorderableList.onAddCallback = value;
  26. }
  27. public ReorderableList.RemoveCallbackDelegate OnRemoveCallback
  28. {
  29. get => m_ReorderableList.onRemoveCallback;
  30. set => m_ReorderableList.onRemoveCallback = value;
  31. }
  32. public ListRecreatedDelegate OnListRecreatedCallback
  33. {
  34. get => m_OnListRecreatedCallback;
  35. set => m_OnListRecreatedCallback = value;
  36. }
  37. public Func<ConcreteSlotValueTypePopupName, bool> AllowedTypeCallback;
  38. internal ReorderableSlotListView(AbstractMaterialNode node, SlotType slotType, bool allowBareResources)
  39. {
  40. m_AllowBareResources = allowBareResources;
  41. styleSheets.Add(Resources.Load<StyleSheet>("Styles/ReorderableSlotListView"));
  42. m_Node = node;
  43. m_SlotType = slotType;
  44. m_Container = new IMGUIContainer(() => OnGUIHandler ()) { name = "ListContainer" };
  45. Add(m_Container);
  46. RecreateList();
  47. AddCallbacks();
  48. }
  49. internal void RecreateList()
  50. {
  51. // Get slots based on type
  52. List<MaterialSlot> slots = new List<MaterialSlot>();
  53. if(m_SlotType == SlotType.Input)
  54. m_Node.GetInputSlots(slots);
  55. else
  56. m_Node.GetOutputSlots(slots);
  57. // Create reorderable list from IDs
  58. List<int> slotIDs = slots.Select(s => s.id).ToList();
  59. m_ReorderableList = new ReorderableList(slotIDs, typeof(int), true, true, true, true);
  60. m_OnListRecreatedCallback();
  61. }
  62. private void OnGUIHandler()
  63. {
  64. if(m_ReorderableList == null)
  65. {
  66. RecreateList();
  67. AddCallbacks();
  68. }
  69. using (var changeCheckScope = new EditorGUI.ChangeCheckScope())
  70. {
  71. m_ReorderableList.index = m_SelectedIndex;
  72. m_ReorderableList.DoLayoutList();
  73. if (changeCheckScope.changed)
  74. m_Node.Dirty(ModificationScope.Node);
  75. }
  76. }
  77. private void AddCallbacks()
  78. {
  79. m_ReorderableList.drawHeaderCallback = (Rect rect) =>
  80. {
  81. var labelRect = new Rect(rect.x, rect.y, rect.width-10, rect.height);
  82. EditorGUI.LabelField(labelRect, label);
  83. };
  84. // Draw Element
  85. m_ReorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  86. {
  87. // Slot is guaranteed to exist in this UI state
  88. MaterialSlot oldSlot = m_Node.FindSlot<MaterialSlot>((int)m_ReorderableList.list[index]);
  89. EditorGUI.BeginChangeCheck();
  90. var displayName = EditorGUI.DelayedTextField( new Rect(rect.x, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), oldSlot.RawDisplayName(), EditorStyles.label);
  91. ConcreteSlotValueTypePopupName concreteValueTypePopupOrig =
  92. oldSlot.concreteValueType.ToConcreteSlotValueTypePopupName(oldSlot.bareResource);
  93. ConcreteSlotValueTypePopupName concreteValueTypePopupNew = (ConcreteSlotValueTypePopupName)EditorGUI.EnumPopup(
  94. new Rect(rect.x + rect.width / 2, rect.y, rect.width - rect.width / 2, EditorGUIUtility.singleLineHeight),
  95. GUIContent.none,
  96. concreteValueTypePopupOrig,
  97. e =>
  98. {
  99. ConcreteSlotValueTypePopupName csvtpn = (ConcreteSlotValueTypePopupName) e;
  100. csvtpn.ToConcreteSlotValueType(out bool isBareResource);
  101. if (isBareResource && !m_AllowBareResources)
  102. return false;
  103. return AllowedTypeCallback?.Invoke(csvtpn) ?? true;
  104. }
  105. );
  106. if (EditorGUI.EndChangeCheck())
  107. {
  108. m_Node.owner.owner.RegisterCompleteObjectUndo("Modify Port");
  109. displayName = NodeUtils.ConvertToValidHLSLIdentifier(displayName);
  110. if (displayName != oldSlot.RawDisplayName())
  111. {
  112. using (var tempSlots = PooledList<MaterialSlot>.Get())
  113. {
  114. m_Node.GetSlots(tempSlots);
  115. // deduplicate against other slot shaderOutputNames
  116. displayName = GraphUtil.DeduplicateName(tempSlots.Where(p => p.id != oldSlot.id).Select(p => p.shaderOutputName), "{0}_{1}", displayName);
  117. }
  118. }
  119. ConcreteSlotValueType concreteValueType = concreteValueTypePopupNew.ToConcreteSlotValueType(out bool isBareResource);
  120. // Because the type may have changed, we can't (always) just modify the existing slot. So create a new one and replace it.
  121. var newSlot = MaterialSlot.CreateMaterialSlot(concreteValueType.ToSlotValueType(), oldSlot.id, displayName, displayName, m_SlotType, Vector4.zero);
  122. newSlot.CopyValuesFrom(oldSlot);
  123. m_Node.AddSlot(newSlot, false);
  124. newSlot.bareResource = isBareResource;
  125. List<int> orderedSlotIds = new List<int>();
  126. if (m_SlotType == SlotType.Input)
  127. {
  128. orderedSlotIds.AddRange(m_ReorderableList.list.OfType<int>());
  129. List<MaterialSlot> slots = new List<MaterialSlot>();
  130. m_Node.GetOutputSlots(slots);
  131. orderedSlotIds.AddRange(slots.Select(s => s.id));
  132. }
  133. else
  134. {
  135. List<MaterialSlot> slots = new List<MaterialSlot>();
  136. m_Node.GetInputSlots(slots);
  137. orderedSlotIds.AddRange(slots.Select(s => s.id));
  138. orderedSlotIds.AddRange(m_ReorderableList.list.OfType<int>());
  139. }
  140. m_Node.SetSlotOrder(orderedSlotIds);
  141. RecreateList();
  142. m_Node.ValidateNode();
  143. }
  144. };
  145. // Element height
  146. m_ReorderableList.elementHeightCallback = (int indexer) =>
  147. {
  148. return m_ReorderableList.elementHeight;
  149. };
  150. // Add callback delegates
  151. m_ReorderableList.onSelectCallback += SelectEntry;
  152. m_ReorderableList.onAddCallback += AddEntry;
  153. m_ReorderableList.onRemoveCallback += RemoveEntry;
  154. m_ReorderableList.onReorderCallback += ReorderEntries;
  155. }
  156. private void SelectEntry(ReorderableList list)
  157. {
  158. m_SelectedIndex = list.index;
  159. }
  160. private void AddEntry(ReorderableList list)
  161. {
  162. m_Node.owner.owner.RegisterCompleteObjectUndo("Add Port");
  163. // Need to get all current slots to get the next valid ID
  164. List<MaterialSlot> slots = new List<MaterialSlot>();
  165. m_Node.GetSlots(slots);
  166. int[] slotIDs = slots.Select(s => s.id).OrderByDescending(s => s).ToArray();
  167. int newSlotID = slotIDs.Length > 0 ? slotIDs[0] + 1 : 0;
  168. string name = NodeUtils.GetDuplicateSafeNameForSlot(m_Node, newSlotID, "New");
  169. // Create a new slot and add it
  170. var newSlot = MaterialSlot.CreateMaterialSlot(SlotValueType.Vector1, newSlotID, name, NodeUtils.GetHLSLSafeName(name), m_SlotType, Vector4.zero);
  171. m_Node.AddSlot(newSlot);
  172. // Select the new slot, then validate the node
  173. m_SelectedIndex = list.list.Count - 1;
  174. m_Node.ValidateNode();
  175. }
  176. private void RemoveEntry(ReorderableList list)
  177. {
  178. m_Node.owner.owner.RegisterCompleteObjectUndo("Remove Port");
  179. // Remove the slot from the node
  180. m_SelectedIndex = list.index;
  181. m_Node.RemoveSlot((int)m_ReorderableList.list[m_SelectedIndex]);
  182. // Then remove it from the list
  183. // Need to do this order to preserve the list indicies for previous step
  184. ReorderableList.defaultBehaviours.DoRemoveButton(list);
  185. // Validate
  186. m_Node.ValidateNode();
  187. }
  188. private void ReorderEntries(ReorderableList list)
  189. {
  190. m_Node.owner.owner.RegisterCompleteObjectUndo("Reorder Ports");
  191. // Get all the current slots
  192. List<MaterialSlot> slots = new List<MaterialSlot>();
  193. if(m_SlotType == SlotType.Input)
  194. m_Node.GetInputSlots<MaterialSlot>(slots);
  195. else
  196. m_Node.GetOutputSlots<MaterialSlot>(slots);
  197. // Store the edges
  198. Dictionary<MaterialSlot, List<IEdge>> edgeDict = new Dictionary<MaterialSlot, List<IEdge>>();
  199. foreach (MaterialSlot slot in slots)
  200. edgeDict.Add(slot, (List<IEdge>)slot.owner.owner.GetEdges(slot.slotReference));
  201. // Get reorder slots so need to remove them all then re-add
  202. foreach (MaterialSlot slot in slots)
  203. m_Node.RemoveSlot(slot.id);
  204. // Order them by their slot ID
  205. slots = slots.OrderBy(s => s.id).ToList();
  206. // Now add the slots back based on the list order
  207. // For each list entry get the slot with that ID
  208. for (int i = 0; i < list.list.Count; i++)
  209. {
  210. var currentSlot = slots.Where(s => s.id == (int)list.list[i]).FirstOrDefault();
  211. m_Node.AddSlot(currentSlot);
  212. }
  213. // Reconnect the edges
  214. foreach (KeyValuePair<MaterialSlot, List<IEdge>> entry in edgeDict)
  215. {
  216. foreach (IEdge edge in entry.Value)
  217. {
  218. m_Node.owner.Connect(edge.outputSlot, edge.inputSlot);
  219. }
  220. }
  221. RecreateList();
  222. m_Node.ValidateNode();
  223. }
  224. }
  225. }