1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Display conditions - List predicates WIP

This commit is contained in:
SpoinkyNL 2020-08-11 22:54:14 +02:00
parent cb69760971
commit ae708fa26a
14 changed files with 162 additions and 95 deletions

View File

@ -37,6 +37,10 @@ namespace Artemis.Core.Models.Profile.Conditions
public override bool Evaluate()
{
// If there are less than two children, ignore the boolean operator
if (Children.Count <= 2)
return Children.All(c => c.Evaluate());
switch (BooleanOperator)
{
case BooleanOperator.And:

View File

@ -14,6 +14,9 @@ namespace Artemis.Core.Models.Profile.Conditions
{
Parent = parent;
DisplayConditionListPredicateEntity = new DisplayConditionListPredicateEntity();
// There is always a child root group, add it
AddChild(new DisplayConditionGroup(this));
}
public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity)
@ -22,15 +25,15 @@ namespace Artemis.Core.Models.Profile.Conditions
DisplayConditionListPredicateEntity = entity;
ListOperator = (ListOperator) entity.ListOperator;
foreach (var childEntity in DisplayConditionListPredicateEntity.Children)
// There should only be one child and it should be a group
var rootGroup = DisplayConditionListPredicateEntity.Children.SingleOrDefault() as DisplayConditionGroupEntity;
if (rootGroup == null)
{
if (childEntity is DisplayConditionGroupEntity groupEntity)
AddChild(new DisplayConditionGroup(this, groupEntity));
else if (childEntity is DisplayConditionPredicateEntity predicateEntity)
AddChild(new DisplayConditionPredicate(this, predicateEntity));
else if (childEntity is DisplayConditionListPredicateEntity listPredicateEntity)
AddChild(new DisplayConditionListPredicate(this, listPredicateEntity));
DisplayConditionListPredicateEntity.Children.Clear();
AddChild(new DisplayConditionGroup(this));
}
else
AddChild(new DisplayConditionGroup(this, rootGroup));
}
public DisplayConditionListPredicateEntity DisplayConditionListPredicateEntity { get; set; }
@ -76,8 +79,8 @@ namespace Artemis.Core.Models.Profile.Conditions
}
// Children
foreach (var child in Children)
child.Initialize(dataModelService);
var rootGroup = (DisplayConditionGroup) Children.Single();
rootGroup.Initialize(dataModelService);
}
public void UpdateList(DataModel dataModel, string path)

View File

@ -13,6 +13,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
{
private string _count;
private IList _list;
private DataModelVisualizationViewModel _listTypePropertyViewModel;
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, PropertyInfo propertyInfo) : base(dataModel, parent, propertyInfo)
{
@ -25,6 +26,12 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
set => SetAndNotify(ref _list, value);
}
public DataModelVisualizationViewModel ListTypePropertyViewModel
{
get => _listTypePropertyViewModel;
set => SetAndNotify(ref _listTypePropertyViewModel, value);
}
public BindableCollection<DataModelVisualizationViewModel> ListChildren { get; set; }
public string Count
@ -42,6 +49,20 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
if (List == null)
return;
if (ListTypePropertyViewModel == null)
{
// Create a property VM describing the type of the list
ListTypePropertyViewModel = CreateListChild(dataModelVisualizationService, List.GetType().GenericTypeArguments[0]);
// Put an empty value into the list type property view model
if (ListTypePropertyViewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
dataModelListClassViewModel.DisplayValue = Activator.CreateInstance(dataModelListClassViewModel.ListType);
else if (ListTypePropertyViewModel is DataModelListPropertyViewModel dataModelListPropertyViewModel)
dataModelListPropertyViewModel.DisplayValue = Activator.CreateInstance(dataModelListPropertyViewModel.ListType);
ListTypePropertyViewModel.Update(dataModelVisualizationService);
}
var index = 0;
foreach (var item in List)
{
@ -83,10 +104,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
return new DataModelListPropertyViewModel(DataModel, this, PropertyInfo) {DisplayViewModel = typeViewModel};
// For primitives, create a property view model, it may be null that is fine
if (listType.IsPrimitive || listType == typeof(string))
return new DataModelListPropertyViewModel(DataModel, this, PropertyInfo);
return new DataModelListPropertyViewModel(DataModel, this, PropertyInfo) {ListType = listType};
// For other value types create a child view model
if (listType.IsClass || listType.IsStruct())
return new DataModelListPropertiesViewModel(DataModel, this, PropertyInfo);
return new DataModelListPropertiesViewModel(DataModel, this, PropertyInfo) {ListType = listType};
return null;
}

View File

@ -35,7 +35,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
Parent = parent;
Children = new BindableCollection<DataModelVisualizationViewModel>();
IsMatchingFilteredTypes = true;
if (dataModel == null && parent == null && propertyInfo == null)
IsRootViewModel = true;
else
@ -176,7 +176,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
IsMatchingFilteredTypes = false;
return;
}
if (looseMatch)
IsMatchingFilteredTypes = filteredTypes.Any(t => t.IsCastableFrom(PropertyInfo.PropertyType));
else

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using Artemis.Core.Plugins.Abstract.DataModels;
namespace Artemis.UI.Shared.Services.DataModelVisualization
{
public class ListDataModelWrapper : DataModel
{
public ListDataModelWrapper()
{
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Extensions;
@ -9,6 +10,7 @@ using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Shared.DataModelVisualization;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Services.DataModelVisualization;
using Artemis.UI.Shared.Services.Interfaces;
using Ninject;
using Ninject.Parameters;
@ -61,6 +63,17 @@ namespace Artemis.UI.Shared.Services
return viewModel;
}
// public DataModelPropertiesViewModel GetListDataModelVisualization(IList list)
// {
// var viewModel = new DataModelPropertiesViewModel(null, null, null);
// viewModel.Children.Add(new DataModelListPropertiesViewModel(null, viewModel, null) {DisplayValue = list});
//
// // Update to populate children
// viewModel.Update(this);
// viewModel.UpdateRequested += (sender, args) => viewModel.Update(this);
// return viewModel;
// }
public bool GetPluginExtendsDataModel(Plugin plugin)
{
return _dataModelService.GetPluginExtendsDataModel(plugin);

View File

@ -27,7 +27,7 @@
</Style.Triggers>
</Style>
<DataTemplate x:Key="DataModelSelectionTemplate">
<ControlTemplate x:Key="DataModelSelectionTemplate">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
@ -48,9 +48,9 @@
</StackPanel.Resources>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</DataTemplate>
</ControlTemplate>
<DataTemplate x:Key="DataModelSelectionTemplateWithValues">
<ControlTemplate x:Key="DataModelSelectionTemplateWithValues">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
@ -96,5 +96,5 @@
</StackPanel.Resources>
<ContentPresenter Content="{Binding}" />
</StackPanel>
</DataTemplate>
</ControlTemplate>
</ResourceDictionary>

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using Artemis.Core.Models.Profile.Conditions.Abstract;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract
@ -28,6 +30,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract
public abstract void Update();
public virtual List<DataModelVisualizationViewModel> GetExtraDataModels()
{
if (Parent != null)
return Parent.GetExtraDataModels();
return new List<DataModelVisualizationViewModel>();
}
public virtual void Delete()
{
Model.Parent.RemoveChild(Model);

View File

@ -29,6 +29,7 @@
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
ToolTip="Delete the group and all its children"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Left"
Visibility="{Binding IsRootGroup, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
@ -40,11 +41,13 @@
</Button>
<Button Grid.Row="0"
Grid.Column="1"
ToolTip="Change the operator of the group"
Style="{StaticResource DisplayConditionButtonLeftClickMenu}"
Background="#E74C4C"
BorderBrush="#E74C4C"
Margin="3 1"
Content="{Binding SelectedBooleanOperator}">
Content="{Binding SelectedBooleanOperator}"
Visibility="{Binding DisplayBooleanOperator, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="And" Command="{s:Action SelectBooleanOperator}" CommandParameter="And" />
@ -57,6 +60,7 @@
<Button x:Name="AddChildButton"
Grid.Row="0"
Grid.Column="2"
ToolTip="Add another condition to the current group"
HorizontalAlignment="Left"
Foreground="#4CE758"
Width="25"

View File

@ -23,6 +23,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{
_profileEditorService = profileEditorService;
_displayConditionsVmFactory = displayConditionsVmFactory;
Children.CollectionChanged += (sender, args) => NotifyOfPropertyChange(nameof(DisplayBooleanOperator));
Execute.PostToUIThread(async () =>
{
await Task.Delay(50);
@ -44,6 +47,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
set => SetAndNotify(ref _isInitialized, value);
}
public bool DisplayBooleanOperator => Children.Count > 1;
public string SelectedBooleanOperator => DisplayConditionGroup.BooleanOperator.Humanize();
public void AttachView(UIElement view)

View File

@ -14,11 +14,19 @@
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
<ResourceDictionary>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<DataTemplate x:Key="DataModelDataTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
@ -28,13 +36,13 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
ToolTip="Delete the list predicate and all its children"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Left"
Foreground="#E74C4C"
@ -62,7 +70,7 @@
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelSelectionTemplate}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
@ -83,7 +91,8 @@
Background="#7B7B7B"
BorderBrush="#7B7B7B"
Content="{Binding SelectedListOperator}"
Click="PropertyButton_OnClick">
Click="PropertyButton_OnClick"
HorizontalAlignment="Left">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Any" Command="{s:Action SelectListOperator}" CommandParameter="Any" />
@ -94,56 +103,18 @@
</Button.ContextMenu>
</Button>
<Button x:Name="AddChildButton"
Grid.Row="0"
Grid.Column="3"
HorizontalAlignment="Left"
Foreground="#4CE758"
Width="25"
Height="25">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignIconForegroundButton}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<materialDesign:PackIcon Kind="Add" Width="18" Height="18" />
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Add static condition"
ToolTip="A condition that compares a data model property to a static input"
Command="{s:Action AddCondition}"
CommandParameter="Static">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormTextarea" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add dynamic condition"
ToolTip="A condition that compares two data model properties"
Command="{s:Action AddCondition}"
CommandParameter="Dynamic">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="InsertLink" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="CodeParentheses" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" ItemsSource="{Binding Children}" Margin="0 4 0 0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<materialDesign:TransitioningContent>
<materialDesign:TransitioningContent.OpeningEffects>
<materialDesign:TransitionEffect Kind="FadeIn" />
<materialDesign:TransitionEffect Kind="SlideInFromLeft" />
</materialDesign:TransitioningContent.OpeningEffects>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
</materialDesign:TransitioningContent>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>

View File

@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
@ -22,7 +23,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private readonly IDataModelVisualizationService _dataModelVisualizationService;
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
private bool _isInitialized;
private DataModelVisualizationViewModel _selectedListProperty;
private DataModelListViewModel _selectedListProperty;
private DataModelPropertiesViewModel _targetDataModel;
private readonly Timer _updateTimer;
@ -66,7 +67,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
set => SetAndNotify(ref _targetDataModel, value);
}
public DataModelVisualizationViewModel SelectedListProperty
public DataModelListViewModel SelectedListProperty
{
get => _selectedListProperty;
set => SetAndNotify(ref _selectedListProperty, value);
@ -132,12 +133,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
{
if (TargetDataModelOpen)
TargetDataModel.Update(_dataModelVisualizationService);
{
TargetDataModel?.Update(_dataModelVisualizationService);
SelectedListProperty?.Update(_dataModelVisualizationService);
}
}
private void TargetDataModelUpdateRequested(object sender, EventArgs e)
{
TargetDataModel.ApplyTypeFilter(true, typeof(IEnumerable));
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
}
public void ApplyList()
@ -148,6 +152,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
Update();
}
public override List<DataModelVisualizationViewModel> GetExtraDataModels()
{
var list = base.GetExtraDataModels();
if (SelectedListProperty != null)
list.Add(SelectedListProperty.ListTypePropertyViewModel);
return list;
}
public override void Update()
{
if (TargetDataModel == null)
@ -157,9 +170,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
// Update the selected list property
if (DisplayConditionListPredicate.ListDataModel != null && DisplayConditionListPredicate.ListPropertyPath != null)
SelectedListProperty = TargetDataModel.GetChildByPath(DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid, DisplayConditionListPredicate.ListPropertyPath);
{
var child = TargetDataModel.GetChildByPath(DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid, DisplayConditionListPredicate.ListPropertyPath);
SelectedListProperty = child as DataModelListViewModel;
}
// Ensure filtering is applied to include Enumerables only
TargetDataModel.ApplyTypeFilter(true, typeof(IEnumerable));
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
// Remove VMs of effects no longer applied on the layer
var toRemove = Children.Where(c => !DisplayConditionListPredicate.Children.Contains(c.Model)).ToList();
@ -174,19 +191,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{
if (Children.Any(c => c.Model == childModel))
continue;
if (!(childModel is DisplayConditionGroup displayConditionGroup))
continue;
switch (childModel)
{
case DisplayConditionGroup displayConditionGroup:
Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this));
break;
case DisplayConditionListPredicate displayConditionListPredicate:
Children.Add(_displayConditionsVmFactory.DisplayConditionListPredicateViewModel(displayConditionListPredicate, this));
break;
case DisplayConditionPredicate displayConditionPredicate:
Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this));
break;
}
var viewModel = _displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this);
viewModel.IsRootGroup = true;
Children.Add(viewModel);
}
foreach (var childViewModel in Children)
@ -196,10 +206,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
private void ExecuteSelectListProperty(object context)
{
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
if (!(context is DataModelListViewModel dataModelListViewModel))
return;
SelectedListProperty = dataModelVisualizationViewModel;
SelectedListProperty = dataModelListViewModel;
if (SelectedListProperty.ListTypePropertyViewModel == null)
SelectedListProperty.Update(_dataModelVisualizationService);
ApplyList();
}
}

View File

@ -21,6 +21,14 @@
<ResourceDictionary>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<DataTemplate x:Key="DataModelDataTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
@ -34,6 +42,7 @@
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
ToolTip="Delete the predicate"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Left"
Foreground="#E74C4C"
@ -61,7 +70,7 @@
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelSelectionTemplate}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
@ -124,7 +133,7 @@
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelSelectionTemplate}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>

View File

@ -54,6 +54,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
_dataModelService = dataModelService;
_eventAggregator = eventAggregator;
_updateTimer = new Timer(500);
_supportedInputTypes = new List<Type>();
SelectLeftPropertyCommand = new DelegateCommand(ExecuteSelectLeftProperty);
SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty);