add help system

This commit is contained in:
Oleksandr Bezdieniezhnykh
2024-05-15 19:06:43 +03:00
parent 6809a9cedf
commit 6aba2e31db
4 changed files with 91 additions and 67 deletions
@@ -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нтер] для збереження і перегляду далі" },
};
}
@@ -303,13 +303,30 @@
Grid.Row="5"
Grid.Column="2"
>
<StatusBarItem>
<TextBlock Margin="3 0 0 0" x:Name="StatusClock" FontSize="16"></TextBlock>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Margin="3 0 0 0" x:Name="StatusClock" FontSize="16" Text="00:00 / 00:00"></TextBlock>
</StatusBarItem>
<StatusBarItem>
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" Text="{Binding Path=CurrentHelp}"></TextBlock>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" FontSize="14" Foreground="DarkBlue" ></TextBlock>
</StatusBarItem>
<StatusBarItem>
<StatusBarItem Grid.Column="3">
<TextBlock x:Name="Status"></TextBlock>
</StatusBarItem>
</StatusBar>
@@ -25,8 +25,6 @@ public partial class MainWindow
private bool _suspendLayout;
public Dictionary<string, List<AnnotationInfo>> 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<AnnotationClass>(_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<VideoFileInfo>(files);
TbFolder.Text = _config.VideosDirectory;
BlinkHelp(files.Count == 0
? HelpTexts.HelpTextsDict[HelpTextEnum.Initial]
: HelpTexts.HelpTextsDict[HelpTextEnum.PlayVideo]);
}
private void OnFormClosed(object? sender, EventArgs e)
@@ -6,28 +6,16 @@ using MediatR;
namespace Azaion.Annotator;
public class PlayerControlHandler:
INotificationHandler<KeyEvent>,
INotificationHandler<AnnClassSelectedEvent>,
INotificationHandler<PlaybackControlEvent>
public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) :
INotificationHandler<KeyEvent>,
INotificationHandler<AnnClassSelectedEvent>,
INotificationHandler<PlaybackControlEvent>
{
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<Key, PlaybackControlEnum> 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();
}
}