// Copyright (c) Wojciech Figat. All rights reserved. using System; using FlaxEngine; using FlaxEngine.GUI; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews { /// /// Prefab asset preview editor viewport. /// /// public class PrefabPreview : AssetPreview { private Prefab _prefab; private Actor _instance; private UIControl _uiControlLinked; internal bool _hasUILinked; internal ContainerControl _uiParentLink; /// /// Gets or sets the prefab asset to preview. /// public Prefab Prefab { get => _prefab; set { if (_prefab == value) return; // Unset and cleanup spawned instance if (_instance) { var instance = _instance; Instance = null; Object.Destroy(instance); } _prefab = value; if (_prefab) { // Load prefab _prefab.WaitForLoaded(); // Spawn prefab var instance = PrefabManager.SpawnPrefab(_prefab, null); if (instance == null) { _prefab = null; throw new Exception("Failed to spawn a prefab for the preview."); } // Set instance Instance = instance; } } } /// /// Gets the instance of the prefab spawned for the preview. /// public Actor Instance { get => _instance; internal set { if (_instance == value) return; if (_instance) { // Unlink UI control if (_uiControlLinked) { if (_uiControlLinked.Control?.Parent == _uiParentLink) _uiControlLinked.Control.Parent = null; _uiControlLinked = null; } foreach (var child in _uiParentLink.Children.ToArray()) { if (child is CanvasRootControl canvasRoot) { canvasRoot.Canvas.EditorOverride(null, null); } } // Remove for the preview Task.RemoveCustomActor(_instance); } _instance = value; _hasUILinked = false; if (_instance) { // Add to the preview Task.AddCustomActor(_instance); UpdateLinkage(); } } } private void UpdateLinkage() { // Clear flag _hasUILinked = false; // Link UI canvases to the preview (eg. after canvas added to the prefab) LinkCanvas(_instance); // Link UI control to the preview var uiControl = _instance as UIControl; if (_uiControlLinked == null && uiControl != null && uiControl.Control != null && uiControl.Control.Parent == null) { uiControl.Control.Parent = _uiParentLink; _uiControlLinked = uiControl; _hasUILinked = true; } else if (_uiControlLinked != null) { if (_uiControlLinked.Control != null && _uiControlLinked.Control.Parent == null) _uiControlLinked.Control.Parent = _uiParentLink; _hasUILinked = true; } // Use UI mode when root is empty UI Control if (_uiControlLinked == null && uiControl != null && uiControl.Control == null) { _hasUILinked = true; } } private void LinkCanvas(Actor actor) { if (actor is UICanvas uiCanvas) { uiCanvas.EditorOverride(Task, _uiParentLink); if (uiCanvas.GUI.Parent == _uiParentLink) _hasUILinked = true; } var children = actor.ChildrenCount; for (int i = 0; i < children; i++) LinkCanvas(actor.GetChild(i)); } /// /// Initializes a new instance of the class. /// /// if set to true use widgets. public PrefabPreview(bool useWidgets) : base(useWidgets) { // Link to itself by default _uiParentLink = this; } /// public override void Update(float deltaTime) { base.Update(deltaTime); if (_instance != null) { UpdateLinkage(); } } /// public override void OnDestroy() { Prefab = null; base.OnDestroy(); } } }