using UnityEngine; using UnityEngine.UIElements; using System.Collections.Generic; using System; using System.IO; #if UNITY_EDITOR using UnityEditor; #endif namespace NEG.Utils.UiToolkits { public class MultiSelectChips : VisualElement { public event Action OnTryingToRemoveItem; public event Action OnTryingToAddItem; public string LabelText { get => label.text; set { if (!string.IsNullOrEmpty(value)) { if (label == null) { InitLabel(); } label.text = value; } else if (label != null) { label.RemoveFromHierarchy(); label = null; } } } public ICollection ItemsSource { get => itemsSource; set { itemsSource = value; UpdateItems(); } } private Label label; private VisualTreeAsset itemPrefab; private ICollection itemsSource; private readonly List spawnedItems = new(); private VisualElement realItemsParent; public new class UxmlFactory : UxmlFactory { } public new class UxmlTraits : VisualElement.UxmlTraits { private readonly UxmlStringAttributeDescription label; public UxmlTraits() { label = new() { name = "label" }; } public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); ((MultiSelectChips)ve).LabelText = label.GetValueFromBag(bag, cc); } } public MultiSelectChips() : base() { #if UNITY_EDITOR string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.FindAssets($"t:Script {nameof(MultiSelectChips)}")[0]); path = path.Remove(path.LastIndexOf('/')); SetVisuals(AssetDatabase.LoadAssetAtPath($"{path}/Resources/MultiSelectChips.uxml")); itemPrefab = AssetDatabase.LoadAssetAtPath($"{path}/Resources/MultiSelectChipItem.uxml"); #else SetVisuals(Resources.Load("MultiSelectChips.uxml")); itemPrefab = Resources.Load("MultiSelectChipItem.uxml"); #endif } public void UpdateItems() { if (itemPrefab == null || itemsSource == null || realItemsParent == null) return; var itemsToDestroy = new List(spawnedItems); itemsToDestroy.RemoveAll((x) => itemsSource.Contains(x.ChipItem)); foreach (var item in itemsToDestroy) { realItemsParent.Remove(item.VisualElement); spawnedItems.Remove(item); } List itemsToAdd = new(itemsSource); foreach (var item in spawnedItems) { if (itemsToAdd.Contains(item.ChipItem)) itemsToAdd.Remove(item.ChipItem); } foreach (var item in itemsToAdd) { VisualElement chipItemVisuals = itemPrefab.Instantiate(); realItemsParent.Insert(0, chipItemVisuals); spawnedItems.Add(new MultiSelectChipItem(chipItemVisuals, item, this)); } } public void TryRemoveItem(IMultiSelectChipItem item) => OnTryingToRemoveItem?.Invoke(item); private void InitLabel() { label = new Label() { pickingMode = PickingMode.Ignore }; Insert(0, label); } private void SetVisuals(VisualTreeAsset treeAsset) { realItemsParent = treeAsset.Instantiate(); Add(realItemsParent); var button = realItemsParent.Q