Files
FlaxEngine/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
2024-09-11 18:32:08 +02:00

277 lines
7.5 KiB
C#

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using FlaxEditor.Content;
using FlaxEditor.GUI;
using FlaxEditor.Surface;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Assets
{
/// <summary>
/// The base class for editor windows that use <see cref="FlaxEditor.Surface.VisjectSurface"/> for content editing by graph functions (eg. material functions, particle emitter functions).
/// </summary>
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
/// <seealso cref="FlaxEditor.Surface.IVisjectSurfaceOwner" />
public abstract class VisjectFunctionSurfaceWindow<TAsset, TSurface> : ClonedAssetEditorWindowBase<TAsset>, IVisjectSurfaceOwner
where TAsset : Asset
where TSurface : VisjectSurface
{
/// <summary>
/// The surface.
/// </summary>
protected TSurface _surface;
/// <summary>
/// The panel for the surface.
/// </summary>
protected readonly Panel _panel;
private readonly ToolStripButton _saveButton;
private readonly ToolStripButton _undoButton;
private readonly ToolStripButton _redoButton;
private readonly ToolStripButton _gridSnapButton;
private bool _showWholeGraphOnLoad = true;
/// <summary>
/// True if temporary asset is dirty, otherwise false.
/// </summary>
protected bool _tmpAssetIsDirty;
/// <summary>
/// True if window is waiting for asset load to load surface.
/// </summary>
protected bool _isWaitingForSurfaceLoad;
/// <summary>
/// The undo.
/// </summary>
protected Undo _undo;
/// <summary>
/// Gets the Visject Surface.
/// </summary>
public TSurface Surface => _surface;
/// <summary>
/// Gets the undo history context for this window.
/// </summary>
public Undo Undo => _undo;
/// <inheritdoc />
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
SurfaceUtils.VisjectCommonToolstripSetup(editor, _toolstrip, _undo,
Save, ShowWholeGraph, ToggleGridSnap, InputActions,
out _saveButton, out _undoButton, out _redoButton, out _gridSnapButton);
// Panel
_panel = new Panel(ScrollBars.None)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
Parent = this
};
}
private void OnUndoRedo(IUndoAction action)
{
MarkAsEdited();
UpdateToolstrip();
}
/// <summary>
/// Shows the whole surface graph.
/// </summary>
public void ShowWholeGraph()
{
_surface.ShowWholeGraph();
}
private void ToggleGridSnap()
{
SurfaceUtils.ToggleSurfaceGridSnap(_surface, _gridSnapButton);
}
/// <summary>
/// Refreshes temporary asset to see changes live when editing the surface.
/// </summary>
/// <returns>True if cannot refresh it, otherwise false.</returns>
public bool RefreshTempAsset()
{
// Early check
if (_asset == null || _isWaitingForSurfaceLoad)
return true;
// Check if surface has been edited
if (_surface.IsEdited)
{
return SaveSurface();
}
return false;
}
/// <inheritdoc />
public override void Save()
{
if (!IsEdited)
return;
if (RefreshTempAsset())
{
return;
}
if (SaveToOriginal())
{
return;
}
ClearEditedFlag();
OnSurfaceEditedChanged();
_item.RefreshThumbnail();
}
/// <inheritdoc />
protected override void UpdateToolstrip()
{
_saveButton.Enabled = IsEdited;
_undoButton.Enabled = _undo.CanUndo;
_redoButton.Enabled = _undo.CanRedo;
base.UpdateToolstrip();
}
/// <inheritdoc />
protected override void UnlinkItem()
{
_isWaitingForSurfaceLoad = false;
base.UnlinkItem();
}
/// <inheritdoc />
protected override void OnAssetLinked()
{
_isWaitingForSurfaceLoad = true;
base.OnAssetLinked();
}
/// <inheritdoc />
public Asset SurfaceAsset => Asset;
/// <inheritdoc />
public abstract string SurfaceName { get; }
/// <inheritdoc />
public abstract byte[] SurfaceData { get; set; }
/// <inheritdoc />
public VisjectSurfaceContext ParentContext => null;
/// <inheritdoc />
public void OnContextCreated(VisjectSurfaceContext context)
{
}
/// <inheritdoc />
public void OnSurfaceEditedChanged()
{
if (_surface.IsEdited)
MarkAsEdited();
}
/// <inheritdoc />
public void OnSurfaceGraphEdited()
{
// Mark as dirty
_tmpAssetIsDirty = true;
}
/// <inheritdoc />
public void OnSurfaceClose()
{
Close();
}
/// <summary>
/// Loads the surface from the asset. Called during <see cref="Update"/> when asset is loaded and surface is missing.
/// </summary>
/// <returns>True if failed, otherwise false.</returns>
protected virtual bool LoadSurface()
{
if (_surface.Load())
{
Editor.LogError("Failed to load surface.");
return true;
}
return false;
}
/// <summary>
/// Saves the surface to the asset. Called during <see cref="Update"/> when asset is loaded and surface is missing.
/// </summary>
/// <returns>True if failed, otherwise false.</returns>
protected virtual bool SaveSurface()
{
_surface.Save();
return false;
}
/// <inheritdoc />
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();
}
}
}
/// <inheritdoc />
public override void OnDestroy()
{
_undo.Clear();
base.OnDestroy();
}
}
}