From 7d37c9dfcce2efc50f8f09374a390fdde08b1df7 Mon Sep 17 00:00:00 2001 From: Lumos Date: Sat, 21 Dec 2019 20:19:24 +0100 Subject: [PATCH 1/2] Allow node input/output tooltips to be overriden through the use of an attribute applied to custom classes. --- .../Attributes/OverrideTooltipAttribute.cs | 23 +++++++++++++++++++ .../OverrideTooltipAttribute.cs.meta | 11 +++++++++ Scripts/Editor/NodeGraphEditor.cs | 14 ++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Scripts/Attributes/OverrideTooltipAttribute.cs create mode 100644 Scripts/Attributes/OverrideTooltipAttribute.cs.meta diff --git a/Scripts/Attributes/OverrideTooltipAttribute.cs b/Scripts/Attributes/OverrideTooltipAttribute.cs new file mode 100644 index 0000000..3e8e572 --- /dev/null +++ b/Scripts/Attributes/OverrideTooltipAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace XNodeEditor { + + /// + /// When applied to the definition of a custom class, allows for the tooltip shown beside the nodes to be overriden. + /// Optionally, whether an output node's value is shown in the tooltip can also be turned off. + /// Leaving the tooltip override blank or null will leave the normal tooltip (type name) in place. + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class OverrideTooltipAttribute : Attribute { + public readonly bool overrideTooltip; + public readonly string tooltip; + public readonly bool hideValue; + + public OverrideTooltipAttribute(string tooltip = "", bool hideValue = false) { + overrideTooltip = !string.IsNullOrEmpty(tooltip); + if (overrideTooltip) this.tooltip = tooltip; + this.hideValue = hideValue; + } + } + +} \ No newline at end of file diff --git a/Scripts/Attributes/OverrideTooltipAttribute.cs.meta b/Scripts/Attributes/OverrideTooltipAttribute.cs.meta new file mode 100644 index 0000000..36d84d2 --- /dev/null +++ b/Scripts/Attributes/OverrideTooltipAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b578945cab8b7c643ac937a49febb57e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 3a0464c..80af4b9 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -123,9 +123,17 @@ namespace XNodeEditor { public virtual string GetPortTooltip(XNode.NodePort port) { Type portType = port.ValueType; string tooltip = ""; - tooltip = portType.PrettyName(); - if (port.IsOutput) { - object obj = port.node.GetValue(port); + + // Now allow tooltips to be overridden or to have their values hidden based on attribute usage + var targetType = portType.HasElementType ? portType.GetElementType() : portType; // For arrays and lists. + // ReSharper disable once PossibleNullReferenceException + var attr = ((OverrideTooltipAttribute[])targetType + .GetCustomAttributes(typeof(OverrideTooltipAttribute), false)).SingleOrDefault(); + tooltip = attr?.overrideTooltip ?? false ? attr.tooltip : targetType.PrettyName(); + var hideValue = attr?.hideValue ?? false; + // ReSharper disable once InvertIf + if (!hideValue && port.IsOutput) { + var obj = port.node.GetValue(port); tooltip += " = " + (obj != null ? obj.ToString() : "null"); } return tooltip; From cbda73ac2252734c149a5d40d7841b4d18fd451b Mon Sep 17 00:00:00 2001 From: Lumos Date: Wed, 25 Dec 2019 11:57:49 +0100 Subject: [PATCH 2/2] Moved attribute to proper namespace and made it apply to fields. C# 4 compliant. --- .../Attributes/OverrideTooltipAttribute.cs | 6 ++-- Scripts/Editor/NodeGraphEditor.cs | 33 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Scripts/Attributes/OverrideTooltipAttribute.cs b/Scripts/Attributes/OverrideTooltipAttribute.cs index 3e8e572..707eb32 100644 --- a/Scripts/Attributes/OverrideTooltipAttribute.cs +++ b/Scripts/Attributes/OverrideTooltipAttribute.cs @@ -1,13 +1,13 @@ using System; -namespace XNodeEditor { +namespace XNode { /// - /// When applied to the definition of a custom class, allows for the tooltip shown beside the nodes to be overriden. + /// When applied to a field marked as node input/output, allows for the tooltip shown beside the nodes to be overriden. /// Optionally, whether an output node's value is shown in the tooltip can also be turned off. /// Leaving the tooltip override blank or null will leave the normal tooltip (type name) in place. /// - [AttributeUsage(AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Field)] public sealed class OverrideTooltipAttribute : Attribute { public readonly bool overrideTooltip; public readonly string tooltip; diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index 80af4b9..164a2b1 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -1,8 +1,9 @@ using System; -using System.Collections.Generic; using System.Linq; +using System.Reflection; using UnityEditor; using UnityEngine; +using XNode; namespace XNodeEditor { /// Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. @@ -121,16 +122,26 @@ namespace XNodeEditor { /// Override to display custom tooltips public virtual string GetPortTooltip(XNode.NodePort port) { - Type portType = port.ValueType; - string tooltip = ""; - - // Now allow tooltips to be overridden or to have their values hidden based on attribute usage - var targetType = portType.HasElementType ? portType.GetElementType() : portType; // For arrays and lists. - // ReSharper disable once PossibleNullReferenceException - var attr = ((OverrideTooltipAttribute[])targetType - .GetCustomAttributes(typeof(OverrideTooltipAttribute), false)).SingleOrDefault(); - tooltip = attr?.overrideTooltip ?? false ? attr.tooltip : targetType.PrettyName(); - var hideValue = attr?.hideValue ?? false; + // Allow tooltips to be overridden or to have their values hidden based on attribute usage + // First, a port managed by a DynamicPortList will have a fieldName of "realName X", so we won't find it directly. + FieldInfo portFieldInfo = null; + string[] fieldNameParts = port.fieldName.Split(' '); + if (port.IsDynamic && fieldNameParts.Length == 2) { + portFieldInfo = port.node.GetType().GetField(fieldNameParts[0]); + } + // If a port isn't dynamic, doesn't match the format, or we didn't find its field, try getting it directly + if (portFieldInfo == null) { + portFieldInfo = port.node.GetType().GetField(port.fieldName); + } + + // If the fieldInfo is still null, abort mission; otherwise, look for our attribute. + OverrideTooltipAttribute attr = null; + if (portFieldInfo != null) { + attr = ((OverrideTooltipAttribute[])portFieldInfo + .GetCustomAttributes(typeof(OverrideTooltipAttribute), false)).SingleOrDefault(); + } + string tooltip = attr != null && attr.overrideTooltip ? attr.tooltip : port.ValueType.PrettyName(); + bool hideValue = attr != null && attr.hideValue; // ReSharper disable once InvertIf if (!hideValue && port.IsOutput) { var obj = port.node.GetValue(port);