diff --git a/src/ui/Controls/VideoPlayer/VideoPlayerControl.cs b/src/ui/Controls/VideoPlayer/VideoPlayerControl.cs index 4058b5fe56..2738a62681 100644 --- a/src/ui/Controls/VideoPlayer/VideoPlayerControl.cs +++ b/src/ui/Controls/VideoPlayer/VideoPlayerControl.cs @@ -365,6 +365,15 @@ public VideoPlayerControl(IVideoPlayer videoPlayerInstance) Margin = new Thickness(2, 0, 0, 0), [AutomationProperties.NameProperty] = Se.Language.General.VideoPosition, }; + + // Right-click the position slider to jump to / copy the current video position + // (SE4 parity for the old "Video position" control). + var goToPositionItem = new Avalonia.Controls.MenuItem { Header = Se.Language.Options.Shortcuts.GeneralGoToVideoPosition }; + goToPositionItem.Click += (_, _) => GoToPositionRequested?.Invoke(); + var copyPositionItem = new Avalonia.Controls.MenuItem { Header = Se.Language.General.Copy }; + copyPositionItem.Click += (_, _) => CopyPositionRequested?.Invoke(); + sliderPosition.ContextFlyout = new MenuFlyout { Items = { goToPositionItem, copyPositionItem } }; + if (Se.Settings.Appearance.ShowHints) { ToolTip.SetTip(sliderPosition, Se.Language.General.VideoPosition); @@ -671,6 +680,8 @@ private void OnVideoWheelChanged(object? sender, PointerWheelEventArgs e) public event Action? UserSeeked; public event Action? VolumeChanged; public event Action? ToggleDisplayProgressTextModeRequested; + public event Action? GoToPositionRequested; + public event Action? CopyPositionRequested; public event Action? VideoFileNamePointerPressed; public void SetPlayPauseIcon(bool isPlaying) diff --git a/src/ui/Features/Main/Layout/InitVideoPlayer.cs b/src/ui/Features/Main/Layout/InitVideoPlayer.cs index d399d4f317..b69c33ac14 100644 --- a/src/ui/Features/Main/Layout/InitVideoPlayer.cs +++ b/src/ui/Features/Main/Layout/InitVideoPlayer.cs @@ -79,6 +79,8 @@ public static Grid MakeLayoutVideoPlayer(MainViewModel vm, Thickness nonFullScre control.VideoFileNamePointerPressed += vm.VideoPlayerControlPointerPressed; control.SurfacePointerPressed += (_, _) => vm.VideoPlayerAreaPointerPressed(); control.UserSeeked += vm.OnVideoPlayerUserSeeked; + control.GoToPositionRequested += () => vm.ShowGoToVideoPositionCommand.Execute(null); + control.CopyPositionRequested += () => vm.CopyVideoPositionCommand.Execute(null); Grid.SetRow(control, 0); mainGrid.Children.Add(control); diff --git a/src/ui/Features/Main/MainViewModel.cs b/src/ui/Features/Main/MainViewModel.cs index 675b0cad4d..dc06985faf 100644 --- a/src/ui/Features/Main/MainViewModel.cs +++ b/src/ui/Features/Main/MainViewModel.cs @@ -5303,6 +5303,21 @@ private async Task ShowGoToVideoPosition() } } + [RelayCommand] + private async Task CopyVideoPosition() + { + var vp = GetVideoPlayerControl(); + if (vp == null || Window == null || string.IsNullOrEmpty(_videoFileName)) + { + return; + } + + // Copy the current position as a timecode, applying the same video offset the player + // shows. SE4 parity: the old "Video position" control let you copy the current position. + var seconds = vp.Position + Se.Settings.General.CurrentVideoOffsetInMs / 1000.0; + await ClipboardHelper.SetTextAsync(Window, TimeCode.FromSeconds(seconds).ToDisplayString()); + } + [RelayCommand] private void ToggleIsWaveformToolbarVisible() {