Community Made Tools

Have you made any useful utilities with Odin?

Login and submit your creations here

ListItemSelector attribute - Easily select items in lists

Authored by Bjarke
Shared 05-09-2019

I'll let the usage-code and gif speak for themselves.

Let me (Bjarke - Sirenix) know on Discord if you have any suggestions of feature requests.

Usage

[CreateAssetMenu] public class SomeScriptableObject : ScriptableObject { [ListItemSelector("SetSelected")] public List<Material> SomeList = new List<Material>(); [BoxGroup("Preview")] [ShowInInspector, InlineEditor(InlineEditorObjectFieldModes.Hidden)] private Material selectedMaterial; public void SetSelected(int index) { this.selectedMaterial = index > 0 ? this.SomeList[index] : null; } }

ListItemSelectorAttribute.cs

using System; public class ListItemSelectorAttribute : Attribute { public string SetSelectedMethod; public ListItemSelectorAttribute(string setSelectedMethod) { this.SetSelectedMethod = setSelectedMethod; } }

ListItemSelectorAttributeDrawer.cs

using UnityEngine; using System; using Sirenix.OdinInspector.Editor; using Sirenix.Utilities.Editor; using UnityEditor; using Sirenix.Utilities; [DrawerPriority(0.01, 0, 0)] public class ListItemSelectorAttributeDrawer : OdinAttributeDrawer<ListItemSelectorAttribute> { private static Color selectedColor = new Color(0.301f, 0.563f, 1f, 0.497f); private bool isListElement; private InspectorProperty baseMemberProperty; private PropertyContext<InspectorProperty> globalSelectedProperty; private InspectorProperty selectedProperty; private Action<object, int> selectedIndexSetter; protected override void Initialize() { this.isListElement = this.Property.Parent != null && this.Property.Parent.ChildResolver is IOrderedCollectionResolver; var isList = !this.isListElement; var listProperty = isList ? this.Property : this.Property.Parent; this.baseMemberProperty = listProperty.FindParent(x => x.Info.PropertyType == PropertyType.Value, true); this.globalSelectedProperty = this.baseMemberProperty.Context.GetGlobal("selectedIndex" + this.baseMemberProperty.GetHashCode(), (InspectorProperty)null); if (isList) { var parentType = this.baseMemberProperty.ParentValues[0].GetType(); this.selectedIndexSetter = EmitUtilities.CreateWeakInstanceMethodCaller<int>(parentType.GetMethod(this.Attribute.SetSelectedMethod, Flags.AllMembers)); } } protected override void DrawPropertyLayout(GUIContent label) { var t = Event.current.type; if (this.isListElement) { if (t == EventType.Layout) { this.CallNextDrawer(label); } else { var rect = GUIHelper.GetCurrentLayoutRect(); var isSelected = this.globalSelectedProperty.Value == this.Property; if (t == EventType.Repaint && isSelected) { EditorGUI.DrawRect(rect, selectedColor); } else if (t == EventType.MouseDown && rect.Contains(Event.current.mousePosition)) { this.globalSelectedProperty.Value = this.Property; } this.CallNextDrawer(label); } } else { this.CallNextDrawer(label); if (Event.current.type != EventType.Layout) { var sel = this.globalSelectedProperty.Value; // Select if (sel != null && sel != this.selectedProperty) { this.selectedProperty = sel; this.Select(this.selectedProperty.Index); } // Deselect when destroyed else if (this.selectedProperty != null && this.selectedProperty.Index < this.Property.Children.Count && this.selectedProperty != this.Property.Children[this.selectedProperty.Index]) { var index = -1; this.Select(index); this.selectedProperty = null; this.globalSelectedProperty.Value = null; } } } } private void Select(int index) { GUIHelper.RequestRepaint(); this.Property.Tree.DelayAction(() => { for (int i = 0; i < this.baseMemberProperty.ParentValues.Count; i++) { this.selectedIndexSetter(this.baseMemberProperty.ParentValues[i], index); } }); } }