// Copyright (c) Wojciech Figat. All rights reserved. using System; using FlaxEditor.Windows; using FlaxEditor.Windows.Assets; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; namespace FlaxEditor.GUI { /// /// Popup that shows the list of scene objects to pick. Supports searching and basic type filtering. /// /// public class SceneObjectSearchPopup : ItemsListContextMenu { /// /// The scene object item. /// /// public class SceneObjectItemView : Item { private SceneObject _object; /// /// Gets the scene object. /// public SceneObject Object => _object; /// /// Initializes a new instance of the class. /// /// The object. public SceneObjectItemView(SceneObject obj) { _object = obj; Category = obj is Actor ? "Actors" : "Scripts"; if (obj is Script script) { var type = TypeUtils.GetObjectType(script); Name = script.Actor ? $"{type.Name} ({script.Actor.Name})" : type.Name; } else if (obj is Actor actor) { Name = actor.Name; } else { Name = obj.ToString(); } TooltipText = Utilities.Utils.GetTooltip(obj); } /// public override void OnDestroy() { _object = null; base.OnDestroy(); } } /// /// Validates if the given scene object item can be used to pick it. /// /// The scene object. /// True if is valid. public delegate bool IsValidDelegate(SceneObject obj); private IsValidDelegate _isValid; private Action _selected; private SceneObjectSearchPopup(IsValidDelegate isValid, Action selected, CustomEditors.IPresenterOwner context) { _isValid = isValid; _selected = selected; ItemClicked += OnItemClicked; if (context is PropertiesWindow || context == null) { // TODO: use async thread to search scenes for (int i = 0; i < Level.ScenesCount; i++) { Find(Level.GetScene(i)); } } else if (context is PrefabWindow prefabWindow) { Find(prefabWindow.Graph.MainActor); } SortItems(); } private void OnItemClicked(Item item) { _selected(((SceneObjectItemView)item).Object); } private void Find(Actor actor) { if (!actor) return; if (_isValid(actor)) AddItem(new SceneObjectItemView(actor)); for (int i = 0; i < actor.ScriptsCount; i++) { var script = actor.GetScript(i); if (_isValid(script)) AddItem(new SceneObjectItemView(script)); } for (int i = 0; i < actor.ChildrenCount; i++) { Find(actor.GetChild(i)); } } /// /// Shows the popup. /// /// The show target. /// The show target location. /// Event called to check if a given scene object item is valid to be used. /// Event called on scene object item pick. /// The presenter owner context (i.e. PrefabWindow, PropertiesWindow). /// The dialog. public static SceneObjectSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action selected, CustomEditors.IPresenterOwner context) { var popup = new SceneObjectSearchPopup(isValid, selected, context); popup.Show(showTarget, showTargetLocation); return popup; } /// public override void OnDestroy() { _isValid = null; _selected = null; base.OnDestroy(); } } }