// 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();
}
}
}