// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.CustomEditors; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Timeline.Undo; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.GUI.Timeline { partial class Timeline { private sealed class TimeIntervalsHeader : ContainerControl { private Timeline _timeline; private bool _isLeftMouseButtonDown; public TimeIntervalsHeader(Timeline timeline) { _timeline = timeline; } /// public override bool OnMouseDown(Float2 location, MouseButton button) { if (base.OnMouseDown(location, button)) return true; if (button == MouseButton.Left) { _isLeftMouseButtonDown = true; _timeline._isMovingPositionHandle = true; StartMouseCapture(); Seek(ref location); Focus(); return true; } return false; } /// public override void OnMouseMove(Float2 location) { base.OnMouseMove(location); if (_isLeftMouseButtonDown) { Seek(ref location); } } /// public override void OnMouseEnter(Float2 location) { base.OnMouseEnter(location); Cursor = CursorType.Hand; } /// public override void OnMouseLeave() { Cursor = CursorType.Default; base.OnMouseLeave(); } /// public override void Defocus() { Cursor = CursorType.Default; base.Defocus(); } private void Seek(ref Float2 location) { if (_timeline.PlaybackState == PlaybackStates.Disabled) return; var locationTimeline = PointToParent(_timeline, location); var locationTime = _timeline._backgroundArea.PointFromParent(_timeline, locationTimeline); var frame = (locationTime.X - StartOffset * 2.0f) / _timeline.Zoom / UnitsPerSecond * _timeline.FramesPerSecond; _timeline.OnSeek((int)frame); } /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (base.OnMouseUp(location, button)) return true; if (button == MouseButton.Left && _isLeftMouseButtonDown) { Seek(ref location); EndMouseCapture(); return true; } return false; } /// public override void OnEndMouseCapture() { _isLeftMouseButtonDown = false; _timeline._isMovingPositionHandle = false; base.OnEndMouseCapture(); } /// public override void OnDestroy() { _timeline = null; base.OnDestroy(); } } class PropertiesEditPopup : ContextMenuBase { private Timeline _timeline; private bool _isDirty; private byte[] _beforeData; private object _undoContext; public PropertiesEditPopup(Timeline timeline, object obj, object undoContext) { const float width = 280.0f; const float height = 160.0f; Size = new Float2(width, height); var panel1 = new Panel(ScrollBars.Vertical) { Bounds = new Rectangle(0, 0.0f, width, height), Parent = this }; var editor = new CustomEditorPresenter(null); editor.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop; editor.Panel.IsScrollable = true; editor.Panel.Parent = panel1; editor.Modified += OnModified; editor.Select(obj); _timeline = timeline; if (timeline.Undo != null && timeline.Undo.Enabled && undoContext != null) { _undoContext = undoContext; if (undoContext is Track track) _beforeData = EditTrackAction.CaptureData(track); else if (undoContext is Timeline) _beforeData = EditTimelineAction.CaptureData(timeline); } } private void OnModified() { _isDirty = true; } /// protected override void OnShow() { Focus(); base.OnShow(); } /// public override void Hide() { if (!Visible) return; Focus(null); if (_isDirty) { if (_beforeData != null) { if (_undoContext is Track track) { var after = EditTrackAction.CaptureData(track); if (!Utils.ArraysEqual(_beforeData, after)) _timeline.Undo.AddAction(new EditTrackAction(_timeline, track, _beforeData, after)); } else if (_undoContext is Timeline) { var after = EditTimelineAction.CaptureData(_timeline); if (!Utils.ArraysEqual(_beforeData, after)) _timeline.Undo.AddAction(new EditTimelineAction(_timeline, _beforeData, after)); } } _timeline.MarkAsEdited(); } base.Hide(); } /// public override bool OnKeyDown(KeyboardKeys key) { if (key == KeyboardKeys.Escape) { Hide(); return true; } return base.OnKeyDown(key); } /// public override void OnDestroy() { _timeline = null; _beforeData = null; _undoContext = null; base.OnDestroy(); } } class TracksPanelArea : Panel { private DragDropEffect _currentDragEffect = DragDropEffect.None; private Timeline _timeline; private bool _needSetup = true; public TracksPanelArea(Timeline timeline) : base(ScrollBars.Vertical) { _timeline = timeline; } /// public override DragDropEffect OnDragEnter(ref Float2 location, DragData data) { var result = base.OnDragEnter(ref location, data); if (result == DragDropEffect.None) { if (_needSetup) { _needSetup = false; _timeline.SetupDragDrop(); } for (int i = 0; i < _timeline.DragHandlers.Count; i++) { var dragHelper = _timeline.DragHandlers[i].Helper; if (dragHelper.OnDragEnter(data)) { result = dragHelper.Effect; break; } } _currentDragEffect = result; } return result; } /// public override DragDropEffect OnDragMove(ref Float2 location, DragData data) { var result = base.OnDragEnter(ref location, data); if (result == DragDropEffect.None) { result = _currentDragEffect; } return result; } /// public override void OnDragLeave() { _currentDragEffect = DragDropEffect.None; _timeline.DragHandlers.ForEach(x => x.Helper.OnDragLeave()); base.OnDragLeave(); } /// public override DragDropEffect OnDragDrop(ref Float2 location, DragData data) { var result = base.OnDragDrop(ref location, data); if (result == DragDropEffect.None && _currentDragEffect != DragDropEffect.None) { for (int i = 0; i < _timeline.DragHandlers.Count; i++) { var e = _timeline.DragHandlers[i]; if (e.Helper.HasValidDrag) { e.Action(_timeline, e.Helper); } } } return result; } /// public override void Draw() { if (IsDragOver && _currentDragEffect != DragDropEffect.None) { var style = Style.Current; Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundSelected * 0.4f); } base.Draw(); } /// public override void OnDestroy() { _timeline = null; base.OnDestroy(); } } } }