This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.Experimental.GraphView;
using UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers;
using UnityEditor.ShaderGraph.Drawing.Views;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector
{
class InspectorView : GraphSubWindow
{
readonly List<Type> m_PropertyDrawerList = new List<Type>();
List<ISelectable> m_CachedSelectionList = new List<ISelectable>();
// There's persistent data that is stored in the graph settings property drawer that we need to hold onto between interactions
IPropertyDrawer m_graphSettingsPropertyDrawer = new GraphDataPropertyDrawer();
public override string windowTitle => "Graph Inspector";
public override string elementName => "InspectorView";
public override string styleName => "InspectorView";
public override string UxmlName => "GraphInspector";
public override string layoutKey => "UnityEditor.ShaderGraph.InspectorWindow";
TabbedView m_GraphInspectorView;
TabbedView m_NodeSettingsTab;
protected VisualElement m_GraphSettingsContainer;
protected VisualElement m_NodeSettingsContainer;
void RegisterPropertyDrawer(Type newPropertyDrawerType)
{
if (typeof(IPropertyDrawer).IsAssignableFrom(newPropertyDrawerType) == false)
Debug.Log("Attempted to register a property drawer that doesn't inherit from IPropertyDrawer!");
var newPropertyDrawerAttribute = newPropertyDrawerType.GetCustomAttribute<SGPropertyDrawerAttribute>();
if (newPropertyDrawerAttribute != null)
{
foreach (var existingPropertyDrawerType in m_PropertyDrawerList)
{
var existingPropertyDrawerAttribute = existingPropertyDrawerType.GetCustomAttribute<SGPropertyDrawerAttribute>();
if (newPropertyDrawerAttribute.propertyType.IsSubclassOf(existingPropertyDrawerAttribute.propertyType))
{
// Derived types need to be at start of list
m_PropertyDrawerList.Insert(0, newPropertyDrawerType);
return;
}
if (existingPropertyDrawerAttribute.propertyType.IsSubclassOf(newPropertyDrawerAttribute.propertyType))
{
// Add new base class type to end of list
m_PropertyDrawerList.Add(newPropertyDrawerType);
// Shift already added existing type to the beginning of the list
m_PropertyDrawerList.Remove(existingPropertyDrawerType);
m_PropertyDrawerList.Insert(0, existingPropertyDrawerType);
return;
}
}
m_PropertyDrawerList.Add(newPropertyDrawerType);
}
else
Debug.Log("Attempted to register property drawer: " + newPropertyDrawerType + " that isn't marked up with the SGPropertyDrawer attribute!");
}
public InspectorView(GraphView graphView) : base(graphView)
{
m_GraphInspectorView = m_MainContainer.Q<TabbedView>("GraphInspectorView");
m_GraphSettingsContainer = m_GraphInspectorView.Q<VisualElement>("GraphSettingsContainer");
m_NodeSettingsContainer = m_GraphInspectorView.Q<VisualElement>("NodeSettingsContainer");
m_ContentContainer.Add(m_GraphInspectorView);
isWindowScrollable = true;
isWindowResizable = true;
var unregisteredPropertyDrawerTypes = TypeCache.GetTypesDerivedFrom<IPropertyDrawer>().ToList();
foreach (var type in unregisteredPropertyDrawerTypes)
{
RegisterPropertyDrawer(type);
}
// By default at startup, show graph settings
m_GraphInspectorView.Activate(m_GraphInspectorView.Q<TabButton>("GraphSettingsButton"));
isWindowScrollable = true;
}
public void InitializeGraphSettings()
{
ShowGraphSettings_Internal(m_GraphSettingsContainer);
}
// If any of the selected items are no longer selected, inspector requires an update
public bool DoesInspectorNeedUpdate()
{
var needUpdate = !m_CachedSelectionList.SequenceEqual(selection);
return needUpdate;
}
public void Update()
{
ShowGraphSettings_Internal(m_GraphSettingsContainer);
m_NodeSettingsContainer.Clear();
try
{
foreach (var selectable in selection)
{
if (selectable is IInspectable inspectable)
{
DrawInspectable(m_NodeSettingsContainer, inspectable);
// Anything selectable in the graph (GraphSettings not included) is only ever interacted with through the
// Node Settings tab so we can make the assumption they want to see that tab
m_GraphInspectorView.Activate(m_GraphInspectorView.Q<TabButton>("NodeSettingsButton"));
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
// Store this for update checks later, copying list deliberately as we dont want a reference
m_CachedSelectionList = new List<ISelectable>(selection);
m_NodeSettingsContainer.MarkDirtyRepaint();
}
void DrawInspectable(
VisualElement outputVisualElement,
IInspectable inspectable,
IPropertyDrawer propertyDrawerToUse = null)
{
InspectorUtils.GatherInspectorContent(m_PropertyDrawerList, outputVisualElement, inspectable, TriggerInspectorUpdate, propertyDrawerToUse);
}
void TriggerInspectorUpdate()
{
Update();
}
// This should be implemented by any inspector class that wants to define its own GraphSettings
// which for SG, is a representation of the settings in GraphData
protected virtual void ShowGraphSettings_Internal(VisualElement contentContainer)
{
var graphEditorView = m_GraphView.GetFirstAncestorOfType<GraphEditorView>();
if (graphEditorView == null)
return;
contentContainer.Clear();
DrawInspectable(contentContainer, (IInspectable)graphView, m_graphSettingsPropertyDrawer);
contentContainer.MarkDirtyRepaint();
}
}
public static class InspectorUtils
{
internal static void GatherInspectorContent(
List<Type> propertyDrawerList,
VisualElement outputVisualElement,
IInspectable inspectable,
Action propertyChangeCallback,
IPropertyDrawer propertyDrawerToUse = null)
{
var dataObject = inspectable.GetObjectToInspect();
if (dataObject == null)
throw new NullReferenceException("DataObject returned by Inspectable is null!");
var properties = inspectable.GetType().GetProperties(BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (properties == null)
throw new NullReferenceException("PropertyInfos returned by Inspectable is null!");
foreach (var propertyInfo in properties)
{
var attribute = propertyInfo.GetCustomAttribute<InspectableAttribute>();
if (attribute == null)
continue;
var propertyType = propertyInfo.GetGetMethod(true).Invoke(inspectable, new object[] {}).GetType();
if (IsPropertyTypeHandled(propertyDrawerList, propertyType, out var propertyDrawerTypeToUse))
{
var propertyDrawerInstance = propertyDrawerToUse ??
(IPropertyDrawer)Activator.CreateInstance(propertyDrawerTypeToUse);
// Assign the inspector update delegate so any property drawer can trigger an inspector update if it needs it
propertyDrawerInstance.inspectorUpdateDelegate = propertyChangeCallback;
// Supply any required data to this particular kind of property drawer
inspectable.SupplyDataToPropertyDrawer(propertyDrawerInstance, propertyChangeCallback);
var propertyGUI = propertyDrawerInstance.DrawProperty(propertyInfo, dataObject, attribute);
outputVisualElement.Add(propertyGUI);
}
}
}
static bool IsPropertyTypeHandled(
List<Type> propertyDrawerList,
Type typeOfProperty,
out Type propertyDrawerToUse)
{
propertyDrawerToUse = null;
// Check to see if a property drawer has been registered that handles this type
foreach (var propertyDrawerType in propertyDrawerList)
{
var typeHandledByPropertyDrawer = propertyDrawerType.GetCustomAttribute<SGPropertyDrawerAttribute>();
// Numeric types and boolean wrapper types like ToggleData handled here
if (typeHandledByPropertyDrawer.propertyType == typeOfProperty)
{
propertyDrawerToUse = propertyDrawerType;
return true;
}
// Generics and Enumerable types are handled here
else if (typeHandledByPropertyDrawer.propertyType.IsAssignableFrom(typeOfProperty))
{
// Before returning it, check for a more appropriate type further
propertyDrawerToUse = propertyDrawerType;
return true;
}
// Enums are weird and need to be handled explicitly as done below as their runtime type isn't the same as System.Enum
else if (typeHandledByPropertyDrawer.propertyType == typeOfProperty.BaseType)
{
propertyDrawerToUse = propertyDrawerType;
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor.Graphing;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph.Internal;
using Object = UnityEngine.Object;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UnityEngine.UIElements.StyleSheets;
namespace UnityEditor.ShaderGraph.Drawing.Inspector
{
class MasterPreviewView : VisualElement
{
PreviewManager m_PreviewManager;
GraphData m_Graph;
PreviewRenderData m_PreviewRenderHandle;
Image m_PreviewTextureView;
public Image previewTextureView
{
get { return m_PreviewTextureView; }
}
Vector2 m_PreviewScrollPosition;
ObjectField m_PreviewMeshPicker;
Mesh m_PreviousMesh;
bool m_RecalculateLayout;
ResizeBorderFrame m_PreviewResizeBorderFrame;
public ResizeBorderFrame previewResizeBorderFrame
{
get { return m_PreviewResizeBorderFrame; }
}
VisualElement m_Preview;
Label m_Title;
public VisualElement preview
{
get { return m_Preview; }
}
List<string> m_DoNotShowPrimitives = new List<string>(new string[] {PrimitiveType.Plane.ToString()});
static Type s_ContextualMenuManipulator = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypesOrNothing()).FirstOrDefault(t => t.FullName == "UnityEngine.UIElements.ContextualMenuManipulator");
static Type s_ObjectSelector = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypesOrNothing()).FirstOrDefault(t => t.FullName == "UnityEditor.ObjectSelector");
public string assetName
{
get { return m_Title.text; }
set { m_Title.text = value; }
}
public MasterPreviewView(PreviewManager previewManager, GraphData graph)
{
style.overflow = Overflow.Hidden;
m_PreviewManager = previewManager;
m_Graph = graph;
styleSheets.Add(Resources.Load<StyleSheet>("Styles/MasterPreviewView"));
m_PreviewRenderHandle = previewManager.masterRenderData;
if (m_PreviewRenderHandle != null)
{
m_PreviewRenderHandle.onPreviewChanged += OnPreviewChanged;
}
var topContainer = new VisualElement() { name = "top" };
{
m_Title = new Label() { name = "title" };
m_Title.text = "Main Preview";
topContainer.Add(m_Title);
}
Add(topContainer);
m_Preview = new VisualElement {name = "middle"};
{
m_PreviewTextureView = CreatePreview(Texture2D.blackTexture);
m_PreviewScrollPosition = new Vector2(0f, 0f);
preview.Add(m_PreviewTextureView);
preview.AddManipulator(new Scrollable(OnScroll));
}
Add(preview);
m_PreviewResizeBorderFrame = new ResizeBorderFrame(this, this) { name = "resizeBorderFrame" };
m_PreviewResizeBorderFrame.maintainAspectRatio = true;
Add(m_PreviewResizeBorderFrame);
m_RecalculateLayout = false;
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
}
Image CreatePreview(Texture texture)
{
if (m_PreviewRenderHandle?.texture != null)
{
texture = m_PreviewRenderHandle.texture;
}
var image = new Image { name = "preview", image = texture };
image.AddManipulator(new Draggable(OnMouseDragPreviewMesh, true));
image.AddManipulator((IManipulator)Activator.CreateInstance(s_ContextualMenuManipulator, (Action<ContextualMenuPopulateEvent>)BuildContextualMenu));
return image;
}
void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
foreach (var primitiveTypeName in Enum.GetNames(typeof(PrimitiveType)))
{
if (m_DoNotShowPrimitives.Contains(primitiveTypeName))
continue;
evt.menu.AppendAction(primitiveTypeName, e => ChangePrimitiveMesh(primitiveTypeName), DropdownMenuAction.AlwaysEnabled);
}
evt.menu.AppendAction("Custom Mesh", e => ChangeMeshCustom(), DropdownMenuAction.AlwaysEnabled);
}
void OnPreviewChanged()
{
m_PreviewTextureView.image = m_PreviewRenderHandle?.texture ?? Texture2D.blackTexture;
if (m_PreviewRenderHandle != null && m_PreviewRenderHandle.shaderData.isOutOfDate)
m_PreviewTextureView.tintColor = new Color(1.0f, 1.0f, 1.0f, 0.3f);
else
m_PreviewTextureView.tintColor = Color.white;
m_PreviewTextureView.MarkDirtyRepaint();
}
void ChangePrimitiveMesh(string primitiveName)
{
Mesh changedPrimitiveMesh = Resources.GetBuiltinResource(typeof(Mesh), string.Format("{0}.fbx", primitiveName)) as Mesh;
ChangeMesh(changedPrimitiveMesh);
}
void ChangeMesh(Mesh mesh)
{
Mesh changedMesh = mesh;
m_PreviewManager.UpdateMasterPreview(ModificationScope.Node);
if (m_Graph.previewData.serializedMesh.mesh != changedMesh)
{
m_Graph.previewData.rotation = Quaternion.identity;
m_PreviewScrollPosition = Vector2.zero;
}
m_Graph.previewData.serializedMesh.mesh = changedMesh;
}
private static EditorWindow Get()
{
PropertyInfo P = s_ObjectSelector.GetProperty("get", BindingFlags.Public | BindingFlags.Static);
return P.GetValue(null, null) as EditorWindow;
}
void OnMeshChanged(Object obj)
{
var mesh = obj as Mesh;
if (mesh == null)
mesh = m_PreviousMesh;
ChangeMesh(mesh);
}
void ChangeMeshCustom()
{
MethodInfo ShowMethod = s_ObjectSelector.GetMethod("Show", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly, Type.DefaultBinder, new[] {typeof(Object), typeof(Type), typeof(Object), typeof(bool), typeof(List<int>), typeof(Action<Object>), typeof(Action<Object>)}, new ParameterModifier[7]);
m_PreviousMesh = m_Graph.previewData.serializedMesh.mesh;
ShowMethod.Invoke(Get(), new object[] { null, typeof(Mesh), null, false, null, (Action<Object>)OnMeshChanged, (Action<Object>)OnMeshChanged });
}
void OnGeometryChanged(GeometryChangedEvent evt)
{
if (m_RecalculateLayout)
{
WindowDockingLayout dockingLayout = new WindowDockingLayout();
dockingLayout.CalculateDockingCornerAndOffset(layout, parent.layout);
dockingLayout.ClampToParentWindow();
dockingLayout.ApplyPosition(this);
m_RecalculateLayout = false;
}
var currentWidth = m_PreviewRenderHandle?.texture != null ? m_PreviewRenderHandle.texture.width : -1;
var currentHeight = m_PreviewRenderHandle?.texture != null ? m_PreviewRenderHandle.texture.height : -1;
var targetWidth = Mathf.Max(1f, m_PreviewTextureView.contentRect.width);
var targetHeight = Mathf.Max(1f, m_PreviewTextureView.contentRect.height);
if (Mathf.Approximately(currentWidth, targetHeight) && Mathf.Approximately(currentHeight, targetWidth))
return;
m_PreviewTextureView.style.width = evt.newRect.width;
m_PreviewTextureView.style.height = evt.newRect.height - 40.0f;
m_PreviewManager.ResizeMasterPreview(new Vector2(evt.newRect.width, evt.newRect.width));
}
void OnScroll(float scrollValue)
{
float rescaleAmount = -scrollValue * .03f;
m_Graph.previewData.scale = Mathf.Clamp(m_Graph.previewData.scale + rescaleAmount, 0.2f, 5f);
m_PreviewManager.UpdateMasterPreview(ModificationScope.Node);
}
void OnMouseDragPreviewMesh(Vector2 deltaMouse)
{
Vector2 previewSize = m_PreviewTextureView.contentRect.size;
m_PreviewScrollPosition -= deltaMouse * (Event.current.shift ? 3f : 1f) / Mathf.Min(previewSize.x, previewSize.y) * 140f;
m_PreviewScrollPosition.y = Mathf.Clamp(m_PreviewScrollPosition.y, -90f, 90f);
Quaternion previewRotation = Quaternion.Euler(m_PreviewScrollPosition.y, 0, 0) * Quaternion.Euler(0, m_PreviewScrollPosition.x, 0);
m_Graph.previewData.rotation = previewRotation;
m_PreviewManager.UpdateMasterPreview(ModificationScope.Node);
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using UnityEngine.UIElements;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEditor.Graphing.Util;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph.Drawing.Inspector
{
public static class PropertyDrawerUtils
{
public static Label CreateLabel(string text, int indentLevel = 0, FontStyle fontStyle = FontStyle.Normal)
{
string label = new string(' ', indentLevel * 4);
var labelVisualElement = new Label(label + text);
labelVisualElement.style.unityFontStyleAndWeight = fontStyle;
return labelVisualElement;
}
public static Label CreateLabel(string text, int indentLevel = 0)
{
string label = new string(' ', indentLevel * 4);
var labelVisualElement = new Label(label + text);
return labelVisualElement;
}
internal static void AddDefaultNodeProperties(VisualElement parentElement, AbstractMaterialNode node, Action setNodesAsDirtyCallback, Action updateNodeViewsCallback)
{
EnumField precisionField = null;
if (node.canSetPrecision)
{
precisionField = new EnumField(node.precision);
var propertyRow = new PropertyRow(new Label("Precision"));
propertyRow.Add(precisionField, (field) =>
{
field.RegisterValueChangedCallback(evt =>
{
if (evt.newValue.Equals(node.precision))
return;
setNodesAsDirtyCallback?.Invoke();
node.owner.owner.RegisterCompleteObjectUndo("Change precision");
node.precision = (Precision)evt.newValue;
node.owner.ValidateGraph();
updateNodeViewsCallback?.Invoke();
node.Dirty(ModificationScope.Graph);
});
});
if (node is Serialization.MultiJsonInternal.UnknownNodeType)
precisionField.SetEnabled(false);
parentElement.Add(propertyRow);
}
EnumField previewField = null;
if (node.hasPreview)
{
previewField = new EnumField(node.m_PreviewMode);
var propertyRow = new PropertyRow(new Label("Preview"));
propertyRow.Add(previewField, (field) =>
{
field.RegisterValueChangedCallback(evt =>
{
if (evt.newValue.Equals(node.m_PreviewMode))
return;
setNodesAsDirtyCallback?.Invoke();
node.owner.owner.RegisterCompleteObjectUndo("Change preview");
node.m_PreviewMode = (PreviewMode)evt.newValue;
updateNodeViewsCallback?.Invoke();
node.Dirty(ModificationScope.Graph);
});
});
if (node is Serialization.MultiJsonInternal.UnknownNodeType)
previewField.SetEnabled(false);
parentElement.Add(propertyRow);
}
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Reflection;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Drawing.Inspector;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using UnityEditor.Graphing.Util;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
internal interface IGetNodePropertyDrawerPropertyData
{
void GetPropertyData(Action setNodesAsDirtyCallback, Action updateNodeViewsCallback);
}
[SGPropertyDrawer(typeof(AbstractMaterialNode))]
public class AbstractMaterialNodePropertyDrawer : IPropertyDrawer, IGetNodePropertyDrawerPropertyData
{
public Action inspectorUpdateDelegate { get; set; }
Action m_setNodesAsDirtyCallback;
Action m_updateNodeViewsCallback;
public void GetPropertyData(Action setNodesAsDirtyCallback, Action updateNodeViewsCallback)
{
m_setNodesAsDirtyCallback = setNodesAsDirtyCallback;
m_updateNodeViewsCallback = updateNodeViewsCallback;
}
VisualElement CreateGUI(AbstractMaterialNode node, InspectableAttribute attribute, out VisualElement propertyVisualElement)
{
VisualElement nodeSettings = new VisualElement();
var nameLabel = PropertyDrawerUtils.CreateLabel($"{node.name} Node", 0, FontStyle.Bold);
nodeSettings.Add(nameLabel);
if (node.sgVersion < node.latestVersion)
{
var help = HelpBoxRow.TryGetDeprecatedHelpBoxRow($"{node.name} Node", () =>
{
m_setNodesAsDirtyCallback?.Invoke();
node.owner.owner.RegisterCompleteObjectUndo($"Update {node.name} Node");
node.ChangeVersion(node.latestVersion);
inspectorUpdateDelegate?.Invoke();
m_updateNodeViewsCallback?.Invoke();
node.Dirty(ModificationScope.Graph);
});
if (help != null)
{
nodeSettings.Insert(0, help);
}
}
PropertyDrawerUtils.AddDefaultNodeProperties(nodeSettings, node, m_setNodesAsDirtyCallback, m_updateNodeViewsCallback);
propertyVisualElement = null;
return nodeSettings;
}
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
(AbstractMaterialNode)actualObject,
attribute,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Reflection;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(bool))]
class BoolPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(bool newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
bool fieldToDraw,
string labelName,
out VisualElement propertyToggle,
int indentLevel = 0)
{
var row = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
// Create and assign toggle as out variable here so that callers can also do additional work with enabling/disabling if needed
propertyToggle = new Toggle();
row.Add((Toggle)propertyToggle, (toggle) =>
{
toggle.value = fieldToDraw;
});
if (valueChangedCallback != null)
{
var toggle = (Toggle)propertyToggle;
toggle.OnToggleChanged(evt => valueChangedCallback(evt.newValue));
}
row.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return row;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(
PropertyInfo propertyInfo,
object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newBoolValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newBoolValue}),
(bool)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Color))]
class ColorPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Color newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Color fieldToDraw,
string labelName,
out VisualElement propertyColorField,
int indentLevel = 0)
{
var colorField = new ColorField { value = fieldToDraw, showEyeDropper = false, hdr = false };
if (valueChangedCallback != null)
{
colorField.RegisterValueChangedCallback(evt => { valueChangedCallback((Color)evt.newValue); });
}
propertyColorField = colorField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyColorField);
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Color)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Cubemap))]
class CubemapPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Cubemap newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Cubemap fieldToDraw,
string labelName,
out VisualElement propertyCubemapField,
int indentLevel = 0)
{
var objectField = new ObjectField { value = fieldToDraw, objectType = typeof(Cubemap)};
if (valueChangedCallback != null)
{
objectField.RegisterValueChangedCallback(evt => { valueChangedCallback((Cubemap)evt.newValue); });
}
propertyCubemapField = objectField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyCubemapField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Cubemap)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Reflection;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Drawing.Inspector;
using UnityEngine.UIElements;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(CustomFunctionNode))]
public class CustomFunctionNodePropertyDrawer : IPropertyDrawer, IGetNodePropertyDrawerPropertyData
{
Action m_setNodesAsDirtyCallback;
Action m_updateNodeViewsCallback;
void IGetNodePropertyDrawerPropertyData.GetPropertyData(Action setNodesAsDirtyCallback, Action updateNodeViewsCallback)
{
m_setNodesAsDirtyCallback = setNodesAsDirtyCallback;
m_updateNodeViewsCallback = updateNodeViewsCallback;
}
VisualElement CreateGUI(CustomFunctionNode node, InspectableAttribute attribute,
out VisualElement propertyVisualElement)
{
var propertySheet = new PropertySheet(PropertyDrawerUtils.CreateLabel($"{node.name} Node", 0, FontStyle.Bold));
PropertyDrawerUtils.AddDefaultNodeProperties(propertySheet, node, m_setNodesAsDirtyCallback, m_updateNodeViewsCallback);
var inputListView = new ReorderableSlotListView(node, SlotType.Input, true);
inputListView.OnAddCallback += list => inspectorUpdateDelegate();
inputListView.OnRemoveCallback += list => inspectorUpdateDelegate();
inputListView.OnListRecreatedCallback += () => inspectorUpdateDelegate();
propertySheet.Add(inputListView);
var outputListView = new ReorderableSlotListView(node, SlotType.Output, true);
outputListView.OnAddCallback += list => inspectorUpdateDelegate();
outputListView.OnRemoveCallback += list => inspectorUpdateDelegate();
outputListView.OnListRecreatedCallback += () => inspectorUpdateDelegate();
propertySheet.Add(outputListView);
propertySheet.Add(new HlslFunctionView(node));
propertyVisualElement = null;
return propertySheet;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(
(CustomFunctionNode)actualObject,
attribute,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(IEnumerable<string>))]
class DropdownPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(int newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
IEnumerable<string> fieldToDraw,
string labelName,
out VisualElement textArrayField,
int indentLevel = 0)
{
var propertyRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
textArrayField = new PopupField<string>(fieldToDraw.ToList(), 0);
propertyRow.Add(textArrayField);
var popupField = (PopupField<string>)textArrayField;
popupField.RegisterValueChangedCallback(evt =>
{
valueChangedCallback(popupField.index);
});
propertyRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return propertyRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newSelectedIndex => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newSelectedIndex}),
(IEnumerable<string>)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var textArrayField);
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Reflection;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Enum))]
class EnumPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Enum newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Enum fieldToDraw,
string labelName,
Enum defaultValue,
out VisualElement propertyVisualElement,
int indentLevel = 0)
{
var row = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
propertyVisualElement = new EnumField(defaultValue);
row.Add((EnumField)propertyVisualElement, (field) =>
{
field.value = fieldToDraw;
});
if (valueChangedCallback != null)
{
var enumField = (EnumField)propertyVisualElement;
enumField.RegisterValueChangedCallback(evt => valueChangedCallback(evt.newValue));
}
return row;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(
PropertyInfo propertyInfo,
object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(newEnumValue =>
propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newEnumValue}),
(Enum)propertyInfo.GetValue(actualObject),
attribute.labelName,
(Enum)attribute.defaultValue,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(float))]
class FloatPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(float newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
float fieldToDraw,
string labelName,
out VisualElement propertyFloatField,
int indentLevel = 0)
{
var floatField = new FloatField {label = "X", value = fieldToDraw};
floatField.labelElement.style.minWidth = 15;
if (valueChangedCallback != null)
{
floatField.RegisterValueChangedCallback(evt => { valueChangedCallback((float)evt.newValue); });
}
propertyFloatField = floatField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyFloatField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(float)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Gradient))]
class GradientPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Gradient newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Gradient fieldToDraw,
string labelName,
out VisualElement propertyGradientField,
int indentLevel = 0)
{
var objectField = new GradientField { value = fieldToDraw, colorSpace = ColorSpace.Linear};
if (valueChangedCallback != null)
{
objectField.RegisterValueChangedCallback(evt => { valueChangedCallback((Gradient)evt.newValue); });
}
propertyGradientField = objectField;
// Any core widgets used by the inspector over and over should come from some kind of factory
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyGradientField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Gradient)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditorInternal;
using UnityEditor.ShaderGraph.Serialization;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(GraphData))]
public class GraphDataPropertyDrawer : IPropertyDrawer
{
public delegate void ChangeConcretePrecisionCallback(ConcretePrecision newValue);
public delegate void PostTargetSettingsChangedCallback();
PostTargetSettingsChangedCallback m_postChangeTargetSettingsCallback;
ChangeConcretePrecisionCallback m_postChangeConcretePrecisionCallback;
Dictionary<Target, bool> m_TargetFoldouts = new Dictionary<Target, bool>();
public void GetPropertyData(
PostTargetSettingsChangedCallback postChangeValueCallback,
ChangeConcretePrecisionCallback changeConcretePrecisionCallback)
{
m_postChangeTargetSettingsCallback = postChangeValueCallback;
m_postChangeConcretePrecisionCallback = changeConcretePrecisionCallback;
}
VisualElement GetSettings(GraphData graphData, Action onChange)
{
var element = new VisualElement() { name = "graphSettings" };
if (graphData.isSubGraph)
return element;
void RegisterActionToUndo(string actionName)
{
graphData.owner.RegisterCompleteObjectUndo(actionName);
}
// Add Label
var targetSettingsLabel = new Label("Target Settings");
targetSettingsLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
element.Add(new PropertyRow(targetSettingsLabel));
var targetList = new ReorderableListView<JsonData<Target>>(
graphData.m_ActiveTargets,
"Active Targets",
false, // disallow reordering (active list is sorted)
target => target.value.displayName);
targetList.GetAddMenuOptions = () => graphData.GetPotentialTargetDisplayNames();
targetList.OnAddMenuItemCallback +=
(list, addMenuOptionIndex, addMenuOption) =>
{
RegisterActionToUndo("Add Target");
graphData.SetTargetActive(addMenuOptionIndex);
m_postChangeTargetSettingsCallback();
};
targetList.RemoveItemCallback +=
(list, itemIndex) =>
{
RegisterActionToUndo("Remove Target");
graphData.SetTargetInactive(list[itemIndex].value);
m_postChangeTargetSettingsCallback();
};
element.Add(targetList);
// Iterate active TargetImplementations
foreach (var target in graphData.activeTargets)
{
// Ensure enabled state is being tracked and get value
bool foldoutActive;
if (!m_TargetFoldouts.TryGetValue(target, out foldoutActive))
{
foldoutActive = true;
m_TargetFoldouts.Add(target, foldoutActive);
}
// Create foldout
var foldout = new Foldout() { text = target.displayName, value = foldoutActive, name = "foldout" };
element.Add(foldout);
foldout.AddToClassList("MainFoldout");
foldout.RegisterValueChangedCallback(evt =>
{
// Update foldout value and rebuild
m_TargetFoldouts[target] = evt.newValue;
foldout.value = evt.newValue;
onChange();
});
if (foldout.value)
{
// Get settings for Target
var context = new TargetPropertyGUIContext();
target.GetPropertiesGUI(ref context, onChange, RegisterActionToUndo);
element.Add(context);
}
}
return element;
}
internal VisualElement CreateGUI(GraphData graphData)
{
var propertySheet = new VisualElement() {name = "graphSettings"};
if (graphData == null)
{
Debug.Log("Attempting to draw something that isn't of type GraphData with a GraphDataPropertyDrawer");
return propertySheet;
}
{
var enumPropertyDrawer = new EnumPropertyDrawer();
propertySheet.Add(enumPropertyDrawer.CreateGUI(
newValue => { m_postChangeConcretePrecisionCallback((ConcretePrecision)newValue); },
graphData.concretePrecision,
"Precision",
ConcretePrecision.Single,
out var propertyVisualElement));
}
if (graphData.isSubGraph)
{
var enumPropertyDrawer = new EnumPropertyDrawer();
propertySheet.Add(enumPropertyDrawer.CreateGUI(
newValue =>
{
graphData.owner.RegisterCompleteObjectUndo("Change Preview Mode");
graphData.previewMode = (PreviewMode)newValue;
},
graphData.previewMode,
"Preview",
PreviewMode.Inherit,
out var propertyVisualElement));
}
propertySheet.Add(GetSettings(graphData, () => this.m_postChangeTargetSettingsCallback()));
return propertySheet;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI((GraphData)actualObject);
}
}
}

View File

@@ -0,0 +1,9 @@
using static UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers.ShaderInputPropertyDrawer;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
interface IShaderPropertyDrawer
{
internal void HandlePropertyField(PropertySheet propertySheet, PreChangeValueCallback preChangeValueCallback, PostChangeValueCallback postChangeValueCallback);
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(int))]
class IntegerPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(int newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
int fieldToDraw,
string labelName,
out VisualElement propertyFloatField,
int indentLevel = 0)
{
var integerField = new IntegerField {value = fieldToDraw};
if (valueChangedCallback != null)
{
integerField.RegisterValueChangedCallback(evt => { valueChangedCallback(evt.newValue); });
}
propertyFloatField = integerField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyFloatField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(int)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,372 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Matrix4x4))]
class MatrixPropertyDrawer : IPropertyDrawer
{
public enum MatrixDimensions
{
Two,
Three,
Four
}
public MatrixDimensions dimension { get; set; }
public delegate Vector4 GetMatrixRowDelegate(int rowNumber);
internal Action PreValueChangeCallback;
internal delegate void ValueChangedCallback(Matrix4x4 newValue);
internal Action PostValueChangeCallback;
// Matrix4x4, Matrix3x3, Matrix2x2 are all value types,
// hence the local value doesn't stay up to date after modified
// Need a callback to fetch the row data directly from the source
internal GetMatrixRowDelegate MatrixRowFetchCallback;
void HandleMatrix2Property(
ValueChangedCallback valueChangedCallback,
PropertySheet propertySheet,
Matrix4x4 matrix2Property,
string labelName = "Default")
{
var vector2PropertyDrawer = new Vector2PropertyDrawer();
vector2PropertyDrawer.preValueChangeCallback = PreValueChangeCallback;
vector2PropertyDrawer.postValueChangeCallback = PostValueChangeCallback;
propertySheet.Add(vector2PropertyDrawer.CreateGUI(
newValue =>
{
Vector2 row1 = MatrixRowFetchCallback(1);
valueChangedCallback(new Matrix4x4()
{
m00 = newValue.x,
m01 = newValue.y,
m02 = 0,
m03 = 0,
m10 = row1.x,
m11 = row1.y,
m12 = 0,
m13 = 0,
m20 = 0,
m21 = 0,
m22 = 0,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 0,
});
},
matrix2Property.GetRow(0),
labelName,
out var row0Field
));
propertySheet.Add(vector2PropertyDrawer.CreateGUI(
newValue =>
{
Vector2 row0 = MatrixRowFetchCallback(0);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = 0,
m03 = 0,
m10 = newValue.x,
m11 = newValue.y,
m12 = 0,
m13 = 0,
m20 = 0,
m21 = 0,
m22 = 0,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 0,
});
},
matrix2Property.GetRow(1),
"",
out var row1Field
));
}
void HandleMatrix3Property(
ValueChangedCallback valueChangedCallback,
PropertySheet propertySheet,
Matrix4x4 matrix3Property,
string labelName = "Default")
{
var vector3PropertyDrawer = new Vector3PropertyDrawer();
vector3PropertyDrawer.preValueChangeCallback = PreValueChangeCallback;
vector3PropertyDrawer.postValueChangeCallback = PostValueChangeCallback;
propertySheet.Add(vector3PropertyDrawer.CreateGUI(
newValue =>
{
Vector3 row1 = MatrixRowFetchCallback(1);
Vector3 row2 = MatrixRowFetchCallback(2);
valueChangedCallback(new Matrix4x4()
{
m00 = newValue.x,
m01 = newValue.y,
m02 = newValue.z,
m03 = 0,
m10 = row1.x,
m11 = row1.y,
m12 = row1.z,
m13 = 0,
m20 = row2.x,
m21 = row2.y,
m22 = row2.z,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 0,
});
},
matrix3Property.GetRow(0),
labelName,
out var row0Field
));
propertySheet.Add(vector3PropertyDrawer.CreateGUI(
newValue =>
{
Vector3 row0 = MatrixRowFetchCallback(0);
Vector3 row2 = MatrixRowFetchCallback(2);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = row0.z,
m03 = 0,
m10 = newValue.x,
m11 = newValue.y,
m12 = newValue.z,
m13 = 0,
m20 = row2.x,
m21 = row2.y,
m22 = row2.z,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 0,
});
},
matrix3Property.GetRow(1),
"",
out var row1Field
));
propertySheet.Add(vector3PropertyDrawer.CreateGUI(
newValue =>
{
Vector3 row0 = MatrixRowFetchCallback(0);
Vector3 row1 = MatrixRowFetchCallback(1);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = row0.z,
m03 = 0,
m10 = row1.x,
m11 = row1.y,
m12 = row1.z,
m13 = 0,
m20 = newValue.x,
m21 = newValue.y,
m22 = newValue.z,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 0,
});
},
matrix3Property.GetRow(2),
"",
out var row2Field
));
}
void HandleMatrix4Property(
ValueChangedCallback valueChangedCallback,
PropertySheet propertySheet,
Matrix4x4 matrix4Property,
string labelName = "Default")
{
var vector4PropertyDrawer = new Vector4PropertyDrawer();
vector4PropertyDrawer.preValueChangeCallback = PreValueChangeCallback;
vector4PropertyDrawer.postValueChangeCallback = PostValueChangeCallback;
propertySheet.Add(vector4PropertyDrawer.CreateGUI(
newValue =>
{
Vector4 row1 = MatrixRowFetchCallback(1);
Vector4 row2 = MatrixRowFetchCallback(2);
Vector4 row3 = MatrixRowFetchCallback(3);
valueChangedCallback(new Matrix4x4()
{
m00 = newValue.x,
m01 = newValue.y,
m02 = newValue.z,
m03 = newValue.w,
m10 = row1.x,
m11 = row1.y,
m12 = row1.z,
m13 = row1.w,
m20 = row2.x,
m21 = row2.y,
m22 = row2.z,
m23 = row2.w,
m30 = row3.x,
m31 = row3.y,
m32 = row3.z,
m33 = row3.w,
});
},
matrix4Property.GetRow(0),
labelName,
out var row0Field
));
propertySheet.Add(vector4PropertyDrawer.CreateGUI(
newValue =>
{
Vector4 row0 = MatrixRowFetchCallback(0);
Vector4 row2 = MatrixRowFetchCallback(2);
Vector4 row3 = MatrixRowFetchCallback(3);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = row0.z,
m03 = row0.w,
m10 = newValue.x,
m11 = newValue.y,
m12 = newValue.z,
m13 = newValue.w,
m20 = row2.x,
m21 = row2.y,
m22 = row2.z,
m23 = row2.w,
m30 = row3.x,
m31 = row3.y,
m32 = row3.z,
m33 = row3.w,
});
},
matrix4Property.GetRow(1),
"",
out var row1Field
));
propertySheet.Add(vector4PropertyDrawer.CreateGUI(
newValue =>
{
Vector4 row0 = MatrixRowFetchCallback(0);
Vector4 row1 = MatrixRowFetchCallback(1);
Vector4 row3 = MatrixRowFetchCallback(3);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = row0.z,
m03 = row0.w,
m10 = row1.x,
m11 = row1.y,
m12 = row1.z,
m13 = row1.w,
m20 = newValue.x,
m21 = newValue.y,
m22 = newValue.z,
m23 = newValue.w,
m30 = row3.x,
m31 = row3.y,
m32 = row3.z,
m33 = row3.w,
});
},
matrix4Property.GetRow(2),
"",
out var row2Field));
propertySheet.Add(vector4PropertyDrawer.CreateGUI(
newValue =>
{
Vector4 row0 = MatrixRowFetchCallback(0);
Vector4 row1 = MatrixRowFetchCallback(1);
Vector4 row2 = MatrixRowFetchCallback(2);
valueChangedCallback(new Matrix4x4()
{
m00 = row0.x,
m01 = row0.y,
m02 = row0.z,
m03 = row0.w,
m10 = row1.x,
m11 = row1.y,
m12 = row1.z,
m13 = row1.w,
m20 = row2.x,
m21 = row2.y,
m22 = row2.z,
m23 = row2.w,
m30 = newValue.x,
m31 = newValue.y,
m32 = newValue.z,
m33 = newValue.w,
});
},
matrix4Property.GetRow(3),
"",
out var row3Field
));
}
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Matrix4x4 fieldToDraw,
string labelName,
out VisualElement propertyMatrixField,
int indentLevel = 0)
{
var propertySheet = new PropertySheet();
switch (dimension)
{
case MatrixDimensions.Two:
HandleMatrix2Property(valueChangedCallback, propertySheet, fieldToDraw, labelName);
break;
case MatrixDimensions.Three:
HandleMatrix3Property(valueChangedCallback, propertySheet, fieldToDraw, labelName);
break;
case MatrixDimensions.Four:
HandleMatrix4Property(valueChangedCallback, propertySheet, fieldToDraw, labelName);
break;
}
propertyMatrixField = propertySheet;
return propertyMatrixField;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Matrix4x4)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.Graphing;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(SampleVirtualTextureNode))]
public class SampleVirtualTextureNodePropertyDrawer : IPropertyDrawer
{
VisualElement CreateGUI(SampleVirtualTextureNode node, InspectableAttribute attribute,
out VisualElement propertyVisualElement)
{
PropertySheet propertySheet = new PropertySheet();
var enumPropertyDrawer = new EnumPropertyDrawer();
propertySheet.Add(enumPropertyDrawer.CreateGUI((newValue) =>
{
if (node.addressMode == (SampleVirtualTextureNode.AddressMode)newValue)
return;
node.owner.owner.RegisterCompleteObjectUndo("Address Mode Change");
node.addressMode = (SampleVirtualTextureNode.AddressMode)newValue;
},
node.addressMode,
"Address Mode",
SampleVirtualTextureNode.AddressMode.VtAddressMode_Wrap,
out var addressModeVisualElement));
propertySheet.Add(enumPropertyDrawer.CreateGUI((newValue) =>
{
if (node.lodCalculation == (SampleVirtualTextureNode.LodCalculation)newValue)
return;
node.owner.owner.RegisterCompleteObjectUndo("Lod Mode Change");
node.lodCalculation = (SampleVirtualTextureNode.LodCalculation)newValue;
},
node.lodCalculation,
"Lod Mode",
SampleVirtualTextureNode.LodCalculation.VtLevel_Automatic,
out var lodCalculationVisualElement));
propertySheet.Add(enumPropertyDrawer.CreateGUI((newValue) =>
{
if (node.sampleQuality == (SampleVirtualTextureNode.QualityMode)newValue)
return;
node.owner.owner.RegisterCompleteObjectUndo("Quality Change");
node.sampleQuality = (SampleVirtualTextureNode.QualityMode)newValue;
},
node.sampleQuality,
"Quality",
SampleVirtualTextureNode.QualityMode.VtSampleQuality_High,
out var qualityVisualElement));
var boolPropertyDrawer = new BoolPropertyDrawer();
propertySheet.Add(boolPropertyDrawer.CreateGUI((newValue) =>
{
if (node.noFeedback == !newValue)
return;
node.owner.owner.RegisterCompleteObjectUndo("Feedback Settings Change");
node.noFeedback = !newValue;
},
!node.noFeedback,
"Automatic Streaming",
out var propertyToggle));
// display warning if the current master node doesn't support virtual texturing
// TODO: Add warning when no active subTarget supports VT
// if (!node.owner.isSubGraph)
// {
// bool supportedByMasterNode =
// node.owner.GetNodes<IMasterNode>().FirstOrDefault()?.supportsVirtualTexturing ?? false;
// if (!supportedByMasterNode)
// propertySheet.Add(new HelpBoxRow(MessageType.Warning),
// (row) => row.Add(new Label(
// "The current master node does not support Virtual Texturing, this node will do regular 2D sampling.")));
// }
// display warning if the current render pipeline doesn't support virtual texturing
IVirtualTexturingEnabledRenderPipeline vtRp =
GraphicsSettings.currentRenderPipeline as IVirtualTexturingEnabledRenderPipeline;
if (vtRp == null)
propertySheet.Add(new HelpBoxRow(MessageType.Warning),
(row) => row.Add(new Label(
"The current render pipeline does not support Virtual Texturing, this node will do regular 2D sampling.")));
else if (vtRp.virtualTexturingEnabled == false)
propertySheet.Add(new HelpBoxRow(MessageType.Warning),
(row) => row.Add(new Label(
"The current render pipeline has disabled Virtual Texturing, this node will do regular 2D sampling.")));
else
{
#if !ENABLE_VIRTUALTEXTURES
propertySheet.Add(new HelpBoxRow(MessageType.Warning),
(row) => row.Add(new Label(
"Virtual Texturing is disabled globally (possibly by the render pipeline settings), this node will do regular 2D sampling.")));
#endif
}
propertyVisualElement = propertySheet;
return propertySheet;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(
(SampleVirtualTextureNode)actualObject,
attribute,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Reflection;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Drawing.Inspector;
using UnityEngine.UIElements;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(SubGraphOutputNode))]
public class SubGraphOutputNodePropertyDrawer : IPropertyDrawer
{
VisualElement CreateGUI(SubGraphOutputNode node, InspectableAttribute attribute,
out VisualElement propertyVisualElement)
{
var propertySheet = new PropertySheet(PropertyDrawerUtils.CreateLabel($"{node.name} Node", 0, FontStyle.Bold));
var inputListView = new ReorderableSlotListView(node, SlotType.Input, false);
inputListView.OnAddCallback += list => inspectorUpdateDelegate();
inputListView.OnRemoveCallback += list => inspectorUpdateDelegate();
inputListView.OnListRecreatedCallback += () => inspectorUpdateDelegate();
inputListView.AllowedTypeCallback = SlotValueHelper.AllowedAsSubgraphOutput;
propertySheet.Add(inputListView);
propertyVisualElement = propertySheet;
return propertySheet;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(
(SubGraphOutputNode)actualObject,
attribute,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Reflection;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(string))]
class TextPropertyDrawer : IPropertyDrawer
{
public TextField textField;
public Label label;
internal delegate void ValueChangedCallback(string newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
string fieldToDraw,
string labelName,
int indentLevel = 0)
{
label = PropertyDrawerUtils.CreateLabel(labelName, indentLevel);
var propertyRow = new PropertyRow(label);
textField = new TextField(512, false, false, ' ') { isDelayed = true };
propertyRow.Add(textField,
textField =>
{
textField.value = fieldToDraw;
});
if (valueChangedCallback != null)
{
textField.RegisterValueChangedCallback(evt => valueChangedCallback(evt.newValue));
}
propertyRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return propertyRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newStringValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newStringValue}),
(string)propertyInfo.GetValue(actualObject),
attribute.labelName);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Texture2DArray))]
class Texture2DArrayPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Texture2DArray newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Texture2DArray fieldToDraw,
string labelName,
out VisualElement propertyColorField,
int indentLevel = 0)
{
var objectField = new ObjectField { value = fieldToDraw, objectType = typeof(Texture2DArray)};
if (valueChangedCallback != null)
{
objectField.RegisterValueChangedCallback(evt => { valueChangedCallback((Texture2DArray)evt.newValue); });
}
propertyColorField = objectField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyColorField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Texture2DArray)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Texture))]
class Texture2DPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Texture newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Texture fieldToDraw,
string labelName,
out VisualElement propertyColorField,
int indentLevel = 0)
{
var objectField = new ObjectField { value = fieldToDraw, objectType = typeof(Texture)};
if (valueChangedCallback != null)
{
objectField.RegisterValueChangedCallback(evt => { valueChangedCallback((Texture)evt.newValue); });
}
propertyColorField = objectField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyColorField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Texture)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Texture3D))]
class Texture3DPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Texture3D newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Texture fieldToDraw,
string labelName,
out VisualElement propertyColorField,
int indentLevel = 0)
{
var objectField = new ObjectField { value = fieldToDraw, objectType = typeof(Texture3D)};
if (valueChangedCallback != null)
{
objectField.RegisterValueChangedCallback(evt => { valueChangedCallback((Texture3D)evt.newValue); });
}
propertyColorField = objectField;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyColorField);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Texture3D)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Reflection;
using UnityEditor.Graphing.Util;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.ShaderGraph.Drawing.Controls;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(ToggleData))]
class ToggleDataPropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(ToggleData newValue);
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
ToggleData fieldToDraw,
string labelName,
out VisualElement propertyToggle,
int indentLevel = 0)
{
var row = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
// Create and assign toggle as out variable here so that callers can also do additional work with enabling/disabling if needed
propertyToggle = new Toggle();
row.Add((Toggle)propertyToggle, (toggle) =>
{
toggle.value = fieldToDraw.isOn;
});
if (valueChangedCallback != null)
{
var toggle = (Toggle)propertyToggle;
toggle.OnToggleChanged(evt => valueChangedCallback(new ToggleData(evt.newValue)));
}
row.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return row;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(
PropertyInfo propertyInfo,
object actualObject,
InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newBoolValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newBoolValue}),
(ToggleData)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Vector2))]
class Vector2PropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Vector2 newValue);
public Action preValueChangeCallback { get; set; }
public Action postValueChangeCallback { get; set; }
EventCallback<KeyDownEvent> m_KeyDownCallback;
EventCallback<FocusOutEvent> m_FocusOutCallback;
public int mUndoGroup { get; set; } = -1;
public Vector2PropertyDrawer()
{
CreateCallbacks();
}
void CreateCallbacks()
{
m_KeyDownCallback = new EventCallback<KeyDownEvent>(evt =>
{
// Record Undo for input field edit
if (mUndoGroup == -1)
{
mUndoGroup = Undo.GetCurrentGroup();
preValueChangeCallback?.Invoke();
}
// Handle escaping input field edit
if (evt.keyCode == KeyCode.Escape && mUndoGroup > -1)
{
Undo.RevertAllDownToGroup(mUndoGroup);
mUndoGroup = -1;
evt.StopPropagation();
}
// Dont record Undo again until input field is unfocused
mUndoGroup++;
postValueChangeCallback?.Invoke();
});
m_FocusOutCallback = new EventCallback<FocusOutEvent>(evt =>
{
// Reset UndoGroup when done editing input field
mUndoGroup = -1;
});
}
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Vector2 fieldToDraw,
string labelName,
out VisualElement propertyVec2Field,
int indentLevel = 0)
{
var vector2Field = new Vector2Field {value = fieldToDraw};
var inputFields = vector2Field.Query("unity-text-input").ToList();
foreach (var inputField in inputFields)
{
inputField.RegisterCallback<KeyDownEvent>(m_KeyDownCallback);
inputField.RegisterCallback<FocusOutEvent>(m_FocusOutCallback);
}
// Bind value changed event to callback to handle dragger behavior before actually settings the value
vector2Field.RegisterValueChangedCallback(evt =>
{
// Only true when setting value via FieldMouseDragger
// Undo recorded once per dragger release
if (mUndoGroup == -1)
preValueChangeCallback?.Invoke();
valueChangedCallback(evt.newValue);
postValueChangeCallback?.Invoke();
});
propertyVec2Field = vector2Field;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyVec2Field);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Vector2)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Vector3))]
class Vector3PropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Vector3 newValue);
public Action preValueChangeCallback { get; set; }
public Action postValueChangeCallback { get; set; }
EventCallback<KeyDownEvent> m_KeyDownCallback;
EventCallback<FocusOutEvent> m_FocusOutCallback;
public int mUndoGroup { get; set; } = -1;
void CreateCallbacks()
{
m_KeyDownCallback = new EventCallback<KeyDownEvent>(evt =>
{
// Record Undo for input field edit
if (mUndoGroup == -1)
{
mUndoGroup = Undo.GetCurrentGroup();
preValueChangeCallback?.Invoke();
}
// Handle escaping input field edit
if (evt.keyCode == KeyCode.Escape && mUndoGroup > -1)
{
Undo.RevertAllDownToGroup(mUndoGroup);
mUndoGroup = -1;
evt.StopPropagation();
}
// Dont record Undo again until input field is unfocused
mUndoGroup++;
postValueChangeCallback?.Invoke();
});
m_FocusOutCallback = new EventCallback<FocusOutEvent>(evt =>
{
// Reset UndoGroup when done editing input field
mUndoGroup = -1;
});
}
public Vector3PropertyDrawer()
{
CreateCallbacks();
}
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Vector3 fieldToDraw,
string labelName,
out VisualElement propertyVec3Field,
int indentLevel = 0)
{
var vector3Field = new Vector3Field {value = fieldToDraw};
var inputFields = vector3Field.Query("unity-text-input").ToList();
foreach (var inputField in inputFields)
{
inputField.RegisterCallback<KeyDownEvent>(m_KeyDownCallback);
inputField.RegisterCallback<FocusOutEvent>(m_FocusOutCallback);
}
vector3Field.RegisterValueChangedCallback(evt =>
{
// Only true when setting value via FieldMouseDragger
// Undo recorded once per dragger release
if (mUndoGroup == -1)
preValueChangeCallback?.Invoke();
valueChangedCallback(evt.newValue);
postValueChangeCallback?.Invoke();
});
propertyVec3Field = vector3Field;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyVec3Field);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Vector3)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.ShaderGraph.Drawing;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers
{
[SGPropertyDrawer(typeof(Vector4))]
class Vector4PropertyDrawer : IPropertyDrawer
{
internal delegate void ValueChangedCallback(Vector4 newValue);
public Action preValueChangeCallback { get; set; }
public Action postValueChangeCallback { get; set; }
EventCallback<KeyDownEvent> m_KeyDownCallback;
EventCallback<FocusOutEvent> m_FocusOutCallback;
public int mUndoGroup { get; set; } = -1;
void CreateCallbacks()
{
m_KeyDownCallback = new EventCallback<KeyDownEvent>(evt =>
{
// Record Undo for input field edit
if (mUndoGroup == -1)
{
mUndoGroup = Undo.GetCurrentGroup();
preValueChangeCallback?.Invoke();
}
// Handle escaping input field edit
if (evt.keyCode == KeyCode.Escape && mUndoGroup > -1)
{
Undo.RevertAllDownToGroup(mUndoGroup);
mUndoGroup = -1;
evt.StopPropagation();
}
// Dont record Undo again until input field is unfocused
mUndoGroup++;
postValueChangeCallback?.Invoke();
});
m_FocusOutCallback = new EventCallback<FocusOutEvent>(evt =>
{
// Reset UndoGroup when done editing input field
mUndoGroup = -1;
});
}
public Vector4PropertyDrawer()
{
CreateCallbacks();
}
internal VisualElement CreateGUI(
ValueChangedCallback valueChangedCallback,
Vector4 fieldToDraw,
string labelName,
out VisualElement propertyVec4Field,
int indentLevel = 0)
{
var vector4Field = new Vector4Field {value = fieldToDraw};
var inputFields = vector4Field.Query("unity-text-input").ToList();
foreach (var inputField in inputFields)
{
inputField.RegisterCallback<KeyDownEvent>(m_KeyDownCallback);
inputField.RegisterCallback<FocusOutEvent>(m_FocusOutCallback);
}
vector4Field.RegisterValueChangedCallback(evt =>
{
// Only true when setting value via FieldMouseDragger
// Undo recorded once per dragger release
if (mUndoGroup == -1)
preValueChangeCallback?.Invoke();
valueChangedCallback(evt.newValue);
postValueChangeCallback?.Invoke();
});
propertyVec4Field = vector4Field;
var defaultRow = new PropertyRow(PropertyDrawerUtils.CreateLabel(labelName, indentLevel));
defaultRow.Add(propertyVec4Field);
defaultRow.styleSheets.Add(Resources.Load<StyleSheet>("Styles/PropertyRow"));
return defaultRow;
}
public Action inspectorUpdateDelegate { get; set; }
public VisualElement DrawProperty(PropertyInfo propertyInfo, object actualObject, InspectableAttribute attribute)
{
return this.CreateGUI(
// Use the setter from the provided property as the callback
newValue => propertyInfo.GetSetMethod(true).Invoke(actualObject, new object[] {newValue}),
(Vector4)propertyInfo.GetValue(actualObject),
attribute.labelName,
out var propertyVisualElement);
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
using UnityEngine;
using UnityEngine.UIElements;
public class TabButton : VisualElement
{
internal new class UxmlFactory : UxmlFactory<TabButton, UxmlTraits> {}
internal new class UxmlTraits : VisualElement.UxmlTraits
{
private readonly UxmlStringAttributeDescription m_Text = new UxmlStringAttributeDescription { name = "text" };
private readonly UxmlStringAttributeDescription m_Target = new UxmlStringAttributeDescription { name = "target" };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
TabButton item = ve as TabButton;
item.m_Label.text = m_Text.GetValueFromBag(bag, cc);
item.TargetId = m_Target.GetValueFromBag(bag, cc);
}
}
static readonly string styleName = "TabButtonStyles";
static readonly string UxmlName = "TabButton";
static readonly string s_UssClassName = "unity-tab-button";
static readonly string s_UssActiveClassName = s_UssClassName + "--active";
private Label m_Label;
public bool IsCloseable { get; set; }
public string TargetId { get; private set; }
public VisualElement Target { get; set; }
public event Action<TabButton> OnSelect;
public event Action<TabButton> OnClose;
public TabButton()
{
Init();
}
public TabButton(string text, VisualElement target)
{
Init();
m_Label.text = text;
Target = target;
}
private void PopulateContextMenu(ContextualMenuPopulateEvent populateEvent)
{
DropdownMenu dropdownMenu = populateEvent.menu;
if (IsCloseable)
{
dropdownMenu.AppendAction("Close Tab", e => OnClose(this));
}
}
private void CreateContextMenu(VisualElement visualElement)
{
ContextualMenuManipulator menuManipulator = new ContextualMenuManipulator(PopulateContextMenu);
visualElement.focusable = true;
visualElement.pickingMode = PickingMode.Position;
visualElement.AddManipulator(menuManipulator);
visualElement.AddManipulator(menuManipulator);
}
private void Init()
{
AddToClassList(s_UssClassName);
styleSheets.Add(Resources.Load<StyleSheet>($"Styles/{styleName}"));
VisualTreeAsset visualTree = Resources.Load<VisualTreeAsset>($"UXML/{UxmlName}");
visualTree.CloneTree(this);
m_Label = this.Q<Label>("Label");
CreateContextMenu(this);
RegisterCallback<MouseDownEvent>(OnMouseDownEvent);
}
public void Select()
{
AddToClassList(s_UssActiveClassName);
if (Target != null)
{
Target.style.display = DisplayStyle.Flex;
Target.style.flexGrow = 1;
}
}
public void Deselect()
{
RemoveFromClassList(s_UssActiveClassName);
MarkDirtyRepaint();
if (Target != null)
{
Target.style.display = DisplayStyle.None;
Target.style.flexGrow = 0;
}
}
private void OnMouseDownEvent(MouseDownEvent e)
{
switch (e.button)
{
case 0:
{
OnSelect?.Invoke(this);
break;
}
case 2 when IsCloseable:
{
OnClose?.Invoke(this);
break;
}
} // End of switch.
e.StopImmediatePropagation();
}
}

View File

@@ -0,0 +1,148 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
public class TabbedView : VisualElement
{
public new class UxmlFactory : UxmlFactory<TabbedView, UxmlTraits> {}
private const string k_styleName = "TabbedView";
private const string s_UssClassName = "unity-tabbed-view";
private const string s_ContentContainerClassName = "unity-tabbed-view__content-container";
private const string s_TabsContainerClassName = "unity-tabbed-view__tabs-container";
private readonly VisualElement m_TabContent;
private readonly VisualElement m_Content;
private readonly List<TabButton> m_Tabs = new List<TabButton>();
private TabButton m_ActiveTab;
public override VisualElement contentContainer => m_Content;
public TabbedView()
{
AddToClassList(s_UssClassName);
styleSheets.Add(Resources.Load<StyleSheet>($"Styles/{k_styleName}"));
m_TabContent = new VisualElement();
m_TabContent.name = "unity-tabs-container";
m_TabContent.AddToClassList(s_TabsContainerClassName);
hierarchy.Add(m_TabContent);
m_Content = new VisualElement();
m_Content.name = "unity-content-container";
m_Content.AddToClassList(s_ContentContainerClassName);
hierarchy.Add(m_Content);
RegisterCallback<AttachToPanelEvent>(ProcessEvent);
}
public void AddTab(TabButton tabButton, bool activate)
{
m_Tabs.Add(tabButton);
m_TabContent.Add(tabButton);
tabButton.OnClose += RemoveTab;
tabButton.OnSelect += Activate;
if (activate)
{
Activate(tabButton);
}
}
public void RemoveTab(TabButton tabButton)
{
int index = m_Tabs.IndexOf(tabButton);
// If this tab is the active one make sure we deselect it first...
if (m_ActiveTab == tabButton)
{
DeselectTab(tabButton);
m_ActiveTab = null;
}
m_Tabs.RemoveAt(index);
m_TabContent.Remove(tabButton);
tabButton.OnClose -= RemoveTab;
tabButton.OnSelect -= Activate;
// If we closed the active tab AND we have any tabs left - active the next valid one...
if ((m_ActiveTab == null) && m_Tabs.Any())
{
int clampedIndex = Mathf.Clamp(index, 0, m_Tabs.Count - 1);
TabButton tabToActivate = m_Tabs[clampedIndex];
Activate(tabToActivate);
}
}
private void ProcessEvent(AttachToPanelEvent e)
{
// This code takes any existing tab buttons and hooks them into the system...
for (int i = 0; i < m_Content.childCount; ++i)
{
VisualElement element = m_Content[i];
if (element is TabButton button)
{
m_Content.Remove(element);
if (button.Target == null)
{
string targetId = button.TargetId;
button.Target = this.Q(targetId);
}
AddTab(button, false);
--i;
}
else
{
element.style.display = DisplayStyle.None;
}
}
// Finally, if we need to, activate this tab...
if (m_ActiveTab != null)
{
SelectTab(m_ActiveTab);
}
else if (m_TabContent.childCount > 0)
{
m_ActiveTab = (TabButton)m_TabContent[0];
SelectTab(m_ActiveTab);
}
}
private void SelectTab(TabButton tabButton)
{
VisualElement target = tabButton.Target;
tabButton.Select();
Add(target);
}
private void DeselectTab(TabButton tabButton)
{
VisualElement target = tabButton.Target;
Remove(target);
tabButton.Deselect();
}
public void Activate(TabButton button)
{
if (m_ActiveTab != null)
{
DeselectTab(m_ActiveTab);
}
m_ActiveTab = button;
SelectTab(m_ActiveTab);
}
}

View File

@@ -0,0 +1,149 @@
using System;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.UIElements.StyleSheets;
namespace UnityEditor.ShaderGraph.Drawing
{
[Serializable]
internal class WindowDockingLayout
{
[SerializeField]
bool m_DockingLeft;
public bool dockingLeft
{
get => m_DockingLeft;
set => m_DockingLeft = value;
}
[SerializeField]
bool m_DockingTop;
public bool dockingTop
{
get => m_DockingTop;
set => m_DockingTop = value;
}
[SerializeField]
float m_VerticalOffset;
public float verticalOffset
{
get => m_VerticalOffset;
set => m_VerticalOffset = value;
}
[SerializeField]
float m_HorizontalOffset;
public float horizontalOffset
{
get => m_HorizontalOffset;
set => m_HorizontalOffset = value;
}
[SerializeField]
Vector2 m_Size;
public Vector2 size
{
get => m_Size;
set => m_Size = value;
}
public void CalculateDockingCornerAndOffset(Rect layout, Rect parentLayout)
{
Vector2 layoutCenter = new Vector2(layout.x + layout.width * .5f, layout.y + layout.height * .5f);
layoutCenter /= parentLayout.size;
m_DockingLeft = layoutCenter.x < .5f;
m_DockingTop = layoutCenter.y < .5f;
if (m_DockingLeft)
{
m_HorizontalOffset = layout.x;
}
else
{
m_HorizontalOffset = parentLayout.width - layout.x - layout.width;
}
if (m_DockingTop)
{
m_VerticalOffset = layout.y;
}
else
{
m_VerticalOffset = parentLayout.height - layout.y - layout.height;
}
m_Size = layout.size;
}
public void ClampToParentWindow()
{
m_HorizontalOffset = Mathf.Max(0f, m_HorizontalOffset);
m_VerticalOffset = Mathf.Max(0f, m_VerticalOffset);
}
public void ApplyPosition(VisualElement target)
{
if (dockingLeft)
{
target.style.right = float.NaN;
target.style.left = horizontalOffset;
}
else
{
target.style.right = horizontalOffset;
target.style.left = float.NaN;
}
if (dockingTop)
{
target.style.bottom = float.NaN;
target.style.top = verticalOffset;
}
else
{
target.style.top = float.NaN;
target.style.bottom = verticalOffset;
}
}
public void ApplySize(VisualElement target)
{
target.style.width = size.x;
target.style.height = size.y;
}
public Rect GetLayout(Rect parentLayout)
{
Rect layout = new Rect();
layout.size = size;
if (dockingLeft)
{
layout.x = horizontalOffset;
}
else
{
layout.x = parentLayout.width - size.x - horizontalOffset;
}
if (dockingTop)
{
layout.y = verticalOffset;
}
else
{
layout.y = parentLayout.height - size.y - verticalOffset;
}
return layout;
}
}
}