From 46a65f99fa9046d8908b33f271bdb45705a2a815 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 23 Jul 2021 16:18:11 +0200 Subject: [PATCH] Add buttons for play/pause/stop Animation timeline in editor window --- .../Editor/GUI/Timeline/AnimationTimeline.cs | 81 ++++++++++++++++++- .../GUI/Timeline/SceneAnimationTimeline.cs | 2 - Source/Editor/GUI/Timeline/Timeline.cs | 16 ++++ .../Viewport/Previews/AnimatedModelPreview.cs | 48 ++++++++++- .../Viewport/Previews/AnimationPreview.cs | 14 ++-- .../Editor/Windows/Assets/AnimationWindow.cs | 2 + 6 files changed, 150 insertions(+), 13 deletions(-) diff --git a/Source/Editor/GUI/Timeline/AnimationTimeline.cs b/Source/Editor/GUI/Timeline/AnimationTimeline.cs index f4d9d6c71..16b5a0b21 100644 --- a/Source/Editor/GUI/Timeline/AnimationTimeline.cs +++ b/Source/Editor/GUI/Timeline/AnimationTimeline.cs @@ -1,6 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System; using FlaxEditor.GUI.Timeline.Tracks; +using FlaxEditor.Viewport.Previews; using FlaxEngine; namespace FlaxEditor.GUI.Timeline @@ -20,12 +22,35 @@ namespace FlaxEditor.GUI.Timeline } } + private AnimationPreview _preview; + + /// + /// Gets or sets the animated preview used for the animation playback. + /// + public AnimationPreview Preview + { + get => _preview; + set + { + if (_preview == value) + return; + _preview = value; + UpdatePlaybackState(); + PreviewChanged?.Invoke(); + } + } + + /// + /// Occurs when the selected animated model preview gets changed. + /// + public event Action PreviewChanged; + /// /// Initializes a new instance of the class. /// /// The undo/redo to use for the history actions recording. Optional, can be null to disable undo support. public AnimationTimeline(FlaxEditor.Undo undo) - : base(PlaybackButtons.None, undo, false, false) + : base(PlaybackButtons.Play | PlaybackButtons.Stop, undo, false, false) { PlaybackState = PlaybackStates.Seeking; ShowPreviewValues = false; @@ -62,6 +87,60 @@ namespace FlaxEditor.GUI.Timeline asset.Reload(); } + private void UpdatePlaybackState() + { + PlaybackStates state; + ShowPlaybackButtonsArea = _preview != null; + if (_preview != null) + { + if (_preview.PlayAnimation) + { + state = PlaybackStates.Playing; + } + else + { + state = PlaybackStates.Paused; + } + } + else + { + state = PlaybackStates.Seeking; + } + PlaybackState = state; + } + + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + UpdatePlaybackState(); + } + + /// + public override void OnPlay() + { + _preview.Play(); + + base.OnPlay(); + } + + /// + public override void OnPause() + { + _preview.Pause(); + + base.OnPause(); + } + + /// + public override void OnStop() + { + _preview.Stop(); + + base.OnStop(); + } + /// public override void OnSeek(int frame) { diff --git a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs index 7549fb984..b550c53ac 100644 --- a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs +++ b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs @@ -37,9 +37,7 @@ namespace FlaxEditor.GUI.Timeline { if (_player == value) return; - _player = value; - UpdatePlaybackState(); PlayerChanged?.Invoke(); } diff --git a/Source/Editor/GUI/Timeline/Timeline.cs b/Source/Editor/GUI/Timeline/Timeline.cs index 58e6a0f32..10dc35e0b 100644 --- a/Source/Editor/GUI/Timeline/Timeline.cs +++ b/Source/Editor/GUI/Timeline/Timeline.cs @@ -289,6 +289,7 @@ namespace FlaxEditor.GUI.Timeline private Image _playbackStop; private Image _playbackPlay; private Label _noTracksLabel; + private ContainerControl _playbackButtonsArea; private PositionHandle _positionHandle; private bool _isRightMouseButtonDown; private Vector2 _rightMouseButtonDownPos; @@ -597,6 +598,19 @@ namespace FlaxEditor.GUI.Timeline } } + /// + /// Gets or sets a value indicating whether show playback buttons area. + /// + public bool ShowPlaybackButtonsArea + { + get => _playbackButtonsArea?.Visible ?? false; + set + { + if (_playbackButtonsArea != null) + _playbackButtonsArea.Visible = value; + } + } + /// /// Gets a value indicating whether user is moving position handle (seeking). /// @@ -723,6 +737,7 @@ namespace FlaxEditor.GUI.Timeline Offsets = new Margin(0, 0, -playbackButtonsSize, playbackButtonsSize), Parent = _splitter.Panel1 }; + _playbackButtonsArea = playbackButtonsArea; var playbackButtonsPanel = new ContainerControl { AutoFocus = false, @@ -2305,6 +2320,7 @@ namespace FlaxEditor.GUI.Timeline _playbackStop = null; _playbackPlay = null; _noTracksLabel = null; + _playbackButtonsArea = null; _positionHandle = null; DragHandlers.Clear(); diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index c59ec87fa..27e76dbf8 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System; using FlaxEditor.GUI.ContextMenu; using FlaxEngine; using FlaxEditor.GUI.Input; @@ -15,11 +16,11 @@ namespace FlaxEditor.Viewport.Previews public class AnimatedModelPreview : AssetPreview { private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton; - private bool _showNodes, _showBounds, _showFloor; + private bool _showNodes, _showBounds, _showFloor, _showCurrentLOD; private AnimatedModel _previewModel; private StaticModel _floorModel; private ContextMenuButton _showCurrentLODButton; - private bool _showCurrentLOD; + private bool _playAnimation; /// /// Gets or sets the skinned model asset to preview. @@ -38,7 +39,22 @@ namespace FlaxEditor.Viewport.Previews /// /// Gets or sets a value indicating whether play the animation in editor. /// - public bool PlayAnimation { get; set; } = false; + public bool PlayAnimation + { + get => _playAnimation; + set + { + if (_playAnimation == value) + return; + _playAnimation = value; + PlayAnimationChanged?.Invoke(); + } + } + + /// + /// Occurs when animation playback state gets changed. + /// + public event Action PlayAnimationChanged; /// /// Gets or sets a value indicating whether show animated model skeleton nodes debug view. @@ -173,6 +189,32 @@ namespace FlaxEditor.Viewport.Previews Task.ViewFlags |= ViewFlags.Shadows; } + /// + /// Starts the animation playback. + /// + public void Play() + { + PlayAnimation = true; + } + + /// + /// Pauses the animation playback. + /// + public void Pause() + { + PlayAnimation = false; + } + + /// + /// Stops the animation playback. + /// + public void Stop() + { + PlayAnimation = false; + _previewModel.ResetAnimation(); + _previewModel.UpdateAnimation(); + } + private void OnBegin(RenderTask task, GPUContext context) { if (!ScaleToFit) diff --git a/Source/Editor/Viewport/Previews/AnimationPreview.cs b/Source/Editor/Viewport/Previews/AnimationPreview.cs index a9bc242b9..b931bacfb 100644 --- a/Source/Editor/Viewport/Previews/AnimationPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimationPreview.cs @@ -23,6 +23,7 @@ namespace FlaxEditor.Viewport.Previews : base(useWidgets) { PlayAnimation = true; + PlayAnimationChanged += OnPlayAnimationChanged; // Playback Speed { @@ -43,11 +44,7 @@ namespace FlaxEditor.Viewport.Previews TooltipText = "Animation playback play (F5) or pause (F6)", Parent = playPauseWidget, }; - _playPauseButton.Clicked += button => - { - PlayAnimation = !PlayAnimation; - button.Icon = PlayAnimation ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; - }; + _playPauseButton.Clicked += button => PlayAnimation = !PlayAnimation; playPauseWidget.Parent = this; } @@ -58,6 +55,11 @@ namespace FlaxEditor.Viewport.Previews Task.ViewFlags |= ViewFlags.Shadows; } + private void OnPlayAnimationChanged() + { + _playPauseButton.Icon = PlayAnimation ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; + } + /// public override void Draw() { @@ -82,13 +84,11 @@ namespace FlaxEditor.Viewport.Previews if (inputOptions.Play.Process(this, key)) { PlayAnimation = true; - _playPauseButton.Icon = PlayAnimation ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; return true; } if (inputOptions.Pause.Process(this, key)) { PlayAnimation = false; - _playPauseButton.Icon = PlayAnimation ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; return true; } return base.OnKeyDown(key); diff --git a/Source/Editor/Windows/Assets/AnimationWindow.cs b/Source/Editor/Windows/Assets/AnimationWindow.cs index 8c0d4d033..12dd4a848 100644 --- a/Source/Editor/Windows/Assets/AnimationWindow.cs +++ b/Source/Editor/Windows/Assets/AnimationWindow.cs @@ -101,6 +101,7 @@ namespace FlaxEditor.Windows.Assets } Window._preview.SetModel(value); + Window._timeline.Preview = value ? Window._preview : null; if (Window._panel2 == null) { @@ -321,6 +322,7 @@ namespace FlaxEditor.Windows.Assets { _isWaitingForTimelineLoad = false; _properties.OnClean(); + _timeline.Preview = null; base.UnlinkItem(); }