Skip to content

Commit

Permalink
Initial ability to create poser datasets
Browse files Browse the repository at this point in the history
  • Loading branch information
Neakita committed Sep 4, 2024
1 parent 74f1eee commit 310c25b
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 11 deletions.
26 changes: 22 additions & 4 deletions SightKeeper.Avalonia/DataSets/Dialogs/CreateDataSetViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ internal sealed partial class CreateDataSetViewModel : DialogViewModel<bool>, ID
protected override bool DefaultResult => false;

public DataSetEditorViewModel DataSetEditor { get; }
public TagsEditorViewModel TagsEditor { get; } = new();

public TagsEditorViewModel TagsEditor
{
get => _tagsEditor;
private set => SetProperty(ref _tagsEditor, value);
}

public ImmutableArray<DataSetType> DataSetTypes { get; } =
[
Expand All @@ -32,19 +37,32 @@ public CreateDataSetViewModel(DataSetEditorViewModel dataSetDataSetEditor)
DataSetEditor.Resolution = DataSet.DefaultResolution;
_dataSetType = DataSetTypes.First();
DataSetEditor.ErrorsChanged += OnDataSetEditorErrorsChanged;
_constructorDisposable = TagsEditor.IsValid.Subscribe(_ => ApplyCommand.NotifyCanExecuteChanged());
_tagsEditorSubscription = TagsEditor.IsValid.Subscribe(_ => ApplyCommand.NotifyCanExecuteChanged());
}

public void Dispose()
{
DataSetEditor.Dispose();
DataSetEditor.ErrorsChanged -= OnDataSetEditorErrorsChanged;
TagsEditor.Dispose();
_constructorDisposable.Dispose();
_tagsEditorSubscription.Dispose();
}

[ObservableProperty] private DataSetType _dataSetType;
private readonly IDisposable _constructorDisposable;
private IDisposable _tagsEditorSubscription;
private TagsEditorViewModel _tagsEditor = new();

partial void OnDataSetTypeChanged(DataSetType value)
{
_tagsEditorSubscription.Dispose();
TagsEditor = value switch
{
DataSetType.Classifier or DataSetType.Detector => new TagsEditorViewModel(),
DataSetType.Poser2D or DataSetType.Poser3D => new PoserTagsEditorViewModel(),
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
};
_tagsEditorSubscription = TagsEditor.IsValid.Subscribe(_ => ApplyCommand.NotifyCanExecuteChanged());
}

private void OnDataSetEditorErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
{
Expand Down
27 changes: 27 additions & 0 deletions SightKeeper.Avalonia/DataSets/Dialogs/PoserTagViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using FluentValidation;
using SightKeeper.Application.DataSets.Tags;

namespace SightKeeper.Avalonia.DataSets.Dialogs;

internal sealed class PoserTagViewModel : TagViewModel, PoserTagData, IDisposable
{
IReadOnlyCollection<TagData> PoserTagData.KeyPointTags => _tagsEditor.Tags;

public ICommand AddKeyPointTagCommand => _tagsEditor.AddTagCommand;
public IReadOnlyCollection<TagViewModel> KeyPointTags => _tagsEditor.Tags;
public BehaviorObservable<bool> IsKeyPointsValid => _tagsEditor.IsValid;

public PoserTagViewModel(string name, IValidator<TagData> validator) : base(name, validator)
{
}

public void Dispose()
{
_tagsEditor.Dispose();
}

private readonly TagsEditorViewModel _tagsEditor = new();
}
23 changes: 23 additions & 0 deletions SightKeeper.Avalonia/DataSets/Dialogs/PoserTagsEditorViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Reactive.Disposables;
using SightKeeper.Application.DataSets.Tags;
using SightKeeper.Application.Extensions;

namespace SightKeeper.Avalonia.DataSets.Dialogs;

internal sealed class PoserTagsEditorViewModel : TagsEditorViewModel
{
protected override TagViewModel CreateTagViewModel(string name, TagDataValidator validator)
{
PoserTagViewModel tag = new(name, validator);
tag.IsKeyPointsValid.Subscribe(_ => UpdateIsValid()).DisposeWith(_disposable);
return tag;
}

protected override bool IsTagValid(TagViewModel tag)
{
return base.IsTagValid(tag) && ((PoserTagViewModel)tag).IsKeyPointsValid;
}

private readonly CompositeDisposable _disposable = new();
}
2 changes: 1 addition & 1 deletion SightKeeper.Avalonia/DataSets/Dialogs/TagViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged
}

public ViewModelValidator<TagData> Validator { get; }
public bool HasErrors => Validator.HasErrors;
public virtual bool HasErrors => Validator.HasErrors;

public TagViewModel(string name, IValidator<TagData> validator)
{
Expand Down
32 changes: 29 additions & 3 deletions SightKeeper.Avalonia/DataSets/Dialogs/TagsEditor.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SightKeeper.Avalonia.DataSets.Dialogs"
xmlns:behaviors="clr-namespace:SightKeeper.Avalonia.Behaviors"
xmlns:icons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SightKeeper.Avalonia.DataSets.Dialogs.TagsEditor"
x:DataType="local:TagsEditorViewModel">
Expand All @@ -29,11 +30,36 @@
</Button>
</Grid>
<ItemsControl ItemsSource="{Binding Tags}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl.DataTemplates>
<DataTemplate x:DataType="local:PoserTagViewModel">
<HeaderedContentControl>
<HeaderedContentControl.Header>
<Grid ColumnDefinitions="Auto 8 *">
<Button Grid.Column="0" Content="{icons:MaterialIconExt Kind=Plus}"
Classes="square"
ToolTip.Tip="Create keypoint tag"
Command="{Binding AddKeyPointTagCommand}"
CommandParameter="{Binding #TagNameTextBox.Text}">
<Interaction.Behaviors>
<behaviors:ClearTextBoxWhenClickingBehavior TextBox="TagNameTextBox"/>
</Interaction.Behaviors>
</Button>
<TextBox Grid.Column="2" Text="{Binding Name}"/>
</Grid>
</HeaderedContentControl.Header>
<ItemsControl ItemsSource="{Binding KeyPointTags}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</HeaderedContentControl>
</DataTemplate>
<DataTemplate x:DataType="local:TagViewModel">
<TextBox Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>
</StackPanel>
</UserControl>
21 changes: 18 additions & 3 deletions SightKeeper.Avalonia/DataSets/Dialogs/TagsEditorViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace SightKeeper.Avalonia.DataSets.Dialogs;

internal sealed partial class TagsEditorViewModel : ViewModel, IDisposable
internal partial class TagsEditorViewModel : ViewModel, IDisposable
{
public BehaviorObservable<bool> IsValid => _isValid;
public IReadOnlyCollection<TagViewModel> Tags => _tags;
Expand All @@ -25,26 +25,41 @@ public void Dispose()
}
}

protected virtual TagViewModel CreateTagViewModel(string name, TagDataValidator validator)
{
return new TagViewModel(name, validator);
}

private readonly BehaviorSubject<bool> _isValid = new(true);
private readonly AvaloniaList<TagViewModel> _tags = new();

[RelayCommand(CanExecute = nameof(CanAddTag))]
private void AddTag(string name)
{
TagDataValidator validator = new(Tags);
TagViewModel tag = new(name, validator);
TagViewModel tag = CreateTagViewModel(name, validator);
tag.PropertyChanged += OnTagPropertyChanged;
tag.ErrorsChanged += OnTagErrorsChanged;
_tags.Add(tag);
}

private void OnTagErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
{
bool isValid = Tags.All(tag => !tag.HasErrors);
UpdateIsValid();
}

protected void UpdateIsValid()
{
bool isValid = Tags.All(IsTagValid);
if (IsValid != isValid)
_isValid.OnNext(isValid);
}

protected virtual bool IsTagValid(TagViewModel tag)
{
return !tag.HasErrors;
}

private void OnTagPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(TagViewModel.Name))
Expand Down

0 comments on commit 310c25b

Please sign in to comment.