UnityGame/Library/PackageCache/com.unity.shadergraph/Editor/Drawing/Views/ContextView.cs
2024-10-27 10:53:47 +03:00

155 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.Experimental.GraphView;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Serialization;
namespace UnityEditor.ShaderGraph
{
sealed class ContextView : StackNode, IDisposable
{
ContextData m_ContextData;
// Currently we only need one Port per context
// As the Contexts are hardcoded we know their directions
Port m_Port;
//need this from graph view specifically for nodecreation
EditorWindow m_EditorWindow;
// When dealing with more Contexts, `name` should be serialized in the ContextData
// Right now we dont do this so we dont overcommit to serializing unknowns
public ContextView(string name, ContextData contextData, EditorWindow editorWindow)
{
// Set data
m_ContextData = contextData;
m_EditorWindow = editorWindow;
// Header
var headerLabel = new Label() { name = "headerLabel" };
headerLabel.text = name;
headerContainer.Add(headerLabel);
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
// Disable the context menu for block nodes. This prevents a duplicate "disconnect all"
// option from getting registered which grays out stack block node's option.
if (evt.target is MaterialNodeView) return;
// If the user didn't click on a block node (i.e. the stack frame), include the "Add Block Node" item.
InsertCreateNodeAction(evt, childCount, 0);
evt.menu.InsertSeparator(null, 1);
}
public ContextData contextData => m_ContextData;
public Port port => m_Port;
// We need to use graphViewChange.movedElements to check whether a BlockNode has moved onto the GraphView
// but Nodes return in movedElements when they are mid-drag because they are removed from the stack (placeholder)
// StackNode has `dragEntered` but its protected so we need `isDragging`
public bool isDragging => dragEntered;
public void AddPort(Direction direction)
{
var capacity = direction == Direction.Input ? Port.Capacity.Single : Port.Capacity.Multi;
var container = direction == Direction.Input ? inputContainer : outputContainer;
m_Port = Port.Create<Edge>(Orientation.Vertical, direction, capacity, null);
m_Port.portName = "";
// Vertical ports have no representation in Model
// Therefore we need to disable interaction
m_Port.pickingMode = PickingMode.Ignore;
container.Add(m_Port);
}
public void InsertBlock(MaterialNodeView nodeView)
{
if (!(nodeView.userData is BlockNode blockNode))
return;
// If index is -1 the node is being added to the end of the Stack
if (blockNode.index == -1)
{
AddElement(nodeView);
return;
}
// Add or Insert based on index
if (blockNode.index >= contentContainer.childCount)
{
AddElement(nodeView);
}
else
{
InsertElement(blockNode.index, nodeView);
}
}
public void InsertElements(int insertIndex, IEnumerable<GraphElement> elements)
{
var blockDatas = elements.Select(x => x.userData as BlockNode).ToArray();
for (int i = 0; i < blockDatas.Length; i++)
{
contextData.blocks.Remove(blockDatas[i]);
}
int count = elements.Count();
var refs = new JsonRef<BlockNode>[count];
for (int i = 0; i < count; i++)
{
refs[i] = blockDatas[i];
}
contextData.blocks.InsertRange(insertIndex, refs);
var window = m_EditorWindow as MaterialGraphEditWindow;
window?.graphEditorView?.graphView?.graph?.ValidateCustomBlockLimit();
}
protected override bool AcceptsElement(GraphElement element, ref int proposedIndex, int maxIndex)
{
return element.userData is BlockNode blockNode && blockNode.descriptor != null &&
blockNode.descriptor.shaderStage == contextData.shaderStage;
}
protected override void OnSeparatorContextualMenuEvent(ContextualMenuPopulateEvent evt, int separatorIndex)
{
base.OnSeparatorContextualMenuEvent(evt, separatorIndex);
InsertCreateNodeAction(evt, separatorIndex, 0);
}
void InsertCreateNodeAction(ContextualMenuPopulateEvent evt, int separatorIndex, int itemIndex)
{
//we need to arbitrarily add the editor position values because node creation context
//exptects a non local coordinate
var mousePosition = evt.mousePosition + m_EditorWindow.position.position;
var graphView = GetFirstAncestorOfType<MaterialGraphView>();
evt.menu.InsertAction(itemIndex, "Add Block Node", (e) =>
{
var context = new NodeCreationContext
{
screenMousePosition = mousePosition,
target = this,
index = separatorIndex,
};
graphView.nodeCreationRequest(context);
});
}
public void Dispose()
{
m_Port = null;
m_ContextData = null;
m_EditorWindow = null;
inputContainer.Clear();
outputContainer.Clear();
}
}
}