123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- using System;
- using System.Linq;
- using UnityEditor.Experimental.GraphView;
- using UnityEditor.Graphing;
- using UnityEditor.Rendering;
- using UnityEditor.ShaderGraph.Drawing;
- using UnityEditor.ShaderGraph.Drawing.Controls;
- using UnityEditor.ShaderGraph.Internal;
- using UnityEngine;
- using UnityEngine.UIElements;
- using UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers;
- using ContextualMenuManipulator = UnityEngine.UIElements.ContextualMenuManipulator;
-
- namespace UnityEditor.ShaderGraph
- {
- sealed class PropertyNodeView : TokenNode, IShaderNodeView, IInspectable, IShaderInputObserver
- {
- static readonly Texture2D exposedIcon = Resources.Load<Texture2D>("GraphView/Nodes/BlackboardFieldExposed");
- public static StyleSheet styleSheet;
-
- // When the properties are changed, this delegate is used to trigger an update in the view that represents those properties
- Action m_TriggerInspectorUpdate;
-
- Action m_ResetReferenceNameAction;
-
- public PropertyNodeView(PropertyNode node, EdgeConnectorListener edgeConnectorListener)
- : base(null, ShaderPort.Create(node.GetOutputSlots<MaterialSlot>().First(), edgeConnectorListener))
- {
- if (styleSheet == null)
- styleSheet = Resources.Load<StyleSheet>("Styles/PropertyNodeView");
- styleSheets.Add(styleSheet);
-
- this.node = node;
- viewDataKey = node.objectId.ToString();
- userData = node;
-
- // Getting the generatePropertyBlock property to see if it is exposed or not
- UpdateIcon();
-
- // Setting the position of the node, otherwise it ends up in the center of the canvas
- SetPosition(new Rect(node.drawState.position.x, node.drawState.position.y, 0, 0));
-
- // Removing the title label since it is not used and taking up space
- this.Q("title-label").RemoveFromHierarchy();
-
- // Add disabled overlay
- Add(new VisualElement() { name = "disabledOverlay", pickingMode = PickingMode.Ignore });
-
- // Update active state
- SetActive(node.isActive);
-
- // Registering the hovering callbacks for highlighting
- RegisterCallback<MouseEnterEvent>(OnMouseHover);
- RegisterCallback<MouseLeaveEvent>(OnMouseHover);
-
- // add the right click context menu
- IManipulator contextMenuManipulator = new ContextualMenuManipulator(AddContextMenuOptions);
- this.AddManipulator(contextMenuManipulator);
- }
-
- // Updating the text label of the output slot
- void UpdateDisplayName()
- {
- var slot = node.GetSlots<MaterialSlot>().ToList().First();
- this.Q<Label>("type").text = slot.displayName;
- }
-
- public Node gvNode => this;
- public AbstractMaterialNode node { get; }
- public VisualElement colorElement => null;
- public string inspectorTitle => $"{property.displayName} (Node)";
-
- [Inspectable("ShaderInput", null)]
- AbstractShaderProperty property => (node as PropertyNode)?.property;
-
- public object GetObjectToInspect()
- {
- return property;
- }
-
- public void SupplyDataToPropertyDrawer(IPropertyDrawer propertyDrawer, Action inspectorUpdateDelegate)
- {
- if (propertyDrawer is ShaderInputPropertyDrawer shaderInputPropertyDrawer)
- {
- var propNode = node as PropertyNode;
- var graph = node.owner as GraphData;
-
- var shaderInputViewModel = new ShaderInputViewModel()
- {
- model = property,
- parentView = null,
- isSubGraph = graph.isSubGraph,
- isInputExposed = property.isExposed,
- inputName = property.displayName,
- inputTypeName = property.GetPropertyTypeString(),
- requestModelChangeAction = this.RequestModelChange
- };
- shaderInputPropertyDrawer.GetViewModel(shaderInputViewModel, node.owner, this.OnDisplayNameUpdated);
-
- this.m_TriggerInspectorUpdate = inspectorUpdateDelegate;
- this.m_ResetReferenceNameAction = shaderInputPropertyDrawer.ResetReferenceName;
- }
- }
-
- void RequestModelChange(IGraphDataAction changeAction)
- {
- node.owner?.owner.graphDataStore.Dispatch(changeAction);
- }
-
- internal static void AddMainColorMenuOptions(ContextualMenuPopulateEvent evt, ColorShaderProperty colorProp, GraphData graphData, Action inspectorUpdateAction)
- {
- if (!graphData.isSubGraph)
- {
- if (!colorProp.isMainColor)
- {
- evt.menu.AppendAction(
- "Set as Main Color",
- e =>
- {
- ColorShaderProperty col = graphData.GetMainColor();
- if (col != null)
- {
- if (EditorUtility.DisplayDialog("Change Main Color Action", $"Are you sure you want to change the Main Color from {col.displayName} to {colorProp.displayName}?", "Yes", "Cancel"))
- {
- graphData.owner.RegisterCompleteObjectUndo("Change Main Color");
- col.isMainColor = false;
- colorProp.isMainColor = true;
- inspectorUpdateAction();
- }
- return;
- }
-
- graphData.owner.RegisterCompleteObjectUndo("Set Main Color");
- colorProp.isMainColor = true;
- inspectorUpdateAction();
- });
- }
- else
- {
- evt.menu.AppendAction(
- "Clear Main Color",
- e =>
- {
- graphData.owner.RegisterCompleteObjectUndo("Clear Main Color");
- colorProp.isMainColor = false;
- inspectorUpdateAction();
- });
- }
- }
- }
-
- internal static void AddMainTextureMenuOptions(ContextualMenuPopulateEvent evt, Texture2DShaderProperty texProp, GraphData graphData, Action inspectorUpdateAction)
- {
- if (!graphData.isSubGraph)
- {
- if (!texProp.isMainTexture)
- {
- evt.menu.AppendAction(
- "Set as Main Texture",
- e =>
- {
- Texture2DShaderProperty tex = graphData.GetMainTexture();
- // There's already a main texture, ask the user if they want to change and toggle the old one to not be main
- if (tex != null)
- {
- if (EditorUtility.DisplayDialog("Change Main Texture Action", $"Are you sure you want to change the Main Texture from {tex.displayName} to {texProp.displayName}?", "Yes", "Cancel"))
- {
- graphData.owner.RegisterCompleteObjectUndo("Change Main Texture");
- tex.isMainTexture = false;
- texProp.isMainTexture = true;
- inspectorUpdateAction();
- }
- return;
- }
-
- graphData.owner.RegisterCompleteObjectUndo("Set Main Texture");
- texProp.isMainTexture = true;
- inspectorUpdateAction();
- });
- }
- else
- {
- evt.menu.AppendAction(
- "Clear Main Texture",
- e =>
- {
- graphData.owner.RegisterCompleteObjectUndo("Clear Main Texture");
- texProp.isMainTexture = false;
- inspectorUpdateAction();
- });
- }
- }
- }
-
- void AddContextMenuOptions(ContextualMenuPopulateEvent evt)
- {
- // Checks if the reference name has been overridden and appends menu action to reset it, if so
- if (property.isRenamable &&
- !string.IsNullOrEmpty(property.overrideReferenceName))
- {
- evt.menu.AppendAction(
- "Reset Reference",
- e =>
- {
- m_ResetReferenceNameAction();
- DirtyNodes(ModificationScope.Graph);
- },
- DropdownMenuAction.AlwaysEnabled);
- }
-
- if (property is ColorShaderProperty colorProp)
- {
- AddMainColorMenuOptions(evt, colorProp, node.owner, m_TriggerInspectorUpdate);
- }
-
- if (property is Texture2DShaderProperty texProp)
- {
- AddMainTextureMenuOptions(evt, texProp, node.owner, m_TriggerInspectorUpdate);
- }
- }
-
- void OnDisplayNameUpdated(bool triggerPropertyViewUpdate = false, ModificationScope modificationScope = ModificationScope.Node)
- {
- if (triggerPropertyViewUpdate)
- m_TriggerInspectorUpdate?.Invoke();
-
- UpdateDisplayName();
- }
-
- void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node)
- {
- var graph = node.owner as GraphData;
-
- var colorManager = GetFirstAncestorOfType<GraphEditorView>().colorManager;
- var nodes = GetFirstAncestorOfType<GraphEditorView>().graphView.Query<MaterialNodeView>().ToList();
-
- colorManager.SetNodesDirty(nodes);
- colorManager.UpdateNodeViews(nodes);
-
- foreach (var node in graph.GetNodes<PropertyNode>())
- {
- node.Dirty(modificationScope);
- }
- }
-
- public void SetColor(Color newColor)
- {
- // Nothing to do here yet
- }
-
- public void ResetColor()
- {
- // Nothing to do here yet
- }
-
- public void UpdatePortInputTypes()
- {
- }
-
- public void UpdateDropdownEntries()
- {
- }
-
- public bool FindPort(SlotReference slot, out ShaderPort port)
- {
- port = output as ShaderPort;
- return port != null && port.slot.slotReference.Equals(slot);
- }
-
- void UpdateIcon()
- {
- var graph = node?.owner as GraphData;
- if ((graph != null) && (property != null))
- icon = (graph.isSubGraph || property.isExposed) ? exposedIcon : null;
- else
- icon = null;
- }
-
- public void OnModified(ModificationScope scope)
- {
- //disconnected property nodes are always active
- if (!node.IsSlotConnected(PropertyNode.OutputSlotId))
- node.SetActive(true);
-
- SetActive(node.isActive);
-
- if (scope == ModificationScope.Graph)
- {
- UpdateIcon();
- }
-
- if (scope == ModificationScope.Topological || scope == ModificationScope.Node)
- {
- UpdateDisplayName();
- }
- }
-
- public void SetActive(bool state)
- {
- // Setup
- var disabledString = "disabled";
-
- if (!state)
- {
- // Add elements to disabled class list
- AddToClassList(disabledString);
- }
- else
- {
- // Remove elements from disabled class list
- RemoveFromClassList(disabledString);
- }
- }
-
- public void AttachMessage(string errString, ShaderCompilerMessageSeverity severity)
- {
- ClearMessage();
- IconBadge badge;
- if (severity == ShaderCompilerMessageSeverity.Error)
- {
- badge = IconBadge.CreateError(errString);
- }
- else
- {
- badge = IconBadge.CreateComment(errString);
- }
-
- Add(badge);
- badge.AttachTo(this, SpriteAlignment.RightCenter);
- }
-
- public void ClearMessage()
- {
- var badge = this.Q<IconBadge>();
- if (badge != null)
- {
- badge.Detach();
- badge.RemoveFromHierarchy();
- }
- }
-
- SGBlackboardRow GetAssociatedBlackboardRow()
- {
- var graphView = GetFirstAncestorOfType<GraphEditorView>();
-
- var blackboardController = graphView?.blackboardController;
- if (blackboardController == null)
- return null;
-
- var propNode = (PropertyNode)node;
- return blackboardController.GetBlackboardRow(propNode.property);
- }
-
- void OnMouseHover(EventBase evt)
- {
- var propRow = GetAssociatedBlackboardRow();
- if (propRow != null)
- {
- if (evt.eventTypeId == MouseEnterEvent.TypeId())
- {
- propRow.AddToClassList("hovered");
- }
- else
- {
- propRow.RemoveFromClassList("hovered");
- }
- }
- }
-
- public void Dispose()
- {
- var propRow = GetAssociatedBlackboardRow();
- // If this node view is deleted, remove highlighting from associated blackboard row
- if (propRow != null)
- {
- propRow.RemoveFromClassList("hovered");
- }
- styleSheets.Clear();
- m_TriggerInspectorUpdate = null;
- m_ResetReferenceNameAction = null;
- UnregisterCallback<MouseEnterEvent>(OnMouseHover);
- UnregisterCallback<MouseLeaveEvent>(OnMouseHover);
- }
-
- public void OnShaderInputUpdated(ModificationScope modificationScope)
- {
- if (modificationScope == ModificationScope.Layout)
- UpdateDisplayName();
- }
- }
- }
|