Files
test/Assets/EditorAttributes/Editor/Scripts/Drawers/DropdownAttributeDrawers/SceneDropdownDrawer.cs
T

151 lines
4.8 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
namespace EditorAttributes.Editor
{
[CustomPropertyDrawer(typeof(SceneDropdownAttribute))]
public class SceneDropdownDrawer : PropertyDrawerBase
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var root = new VisualElement();
var errorBox = new HelpBox();
if (property.propertyType == SerializedPropertyType.String || property.propertyType == SerializedPropertyType.Integer)
{
var sceneNames = GetSceneNames(errorBox);
var dropdownField = IsCollectionValid(sceneNames) ? new DropdownField(property.displayName, sceneNames, GetDropdownDefaultValue(sceneNames, property))
: new DropdownField(property.displayName, new List<string>() { "NULL" }, 0);
dropdownField.tooltip = property.tooltip;
dropdownField.AddToClassList(BaseField<Void>.alignedFieldUssClassName);
dropdownField.RegisterValueChangedCallback(callback => ApplyPropertyValue(property, dropdownField));
AddPropertyContextMenu(dropdownField, property);
if (dropdownField.value != "NULL")
{
dropdownField.showMixedValue = property.hasMultipleDifferentValues;
ApplyPropertyValue(property, dropdownField);
}
root.Add(dropdownField);
DisplayErrorBox(root, errorBox);
dropdownField.TrackPropertyValue(property, (trackedProperty) =>
{
string sceneName = trackedProperty.propertyType == SerializedPropertyType.Integer ? SceneNameFromIndex(trackedProperty.intValue) : trackedProperty.stringValue;
if (dropdownField.choices.Contains(sceneName))
{
dropdownField.SetValueWithoutNotify(sceneName);
}
else
{
Debug.LogWarning($"The value <b>{trackedProperty.boxedValue}</b> set to the <b>{trackedProperty.name}</b> variable is not a valid scene identifier.", trackedProperty.serializedObject.targetObject);
}
});
ExecuteLater(dropdownField, () => dropdownField.Q(className: DropdownField.inputUssClassName).style.backgroundColor = EditorExtension.GLOBAL_COLOR / 2f);
UpdateVisualElement(dropdownField, () =>
{
var sceneNames = GetSceneNames(errorBox);
if (IsCollectionValid(sceneNames))
dropdownField.choices = sceneNames;
});
return root;
}
else
{
errorBox.text = "The SceneDropdown attribute can only be attached to a string or int";
DisplayErrorBox(root, errorBox);
return root;
}
}
protected override void PasteValue(VisualElement element, SerializedProperty property, string clipboardValue)
{
var dropdown = element as DropdownField;
string sceneName = int.TryParse(clipboardValue, out int sceneIndex) ? SceneNameFromIndex(sceneIndex) : clipboardValue;
if (dropdown.choices.Contains(sceneName))
{
dropdown.value = sceneName;
}
else
{
Debug.LogWarning($"Could not paste value \"{clipboardValue}\" since is not availiable as an option in the dropdown");
}
}
private List<string> GetSceneNames(HelpBox errorBox)
{
var sceneList = new List<string>();
var activeSceneList = EditorBuildSettingsScene.GetActiveSceneList(EditorBuildSettings.scenes);
if (activeSceneList == null || activeSceneList.Length == 0)
{
errorBox.text = "There are no scenes in the active build settings";
return sceneList;
}
foreach (var scene in activeSceneList)
{
var sceneName = scene.Split('/')[^1].Split('.')[0]; // Remove the asset paths and file extension from the name
sceneList.Add(sceneName);
}
return sceneList;
}
private string SceneNameFromIndex(int BuildIndex)
{
var path = SceneUtility.GetScenePathByBuildIndex(BuildIndex);
if (path == string.Empty)
return "";
var slashIndex = path.LastIndexOf('/');
var name = path[(slashIndex + 1)..];
var dotIndex = name.LastIndexOf('.');
return name[..dotIndex];
}
private string GetDropdownDefaultValue(List<string> collectionValues, SerializedProperty property)
{
var propertyStringValue = property.propertyType == SerializedPropertyType.String ? property.stringValue : SceneNameFromIndex(property.intValue);
return collectionValues.Contains(propertyStringValue) ? propertyStringValue : collectionValues[0];
}
private void ApplyPropertyValue(SerializedProperty property, DropdownField dropdown)
{
if (property.hasMultipleDifferentValues)
return;
if (property.propertyType == SerializedPropertyType.String)
{
property.stringValue = dropdown.value;
}
else
{
property.intValue = dropdown.index;
}
property.serializedObject.ApplyModifiedProperties();
}
}
}