added yarn spinner package
This commit is contained in:
+47
@@ -0,0 +1,47 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
[CustomPropertyDrawer(typeof(MarkupPalette.BasicMarker))]
|
||||
public class BasicMarkerPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override VisualElement CreatePropertyGUI(SerializedProperty property)
|
||||
{
|
||||
var container = new VisualElement();
|
||||
|
||||
var name = property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Marker));
|
||||
|
||||
var nameField = new PropertyField(name);
|
||||
var showColourField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.CustomColor)));
|
||||
var colourField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Color)));
|
||||
var boldField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Boldened)));
|
||||
var italicsField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Italicised)));
|
||||
var underlinedField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Underlined)));
|
||||
var strikedField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Strikedthrough)));
|
||||
|
||||
var foldout = new Foldout { text = name.stringValue };
|
||||
|
||||
showColourField.RegisterCallback((ChangeEvent<bool> b) =>
|
||||
{
|
||||
colourField.style.display = b.newValue ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
|
||||
foldout.Add(nameField);
|
||||
foldout.Add(showColourField);
|
||||
foldout.Add(colourField);
|
||||
foldout.Add(boldField);
|
||||
foldout.Add(italicsField);
|
||||
foldout.Add(underlinedField);
|
||||
foldout.Add(strikedField);
|
||||
|
||||
container.Add(foldout);
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eaeba2d10a544bf58c014880b8b71dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/BasicMarkerPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(YarnProjectImporter.SerializedDeclaration))]
|
||||
public class DeclarationPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws either a property field or a label field for <paramref
|
||||
/// name="property"/> at <paramref name="position"/>, depending on
|
||||
/// the value of <paramref name="readOnly"/>.
|
||||
/// </summary>
|
||||
/// <param name="position">The rectangle in which to draw the
|
||||
/// control.</param>
|
||||
/// <param name="property">The property to draw a control
|
||||
/// for.</param>
|
||||
/// <param name="readOnly">Whether the property is read-only or
|
||||
/// not.</param>
|
||||
private void DrawPropertyField(Rect position, SerializedProperty property, bool readOnly, string? label = null)
|
||||
{
|
||||
if (label == null)
|
||||
{
|
||||
label = property.displayName;
|
||||
}
|
||||
if (readOnly)
|
||||
{
|
||||
switch (property.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Integer:
|
||||
EditorGUI.LabelField(position, label, property.intValue.ToString());
|
||||
break;
|
||||
case SerializedPropertyType.Boolean:
|
||||
var boolText = property.boolValue ? "True" : "False";
|
||||
EditorGUI.LabelField(position, label, boolText);
|
||||
break;
|
||||
case SerializedPropertyType.Float:
|
||||
EditorGUI.LabelField(position, label, property.floatValue.ToString());
|
||||
break;
|
||||
case SerializedPropertyType.String:
|
||||
EditorGUI.LabelField(position, label, property.stringValue);
|
||||
break;
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
EditorGUI.ObjectField(position, property);
|
||||
}
|
||||
break;
|
||||
case SerializedPropertyType.Enum:
|
||||
var displayValue = property.enumDisplayNames[property.enumValueIndex];
|
||||
EditorGUI.LabelField(position, label, displayValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (property.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.String:
|
||||
property.stringValue = EditorGUI.TextField(position, label, property.stringValue);
|
||||
break;
|
||||
case SerializedPropertyType.Float:
|
||||
property.floatValue = EditorGUI.FloatField(position, label, property.floatValue);
|
||||
break;
|
||||
case SerializedPropertyType.Integer:
|
||||
property.floatValue = EditorGUI.IntField(position, label, property.intValue);
|
||||
break;
|
||||
default:
|
||||
// Just use a regular field for other kinds of
|
||||
// properties
|
||||
EditorGUI.PropertyField(position, property, new GUIContent(label));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
// A serialized declaration is read-only if it came from a Yarn
|
||||
// script. We don't allow editing those in this panel, because
|
||||
// the text of the Yarn script belongs to the user.
|
||||
bool propertyIsReadOnly = property.FindPropertyRelative("sourceYarnAsset").objectReferenceValue != null;
|
||||
|
||||
propertyIsReadOnly |= property.FindPropertyRelative("isImplicit").boolValue;
|
||||
|
||||
const float leftInset = 8;
|
||||
|
||||
Rect RectForFieldIndex(int index, int lineCount = 1)
|
||||
{
|
||||
float verticalOffset = EditorGUIUtility.singleLineHeight * index + EditorGUIUtility.standardVerticalSpacing * index;
|
||||
float height = EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount - 1);
|
||||
|
||||
return new Rect(
|
||||
position.x + leftInset,
|
||||
position.y + verticalOffset,
|
||||
position.width - leftInset,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
var foldoutPosition = RectForFieldIndex(0);
|
||||
|
||||
SerializedProperty nameProperty = property.FindPropertyRelative("name");
|
||||
string name = nameProperty.stringValue;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = "Variable";
|
||||
}
|
||||
|
||||
property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, name);
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
var namePosition = RectForFieldIndex(1);
|
||||
var typePosition = RectForFieldIndex(2);
|
||||
var defaultValuePosition = RectForFieldIndex(3);
|
||||
var descriptionPosition = RectForFieldIndex(4, 2);
|
||||
var sourcePosition = RectForFieldIndex(6);
|
||||
|
||||
DrawPropertyField(namePosition, nameProperty, propertyIsReadOnly);
|
||||
|
||||
SerializedProperty typeProperty = property.FindPropertyRelative("typeName");
|
||||
|
||||
if (propertyIsReadOnly)
|
||||
{
|
||||
DrawPropertyField(typePosition, typeProperty, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var popupElements = YarnProjectImporter.SerializedDeclaration.BuiltInTypesList;
|
||||
var popupElementNames = popupElements.Select(t => t.Name).ToList();
|
||||
var selectedIndex = popupElementNames.IndexOf(typeProperty.stringValue);
|
||||
|
||||
var prefixPosition = EditorGUI.PrefixLabel(typePosition, new GUIContent("Type"));
|
||||
|
||||
selectedIndex = EditorGUI.Popup(prefixPosition, selectedIndex, popupElementNames.ToArray());
|
||||
if (selectedIndex >= 0 && selectedIndex <= popupElementNames.Count)
|
||||
{
|
||||
typeProperty.stringValue = popupElementNames[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
SerializedProperty? defaultValueProperty;
|
||||
|
||||
var type = YarnProjectImporter.SerializedDeclaration.BuiltInTypesList.FirstOrDefault(t => t.Name == typeProperty.stringValue);
|
||||
|
||||
if (type == Types.Number)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueNumber");
|
||||
}
|
||||
else if (type == Types.String)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueString");
|
||||
}
|
||||
else if (type == Types.Boolean)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueBool");
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValueProperty = null;
|
||||
}
|
||||
|
||||
|
||||
if (defaultValueProperty == null)
|
||||
{
|
||||
EditorGUI.LabelField(defaultValuePosition, "Default Value", $"Variable type {typeProperty.stringValue} is not allowed");
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawPropertyField(defaultValuePosition, defaultValueProperty, propertyIsReadOnly, "Default Value");
|
||||
}
|
||||
|
||||
|
||||
// Don't use DrawPropertyField here because we want to use
|
||||
// a special gui style and directly use the string value
|
||||
SerializedProperty descriptionProperty = property.FindPropertyRelative("description");
|
||||
if (propertyIsReadOnly)
|
||||
{
|
||||
descriptionPosition = EditorGUI.PrefixLabel(descriptionPosition, new GUIContent(descriptionProperty.displayName));
|
||||
EditorGUI.SelectableLabel(descriptionPosition, descriptionProperty.stringValue, EditorStyles.wordWrappedLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
var wordWrappedTextField = EditorStyles.textField;
|
||||
wordWrappedTextField.wordWrap = true;
|
||||
|
||||
descriptionProperty.stringValue = EditorGUI.TextField(descriptionPosition, descriptionProperty.displayName, descriptionProperty.stringValue, wordWrappedTextField);
|
||||
}
|
||||
|
||||
if (!propertyIsReadOnly)
|
||||
{
|
||||
EditorGUI.LabelField(sourcePosition, "Declared In", "this file");
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializedProperty sourceProperty = property.FindPropertyRelative("sourceYarnAsset");
|
||||
EditorGUI.ObjectField(sourcePosition, "Declared In", sourceProperty.objectReferenceValue, typeof(TextAsset), false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
|
||||
return GetPropertyHeightImpl(property, label);
|
||||
}
|
||||
|
||||
public static float GetPropertyHeightImpl(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int lines;
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
lines = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines = 1;
|
||||
}
|
||||
|
||||
return EditorGUIUtility.singleLineHeight * lines + EditorGUIUtility.standardVerticalSpacing * lines + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05c509d58b0f0441995b7356c9876e60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DeclarationPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(FunctionInfo))]
|
||||
public class DerivedFunctionsPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
const float leftInset = 8;
|
||||
|
||||
Rect RectForFieldIndex(int index, int lineCount = 1)
|
||||
{
|
||||
float verticalOffset = EditorGUIUtility.singleLineHeight * index + EditorGUIUtility.standardVerticalSpacing * index;
|
||||
float height = EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount - 1);
|
||||
|
||||
return new Rect(
|
||||
position.x + leftInset,
|
||||
position.y + verticalOffset,
|
||||
position.width - leftInset,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
var foldoutPosition = RectForFieldIndex(0);
|
||||
|
||||
SerializedProperty nameProperty = property.FindPropertyRelative("Name");
|
||||
string name = nameProperty?.stringValue ?? "FUNCTION NAME";
|
||||
|
||||
property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, name);
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
EditorGUI.indentLevel += 1;
|
||||
var typePosition = RectForFieldIndex(1);
|
||||
var paramPosition = RectForFieldIndex(2);
|
||||
|
||||
SerializedProperty typeProperty = property.FindPropertyRelative("ReturnType");
|
||||
EditorGUI.LabelField(typePosition, typeProperty?.stringValue ?? "RETURN");
|
||||
|
||||
SerializedProperty paramProperty = property.FindPropertyRelative("Parameters");
|
||||
int count = paramProperty?.arraySize ?? 0;
|
||||
if (count > 0)
|
||||
{
|
||||
string[] p = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
p[i] = paramProperty.GetArrayElementAtIndex(i).stringValue;
|
||||
}
|
||||
EditorGUI.LabelField(paramPosition, $"({string.Join(", ", p)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.LabelField(paramPosition, $"No Parameters");
|
||||
}
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
|
||||
int lines = 1;
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
lines = 3;
|
||||
}
|
||||
|
||||
return EditorGUIUtility.singleLineHeight * lines + EditorGUIUtility.standardVerticalSpacing * lines + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ff5754fb8fe74e3fa7e65606e3feefa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DerivedFunctionsPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(DialogueReference))]
|
||||
public class DialogueReferenceDrawer : PropertyDrawer
|
||||
{
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
position = EditorGUI.PrefixLabel(position, label);
|
||||
|
||||
var projectProperty = property.FindPropertyRelative(nameof(DialogueReference.project));
|
||||
var nodeNameProperty = property.FindPropertyRelative(nameof(DialogueReference.nodeName));
|
||||
|
||||
position = GetLineRect(position, out var projectRect);
|
||||
position = GetLineRect(position, out var nodeNameRect);
|
||||
EditorGUI.PropertyField(projectRect, projectProperty, GUIContent.none);
|
||||
EditorGUI.PropertyField(nodeNameRect, nodeNameProperty, GUIContent.none);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a rectangle, computes a rectangle of the same width as the
|
||||
/// input with the height of a single line, taking into account vertical
|
||||
/// spacing.
|
||||
/// </summary>
|
||||
/// <param name="input">A rectangle representing the total area
|
||||
/// availalbe.</param>
|
||||
/// <param name="lineRect">On return, a rectangle with the same width as
|
||||
/// <paramref name="input"/> and with a single line's worth of
|
||||
/// height.</param>
|
||||
/// <returns>The remaining available space.</returns>
|
||||
private Rect GetLineRect(Rect input, out Rect lineRect)
|
||||
{
|
||||
lineRect = input;
|
||||
lineRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
var remainder = input;
|
||||
var offset = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
remainder.y += offset;
|
||||
remainder.height -= offset;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the height, in pixels, needed for drawing the inspector for
|
||||
/// a <see cref="DialogueReference"/>.
|
||||
/// </summary>
|
||||
/// <param name="property">A serialized property representing a <see
|
||||
/// cref="DialogueReference"/> object.</param>
|
||||
/// <param name="label">The label to display for <paramref
|
||||
/// name="property"/>.</param>
|
||||
/// <returns>The displayed height for the property.</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
const int lineCount = 2;
|
||||
return lineCount * EditorGUIUtility.singleLineHeight +
|
||||
(lineCount - 1) * EditorGUIUtility.standardVerticalSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2e67f1d1bf1140a6910d4cc0225235c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DialogueReferenceDrawer.cs
|
||||
uploadId: 968678
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity.Attributes;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
/// <summary>
|
||||
/// Property drawer for <see cref="DialogueReference"/>
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(YarnNodeAttribute))]
|
||||
public class YarnNodeAttributeDrawer : PropertyDrawer
|
||||
{
|
||||
private const string NodeTextControlNamePrefix = "DialogueReference.NodeName.";
|
||||
|
||||
private YarnProject? lastProject;
|
||||
private string? lastNodeName;
|
||||
private bool referenceExists;
|
||||
private bool editNodeAsText;
|
||||
private bool focusNodeTextField;
|
||||
|
||||
private GUIContent? nodenameContent;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// -- Yarn Project asset reference
|
||||
SerializedProperty projectProp;
|
||||
|
||||
if (this.attribute is not YarnNodeAttribute attribute)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Internal error: attribute is not a {nameof(YarnNodeAttribute)}");
|
||||
}
|
||||
|
||||
var propertyPathComponents = new System.Collections.Generic.Stack<string>(property.propertyPath.Split('.'));
|
||||
|
||||
while (true)
|
||||
{
|
||||
string testPath;
|
||||
|
||||
if (propertyPathComponents.Count == 0)
|
||||
{
|
||||
testPath = attribute.yarnProjectAttribute;
|
||||
}
|
||||
else
|
||||
{
|
||||
var components = new System.Collections.Generic.List<string>(propertyPathComponents);
|
||||
components.Reverse();
|
||||
|
||||
testPath = string.Join(".", components) + "." + attribute.yarnProjectAttribute;
|
||||
}
|
||||
|
||||
projectProp = property.serializedObject.FindProperty(testPath);
|
||||
|
||||
if (projectProp != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (propertyPathComponents.Count > 0)
|
||||
{
|
||||
propertyPathComponents.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (projectProp == null)
|
||||
{
|
||||
EditorGUI.HelpBox(position, $"{attribute.yarnProjectAttribute} does not exist on {property.serializedObject.targetObject.name}", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var controlId = GUIUtility.GetControlID(FocusType.Passive);
|
||||
position = EditorGUI.PrefixLabel(position, controlId, label);
|
||||
|
||||
var indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
var nodeNameFieldPosition = position;
|
||||
|
||||
var project = projectProp.hasMultipleDifferentValues ? null : projectProp.objectReferenceValue as YarnProject;
|
||||
|
||||
// -- Node name drop down
|
||||
|
||||
// If we want to edit this nodes name as a text field, or if we have
|
||||
// multiple values, or if we have no project and we don't need one,
|
||||
// show a text field and not a dropdown.
|
||||
if ((project == null && attribute.requiresYarnProject == false) || editNodeAsText || projectProp.hasMultipleDifferentValues)
|
||||
{
|
||||
var controlName = NodeTextControlNamePrefix + controlId;
|
||||
|
||||
// Multi-selection with different projects, just show a text
|
||||
// field to edit the node name. Most of the time, it will show
|
||||
// the mixed value dash (—).
|
||||
GUI.SetNextControlName(controlName);
|
||||
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var currentText = property.hasMultipleDifferentValues ? "-" : property.stringValue;
|
||||
currentText = EditorGUI.TextField(nodeNameFieldPosition, currentText);
|
||||
if (change.changed)
|
||||
{
|
||||
property.stringValue = currentText;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
if (editNodeAsText)
|
||||
{
|
||||
if (focusNodeTextField)
|
||||
{
|
||||
// Focusing the text field is delayed like this because
|
||||
// the control needs to exist first before we can focus
|
||||
// it
|
||||
focusNodeTextField = false;
|
||||
EditorGUI.FocusTextInControl(controlName);
|
||||
}
|
||||
else if (ShouldEndEditing(controlName))
|
||||
{
|
||||
editNodeAsText = false;
|
||||
HandleUtility.Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show a dropdown that lets the user choose a node from the
|
||||
// ones present in the Yarn Project.
|
||||
|
||||
// If the Yarn Project is not set, this dropdown is empty and
|
||||
// disabled.
|
||||
if (project == null)
|
||||
{
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
EditorGUI.DropdownButton(nodeNameFieldPosition, GUIContent.none, FocusType.Passive);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeName = property.stringValue;
|
||||
var nodeNameSet = !string.IsNullOrEmpty(nodeName);
|
||||
|
||||
// Cached check if node exists in project
|
||||
if (lastProject != project || lastNodeName != nodeName)
|
||||
{
|
||||
lastProject = project;
|
||||
lastNodeName = nodeName;
|
||||
referenceExists = project.Program.Nodes.ContainsKey(nodeName);
|
||||
}
|
||||
|
||||
if (nodenameContent == null)
|
||||
{
|
||||
nodenameContent = new GUIContent();
|
||||
}
|
||||
|
||||
// Show warning icon if not does not exist in selected project
|
||||
|
||||
if (nodeNameSet)
|
||||
{
|
||||
nodenameContent.text = nodeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodenameContent.text = "(Choose Node)";
|
||||
}
|
||||
|
||||
MessageType iconType = MessageType.None;
|
||||
|
||||
if (!nodeNameSet)
|
||||
{
|
||||
iconType = MessageType.Info;
|
||||
}
|
||||
else if (!referenceExists)
|
||||
{
|
||||
iconType = MessageType.Warning;
|
||||
}
|
||||
else
|
||||
{
|
||||
iconType = MessageType.None;
|
||||
}
|
||||
|
||||
switch (iconType)
|
||||
{
|
||||
case MessageType.Info:
|
||||
nodenameContent.image = EditorGUIUtility.isProSkin ? EditorGUIUtility.IconContent("d_console.infoicon.sml").image : EditorGUIUtility.IconContent("console.infoicon.sml").image;
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
nodenameContent.image = EditorGUIUtility.isProSkin ? EditorGUIUtility.IconContent("d_console.warnicon.sml").image : EditorGUIUtility.IconContent("console.warnicon.sml").image;
|
||||
break;
|
||||
default:
|
||||
nodenameContent.image = null;
|
||||
break;
|
||||
}
|
||||
|
||||
var hasMixedNodeValues = property.hasMultipleDifferentValues;
|
||||
EditorGUI.showMixedValue = hasMixedNodeValues;
|
||||
|
||||
// Generate menu with node list only when user actually opens it
|
||||
if (EditorGUI.DropdownButton(nodeNameFieldPosition, nodenameContent, FocusType.Keyboard))
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
|
||||
menu.AddItem(new GUIContent("Edit..."), false, () =>
|
||||
{
|
||||
editNodeAsText = true;
|
||||
focusNodeTextField = true;
|
||||
});
|
||||
|
||||
menu.AddSeparator("");
|
||||
|
||||
menu.AddItem(new GUIContent("<None>"), !nodeNameSet, () =>
|
||||
{
|
||||
property.stringValue = "";
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
|
||||
if (!referenceExists && nodeNameSet && !hasMixedNodeValues)
|
||||
{
|
||||
menu.AddItem(new GUIContent(nodeName + " (Missing)"), true, () =>
|
||||
{
|
||||
property.stringValue = nodeName;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var node in GetNodes(project))
|
||||
{
|
||||
var name = node.Name;
|
||||
|
||||
menu.AddItem(new GUIContent(name), name == nodeName && !hasMixedNodeValues, () =>
|
||||
{
|
||||
property.stringValue = name;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
menu.DropDown(nodeNameFieldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel = indent;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private static IEnumerable<Node> GetNodes(YarnProject project)
|
||||
{
|
||||
foreach (var node in project.Program.Nodes.Values)
|
||||
{
|
||||
if (node.Name.StartsWith("$"))
|
||||
{
|
||||
// Skip smart variable nodes
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isNodeGroup = false;
|
||||
|
||||
foreach (var header in node.Headers)
|
||||
{
|
||||
if (header.Key == Node.NodeGroupHeader)
|
||||
{
|
||||
// This node is part of a node group; don't include it
|
||||
isNodeGroup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNodeGroup)
|
||||
{
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldEndEditing(string controlName)
|
||||
{
|
||||
if (GUI.GetNameOfFocusedControl() != controlName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyCode = Event.current.keyCode;
|
||||
if (keyCode != KeyCode.Return && keyCode != KeyCode.KeypadEnter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac84e49b2dc3b4c65a64a401894969d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/YarnNodeAttributeDrawer.cs
|
||||
uploadId: 968678
|
||||
Reference in New Issue
Block a user