// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using FlaxEditor.Content;
using FlaxEditor.GUI;
using FlaxEditor.Surface;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Assets
{
///
/// The base class for editor windows that use for content editing by graph functions (eg. material functions, particle emitter functions).
///
///
///
public abstract class VisjectFunctionSurfaceWindow : ClonedAssetEditorWindowBase, IVisjectSurfaceOwner
where TAsset : Asset
where TSurface : VisjectSurface
{
///
/// The surface.
///
protected TSurface _surface;
///
/// The panel for the surface.
///
protected readonly Panel _panel;
private readonly ToolStripButton _saveButton;
private readonly ToolStripButton _undoButton;
private readonly ToolStripButton _redoButton;
private bool _showWholeGraphOnLoad = true;
///
/// True if temporary asset is dirty, otherwise false.
///
protected bool _tmpAssetIsDirty;
///
/// True if window is waiting for asset load to load surface.
///
protected bool _isWaitingForSurfaceLoad;
///
/// The undo.
///
protected Undo _undo;
///
/// Gets the Visject Surface.
///
public TSurface Surface => _surface;
///
/// Gets the undo history context for this window.
///
public Undo Undo => _undo;
///
protected VisjectFunctionSurfaceWindow(Editor editor, AssetItem item)
: base(editor, item)
{
var inputOptions = Editor.Options.Options.Input;
// Undo
_undo = new Undo();
_undo.UndoDone += OnUndoRedo;
_undo.RedoDone += OnUndoRedo;
_undo.ActionDone += OnUndoRedo;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
_toolstrip.AddSeparator();
_toolstrip.AddButton(Editor.Icons.Search64, Editor.ContentFinding.ShowSearch).LinkTooltip($"Open content search tool ({inputOptions.Search})");
_toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
// Panel
_panel = new Panel(ScrollBars.None)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
Parent = this
};
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
InputActions.Add(options => options.Redo, _undo.PerformRedo);
InputActions.Add(options => options.Search, Editor.ContentFinding.ShowSearch);
}
private void OnUndoRedo(IUndoAction action)
{
MarkAsEdited();
UpdateToolstrip();
}
///
/// Shows the whole surface graph.
///
public void ShowWholeGraph()
{
_surface.ShowWholeGraph();
}
///
/// Refreshes temporary asset to see changes live when editing the surface.
///
/// True if cannot refresh it, otherwise false.
public bool RefreshTempAsset()
{
// Early check
if (_asset == null || _isWaitingForSurfaceLoad)
return true;
// Check if surface has been edited
if (_surface.IsEdited)
{
return SaveSurface();
}
return false;
}
///
public override void Save()
{
if (!IsEdited)
return;
if (RefreshTempAsset())
{
return;
}
if (SaveToOriginal())
{
return;
}
ClearEditedFlag();
OnSurfaceEditedChanged();
_item.RefreshThumbnail();
}
///
protected override void UpdateToolstrip()
{
_saveButton.Enabled = IsEdited;
_undoButton.Enabled = _undo.CanUndo;
_redoButton.Enabled = _undo.CanRedo;
base.UpdateToolstrip();
}
///
protected override void UnlinkItem()
{
_isWaitingForSurfaceLoad = false;
base.UnlinkItem();
}
///
protected override void OnAssetLinked()
{
_isWaitingForSurfaceLoad = true;
base.OnAssetLinked();
}
///
public Asset SurfaceAsset => Asset;
///
public abstract string SurfaceName { get; }
///
public abstract byte[] SurfaceData { get; set; }
///
public VisjectSurfaceContext ParentContext => null;
///
public void OnContextCreated(VisjectSurfaceContext context)
{
}
///
public void OnSurfaceEditedChanged()
{
if (_surface.IsEdited)
MarkAsEdited();
}
///
public void OnSurfaceGraphEdited()
{
// Mark as dirty
_tmpAssetIsDirty = true;
}
///
public void OnSurfaceClose()
{
Close();
}
///
/// Loads the surface from the asset. Called during when asset is loaded and surface is missing.
///
/// True if failed, otherwise false.
protected virtual bool LoadSurface()
{
if (_surface.Load())
{
Editor.LogError("Failed to load surface.");
return true;
}
return false;
}
///
/// Saves the surface to the asset. Called during when asset is loaded and surface is missing.
///
/// True if failed, otherwise false.
protected virtual bool SaveSurface()
{
_surface.Save();
return false;
}
///
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (_tmpAssetIsDirty)
{
_tmpAssetIsDirty = false;
RefreshTempAsset();
}
if (_isWaitingForSurfaceLoad && _asset.IsLoaded)
{
_isWaitingForSurfaceLoad = false;
if (LoadSurface())
{
Close();
return;
}
// Setup
_undo.Clear();
_surface.Enabled = true;
ClearEditedFlag();
if (_showWholeGraphOnLoad)
{
_showWholeGraphOnLoad = false;
_surface.ShowWholeGraph();
}
}
}
///
public override void OnDestroy()
{
_undo.Clear();
base.OnDestroy();
}
}
}