// Copyright (c) 2012-2022 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) { // 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 (Ctrl+Z)"); _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)"); _toolstrip.AddSeparator(); _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); } 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 abstract string SurfaceName { get; } /// public abstract byte[] SurfaceData { get; set; } /// 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(); } } }