mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 11:16:30 +00:00
add help system
This commit is contained in:
@@ -17,8 +17,8 @@ public class HelpTexts
|
|||||||
{ HelpTextEnum.Initial, "Натисніть Файл - Відкрити папку... та виберіть папку з вашими відео для анотації" },
|
{ HelpTextEnum.Initial, "Натисніть Файл - Відкрити папку... та виберіть папку з вашими відео для анотації" },
|
||||||
{ HelpTextEnum.PlayVideo, "В списку відео виберіть потрібне та [подвійний клік] чи [Eнтер] на ньому - запустіть його на перегляд" },
|
{ HelpTextEnum.PlayVideo, "В списку відео виберіть потрібне та [подвійний клік] чи [Eнтер] на ньому - запустіть його на перегляд" },
|
||||||
{ HelpTextEnum.PauseForAnnotations, "В потрібному місці відео де є один з об'єктів для анотації зупиніть його [Пробіл] або кн. на панелі" },
|
{ HelpTextEnum.PauseForAnnotations, "В потрібному місці відео де є один з об'єктів для анотації зупиніть його [Пробіл] або кн. на панелі" },
|
||||||
{ HelpTextEnum.AnnotationHelp, "Клавішами [1] - [9] або мишкою оберіть потрібний клас та виділіть область з об'єктом. Виділяйте всі що є об'єкти. " +
|
{ HelpTextEnum.AnnotationHelp, "Клавішами [1] - [9] або мишкою оберіть потрібний клас та виділіть, тобто зробіть анотації всіх необхідних об'єктів. " +
|
||||||
"При потребі [Ctrl] виділяйте анотації та [Del] для видалення. [Eнтер] для збереження і перегляду далі" },
|
"Непотрібні анотації можна виділити (через [Ctrl] декілька) та [Del] видалити. [Eнтер] для збереження і перегляду далі" },
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -303,13 +303,30 @@
|
|||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
>
|
>
|
||||||
<StatusBarItem>
|
<StatusBar.ItemsPanel>
|
||||||
<TextBlock Margin="3 0 0 0" x:Name="StatusClock" FontSize="16"></TextBlock>
|
<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>
|
||||||
<StatusBarItem>
|
<Separator Grid.Column="1" />
|
||||||
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" Text="{Binding Path=CurrentHelp}"></TextBlock>
|
<StatusBarItem Grid.Column="2">
|
||||||
|
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" FontSize="14" Foreground="DarkBlue" ></TextBlock>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<StatusBarItem>
|
<StatusBarItem Grid.Column="3">
|
||||||
<TextBlock x:Name="Status"></TextBlock>
|
<TextBlock x:Name="Status"></TextBlock>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ public partial class MainWindow
|
|||||||
|
|
||||||
public Dictionary<string, List<AnnotationInfo>> Annotations { get; set; } = new();
|
public Dictionary<string, List<AnnotationInfo>> Annotations { get; set; } = new();
|
||||||
|
|
||||||
public string CurrentHelp { get; set; }
|
|
||||||
|
|
||||||
public MainWindow(LibVLC libVLC, MediaPlayer mediaPlayer,
|
public MainWindow(LibVLC libVLC, MediaPlayer mediaPlayer,
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
FormState formState,
|
FormState formState,
|
||||||
@@ -63,7 +61,24 @@ public partial class MainWindow
|
|||||||
AnnotationClasses = new ObservableCollection<AnnotationClass>(_config.AnnotationClasses);
|
AnnotationClasses = new ObservableCollection<AnnotationClass>(_config.AnnotationClasses);
|
||||||
LvClasses.ItemsSource = AnnotationClasses;
|
LvClasses.ItemsSource = AnnotationClasses;
|
||||||
LvClasses.SelectedIndex = 0;
|
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()
|
private void InitControls()
|
||||||
@@ -78,10 +93,7 @@ public partial class MainWindow
|
|||||||
_formState.CurrentVideoLength = TimeSpan.FromMilliseconds(_mediaPlayer.Length);
|
_formState.CurrentVideoLength = TimeSpan.FromMilliseconds(_mediaPlayer.Length);
|
||||||
};
|
};
|
||||||
|
|
||||||
LvFiles.MouseDoubleClick += async (_, _) =>
|
LvFiles.MouseDoubleClick += async (_, _) => await _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play));
|
||||||
{
|
|
||||||
Play((VideoFileInfo)LvFiles.SelectedItem);
|
|
||||||
};
|
|
||||||
|
|
||||||
LvClasses.SelectionChanged += (_, _) =>
|
LvClasses.SelectionChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
@@ -147,20 +159,7 @@ public partial class MainWindow
|
|||||||
Editor.Mediator = _mediator;
|
Editor.Mediator = _mediator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Play(VideoFileInfo videoFileInfo)
|
public void LoadExistingAnnotations()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
var dirInfo = new DirectoryInfo(_config.LabelsDirectory);
|
var dirInfo = new DirectoryInfo(_config.LabelsDirectory);
|
||||||
if (!dirInfo.Exists)
|
if (!dirInfo.Exists)
|
||||||
@@ -190,10 +189,14 @@ public partial class MainWindow
|
|||||||
Path = x.FullName,
|
Path = x.FullName,
|
||||||
Duration = TimeSpan.FromMilliseconds(_mediaPlayer.Media.Duration)
|
Duration = TimeSpan.FromMilliseconds(_mediaPlayer.Media.Duration)
|
||||||
};
|
};
|
||||||
});
|
}).ToList();
|
||||||
|
|
||||||
LvFiles.ItemsSource = new ObservableCollection<VideoFileInfo>(files);
|
LvFiles.ItemsSource = new ObservableCollection<VideoFileInfo>(files);
|
||||||
TbFolder.Text = _config.VideosDirectory;
|
TbFolder.Text = _config.VideosDirectory;
|
||||||
|
|
||||||
|
BlinkHelp(files.Count == 0
|
||||||
|
? HelpTexts.HelpTextsDict[HelpTextEnum.Initial]
|
||||||
|
: HelpTexts.HelpTextsDict[HelpTextEnum.PlayVideo]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFormClosed(object? sender, EventArgs e)
|
private void OnFormClosed(object? sender, EventArgs e)
|
||||||
|
|||||||
@@ -6,27 +6,15 @@ using MediatR;
|
|||||||
|
|
||||||
namespace Azaion.Annotator;
|
namespace Azaion.Annotator;
|
||||||
|
|
||||||
public class PlayerControlHandler:
|
public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) :
|
||||||
INotificationHandler<KeyEvent>,
|
INotificationHandler<KeyEvent>,
|
||||||
INotificationHandler<AnnClassSelectedEvent>,
|
INotificationHandler<AnnClassSelectedEvent>,
|
||||||
INotificationHandler<PlaybackControlEvent>
|
INotificationHandler<PlaybackControlEvent>
|
||||||
{
|
{
|
||||||
private const int STEP = 20;
|
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 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()
|
private readonly Dictionary<Key, PlaybackControlEnum> KeysControlEnumDict = new()
|
||||||
{
|
{
|
||||||
@@ -43,10 +31,10 @@ public class PlayerControlHandler:
|
|||||||
|
|
||||||
private void SelectClass(AnnotationClass annClass)
|
private void SelectClass(AnnotationClass annClass)
|
||||||
{
|
{
|
||||||
_mainWindow.Editor.CurrentAnnClass = annClass;
|
mainWindow.Editor.CurrentAnnClass = annClass;
|
||||||
foreach (var ann in _mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected))
|
foreach (var ann in mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected))
|
||||||
ann.AnnotationClass = annClass;
|
ann.AnnotationClass = annClass;
|
||||||
_mainWindow.LvClasses.SelectedIndex = annClass.Id;
|
mainWindow.LvClasses.SelectedIndex = annClass.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(KeyEvent notification, CancellationToken cancellationToken)
|
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)
|
if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9)
|
||||||
keyNumber = key - Key.NumPad1;
|
keyNumber = key - Key.NumPad1;
|
||||||
if (keyNumber.HasValue)
|
if (keyNumber.HasValue)
|
||||||
SelectClass(_mainWindow.AnnotationClasses[keyNumber.Value]);
|
SelectClass(mainWindow.AnnotationClasses[keyNumber.Value]);
|
||||||
|
|
||||||
if (KeysControlEnumDict.TryGetValue(key, out var value))
|
if (KeysControlEnumDict.TryGetValue(key, out var value))
|
||||||
await ControlPlayback(value);
|
await ControlPlayback(value);
|
||||||
@@ -81,10 +69,12 @@ public class PlayerControlHandler:
|
|||||||
switch (controlEnum)
|
switch (controlEnum)
|
||||||
{
|
{
|
||||||
case PlaybackControlEnum.Play:
|
case PlaybackControlEnum.Play:
|
||||||
mediaPlayer.Play();
|
Play();
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.Pause:
|
case PlaybackControlEnum.Pause:
|
||||||
mediaPlayer.Pause();
|
mediaPlayer.Pause();
|
||||||
|
if (!mediaPlayer.IsPlaying)
|
||||||
|
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]);
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.Stop:
|
case PlaybackControlEnum.Stop:
|
||||||
mediaPlayer.Stop();
|
mediaPlayer.Stop();
|
||||||
@@ -101,10 +91,10 @@ public class PlayerControlHandler:
|
|||||||
await SaveAnnotations();
|
await SaveAnnotations();
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.RemoveSelectedAnns:
|
case PlaybackControlEnum.RemoveSelectedAnns:
|
||||||
_mainWindow.Editor.RemoveSelectedAnns();
|
mainWindow.Editor.RemoveSelectedAnns();
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.RemoveAllAnns:
|
case PlaybackControlEnum.RemoveAllAnns:
|
||||||
_mainWindow.Editor.RemoveAllAnns();
|
mainWindow.Editor.RemoveAllAnns();
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.None:
|
case PlaybackControlEnum.None:
|
||||||
break;
|
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()
|
private async Task SaveAnnotations()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_formState.CurrentFile))
|
if (string.IsNullOrEmpty(formState.CurrentFile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var fName = _formState.GetTimeName(TimeSpan.FromMilliseconds(mediaPlayer.Time));
|
var fName = formState.GetTimeName(TimeSpan.FromMilliseconds(mediaPlayer.Time));
|
||||||
var currentAnns = _mainWindow.Editor.CurrentAnns
|
var currentAnns = mainWindow.Editor.CurrentAnns
|
||||||
.Select(x => x.Info.ToLabelCoordinates(_mainWindow.Editor.RenderSize, _formState.CurrentVideoSize))
|
.Select(x => x.Info.ToLabelCoordinates(mainWindow.Editor.RenderSize, formState.CurrentVideoSize))
|
||||||
.ToList();
|
.ToList();
|
||||||
var labels = string.Join(Environment.NewLine, currentAnns.Select(x => x.ToString()));
|
var labels = string.Join(Environment.NewLine, currentAnns.Select(x => x.ToString()));
|
||||||
|
|
||||||
if (!Directory.Exists(_config.LabelsDirectory))
|
if (!Directory.Exists(config.LabelsDirectory))
|
||||||
Directory.CreateDirectory(_config.LabelsDirectory);
|
Directory.CreateDirectory(config.LabelsDirectory);
|
||||||
if (!Directory.Exists(_config.ImagesDirectory))
|
if (!Directory.Exists(config.ImagesDirectory))
|
||||||
Directory.CreateDirectory(_config.ImagesDirectory);
|
Directory.CreateDirectory(config.ImagesDirectory);
|
||||||
|
|
||||||
await File.WriteAllTextAsync($"{_config.LabelsDirectory}/{fName}.txt", labels);
|
await File.WriteAllTextAsync($"{config.LabelsDirectory}/{fName}.txt", labels);
|
||||||
mediaPlayer.TakeSnapshot(0, $"{_config.ImagesDirectory}/{fName}.jpg", 0, 0);
|
mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", 0, 0);
|
||||||
|
|
||||||
_mainWindow.Annotations[fName] = currentAnns;
|
mainWindow.Annotations[fName] = currentAnns;
|
||||||
_mainWindow.Editor.RemoveAllAnns();
|
mainWindow.Editor.RemoveAllAnns();
|
||||||
mediaPlayer.Play();
|
mediaPlayer.Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user