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

Data model conditions - Added event predicates (WIP commit)

This commit is contained in:
SpoinkyNL 2020-10-24 20:09:51 +02:00
parent 574c4b21ec
commit fbd319beb9
24 changed files with 568 additions and 37 deletions

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cconditions_005Cwrappers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes_005Cconditional/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes_005Cdirect/@EntryIndexedValue">True</s:Boolean>

View File

@ -1,4 +1,5 @@
using System;
using System.Linq;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
@ -39,6 +40,7 @@ namespace Artemis.Core
/// </summary>
public DataModelPath? EventPath { get; private set; }
public Type? EventArgumentType { get; set; }
internal DataModelConditionEventEntity Entity { get; set; }
@ -57,6 +59,11 @@ namespace Artemis.Core
return false;
_eventTriggered = false;
// If there is a child (root group), it must evaluate to true whenever the event triggered
if (Children.Any())
return Children[0].Evaluate();
// If there are no children, we always evaluate to true whenever the event triggered
return true;
}
@ -84,6 +91,31 @@ namespace Artemis.Core
EventPath?.Dispose();
EventPath = path != null ? new DataModelPath(path) : null;
SubscribeToEventPath();
// Remove the old root group that was tied to the old data model
while (Children.Any())
RemoveChild(Children[0]);
if (EventPath != null)
{
EventArgumentType = GetEventArgumentType();
// Create a new root group
AddChild(new DataModelConditionGroup(this));
}
else
{
EventArgumentType = null;
}
}
private Type? GetEventArgumentType()
{
if (EventPath == null || !EventPath.IsValid)
return null;
// Cannot rely on EventPath.GetValue() because part of the path might be null
Type eventType = EventPath.GetPropertyType()!;
return eventType.IsGenericType ? eventType.GetGenericArguments()[0] : typeof(DataModelEventArgs);
}
#region IDisposable
@ -117,6 +149,12 @@ namespace Artemis.Core
// Target list
EventPath?.Save();
Entity.EventPath = EventPath?.Entity;
// Children
Entity.Children.Clear();
Entity.Children.AddRange(Children.Select(c => c.GetEntity()));
foreach (DataModelConditionPart child in Children)
child.Save();
}
internal override DataModelConditionPartEntity GetEntity()
@ -137,6 +175,18 @@ namespace Artemis.Core
EventPath = eventPath;
SubscribeToEventPath();
EventArgumentType = GetEventArgumentType();
// There should only be one child and it should be a group
if (Entity.Children.FirstOrDefault() is DataModelConditionGroupEntity rootGroup)
{
AddChild(new DataModelConditionGroup(this, rootGroup));
}
else
{
Entity.Children.Clear();
AddChild(new DataModelConditionGroup(this));
}
}
private bool PointsToEvent(DataModelPath dataModelPath)

View File

@ -0,0 +1,154 @@
using System;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core
{
/// <summary>
/// A predicate like evaluated inside a <see cref="DataModelConditionEvent" />
/// </summary>
public class DataModelConditionEventPredicate : DataModelConditionPredicate
{
/// <summary>
/// Creates a new instance of the <see cref="DataModelConditionEventPredicate" /> class
/// </summary>
/// <param name="parent"></param>
/// <param name="predicateType"></param>
public DataModelConditionEventPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
: base(parent, predicateType, new DataModelConditionEventPredicateEntity())
{
DataModelConditionEvent = null!;
ApplyParentEvent();
Initialize();
}
internal DataModelConditionEventPredicate(DataModelConditionPart parent, DataModelConditionEventPredicateEntity entity)
: base(parent, entity)
{
DataModelConditionEvent = null!;
ApplyParentEvent();
Initialize();
}
/// <summary>
/// Gets the data model condition event this predicate belongs to
/// </summary>
public DataModelConditionEvent DataModelConditionEvent { get; private set; }
private void ApplyParentEvent()
{
DataModelConditionPart? current = Parent;
while (current != null)
{
if (current is DataModelConditionEvent parentEvent)
{
DataModelConditionEvent = parentEvent;
return;
}
current = current.Parent;
}
if (DataModelConditionEvent == null)
throw new ArtemisCoreException("This data model condition event predicate does not belong to a data model condition event");
}
private object? GetEventPathValue(DataModelPath path, object target)
{
if (!(path.Target is EventPredicateWrapperDataModel wrapper))
throw new ArtemisCoreException("Data model condition event predicate has a path with an invalid target");
wrapper.UntypedArguments = target;
return path.GetValue();
}
#region Initialization
protected override void InitializeLeftPath()
{
if (Entity.LeftPath != null)
LeftPath = DataModelConditionEvent.EventArgumentType != null
? new DataModelPath(EventPredicateWrapperDataModel.Create(DataModelConditionEvent.EventArgumentType), Entity.LeftPath)
: null;
}
protected override void InitializeRightPath()
{
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
{
// Right side dynamic using event arguments
if (Entity.RightPath.WrapperType == PathWrapperType.Event)
{
RightPath = DataModelConditionEvent.EventArgumentType != null
? new DataModelPath(EventPredicateWrapperDataModel.Create(DataModelConditionEvent.EventArgumentType), Entity.RightPath)
: null;
}
// Right side dynamic
else
RightPath = new DataModelPath(null, Entity.RightPath);
}
}
#endregion
#region Modification
/// <inheritdoc />
public override Type? GetPreferredRightSideType()
{
Type? preferredType = Operator?.RightSideType;
Type? leftSideType = LeftPath?.GetPropertyType();
if (preferredType == null)
return null;
if (leftSideType != null && preferredType.IsAssignableFrom(leftSideType))
preferredType = leftSideType;
return preferredType;
}
#endregion
#region Evaluation
/// <summary>
/// Not supported for event predicates, always returns <c>false</c>
/// </summary>
public override bool Evaluate()
{
return false;
}
internal override bool EvaluateObject(object target)
{
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
return false;
// Compare with a static value
if (PredicateType == ProfileRightSideType.Static)
{
object? leftSideValue = GetEventPathValue(LeftPath, target);
if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null)
return false;
return Operator.InternalEvaluate(leftSideValue, RightStaticValue);
}
if (RightPath == null || !RightPath.IsValid)
return false;
// Compare with dynamic values
if (PredicateType == ProfileRightSideType.Dynamic)
{
// If the path targets a property inside the event, evaluate on the event path value instead of the right path value
if (RightPath.Target is EventPredicateWrapperDataModel)
return Operator.InternalEvaluate(GetEventPathValue(LeftPath, target), GetEventPathValue(RightPath, target));
return Operator.InternalEvaluate(GetEventPathValue(LeftPath, target), RightPath.GetValue());
}
return false;
}
#endregion
}
}

View File

@ -1,4 +1,5 @@
using System;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core
@ -76,11 +77,12 @@ namespace Artemis.Core
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
{
// Right side dynamic inside the list
// TODO: Come up with a general wrapper solution because this will clash with events
if (Entity.RightPath.DataModelGuid == Constants.CorePluginInfo.Guid)
if (Entity.RightPath.WrapperType == PathWrapperType.List)
{
RightPath = DataModelConditionList.ListType != null
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
: null;
}
// Right side dynamic
else
RightPath = new DataModelPath(null, Entity.RightPath);

View File

@ -0,0 +1,37 @@
using System;
using Artemis.Core.DataModelExpansions;
namespace Artemis.Core
{
internal class EventPredicateWrapperDataModel<T> : EventPredicateWrapperDataModel
{
[DataModelProperty(Name = "Event arguments", Description = "The arguments provided when the event triggers")]
public T Arguments => (UntypedArguments is T typedArguments ? typedArguments : default)!;
}
/// <summary>
/// Represents a datamodel that wraps the event arguments of an event
/// </summary>
public abstract class EventPredicateWrapperDataModel : DataModel
{
internal EventPredicateWrapperDataModel()
{
PluginInfo = Constants.CorePluginInfo;
}
[DataModelIgnore]
public object? UntypedArguments { get; set; }
/// <summary>
/// Creates a new instance of the <see cref="EventPredicateWrapperDataModel"/> class
/// </summary>
public static EventPredicateWrapperDataModel Create(Type type)
{
object? instance = Activator.CreateInstance(typeof(EventPredicateWrapperDataModel<>).MakeGenericType(type));
if (instance == null)
throw new ArtemisCoreException($"Failed to create an instance of EventPredicateWrapperDataModel<T> for type {type.Name}");
return (EventPredicateWrapperDataModel) instance;
}
}
}

View File

@ -9,6 +9,9 @@ namespace Artemis.Core
public T Value => (UntypedValue is T typedValue ? typedValue : default)!;
}
/// <summary>
/// Represents a datamodel that wraps a value in a list
/// </summary>
public abstract class ListPredicateWrapperDataModel : DataModel
{
internal ListPredicateWrapperDataModel()
@ -19,6 +22,9 @@ namespace Artemis.Core
[DataModelIgnore]
public object? UntypedValue { get; set; }
/// <summary>
/// Creates a new instance of the <see cref="ListPredicateWrapperDataModel"/> class
/// </summary>
public static ListPredicateWrapperDataModel Create(Type type)
{
object? instance = Activator.CreateInstance(typeof(ListPredicateWrapperDataModel<>).MakeGenericType(type));

View File

@ -58,6 +58,9 @@ namespace Artemis.Core
/// </summary>
public void Trigger()
{
DataModelEventArgs eventArgs = new DataModelEventArgs {TriggerTime = DateTime.Now};
LastEventArguments = eventArgs;
LastTrigger = DateTime.Now;
TriggerCount++;
@ -74,10 +77,15 @@ namespace Artemis.Core
/// <inheritdoc />
public int TriggerCount { get; private set; }
/// <summary>
/// Gets the event arguments of the last time the event was triggered
/// </summary>
public DataModelEventArgs? LastEventArguments { get; private set; }
/// <inheritdoc />
[DataModelIgnore]
public Type? ArgumentsType => null;
public Type ArgumentsType => typeof(DataModelEventArgs);
/// <inheritdoc />
public event EventHandler? EventTriggered;

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
/// <summary>
/// Gets the type of arguments this event contains
/// </summary>
Type? ArgumentsType { get; }
Type ArgumentsType { get; }
/// <summary>
/// Fires when the event is triggered

View File

@ -1,4 +1,5 @@
using Artemis.Storage.Entities.Profile.Abstract;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Storage.Entities.Profile.Conditions
{
@ -6,7 +7,7 @@ namespace Artemis.Storage.Entities.Profile.Conditions
{
public DataModelConditionEventEntity()
{
Children = new List<DataModelConditionPartEntity>();
}
public DataModelPathEntity EventPath { get; set; }

View File

@ -0,0 +1,6 @@
namespace Artemis.Storage.Entities.Profile.Conditions
{
public class DataModelConditionEventPredicateEntity : DataModelConditionPredicateEntity
{
}
}

View File

@ -6,5 +6,14 @@ namespace Artemis.Storage.Entities.Profile
{
public string Path { get; set; }
public Guid? DataModelGuid { get; set; }
public PathWrapperType WrapperType { get; set; }
}
public enum PathWrapperType
{
None,
List,
Event
}
}

View File

@ -7,6 +7,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dependencyproperties/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=propertyinput/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cdatamodelvisualization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cdialog/@EntryIndexedValue">True</s:Boolean>

View File

@ -0,0 +1,17 @@
using Artemis.Core;
namespace Artemis.UI.Shared
{
public static class DataModelWrapperExtensions
{
public static DataModelPropertiesViewModel CreateViewModel(this EventPredicateWrapperDataModel wrapper)
{
return new DataModelPropertiesViewModel(wrapper, null, new DataModelPath(wrapper));
}
public static DataModelPropertiesViewModel CreateViewModel(this ListPredicateWrapperDataModel wrapper)
{
return new DataModelPropertiesViewModel(wrapper, null, new DataModelPath(wrapper));
}
}
}

View File

@ -65,11 +65,12 @@ namespace Artemis.UI.Ninject.Factories
public interface IDataModelConditionsVmFactory : IVmFactory
{
DataModelConditionGroupViewModel DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup, bool isListGroup);
DataModelConditionGroupViewModel DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup, ConditionGroupType groupType);
DataModelConditionListViewModel DataModelConditionListViewModel(DataModelConditionList dataModelConditionList);
DataModelConditionEventViewModel DataModelConditionEventViewModel(DataModelConditionEvent dataModelConditionEvent);
DataModelConditionGeneralPredicateViewModel DataModelConditionGeneralPredicateViewModel(DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate);
DataModelConditionListPredicateViewModel DataModelConditionListPredicateViewModel(DataModelConditionListPredicate dataModelConditionListPredicate);
DataModelConditionEventPredicateViewModel DataModelConditionEventPredicateViewModel(DataModelConditionEventPredicate dataModelConditionEventPredicate);
}
public interface ILayerPropertyVmFactory : IVmFactory

View File

@ -1,12 +1,12 @@
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Conditions.DataModelConditionEventView"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Conditions"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
@ -21,9 +21,10 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
ToolTip="Delete the event trigger"
@ -43,5 +44,20 @@
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
<TextBlock Grid.Row="0"
Grid.Column="2"
VerticalAlignment="Center"
Margin="5 0 0 0">
triggered
</TextBlock>
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" ItemsSource="{Binding Items}" Margin="0 4 0 0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>

View File

@ -51,6 +51,31 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public override void Update()
{
LeftSideSelectionViewModel.ChangeDataModelPath(DataModelConditionEvent.EventPath);
// Remove VMs of effects no longer applied on the layer
Items.RemoveRange(Items.Where(c => !DataModelConditionEvent.Children.Contains(c.Model)).ToList());
if (DataModelConditionEvent.EventPath == null || !DataModelConditionEvent.EventPath.IsValid)
return;
List<DataModelConditionViewModel> viewModels = new List<DataModelConditionViewModel>();
foreach (DataModelConditionPart childModel in Model.Children)
{
if (Items.Any(c => c.Model == childModel))
continue;
if (!(childModel is DataModelConditionGroup dataModelConditionGroup))
continue;
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.Event);
viewModel.IsRootGroup = true;
viewModels.Add(viewModel);
}
if (viewModels.Any())
Items.AddRange(viewModels);
foreach (DataModelConditionViewModel childViewModel in Items)
childViewModel.Update();
}
public void ApplyEvent()

View File

@ -21,12 +21,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
private bool _isRootGroup;
public DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup,
bool isListGroup,
ConditionGroupType groupType,
IProfileEditorService profileEditorService,
IDataModelConditionsVmFactory dataModelConditionsVmFactory)
: base(dataModelConditionGroup)
{
IsListGroup = isListGroup;
GroupType = groupType;
_profileEditorService = profileEditorService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
@ -39,7 +39,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
});
}
public bool IsListGroup { get; }
public ConditionGroupType GroupType { get; set; }
public DataModelConditionGroup DataModelConditionGroup => (DataModelConditionGroup) Model;
public bool IsRootGroup
@ -68,10 +68,20 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void AddCondition()
{
if (!IsListGroup)
DataModelConditionGroup.AddChild(new DataModelConditionGeneralPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
else
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
switch (GroupType)
{
case ConditionGroupType.General:
DataModelConditionGroup.AddChild(new DataModelConditionGeneralPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
break;
case ConditionGroupType.List:
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
break;
case ConditionGroupType.Event:
DataModelConditionGroup.AddChild(new DataModelConditionEventPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
break;
default:
throw new ArgumentOutOfRangeException();
}
Update();
_profileEditorService.UpdateSelectedProfileElement();
@ -101,7 +111,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
switch (childModel)
{
case DataModelConditionGroup dataModelConditionGroup:
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, IsListGroup));
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, GroupType));
break;
case DataModelConditionList dataModelConditionList:
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionListViewModel(dataModelConditionList));
@ -110,12 +120,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionEventViewModel(dataModelConditionEvent));
break;
case DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate:
if (!IsListGroup)
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionGeneralPredicateViewModel(dataModelConditionGeneralPredicate));
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionGeneralPredicateViewModel(dataModelConditionGeneralPredicate));
break;
case DataModelConditionListPredicate dataModelConditionListPredicate:
if (IsListGroup)
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionListPredicateViewModel(dataModelConditionListPredicate));
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionListPredicateViewModel(dataModelConditionListPredicate));
break;
case DataModelConditionEventPredicate dataModelConditionEventPredicate:
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionEventPredicateViewModel(dataModelConditionEventPredicate));
break;
}
}
@ -190,4 +201,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
Updated?.Invoke(this, EventArgs.Empty);
}
}
public enum ConditionGroupType
{
General,
List,
Event
}
}

View File

@ -115,7 +115,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
if (!(childModel is DataModelConditionGroup dataModelConditionGroup))
continue;
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, true);
DataModelConditionGroupViewModel viewModel = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(dataModelConditionGroup, ConditionGroupType.List);
viewModel.IsRootGroup = true;
viewModels.Add(viewModel);
}

View File

@ -0,0 +1,94 @@
<UserControl
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:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
xmlns:DataModelConditions="clr-namespace:Artemis.UI.Screens.ProfileEditor.Conditions"
x:Class="Artemis.UI.Screens.ProfileEditor.Conditions.DataModelConditionEventPredicateView"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type DataModelConditions:DataModelConditionEventPredicateViewModel}}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.xaml" />
<ResourceDictionary>
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid Margin="0 3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
ToolTip="Delete the predicate"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Left"
Foreground="#E74C4C"
Width="25"
Height="25"
Command="{s:Action Delete}">
<materialDesign:PackIcon Kind="Close" Width="18" Height="18" />
</Button>
<!-- Left side -->
<ContentControl Grid.Row="0"
Grid.Column="1"
s:View.Model="{Binding LeftSideSelectionViewModel}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
<!-- Operator -->
<Button Grid.Row="0"
Grid.Column="2"
Style="{StaticResource DataModelConditionButtonLeftClickMenu}"
Background="#7B7B7B"
BorderBrush="#7B7B7B"
Content="{Binding SelectedOperator.Description}"
Click="PropertyButton_OnClick">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding Operators}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="{Binding Icon}" VerticalAlignment="Center" Margin="0 0 15 0" />
<TextBlock Text="{Binding Description}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ContextMenu.ItemTemplate>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="Command" Value="{Binding Data.SelectOperatorCommand, Source={StaticResource DataContextProxy}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="CommandTarget" Value="{Binding}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
</Button>
<!-- Right side, either a selection or an input -->
<ContentControl Grid.Row="0"
Grid.Column="3"
s:View.Model="{Binding RightSideSelectionViewModel}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
<ContentControl Grid.Row="0"
Grid.Column="3"
s:View.Model="{Binding RightSideInputViewModel}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
</Grid>
</UserControl>

View File

@ -0,0 +1,26 @@
using System.Windows;
using System.Windows.Controls;
namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
/// <summary>
/// Interaction logic for DataModelConditionEventPredicateView.xaml
/// </summary>
public partial class DataModelConditionEventPredicateView : UserControl
{
public DataModelConditionEventPredicateView()
{
InitializeComponent();
}
private void PropertyButton_OnClick(object sender, RoutedEventArgs e)
{
// DataContext is not set when using left button, I don't know why but there it is
if (sender is Button button && button.ContextMenu != null)
{
button.ContextMenu.DataContext = button.DataContext;
button.ContextMenu.IsOpen = true;
}
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
public class DataModelConditionEventPredicateViewModel : DataModelConditionPredicateViewModel
{
private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService;
public DataModelConditionEventPredicateViewModel(DataModelConditionEventPredicate dataModelConditionEventPredicate,
IProfileEditorService profileEditorService,
IDataModelUIService dataModelUIService,
IConditionOperatorService conditionOperatorService,
ISettingsService settingsService)
: base(dataModelConditionEventPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
{
_profileEditorService = profileEditorService;
_dataModelUIService = dataModelUIService;
LeftSideColor = new SolidColorBrush(Color.FromRgb(185, 164, 10));
Initialize();
}
public DataModelConditionEventPredicate DataModelConditionEventPredicate => (DataModelConditionEventPredicate) Model;
public override void Initialize()
{
base.Initialize();
DataModelPropertiesViewModel eventDataModel = GetEventDataModel();
LeftSideSelectionViewModel.ChangeDataModel(eventDataModel);
}
protected override List<Type> GetSupportedInputTypes()
{
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
List<Type> supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
return supportedInputTypes;
}
protected override Type GetLeftSideType()
{
return LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
}
protected override List<DataModelPropertiesViewModel> GetExtraRightSideDataModelViewModels()
{
return new List<DataModelPropertiesViewModel> {GetEventDataModel()};
}
private DataModelPropertiesViewModel GetEventDataModel()
{
EventPredicateWrapperDataModel wrapper = EventPredicateWrapperDataModel.Create(
DataModelConditionEventPredicate.DataModelConditionEvent.EventArgumentType
);
return wrapper.CreateViewModel();
}
}
}

View File

@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
xmlns:DataModelConditions="clr-namespace:Artemis.UI.Screens.ProfileEditor.Conditions"
x:Class="Artemis.UI.Screens.ProfileEditor.Conditions.DataModelConditionListPredicateView"
@ -17,16 +16,7 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.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.MergedDictionaries>
</ResourceDictionary>

View File

@ -86,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
if (e.RenderProfileElement.DisplayCondition == null)
e.RenderProfileElement.DisplayCondition = new DataModelConditionGroup(null);
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(e.RenderProfileElement.DisplayCondition, false);
ActiveItem = _dataModelConditionsVmFactory.DataModelConditionGroupViewModel(e.RenderProfileElement.DisplayCondition, ConditionGroupType.General);
ActiveItem.IsRootGroup = true;
ActiveItem.Update();

View File

@ -22,7 +22,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
_profileEditorService = profileEditorService;
DataBindingCondition = dataBindingCondition;
ActiveItem = dataModelConditionsVmFactory.DataModelConditionGroupViewModel(DataBindingCondition.Condition, false);
ActiveItem = dataModelConditionsVmFactory.DataModelConditionGroupViewModel(DataBindingCondition.Condition, ConditionGroupType.General);
ActiveItem.IsRootGroup = true;
ActiveItem.Update();
ActiveItem.Updated += ActiveItemOnUpdated;