// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using FlaxEditor.Content; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.GUI { /// /// Popup that shows the list of content items to pick. Supports searching and basic items filtering. /// /// public class ContentSearchPopup : ItemsListContextMenu { /// /// The content item. /// /// public class ContentItemView : Item, IContentItemOwner { /// /// The icon size (in pixels). /// public const float IconSize = 28; /// /// Gets the item. /// public ContentItem ContentItem; /// /// Initializes a new instance of the class. /// /// The item. public ContentItemView(ContentItem item) { ContentItem = item; ContentItem.AddReference(this); Name = item.ShortName; TooltipText = item.Path; Height = IconSize + 4; } /// protected override void GetTextRect(out Rectangle rect) { var height = Height; rect = new Rectangle(IconSize + 4, (height - 16) * 0.5f, Width - IconSize - 6, 16); } /// public override void Draw() { base.Draw(); // Draw icon var iconRect = new Rectangle(2, 2, IconSize, IconSize); ContentItem.DrawThumbnail(ref iconRect); } /// public override void OnDestroy() { if (ContentItem != null) { ContentItem.RemoveReference(this); ContentItem = null; } base.OnDestroy(); } /// public void OnItemDeleted(ContentItem item) { Dispose(); } /// public void OnItemRenamed(ContentItem item) { Name = ContentItem.ShortName; } /// public void OnItemReimported(ContentItem item) { } /// public void OnItemDispose(ContentItem item) { Dispose(); } } /// /// Validates if the given content item can be used to pick it. /// /// The item. /// True if is valid. public delegate bool IsValidDelegate(ContentItem item); private IsValidDelegate _isValid; private Action _selected; /// protected ContentSearchPopup() { } /// protected ContentSearchPopup(IsValidDelegate isValid, Action selected) { _isValid = isValid; _selected = selected; ItemClicked += OnItemClicked; // TODO: use async thread to search workspace items foreach (var project in Editor.Instance.ContentDatabase.Projects) { if (project.Content != null) FindItems(project.Content.Folder); } SortItems(); } private void OnItemClicked(Item item) { _selected.Invoke(((ContentItemView)item).ContentItem); } private void FindItems(ContentFolder folder) { for (int i = 0; i < folder.Children.Count; i++) { if (folder.Children[i] is ContentItem item && _isValid(item)) { AddItem(new ContentItemView(item)); } } for (int i = 0; i < folder.Children.Count; i++) { if (folder.Children[i] is ContentFolder child) { FindItems(child); } } } /// /// Shows the popup. /// /// The show target. /// The show target location. /// Event called to check if a given content item is valid to be used. /// Event called on content item pick. /// The dialog. public static ContentSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action selected) { var popup = new ContentSearchPopup(isValid, selected); popup.Show(showTarget, showTargetLocation); return popup; } /// public override void OnDestroy() { _isValid = null; _selected = null; base.OnDestroy(); } } /// /// Popup that shows the list of assets to pick. Supports searching and basic items filtering. /// public class AssetSearchPopup : ContentSearchPopup { /// /// The asset item. /// public class AssetItemView : ContentItemView { /// /// Gets the asset. /// public AssetItem AssetItem => (AssetItem)ContentItem; /// /// Initializes a new instance of the class. /// /// The asset. public AssetItemView(AssetItem asset) : base(asset) { } } /// /// Validates if the given asset item can be used to pick it. /// /// The asset. /// True if is valid. public new delegate bool IsValidDelegate(AssetItem asset); private IsValidDelegate _isValid; private Action _selected; private AssetSearchPopup(IsValidDelegate isValid, Action selected) { _isValid = isValid; _selected = selected; ItemClicked += OnItemClicked; // TODO: use async thread to search workspace items foreach (var project in Editor.Instance.ContentDatabase.Projects) { if (project.Content != null) FindAssets(project.Content.Folder); } SortItems(); } private void OnItemClicked(Item item) { _selected(((AssetItemView)item).AssetItem); } private void FindAssets(ContentFolder folder) { for (int i = 0; i < folder.Children.Count; i++) { if (folder.Children[i] is AssetItem asset && _isValid(asset)) { AddItem(new AssetItemView(asset)); } } for (int i = 0; i < folder.Children.Count; i++) { if (folder.Children[i] is ContentFolder child) { FindAssets(child); } } } /// /// Shows the popup. /// /// The show target. /// The show target location. /// Event called to check if a given asset item is valid to be used. /// Event called on asset item pick. /// The dialog. public static AssetSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action selected) { var popup = new AssetSearchPopup(isValid, selected); popup.Show(showTarget, showTargetLocation); return popup; } /// public override void OnDestroy() { _isValid = null; _selected = null; base.OnDestroy(); } } }