BlackboardFieldView.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 UnityEditor.Graphing.Util;
  8. using UnityEditor.Experimental.GraphView;
  9. using UnityEditor.ShaderGraph.Internal;
  10. namespace UnityEditor.ShaderGraph.Drawing
  11. {
  12. abstract class BlackboardFieldView : VisualElement
  13. {
  14. readonly BlackboardField m_BlackboardField;
  15. readonly GraphData m_Graph;
  16. public GraphData graph => m_Graph;
  17. ShaderInput m_Input;
  18. Toggle m_ExposedToogle;
  19. TextField m_ReferenceNameField;
  20. List<VisualElement> m_Rows;
  21. public List<VisualElement> rows => m_Rows;
  22. int m_UndoGroup = -1;
  23. public int undoGroup => m_UndoGroup;
  24. static Type s_ContextualMenuManipulator = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypesOrNothing()).FirstOrDefault(t => t.FullName == "UnityEngine.UIElements.ContextualMenuManipulator");
  25. IManipulator m_ResetReferenceMenu;
  26. EventCallback<KeyDownEvent> m_KeyDownCallback;
  27. public EventCallback<KeyDownEvent> keyDownCallback => m_KeyDownCallback;
  28. EventCallback<FocusOutEvent> m_FocusOutCallback;
  29. public EventCallback<FocusOutEvent> focusOutCallback => m_FocusOutCallback;
  30. public BlackboardFieldView(BlackboardField blackboardField, GraphData graph, ShaderInput input)
  31. {
  32. styleSheets.Add(Resources.Load<StyleSheet>("Styles/ShaderGraphBlackboard"));
  33. m_BlackboardField = blackboardField;
  34. m_Graph = graph;
  35. m_Input = input;
  36. m_Rows = new List<VisualElement>();
  37. m_KeyDownCallback = new EventCallback<KeyDownEvent>(evt =>
  38. {
  39. // Record Undo for input field edit
  40. if (m_UndoGroup == -1)
  41. {
  42. m_UndoGroup = Undo.GetCurrentGroup();
  43. graph.owner.RegisterCompleteObjectUndo("Change property value");
  44. }
  45. // Handle scaping input field edit
  46. if (evt.keyCode == KeyCode.Escape && m_UndoGroup > -1)
  47. {
  48. Undo.RevertAllDownToGroup(m_UndoGroup);
  49. m_UndoGroup = -1;
  50. evt.StopPropagation();
  51. }
  52. // Dont record Undo again until input field is unfocused
  53. m_UndoGroup++;
  54. this.MarkDirtyRepaint();
  55. });
  56. m_FocusOutCallback = new EventCallback<FocusOutEvent>(evt =>
  57. {
  58. // Reset UndoGroup when done editing input field
  59. m_UndoGroup = -1;
  60. });
  61. BuildDefaultFields(input);
  62. BuildCustomFields(input);
  63. AddToClassList("sgblackboardFieldView");
  64. }
  65. void BuildDefaultFields(ShaderInput input)
  66. {
  67. if(!m_Graph.isSubGraph)
  68. {
  69. m_ExposedToogle = new Toggle();
  70. m_ExposedToogle.OnToggleChanged(evt =>
  71. {
  72. m_Graph.owner.RegisterCompleteObjectUndo("Change Exposed Toggle");
  73. input.generatePropertyBlock = evt.newValue;
  74. m_BlackboardField.icon = input.generatePropertyBlock ? BlackboardProvider.exposedIcon : null;
  75. Rebuild();
  76. DirtyNodes(ModificationScope.Graph);
  77. });
  78. m_ExposedToogle.value = input.generatePropertyBlock;
  79. AddRow("Exposed", m_ExposedToogle, input.isExposable);
  80. }
  81. if(!m_Graph.isSubGraph || input is ShaderKeyword)
  82. {
  83. m_ReferenceNameField = new TextField(512, false, false, ' ') { isDelayed = true };
  84. m_ReferenceNameField.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyNameReferenceField"));
  85. m_ReferenceNameField.value = input.referenceName;
  86. m_ReferenceNameField.RegisterValueChangedCallback(evt =>
  87. {
  88. m_Graph.owner.RegisterCompleteObjectUndo("Change Reference Name");
  89. if (m_ReferenceNameField.value != m_Input.referenceName)
  90. m_Graph.SanitizeGraphInputReferenceName(input, evt.newValue);
  91. m_ReferenceNameField.value = input.referenceName;
  92. if (string.IsNullOrEmpty(input.overrideReferenceName))
  93. m_ReferenceNameField.RemoveFromClassList("modified");
  94. else
  95. m_ReferenceNameField.AddToClassList("modified");
  96. Rebuild();
  97. DirtyNodes(ModificationScope.Graph);
  98. UpdateReferenceNameResetMenu();
  99. });
  100. if (!string.IsNullOrEmpty(input.overrideReferenceName))
  101. m_ReferenceNameField.AddToClassList("modified");
  102. AddRow("Reference", m_ReferenceNameField, input.isRenamable);
  103. }
  104. }
  105. public abstract void BuildCustomFields(ShaderInput input);
  106. public abstract void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node);
  107. void UpdateReferenceNameResetMenu()
  108. {
  109. if (string.IsNullOrEmpty(m_Input.overrideReferenceName))
  110. {
  111. this.RemoveManipulator(m_ResetReferenceMenu);
  112. m_ResetReferenceMenu = null;
  113. }
  114. else
  115. {
  116. m_ResetReferenceMenu = (IManipulator)Activator.CreateInstance(s_ContextualMenuManipulator, (Action<ContextualMenuPopulateEvent>)BuildContextualMenu);
  117. this.AddManipulator(m_ResetReferenceMenu);
  118. }
  119. }
  120. void BuildContextualMenu(ContextualMenuPopulateEvent evt)
  121. {
  122. evt.menu.AppendAction("Reset Reference", e =>
  123. {
  124. m_Input.overrideReferenceName = null;
  125. m_ReferenceNameField.value = m_Input.referenceName;
  126. m_ReferenceNameField.RemoveFromClassList("modified");
  127. DirtyNodes(ModificationScope.Graph);
  128. }, DropdownMenuAction.AlwaysEnabled);
  129. }
  130. public VisualElement AddRow(string labelText, VisualElement control, bool enabled = true)
  131. {
  132. VisualElement rowView = CreateRow(labelText, control, enabled);
  133. Add(rowView);
  134. m_Rows.Add(rowView);
  135. return rowView;
  136. }
  137. public void Rebuild()
  138. {
  139. // Delete all rows
  140. for (int i = 0; i < m_Rows.Count; i++)
  141. {
  142. if (m_Rows[i].parent == this)
  143. Remove(m_Rows[i]);
  144. }
  145. // Rebuild
  146. BuildDefaultFields(m_Input);
  147. BuildCustomFields(m_Input);
  148. }
  149. VisualElement CreateRow(string labelText, VisualElement control, bool enabled)
  150. {
  151. VisualElement rowView = new VisualElement();
  152. rowView.AddToClassList("rowView");
  153. if(!string.IsNullOrEmpty(labelText))
  154. {
  155. Label label = new Label(labelText);
  156. label.SetEnabled(enabled);
  157. label.AddToClassList("rowViewLabel");
  158. rowView.Add(label);
  159. }
  160. control.AddToClassList("rowViewControl");
  161. control.SetEnabled(enabled);
  162. rowView.Add(control);
  163. return rowView;
  164. }
  165. }
  166. }