Data model visualization - Moved services and VMs to UI.Shared

Data model visualization - Added support for custom display VMs
Data model visualization - Added framework for custom input VMs
Shared UI - Made internal converters public
This commit is contained in:
Robert committed 2020-07-02 16:04:21 +02:00
1 parent addb06c348
commit 448d94915c
30 files changed
+537 -129

No files matched your search

@@ -1,75 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
using Stylet;
namespace Artemis.UI.DataModelVisualization
{
public class DataModelListViewModel : DataModelVisualizationViewModel
{
private BindableCollection<DataModelVisualizationViewModel> _children;
private IList _list;
private string _count;
public DataModelListViewModel(PropertyInfo propertyInfo, DataModelPropertyAttribute propertyDescription, DataModelVisualizationViewModel parent)
{
PropertyInfo = propertyInfo;
Parent = parent;
PropertyDescription = propertyDescription;
Children = new BindableCollection<DataModelVisualizationViewModel>();
}
public BindableCollection<DataModelVisualizationViewModel> Children
{
get => _children;
set => SetAndNotify(ref _children, value);
}
public IList List
{
get => _list;
set => SetAndNotify(ref _list, value);
}
public string Count
{
get => _count;
set => SetAndNotify(ref _count, value);
}
public override void Update()
{
if (PropertyInfo != null && Parent?.Model != null && PropertyInfo.GetValue(Parent.Model) is IList listValue)
{
Model = new List<object>(listValue.Cast<object>());
List = (IList) Model;
}
var index = 0;
foreach (var item in List)
{
DataModelVisualizationViewModel child;
if (Children.Count <= index)
{
child = CreateChild(item);
Children.Add(child);
}
else
{
child = Children[index];
child.Model = item;
}
child.Update();
index++;
}
while (Children.Count > List.Count)
Children.RemoveAt(Children.Count - 1);
Count = $"{Children.Count} {(Children.Count == 1 ? "item" : "items")}";
}
}
}
@@ -1,23 +0,0 @@
using System.Reflection;
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
namespace Artemis.UI.DataModelVisualization
{
public class DataModelPropertyViewModel : DataModelVisualizationViewModel
{
public DataModelPropertyViewModel(PropertyInfo propertyInfo, DataModelPropertyAttribute propertyDescription, DataModelVisualizationViewModel parent)
{
PropertyInfo = propertyInfo;
Parent = parent;
PropertyDescription = propertyDescription;
}
public override void Update()
{
if (PropertyInfo != null && Parent?.Model != null)
Model = PropertyInfo.GetValue(Parent.Model);
UpdateListStatus();
}
}
}
@@ -1,56 +0,0 @@
using System.Reflection;
using Artemis.Core.Extensions;
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
using Stylet;
namespace Artemis.UI.DataModelVisualization
{
public class DataModelViewModel : DataModelVisualizationViewModel
{
private BindableCollection<DataModelVisualizationViewModel> _children;
public DataModelViewModel()
{
Children = new BindableCollection<DataModelVisualizationViewModel>();
}
public DataModelViewModel(PropertyInfo propertyInfo, object model, DataModelPropertyAttribute propertyDescription, DataModelVisualizationViewModel parent)
{
PropertyInfo = propertyInfo;
Model = model;
PropertyDescription = propertyDescription;
Parent = parent;
Children = new BindableCollection<DataModelVisualizationViewModel>();
PopulateProperties();
}
public BindableCollection<DataModelVisualizationViewModel> Children
{
get => _children;
set => SetAndNotify(ref _children, value);
}
public void PopulateProperties()
{
Children.Clear();
foreach (var propertyInfo in Model.GetType().GetProperties())
{
var child = CreateChild(propertyInfo);
if (child != null)
Children.Add(child);
}
}
public override void Update()
{
if (PropertyInfo != null && PropertyInfo.PropertyType.IsStruct())
Model = PropertyInfo.GetValue(Parent.Model);
foreach (var dataModelVisualizationViewModel in Children)
dataModelVisualizationViewModel.Update();
UpdateListStatus();
}
}
}
@@ -1,123 +0,0 @@
using System;
using System.Collections;
using System.Reflection;
using Artemis.Core.Extensions;
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
using Humanizer;
using Stylet;
namespace Artemis.UI.DataModelVisualization
{
public abstract class DataModelVisualizationViewModel : PropertyChangedBase
{
private DataModelPropertyAttribute _propertyDescription;
private PropertyInfo _propertyInfo;
private Type _propertyType;
private DataModelVisualizationViewModel _parent;
private object _model;
private bool _isListProperty;
private string _listDescription;
public DataModelPropertyAttribute PropertyDescription
{
get => _propertyDescription;
protected set => SetAndNotify(ref _propertyDescription, value);
}
public PropertyInfo PropertyInfo
{
get => _propertyInfo;
protected set => SetAndNotify(ref _propertyInfo, value);
}
public Type PropertyType
{
get => _propertyType;
set => SetAndNotify(ref _propertyType, value);
}
public DataModelVisualizationViewModel Parent
{
get => _parent;
protected set => SetAndNotify(ref _parent, value);
}
public object Model
{
get => _model;
set => SetAndNotify(ref _model, value);
}
public bool IsListProperty
{
get => _isListProperty;
set => SetAndNotify(ref _isListProperty, value);
}
public string ListDescription
{
get => _listDescription;
set => SetAndNotify(ref _listDescription, value);
}
public abstract void Update();
protected DataModelVisualizationViewModel CreateChild(PropertyInfo propertyInfo)
{
// Skip properties decorated with DataModelIgnore
if (Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute)))
return null;
var dataModelPropertyAttribute = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute));
// If no DataModelProperty attribute was provided, pull one out of our ass
if (dataModelPropertyAttribute == null)
dataModelPropertyAttribute = new DataModelPropertyAttribute {Name = propertyInfo.Name.Humanize()};
// For primitives, create a property view model, it may be null that is fine
if (propertyInfo.PropertyType.IsPrimitive || propertyInfo.PropertyType == typeof(string))
return new DataModelPropertyViewModel(propertyInfo, dataModelPropertyAttribute, this);
if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
return new DataModelListViewModel(propertyInfo, dataModelPropertyAttribute, this);
// For other value types create a child view model if the value type is not null
if (propertyInfo.PropertyType.IsClass || propertyInfo.PropertyType.IsStruct())
{
var value = propertyInfo.GetValue(Model);
if (value == null)
return null;
return new DataModelViewModel(propertyInfo, value, dataModelPropertyAttribute, this);
}
return null;
}
protected DataModelVisualizationViewModel CreateChild(object value)
{
var dataModelPropertyAttribute = new DataModelPropertyAttribute {Name = "Unknown property"};
// For primitives, create a property view model, it may be null that is fine
if (value.GetType().IsPrimitive || value is string)
return new DataModelPropertyViewModel(null, dataModelPropertyAttribute, this) {Model = value};
// For other value types create a child view model if the value type is not null
if (value.GetType().IsClass || value.GetType().IsStruct())
return new DataModelViewModel(null, value, dataModelPropertyAttribute, this);
return null;
}
protected void UpdateListStatus()
{
if (Parent is DataModelListViewModel listViewModel)
{
IsListProperty = true;
ListDescription = $"List item [{listViewModel.List.IndexOf(Model)}]";
PropertyType = Model.GetType();
}
else
{
IsListProperty = false;
PropertyType = PropertyInfo?.PropertyType;
}
}
}
}
@@ -0,0 +1,40 @@
<UserControl x:Class="Artemis.UI.DataModelVisualization.SKColorDataModelDisplayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.DataModelVisualization"
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:SKColorDataModelDisplayViewModel}}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI.Shared;component/Resources/ArtemisShared.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:ColorToStringConverter x:Key="SKColorToStringConverter" />
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
</ResourceDictionary>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock x:Name="HexDisplay"
Text="{Binding DisplayValue, Converter={StaticResource SKColorToStringConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"/>
<Border Width="{Binding ActualHeight, ElementName=HexDisplay}"
Height="{Binding ActualHeight, ElementName=HexDisplay}"
CornerRadius="{Binding ActualHeight, ElementName=HexDisplay}"
Margin="5 0 0 0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Background="{StaticResource Checkerboard}">
<Ellipse Stroke="{DynamicResource NormalBorderBrush}">
<Ellipse.Fill>
<SolidColorBrush Color="{Binding DisplayValue, Converter={StaticResource SKColorToColorConverter}}" />
</Ellipse.Fill>
</Ellipse>
</Border>
</StackPanel>
</UserControl>
@@ -0,0 +1,9 @@
using Artemis.UI.Shared.DataModelVisualization;
using SkiaSharp;
namespace Artemis.UI.DataModelVisualization
{
public class SKColorDataModelDisplayViewModel : DataModelDisplayViewModel<SKColor>
{
}
}
@@ -4,7 +4,6 @@ using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.UI.Shared.PropertyInput;
using Artemis.UI.Shared.Services.Interfaces;
using FluentValidation;
// using PropertyChanged;
using SkiaSharp;
using Stylet;
@@ -17,15 +16,12 @@ namespace Artemis.UI.PropertyInput
{
}
// Since SKPoint is immutable we need to create properties that replace the SKPoint entirely
// [DependsOn(nameof(InputValue))]
public float X
{
get => InputValue.X;
set => InputValue = new SKPoint(value, Y);
}
// [DependsOn(nameof(InputValue))]
public float Y
{
get => InputValue.Y;
@@ -4,11 +4,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Debug.Tabs"
xmlns:dataModel="clr-namespace:Artemis.UI.DataModelVisualization"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:wpf="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:plugins="clr-namespace:Artemis.Core.Plugins.Abstract;assembly=Artemis.Core"
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance local:DataModelDebugViewModel}">
<UserControl.Resources>
@@ -101,6 +101,8 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Value description -->
<TextBlock Grid.Column="0" Margin="0 0 5 0" FontWeight="Bold">
<Run>[</Run><Run Text="{Binding PropertyType.Name, Mode=OneWay}" /><Run>]</Run>
</TextBlock>
@@ -112,17 +114,24 @@
Text="{Binding ListDescription}"
ToolTip="{Binding PropertyDescription.Description}"
Visibility="{Binding IsListProperty, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<!-- Value display -->
<TextBlock Grid.Column="2"
Text="{Binding Model, Mode=OneWay}"
FontFamily="Consolas"
HorizontalAlignment="Right"
Visibility="{Binding Model, Converter={StaticResource NullToVisibilityConverter}}" />
Visibility="{Binding ShowToString, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<TextBlock Grid.Column="2"
Text="null"
FontFamily="Consolas"
HorizontalAlignment="Right"
Foreground="{DynamicResource MaterialDesignCheckBoxDisabled}"
Visibility="{Binding Model, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
Visibility="{Binding ShowNull, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<ContentControl Grid.Column="2"
s:View.Model="{Binding DisplayViewModel}"
FontFamily="Consolas"
Visibility="{Binding ShowViewModel, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.Resources>
@@ -3,8 +3,9 @@ using System.Linq;
using System.Timers;
using Artemis.Core.Events;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.DataModelVisualization;
using Artemis.UI.Services;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Services;
using Stylet;
namespace Artemis.UI.Screens.Settings.Debug.Tabs
@@ -1,43 +0,0 @@
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.DataModelVisualization;
using Artemis.UI.Services.Interfaces;
namespace Artemis.UI.Services
{
public class DataModelVisualizationService : IDataModelVisualizationService
{
private readonly IDataModelService _dataModelService;
public DataModelVisualizationService(IDataModelService dataModelService)
{
_dataModelService = dataModelService;
}
public DataModelViewModel GetMainDataModelVisualization()
{
var viewModel = new DataModelViewModel();
foreach (var dataModelExpansion in _dataModelService.DataModelExpansions)
viewModel.Children.Add(new DataModelViewModel(null, dataModelExpansion, dataModelExpansion.DataModelDescription, viewModel));
return viewModel;
}
public DataModelViewModel GetPluginDataModelVisualization(Plugin plugin)
{
var dataModel = _dataModelService.GetPluginDataModel(plugin);
if (dataModel == null)
return null;
var viewModel = new DataModelViewModel();
viewModel.Children.Add(new DataModelViewModel(null, dataModel, dataModel.DataModelDescription, viewModel));
return viewModel;
}
}
public interface IDataModelVisualizationService : IArtemisUIService
{
DataModelViewModel GetMainDataModelVisualization();
DataModelViewModel GetPluginDataModelVisualization(Plugin plugin);
}
}
+15 -2
View File
@@ -1,6 +1,10 @@
using System.Windows;
using System;
using System.Windows;
using Artemis.Core;
using Artemis.UI.DataModelVisualization;
using Artemis.UI.Screens.Settings.Debug;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services;
using MaterialDesignExtensions.Controls;
using Ninject;
using Stylet;
@@ -11,12 +15,21 @@ namespace Artemis.UI.Services
{
private readonly IKernel _kernel;
private readonly IWindowManager _windowManager;
private readonly IDataModelVisualizationService _dataModelVisualizationService;
private DebugViewModel _debugViewModel;
public DebugService(IKernel kernel, IWindowManager windowManager)
public DebugService(IKernel kernel, IWindowManager windowManager, IDataModelVisualizationService dataModelVisualizationService)
{
_kernel = kernel;
_windowManager = windowManager;
_dataModelVisualizationService = dataModelVisualizationService;
RegisterBuiltInDataModelDisplays();
}
private void RegisterBuiltInDataModelDisplays()
{
_dataModelVisualizationService.RegisterDataModelDisplay<SKColorDataModelDisplayViewModel>(Constants.CorePluginInfo);
}
public void ShowDebugger()
@@ -141,13 +141,13 @@ namespace Artemis.UI.Services
private void RegisterBuiltInPropertyEditors()
{
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(BrushPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(ColorGradientPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(FloatPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(IntPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(SKColorPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(SKPointPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(SKSizePropertyInputViewModel));
_profileEditorService.RegisterPropertyInput<BrushPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<ColorGradientPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<FloatPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<IntPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<SKColorPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<SKPointPropertyInputViewModel>(Constants.CorePluginInfo);
_profileEditorService.RegisterPropertyInput<SKSizePropertyInputViewModel>(Constants.CorePluginInfo);
}
}
}