Add Dropdown attribute

This commit is contained in:
VladV 2022-07-04 18:25:11 +03:00
parent 2f01e1016b
commit 9e6d661229
10 changed files with 318 additions and 0 deletions

View File

@ -0,0 +1,190 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TriInspector;
using TriInspector.Drawers;
using TriInspector.Resolvers;
using UnityEditor;
using UnityEngine;
[assembly: RegisterTriAttributeDrawer(typeof(DropdownDrawer), TriDrawerOrder.Decorator)]
namespace TriInspector.Drawers
{
public class DropdownDrawer : TriAttributeDrawer<DropdownAttribute>
{
private DropdownResolver _resolver;
public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)
{
_resolver = DropdownResolver.Create(typeof(DropdownValueResolver<>), propertyDefinition, Attribute.Values);
if (_resolver.TryGetErrorString(out var error))
{
_resolver = DropdownResolver.Create(typeof(DropdownItemResolver<>), propertyDefinition,
Attribute.Values);
if (_resolver.TryGetErrorString(out error))
{
return error;
}
}
return TriExtensionInitializationResult.Ok;
}
public override TriElement CreateElement(TriProperty property, TriElement next)
{
return new DropdownElement(property, _resolver);
}
private class DropdownElement : TriElement
{
private readonly TriProperty _property;
private readonly DropdownResolver _resolver;
private string _currentText;
public DropdownElement(TriProperty property, DropdownResolver resolver)
{
_property = property;
_resolver = resolver;
}
protected override void OnAttachToPanel()
{
base.OnAttachToPanel();
_property.ValueChanged += OnValueChanged;
RefreshCurrentText();
}
protected override void OnDetachFromPanel()
{
_property.ValueChanged -= OnValueChanged;
base.OnDetachFromPanel();
}
public override float GetHeight(float width)
{
return EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position)
{
var controlId = GUIUtility.GetControlID(FocusType.Passive);
position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent);
if (GUI.Button(position, _currentText, EditorStyles.popup))
{
ShowDropdown(position);
}
}
private void OnValueChanged(TriProperty property)
{
RefreshCurrentText();
}
private void RefreshCurrentText()
{
var items = _resolver.GetDropdownItems(_property);
_currentText = items
.FirstOrDefault(it => _resolver.EqualityComparer.Equals(it.Value, _property.Value))
?.Text ?? "";
}
private void ShowDropdown(Rect position)
{
var items = _resolver.GetDropdownItems(_property);
var menu = new GenericMenu();
foreach (var item in items)
{
var isOn = _resolver.EqualityComparer.Equals(item.Value, _property.Value);
menu.AddItem(new GUIContent(item.Text), isOn, _property.SetValue, item.Value);
}
menu.DropDown(position);
}
}
private abstract class DropdownResolver
{
public abstract IEqualityComparer EqualityComparer { get; }
public abstract void Initialize(TriPropertyDefinition propertyDefinition, string expression);
public abstract bool TryGetErrorString(out string error);
public abstract IEnumerable<ITriDropdownItem> GetDropdownItems(TriProperty property);
public static DropdownResolver Create(Type resolverType,
TriPropertyDefinition propertyDefinition, string expression)
{
var elementType = propertyDefinition.FieldType;
var resolver = (DropdownResolver) Activator.CreateInstance(resolverType.MakeGenericType(elementType));
resolver.Initialize(propertyDefinition, expression);
return resolver;
}
}
private class DropdownItemResolver<T> : DropdownResolver
{
private ValueResolver<IEnumerable<TriDropdownItem<T>>> _resolver;
public override IEqualityComparer EqualityComparer { get; } = EqualityComparer<T>.Default;
public override void Initialize(TriPropertyDefinition propertyDefinition, string expression)
{
_resolver = ValueResolver.Resolve<IEnumerable<TriDropdownItem<T>>>(propertyDefinition, expression);
}
public override bool TryGetErrorString(out string error)
{
return _resolver.TryGetErrorString(out error);
}
public override IEnumerable<ITriDropdownItem> GetDropdownItems(TriProperty property)
{
var values = _resolver.GetValue(property, Enumerable.Empty<TriDropdownItem<T>>());
foreach (var value in values)
{
yield return value;
}
}
}
private class DropdownValueResolver<T> : DropdownResolver
{
private ValueResolver<IEnumerable<T>> _resolver;
public override IEqualityComparer EqualityComparer { get; } = EqualityComparer<T>.Default;
public override void Initialize(TriPropertyDefinition propertyDefinition, string expression)
{
_resolver = ValueResolver.Resolve<IEnumerable<T>>(propertyDefinition, expression);
}
public override bool TryGetErrorString(out string error)
{
return _resolver.TryGetErrorString(out error);
}
public override IEnumerable<ITriDropdownItem> GetDropdownItems(TriProperty property)
{
var values = _resolver.GetValue(property, Enumerable.Empty<T>());
foreach (var value in values)
{
yield return new TriDropdownItem {Text = $"{value}", Value = value,};
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 355fb8aedd1f4aca846a8bbf96558a5d
timeCreated: 1656941791

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f3a78924b3514722b6a7e06f0c77121d
timeCreated: 1656933680

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using TriInspector;
using UnityEngine;
public class Decorators_DropdownSample : ScriptableObject
{
[Dropdown(nameof(_intValues))]
public int intValue = 1;
[Dropdown(nameof(GetStringValues))]
public string stringValue;
[Dropdown(nameof(GetVectorValues))]
public Vector3 vectorValue;
private int[] _intValues = {1, 2, 3, 4, 5,};
private IEnumerable<string> GetStringValues()
{
yield return "One";
yield return "Two";
yield return "Three";
}
private IEnumerable<TriDropdownItem<Vector3>> GetVectorValues()
{
return new TriDropdownList<Vector3>
{
{"Zero", Vector3.zero},
{"One/Forward", Vector3.forward},
{"One/Backward", Vector3.back},
{"One/Left", Vector3.left},
{"One/Right", Vector3.right},
};
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 69374eab3b684d3babd15136620a9862
timeCreated: 1656933689

View File

@ -10,6 +10,7 @@ _Advanced inspector attributes for Unity_
- [Attributes](#Attributes)
- [Misc](#Misc)
- [Validation](#Validation)
- [Decorators](#Decorators)
- [Styling](#Styling)
- [Collections](#Collections)
- [Conditionals](#Conditionals)
@ -170,6 +171,32 @@ private bool VisibleInEditMode => !Application.isPlaying;
public GameObject obj;
```
### Decorators
#### Dropdown
![Dropdown](https://user-images.githubusercontent.com/26966368/177182904-8bb40579-3dc5-441b-8f6b-3ff3d274f71f.png)
```csharp
[Dropdown(nameof(intValues))]
public int intValue = 1;
[Dropdown(nameof(GetVectorValues))]
public Vector3 vectorValue;
private int[] intValues = {1, 2, 3, 4, 5};
private IEnumerable<TriDropdownItem<Vector3>> GetVectorValues()
{
return new TriDropdownList<Vector3>
{
{"Zero", Vector3.zero},
{"One/Forward", Vector3.forward},
{"One/Backward", Vector3.back},
};
}
```
### Styling
#### Title

View File

@ -0,0 +1,17 @@
using System;
using System.Diagnostics;
namespace TriInspector
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[Conditional("UNITY_EDITOR")]
public sealed class DropdownAttribute : Attribute
{
public string Values { get; }
public DropdownAttribute(string values)
{
Values = values;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 715d2fca9b1e4330be5d88eddbbdd801
timeCreated: 1656933469

View File

@ -0,0 +1,33 @@
using System.Collections.Generic;
namespace TriInspector
{
public class TriDropdownList<T> : List<TriDropdownItem<T>>
{
public void Add(string text, T value)
{
Add(new TriDropdownItem<T> {Text = text, Value = value,});
}
}
public interface ITriDropdownItem
{
string Text { get; }
object Value { get; }
}
public struct TriDropdownItem : ITriDropdownItem
{
public string Text { get; set; }
public object Value { get; set; }
}
public struct TriDropdownItem<T> : ITriDropdownItem
{
public string Text;
public T Value;
string ITriDropdownItem.Text => Text;
object ITriDropdownItem.Value => Value;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bdeda5f861ce4f359c0a25554ffe70bf
timeCreated: 1656937692