AnnulusGames / Alchemy

Provides a rich set of editor extensions and serialization extensions for Unity.
https://annulusgames.github.io/Alchemy/
MIT License
550 stars 32 forks source link

[Bug] ListView Lost focus every time enter value #97

Open aprius opened 2 months ago

aprius commented 2 months ago

Alchemy v2.0.1 Unity 6000.0.f14

public List<string> samples;

https://github.com/user-attachments/assets/d07e0b22-9666-408b-a9cc-21aed344986b

Every time I fill in a value, the focus is lost and I have to click again to continue filling in.

aprius commented 2 months ago

@AnnulusGames The cause seems to be the PropertyListView class.

KiyoK7227 commented 2 months ago

This bug is troubling me too. I’ve been writing things in Notepad and copying and pasting them, but it's not ideal. I hope this will be fixed.

aprius commented 2 months ago

It seems Unity changed something with ListView but I haven't found anything from their changelog so I tried to fix it by every time I enter a value I will focus back on the last element I was editing. Another problem while I fixed it this stupid way is that the focus doesn't move the cursor to the end but instead it selects the entire content and so again I have to add a RightArrow button press action to focus at the end so I can continue entering content. I don't think this is a good way but I haven't found a solution yet or wait for a fix from Unity if there is one

aprius commented 2 months ago
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UIElements;
using Alchemy.Inspector;

namespace Alchemy.Editor.Elements
{
    /// <summary>
    /// Visual Element that draws SerializedProperty of Array or List
    /// </summary>
    public sealed class PropertyListView : BindableElement
    {
        public PropertyListView(SerializedProperty property)
        {
            Assert.IsTrue(property.isArray);

            var parentObj = property.GetDeclaredObject();
            var events = property.GetAttribute<OnListViewChangedAttribute>(true);
            VisualElement lastFocusedElement = null;

            listView = GUIHelper.CreateListViewFromFieldInfo(parentObj, property.GetFieldInfo());
            listView.headerTitle = ObjectNames.NicifyVariableName(property.displayName);
            listView.bindItem = (element, index) =>
            {
                var arrayElement = property.GetArrayElementAtIndex(index);
                var e = new AlchemyPropertyField(arrayElement, property.GetPropertyType(true), true);
                element.Add(e);
                element.Bind(arrayElement.serializedObject);
                var field = lastFocusedElement?.Q<TextField>();
                if (field != null)
                {
                    field.Focus();
                    field.SelectRange(field.value.Length, field.value.Length);
                    using var evt = KeyboardEventBase<KeyDownEvent>.GetPooled('\0', KeyCode.RightArrow, EventModifiers.FunctionKey);
                    field.SendEvent(evt);
                }

                if (events != null)
                {
                    e.TrackPropertyValue(arrayElement, x =>
                    {
                        ReflectionHelper.Invoke(parentObj, events.OnItemChanged,
                            new object[] { index, x.GetValue<object>() });
                    });
                }
            };
            listView.unbindItem = (element, index) =>
            {
                lastFocusedElement = element;
                element.Clear();
                element.Unbind();
            };

            var label = listView.Q<Label>();
            if (label != null) label.style.unityFontStyleAndWeight = FontStyle.Bold;

            listView.BindProperty(property);
            Add(listView);
        }

        readonly ListView listView;

        public string Label
        {
            get => listView.headerTitle;
            set => listView.headerTitle = value;
        }
    }
}