// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using System.Reflection; using System.Xml; using FlaxEditor.Content; using FlaxEditor.Content.Import; using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; using FlaxEditor.GUI.Timeline; using FlaxEditor.Scripting; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Windows.Assets { /// /// Editor window to view/modify asset. /// /// /// public sealed class AnimationWindow : AssetEditorWindowBase { [CustomEditor(typeof(ProxyEditor))] private sealed class PropertiesProxy { private AnimationWindow Window; private Animation Asset; private ModelImportSettings ImportSettings = new ModelImportSettings(); public void OnLoad(AnimationWindow window) { // Link Window = window; Asset = window.Asset; // Try to restore target asset import options (useful for fast reimport) ModelImportSettings.TryRestore(ref ImportSettings, window.Item.Path); } public void OnClean() { // Unlink Window = null; Asset = null; } public void Reimport() { Editor.Instance.ContentImporting.Reimport((BinaryAssetItem)Window.Item, ImportSettings, true); } private class ProxyEditor : GenericEditor { /// public override void Initialize(LayoutElementsContainer layout) { var proxy = (PropertiesProxy)Values[0]; if (proxy.Asset == null || !proxy.Asset.IsLoaded) { layout.Label("Loading..."); return; } base.Initialize(layout); // General properties { var group = layout.Group("General"); var info = proxy.Asset.Info; group.Label("Length: " + info.Length + "s"); group.Label("Frames: " + info.FramesCount); group.Label("Channels: " + info.ChannelsCount); group.Label("Keyframes: " + info.KeyframesCount); } // Import Settings { var group = layout.Group("Import Settings"); var importSettingsField = typeof(PropertiesProxy).GetField("ImportSettings", BindingFlags.NonPublic | BindingFlags.Instance); var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings }; group.Object(importSettingsValues); layout.Space(5); var reimportButton = group.Button("Reimport"); reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport(); } } } } private CustomEditorPresenter _propertiesPresenter; private PropertiesProxy _properties; private SplitPanel _panel; private AnimationTimeline _timeline; private Undo _undo; private ToolStripButton _saveButton; private ToolStripButton _undoButton; private ToolStripButton _redoButton; private bool _isWaitingForTimelineLoad; /// /// Gets the animation timeline editor. /// public AnimationTimeline Timeline => _timeline; /// /// Gets the undo history context for this window. /// public Undo Undo => _undo; /// public AnimationWindow(Editor editor, AssetItem item) : base(editor, item) { // Undo _undo = new Undo(); _undo.UndoDone += OnUndoRedo; _undo.RedoDone += OnUndoRedo; _undo.ActionDone += OnUndoRedo; // Main panel _panel = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical) { AnchorPreset = AnchorPresets.StretchAll, SplitterValue = 0.8f, Offsets = new Margin(0, 0, _toolstrip.Bottom, 0), Parent = this }; // Timeline _timeline = new AnimationTimeline(_undo) { AnchorPreset = AnchorPresets.StretchAll, Offsets = Margin.Zero, Parent = _panel.Panel1, Enabled = false }; _timeline.Modified += MarkAsEdited; // Asset properties _propertiesPresenter = new CustomEditorPresenter(null); _propertiesPresenter.Panel.Parent = _panel.Panel2; _properties = new PropertiesProxy(); _propertiesPresenter.Select(_properties); _propertiesPresenter.Modified += MarkAsEdited; // Toolstrip _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save"); _toolstrip.AddSeparator(); _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)"); _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/animation/index.html")).LinkTooltip("See documentation to learn more"); // Setup input actions InputActions.Add(options => options.Undo, _undo.PerformUndo); InputActions.Add(options => options.Redo, _undo.PerformRedo); } private void OnUndoRedo(IUndoAction action) { MarkAsEdited(); UpdateToolstrip(); } /// protected override void OnAssetLoaded() { _properties.OnLoad(this); _propertiesPresenter.BuildLayout(); ClearEditedFlag(); base.OnAssetLoaded(); } /// public override void Save() { if (!IsEdited) return; _timeline.Save(_asset); ClearEditedFlag(); _item.RefreshThumbnail(); } /// protected override void UpdateToolstrip() { _saveButton.Enabled = IsEdited; _undoButton.Enabled = _undo.CanUndo; _redoButton.Enabled = _undo.CanRedo; base.UpdateToolstrip(); } /// protected override void UnlinkItem() { _isWaitingForTimelineLoad = false; _properties.OnClean(); base.UnlinkItem(); } /// protected override void OnAssetLinked() { _isWaitingForTimelineLoad = true; base.OnAssetLinked(); } /// public override void OnItemReimported(ContentItem item) { // Refresh the properties (will get new data in OnAssetLoaded) _properties.OnClean(); _propertiesPresenter.BuildLayout(); ClearEditedFlag(); // Reload timeline _timeline.Enabled = false; _isWaitingForTimelineLoad = true; base.OnItemReimported(item); } /// public override void Update(float deltaTime) { base.Update(deltaTime); if (_isWaitingForTimelineLoad && _asset.IsLoaded) { _isWaitingForTimelineLoad = false; _timeline.Load(_asset); _undo.Clear(); _timeline.Enabled = true; ClearEditedFlag(); } } /// public override bool UseLayoutData => true; /// public override void OnLayoutSerialize(XmlWriter writer) { writer.WriteAttributeString("TimelineSplitter", _timeline.Splitter.SplitterValue.ToString()); writer.WriteAttributeString("TimeShowMode", _timeline.TimeShowMode.ToString()); writer.WriteAttributeString("ShowPreviewValues", _timeline.ShowPreviewValues.ToString()); } /// public override void OnLayoutDeserialize(XmlElement node) { float value1; Timeline.TimeShowModes value2; bool value3; if (float.TryParse(node.GetAttribute("TimelineSplitter"), out value1)) _timeline.Splitter.SplitterValue = value1; if (Enum.TryParse(node.GetAttribute("TimeShowMode"), out value2)) _timeline.TimeShowMode = value2; if (bool.TryParse(node.GetAttribute("ShowPreviewValues"), out value3)) _timeline.ShowPreviewValues = value3; } /// public override void OnLayoutDeserialize() { _timeline.Splitter.SplitterValue = 0.2f; } /// public override void OnDestroy() { if (_undo != null) { _undo.Enabled = false; _undo.Clear(); _undo = null; } _timeline = null; _propertiesPresenter = null; _properties = null; _panel = null; _saveButton = null; _undoButton = null; _redoButton = null; base.OnDestroy(); } } }