diff --git a/Azaion.Annotator/Azaion.Annotator/HelpTexts.cs b/Azaion.Annotator/Azaion.Annotator/HelpTexts.cs index d936aa4..d719f2d 100644 --- a/Azaion.Annotator/Azaion.Annotator/HelpTexts.cs +++ b/Azaion.Annotator/Azaion.Annotator/HelpTexts.cs @@ -17,8 +17,8 @@ public class HelpTexts { HelpTextEnum.Initial, "Натисніть Файл - Відкрити папку... та виберіть папку з вашими відео для анотації" }, { HelpTextEnum.PlayVideo, "В списку відео виберіть потрібне та [подвійний клік] чи [Eнтер] на ньому - запустіть його на перегляд" }, { HelpTextEnum.PauseForAnnotations, "В потрібному місці відео де є один з об'єктів для анотації зупиніть його [Пробіл] або кн. на панелі" }, - { HelpTextEnum.AnnotationHelp, "Клавішами [1] - [9] або мишкою оберіть потрібний клас та виділіть область з об'єктом. Виділяйте всі що є об'єкти. " + - "При потребі [Ctrl] виділяйте анотації та [Del] для видалення. [Eнтер] для збереження і перегляду далі" }, + { HelpTextEnum.AnnotationHelp, "Клавішами [1] - [9] або мишкою оберіть потрібний клас та виділіть, тобто зробіть анотації всіх необхідних об'єктів. " + + "Непотрібні анотації можна виділити (через [Ctrl] декілька) та [Del] видалити. [Eнтер] для збереження і перегляду далі" }, }; } diff --git a/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml b/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml index 559b9b7..e86c6d2 100644 --- a/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml +++ b/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml @@ -303,13 +303,30 @@ Grid.Row="5" Grid.Column="2" > - - + + + + + + + + + + + + + + + + + + - - + + + - + diff --git a/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml.cs b/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml.cs index 89f9e0e..aacb45b 100644 --- a/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml.cs +++ b/Azaion.Annotator/Azaion.Annotator/MainWindow.xaml.cs @@ -25,8 +25,6 @@ public partial class MainWindow private bool _suspendLayout; public Dictionary> Annotations { get; set; } = new(); - - public string CurrentHelp { get; set; } public MainWindow(LibVLC libVLC, MediaPlayer mediaPlayer, IMediator mediator, @@ -63,7 +61,24 @@ public partial class MainWindow AnnotationClasses = new ObservableCollection(_config.AnnotationClasses); LvClasses.ItemsSource = AnnotationClasses; LvClasses.SelectedIndex = 0; - CurrentHelp = HelpTexts.HelpTextsDict[HelpTextEnum.Initial]; + + if (LvFiles.Items.IsEmpty) + BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]); + } + + public void BlinkHelp(string helpText, int times = 3) + { + _ = Task.Run(async () => + { + for (int i = 0; i < times; i++) + { + Dispatcher.Invoke(() => StatusHelp.Text = helpText); + await Task.Delay(200); + Dispatcher.Invoke(() => StatusHelp.Text = ""); + await Task.Delay(200); + } + Dispatcher.Invoke(() => StatusHelp.Text = helpText); + }); } private void InitControls() @@ -78,11 +93,8 @@ public partial class MainWindow _formState.CurrentVideoLength = TimeSpan.FromMilliseconds(_mediaPlayer.Length); }; - LvFiles.MouseDoubleClick += async (_, _) => - { - Play((VideoFileInfo)LvFiles.SelectedItem); - }; - + LvFiles.MouseDoubleClick += async (_, _) => await _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play)); + LvClasses.SelectionChanged += (_, _) => { var selectedClass = (AnnotationClass)LvClasses.SelectedItem; @@ -146,21 +158,8 @@ public partial class MainWindow Editor.FormState = _formState; Editor.Mediator = _mediator; } - - private void Play(VideoFileInfo videoFileInfo) - { - if (LvFiles.SelectedItem == null) - return; - var fileInfo = (VideoFileInfo)LvFiles.SelectedItem; - - _formState.CurrentFile = fileInfo.Name; - LoadExistingAnnotations(); - - _mediaPlayer.Stop(); - _mediaPlayer.Play(new Media(_libVLC, fileInfo.Path)); - } - - private void LoadExistingAnnotations() + + public void LoadExistingAnnotations() { var dirInfo = new DirectoryInfo(_config.LabelsDirectory); if (!dirInfo.Exists) @@ -190,10 +189,14 @@ public partial class MainWindow Path = x.FullName, Duration = TimeSpan.FromMilliseconds(_mediaPlayer.Media.Duration) }; - }); + }).ToList(); LvFiles.ItemsSource = new ObservableCollection(files); TbFolder.Text = _config.VideosDirectory; + + BlinkHelp(files.Count == 0 + ? HelpTexts.HelpTextsDict[HelpTextEnum.Initial] + : HelpTexts.HelpTextsDict[HelpTextEnum.PlayVideo]); } private void OnFormClosed(object? sender, EventArgs e) diff --git a/Azaion.Annotator/Azaion.Annotator/PlayerControlHandler.cs b/Azaion.Annotator/Azaion.Annotator/PlayerControlHandler.cs index ab13a25..3b89fc6 100644 --- a/Azaion.Annotator/Azaion.Annotator/PlayerControlHandler.cs +++ b/Azaion.Annotator/Azaion.Annotator/PlayerControlHandler.cs @@ -6,28 +6,16 @@ using MediatR; namespace Azaion.Annotator; -public class PlayerControlHandler: - INotificationHandler, - INotificationHandler, - INotificationHandler +public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) : + INotificationHandler, + INotificationHandler, + INotificationHandler { private const int STEP = 20; - private const int LARGE_STEP = 2000; + private const int LARGE_STEP = 5000; private static readonly string[] CatchSenders = ["ForegroundWindow", "ScrollViewer"]; - private MediaPlayer mediaPlayer; - private readonly MainWindow _mainWindow; - private readonly FormState _formState; - private readonly Config _config; - public PlayerControlHandler(MediaPlayer mediaPlayer1, MainWindow mainWindow, FormState formState, Config config) - { - mediaPlayer = mediaPlayer1; - _mainWindow = mainWindow; - _formState = formState; - _config = config; - } - private readonly Dictionary KeysControlEnumDict = new() { { Key.Space, PlaybackControlEnum.Pause }, @@ -43,10 +31,10 @@ public class PlayerControlHandler: private void SelectClass(AnnotationClass annClass) { - _mainWindow.Editor.CurrentAnnClass = annClass; - foreach (var ann in _mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected)) + mainWindow.Editor.CurrentAnnClass = annClass; + foreach (var ann in mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected)) ann.AnnotationClass = annClass; - _mainWindow.LvClasses.SelectedIndex = annClass.Id; + mainWindow.LvClasses.SelectedIndex = annClass.Id; } public async Task Handle(KeyEvent notification, CancellationToken cancellationToken) @@ -62,7 +50,7 @@ public class PlayerControlHandler: if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9) keyNumber = key - Key.NumPad1; if (keyNumber.HasValue) - SelectClass(_mainWindow.AnnotationClasses[keyNumber.Value]); + SelectClass(mainWindow.AnnotationClasses[keyNumber.Value]); if (KeysControlEnumDict.TryGetValue(key, out var value)) await ControlPlayback(value); @@ -81,10 +69,12 @@ public class PlayerControlHandler: switch (controlEnum) { case PlaybackControlEnum.Play: - mediaPlayer.Play(); + Play(); break; case PlaybackControlEnum.Pause: mediaPlayer.Pause(); + if (!mediaPlayer.IsPlaying) + mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]); break; case PlaybackControlEnum.Stop: mediaPlayer.Stop(); @@ -101,10 +91,10 @@ public class PlayerControlHandler: await SaveAnnotations(); break; case PlaybackControlEnum.RemoveSelectedAnns: - _mainWindow.Editor.RemoveSelectedAnns(); + mainWindow.Editor.RemoveSelectedAnns(); break; case PlaybackControlEnum.RemoveAllAnns: - _mainWindow.Editor.RemoveAllAnns(); + mainWindow.Editor.RemoveAllAnns(); break; case PlaybackControlEnum.None: break; @@ -113,27 +103,41 @@ public class PlayerControlHandler: } } + private void Play() + { + if (mainWindow.LvFiles.SelectedItem == null) + return; + var fileInfo = (VideoFileInfo)mainWindow.LvFiles.SelectedItem; + + formState.CurrentFile = fileInfo.Name; + mainWindow.LoadExistingAnnotations(); + + mediaPlayer.Stop(); + mediaPlayer.Play(new Media(libVLC, fileInfo.Path)); + mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]); + } + private async Task SaveAnnotations() { - if (string.IsNullOrEmpty(_formState.CurrentFile)) + if (string.IsNullOrEmpty(formState.CurrentFile)) return; - var fName = _formState.GetTimeName(TimeSpan.FromMilliseconds(mediaPlayer.Time)); - var currentAnns = _mainWindow.Editor.CurrentAnns - .Select(x => x.Info.ToLabelCoordinates(_mainWindow.Editor.RenderSize, _formState.CurrentVideoSize)) + var fName = formState.GetTimeName(TimeSpan.FromMilliseconds(mediaPlayer.Time)); + var currentAnns = mainWindow.Editor.CurrentAnns + .Select(x => x.Info.ToLabelCoordinates(mainWindow.Editor.RenderSize, formState.CurrentVideoSize)) .ToList(); var labels = string.Join(Environment.NewLine, currentAnns.Select(x => x.ToString())); - if (!Directory.Exists(_config.LabelsDirectory)) - Directory.CreateDirectory(_config.LabelsDirectory); - if (!Directory.Exists(_config.ImagesDirectory)) - Directory.CreateDirectory(_config.ImagesDirectory); + if (!Directory.Exists(config.LabelsDirectory)) + Directory.CreateDirectory(config.LabelsDirectory); + if (!Directory.Exists(config.ImagesDirectory)) + Directory.CreateDirectory(config.ImagesDirectory); - await File.WriteAllTextAsync($"{_config.LabelsDirectory}/{fName}.txt", labels); - mediaPlayer.TakeSnapshot(0, $"{_config.ImagesDirectory}/{fName}.jpg", 0, 0); + await File.WriteAllTextAsync($"{config.LabelsDirectory}/{fName}.txt", labels); + mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", 0, 0); - _mainWindow.Annotations[fName] = currentAnns; - _mainWindow.Editor.RemoveAllAnns(); + mainWindow.Annotations[fName] = currentAnns; + mainWindow.Editor.RemoveAllAnns(); mediaPlayer.Play(); } } \ No newline at end of file