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

Conditions - Simplified adding new parts to conditions

Conditions - Added toggle for switching between static and dynamic conditions
Conditions - Automatically change to list condition when selecting a list and vice versa
This commit is contained in:
Robert 2020-10-13 20:51:53 +02:00
parent ef62e30c6f
commit 879d19e4ea
19 changed files with 439 additions and 333 deletions

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.Core.Services; using System.Collections.ObjectModel;
using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Abstract;
namespace Artemis.Core namespace Artemis.Core
@ -20,18 +20,22 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets the children of this part /// Gets the children of this part
/// </summary> /// </summary>
public IReadOnlyList<DataModelConditionPart> Children => _children.AsReadOnly(); public ReadOnlyCollection<DataModelConditionPart> Children => _children.AsReadOnly();
/// <summary> /// <summary>
/// Adds a child to the display condition part's <see cref="Children" /> collection /// Adds a child to the display condition part's <see cref="Children" /> collection
/// </summary> /// </summary>
/// <param name="dataModelConditionPart"></param> /// <param name="dataModelConditionPart"></param>
public void AddChild(DataModelConditionPart dataModelConditionPart) /// <param name="index">An optional index at which to insert the condition</param>
public void AddChild(DataModelConditionPart dataModelConditionPart, int? index = null)
{ {
if (!_children.Contains(dataModelConditionPart)) if (!_children.Contains(dataModelConditionPart))
{ {
dataModelConditionPart.Parent = this; dataModelConditionPart.Parent = this;
_children.Add(dataModelConditionPart); if (index != null)
_children.Insert(index.Value, dataModelConditionPart);
else
_children.Add(dataModelConditionPart);
} }
} }

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
/// </summary> /// </summary>
/// <param name="parent"></param> /// <param name="parent"></param>
/// <param name="predicateType"></param> /// <param name="predicateType"></param>
public DataModelConditionListPredicate(DataModelConditionPart parent, ListRightSideType predicateType) public DataModelConditionListPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
{ {
Parent = parent; Parent = parent;
PredicateType = predicateType; PredicateType = predicateType;
@ -32,7 +32,7 @@ namespace Artemis.Core
{ {
Parent = parent; Parent = parent;
Entity = entity; Entity = entity;
PredicateType = (ListRightSideType) entity.PredicateType; PredicateType = (ProfileRightSideType) entity.PredicateType;
DataModelConditionList = null!; DataModelConditionList = null!;
ApplyParentList(); ApplyParentList();
@ -42,7 +42,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets or sets the predicate type /// Gets or sets the predicate type
/// </summary> /// </summary>
public ListRightSideType PredicateType { get; set; } public ProfileRightSideType PredicateType { get; set; }
/// <summary> /// <summary>
/// Gets the operator /// Gets the operator
@ -66,7 +66,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets the right static value, only used it <see cref="PredicateType" /> is /// Gets the right static value, only used it <see cref="PredicateType" /> is
/// <see cref="ListRightSideType.Static" /> /// <see cref="ProfileRightSideType.Static" />
/// </summary> /// </summary>
public object? RightStaticValue { get; private set; } public object? RightStaticValue { get; private set; }
@ -92,11 +92,10 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Updates the right side of the predicate using a path to a value inside the list item, makes the predicate dynamic /// Updates the right side of the predicate using a path and makes the predicate dynamic
/// and re-compiles the expression
/// </summary> /// </summary>
/// <param name="path">The path pointing to the right side value inside the list</param> /// <param name="path">The path pointing to the right side value</param>
public void UpdateRightSideDynamicList(DataModelPath? path) public void UpdateRightSideDynamic(DataModelPath? path)
{ {
if (path != null && !path.IsValid) if (path != null && !path.IsValid)
throw new ArtemisCoreException("Cannot update right side of predicate to an invalid path"); throw new ArtemisCoreException("Cannot update right side of predicate to an invalid path");
@ -104,20 +103,7 @@ namespace Artemis.Core
RightPath?.Dispose(); RightPath?.Dispose();
RightPath = path != null ? new DataModelPath(path) : null; RightPath = path != null ? new DataModelPath(path) : null;
PredicateType = ListRightSideType.DynamicList; PredicateType = ProfileRightSideType.Dynamic;
}
/// <summary>
/// Updates the right side of the predicate using path to a value in a data model, makes the predicate dynamic and
/// re-compiles the expression
/// </summary>
/// <param name="path">The path pointing to the right side value inside the list</param>
public void UpdateRightSideDynamic(DataModelPath? path)
{
RightPath?.Dispose();
RightPath = path;
PredicateType = ListRightSideType.Dynamic;
} }
/// <summary> /// <summary>
@ -126,7 +112,7 @@ namespace Artemis.Core
/// <param name="staticValue">The right side value to use</param> /// <param name="staticValue">The right side value to use</param>
public void UpdateRightSideStatic(object? staticValue) public void UpdateRightSideStatic(object? staticValue)
{ {
PredicateType = ListRightSideType.Static; PredicateType = ProfileRightSideType.Static;
RightPath?.Dispose(); RightPath?.Dispose();
RightPath = null; RightPath = null;
@ -214,7 +200,7 @@ namespace Artemis.Core
return false; return false;
// Compare with a static value // Compare with a static value
if (PredicateType == ListRightSideType.Static) if (PredicateType == ProfileRightSideType.Static)
{ {
object? leftSideValue = GetListPathValue(LeftPath, target); object? leftSideValue = GetListPathValue(LeftPath, target);
if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null) if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null)
@ -227,10 +213,13 @@ namespace Artemis.Core
return false; return false;
// Compare with dynamic values // Compare with dynamic values
if (PredicateType == ListRightSideType.Dynamic) if (PredicateType == ProfileRightSideType.Dynamic)
{
// If the path targets a property inside the list, evaluate on the list path value instead of the right path value
if (RightPath.Target is ListPredicateWrapperDataModel)
return Operator.Evaluate(GetListPathValue(LeftPath, target), GetListPathValue(RightPath, target));
return Operator.Evaluate(GetListPathValue(LeftPath, target), RightPath.GetValue()); return Operator.Evaluate(GetListPathValue(LeftPath, target), RightPath.GetValue());
if (PredicateType == ListRightSideType.DynamicList) }
return Operator.Evaluate(GetListPathValue(LeftPath, target), GetListPathValue(RightPath, target));
return false; return false;
} }
@ -317,17 +306,22 @@ namespace Artemis.Core
} }
// Right side dynamic // Right side dynamic
if (PredicateType == ListRightSideType.Dynamic && Entity.RightPath != null) if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
RightPath = new DataModelPath(null, Entity.RightPath);
// Right side dynamic inside the list
else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPath != null)
{ {
RightPath = DataModelConditionList.ListType != null // Right side dynamic inside the list
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath) // TODO: Come up with a general wrapper solution because this will clash with events
: null; if (Entity.RightPath.DataModelGuid == Constants.CorePluginInfo.Guid)
{
RightPath = DataModelConditionList.ListType != null
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
: null;
}
// Right side dynamic
else
RightPath = new DataModelPath(null, Entity.RightPath);
} }
// Right side static // Right side static
else if (PredicateType == ListRightSideType.Static && Entity.RightStaticValue != null) else if (PredicateType == ProfileRightSideType.Static && Entity.RightStaticValue != null)
try try
{ {
if (LeftPath != null && LeftPath.IsValid) if (LeftPath != null && LeftPath.IsValid)
@ -374,7 +368,7 @@ namespace Artemis.Core
private void ValidateRightSide() private void ValidateRightSide()
{ {
Type? leftType = LeftPath?.GetPropertyType(); Type? leftType = LeftPath?.GetPropertyType();
if (PredicateType == ListRightSideType.Dynamic) if (PredicateType == ProfileRightSideType.Dynamic)
{ {
if (RightPath == null || !RightPath.IsValid) if (RightPath == null || !RightPath.IsValid)
return; return;
@ -383,15 +377,6 @@ namespace Artemis.Core
if (leftType != null && !leftType.IsCastableFrom(rightSideType)) if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamic(null); UpdateRightSideDynamic(null);
} }
else if (PredicateType == ListRightSideType.DynamicList)
{
if (RightPath == null || !RightPath.IsValid)
return;
Type rightSideType = RightPath.GetPropertyType()!;
if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamicList(null);
}
else else
{ {
if (RightStaticValue != null && (leftType == null || leftType.IsCastableFrom(RightStaticValue.GetType()))) if (RightStaticValue != null && (leftType == null || leftType.IsCastableFrom(RightStaticValue.GetType())))
@ -455,25 +440,4 @@ namespace Artemis.Core
#endregion #endregion
} }
/// <summary>
/// An enum defining the right side type of a profile entity
/// </summary>
public enum ListRightSideType
{
/// <summary>
/// A static right side value
/// </summary>
Static,
/// <summary>
/// A dynamic right side value based on a path in a data model
/// </summary>
Dynamic,
/// <summary>
/// A dynamic right side value based on a path in the list
/// </summary>
DynamicList
}
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Artemis.Storage.Entities.Profile.DataBindings; using Artemis.Storage.Entities.Profile.DataBindings;
@ -25,7 +26,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets a list of conditions applied to this data binding /// Gets a list of conditions applied to this data binding
/// </summary> /// </summary>
public IReadOnlyList<DataBindingCondition<TLayerProperty, TProperty>> Conditions => _conditions.AsReadOnly(); public ReadOnlyCollection<DataBindingCondition<TLayerProperty, TProperty>> Conditions => _conditions.AsReadOnly();
/// <inheritdoc /> /// <inheritdoc />
public DataBinding<TLayerProperty, TProperty> DataBinding { get; } public DataBinding<TLayerProperty, TProperty> DataBinding { get; }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using Artemis.Storage.Entities.Profile.DataBindings; using Artemis.Storage.Entities.Profile.DataBindings;
namespace Artemis.Core namespace Artemis.Core
@ -28,7 +29,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets a list of modifiers applied to this data binding /// Gets a list of modifiers applied to this data binding
/// </summary> /// </summary>
public IReadOnlyList<DataBindingModifier<TLayerProperty, TProperty>> Modifiers => _modifiers.AsReadOnly(); public ReadOnlyCollection<DataBindingModifier<TLayerProperty, TProperty>> Modifiers => _modifiers.AsReadOnly();
internal DirectDataBindingEntity Entity { get; } internal DirectDataBindingEntity Entity { get; }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using Artemis.Storage.Entities.Profile; using Artemis.Storage.Entities.Profile;
@ -215,7 +216,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets a read-only list of all the keyframes on this layer property /// Gets a read-only list of all the keyframes on this layer property
/// </summary> /// </summary>
public IReadOnlyList<LayerPropertyKeyframe<T>> Keyframes => _keyframes.AsReadOnly(); public ReadOnlyCollection<LayerPropertyKeyframe<T>> Keyframes => _keyframes.AsReadOnly();
/// <summary> /// <summary>
/// Gets the current keyframe in the timeline according to the current progress /// Gets the current keyframe in the timeline according to the current progress

View File

@ -6,6 +6,7 @@
xmlns:shared="clr-namespace:Artemis.UI.Shared" xmlns:shared="clr-namespace:Artemis.UI.Shared"
xmlns:input="clr-namespace:Artemis.UI.Shared.Input" xmlns:input="clr-namespace:Artemis.UI.Shared.Input"
xmlns:s="https://github.com/canton7/Stylet" 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" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance input:DataModelDynamicViewModel}"> d:DataContext="{d:DesignInstance input:DataModelDynamicViewModel}">
@ -24,45 +25,71 @@
</DataTrigger> </DataTrigger>
</DataTemplate.Triggers> </DataTemplate.Triggers>
</DataTemplate> </DataTemplate>
<Style x:Key="DataModelConditionButtonCornerToggle" BasedOn="{StaticResource DataModelConditionButton}" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding DisplaySwitchButton}" Value="True">
<Setter Property="materialDesign:ButtonAssist.CornerRadius" Value="0 2 2 0" />
</DataTrigger>
<DataTrigger Binding="{Binding DisplaySwitchButton}" Value="False">
<Setter Property="materialDesign:ButtonAssist.CornerRadius" Value="2" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary> </ResourceDictionary>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<Button Background="{Binding ButtonBrush}" <StackPanel Orientation="Horizontal">
BorderBrush="{Binding ButtonBrush}" <Button Style="{StaticResource MaterialDesignFlatDarkBgButton}"
Style="{StaticResource DataModelConditionButton}" Height="22"
ToolTip="{Binding DisplayPath}" Padding="0"
IsEnabled="{Binding IsEnabled}" Width="22"
HorizontalAlignment="Left" FontSize="12"
Click="PropertyButton_OnClick"> materialDesign:ButtonAssist.CornerRadius="2 0 0 2"
<Button.ContextMenu> Margin="3 0 -3 0"
<ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}"> HorizontalAlignment="Left"
<ContextMenu.ItemContainerStyle> ToolTip="Switch to manual input"
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}"> Command="{s:Action SwitchToStatic}"
<Setter Property="ItemsSource" Value="{Binding Children}" /> Visibility="{Binding DisplaySwitchButton, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
<Setter Property="Command" Value="{Binding Data.SelectPropertyCommand, Source={StaticResource DataContextProxy}}" /> <materialDesign:PackIcon Kind="SwapHorizontal" />
<Setter Property="CommandParameter" Value="{Binding}" /> </Button>
<Setter Property="CommandTarget" Value="{Binding}" /> <Button Background="{Binding ButtonBrush}"
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" /> BorderBrush="{Binding ButtonBrush}"
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" /> Style="{StaticResource DataModelConditionButtonCornerToggle}"
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" /> ToolTip="{Binding DisplayPath}"
</Style> IsEnabled="{Binding IsEnabled}"
</ContextMenu.ItemContainerStyle> HorizontalAlignment="Left"
</ContextMenu> Click="PropertyButton_OnClick">
</Button.ContextMenu> <Button.ContextMenu>
<Grid> <ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}">
<Grid Visibility="{Binding IsValid,Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"> <ContextMenu.ItemContainerStyle>
<TextBlock Text="{Binding DisplayValue}" <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
Visibility="{Binding DataModelPath, Converter={StaticResource NullToVisibilityConverter}}" /> <Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding Data.SelectPropertyCommand, Source={StaticResource DataContextProxy}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
<Grid>
<Grid Visibility="{Binding IsValid,Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
<TextBlock Text="{Binding DisplayValue}"
Visibility="{Binding DataModelPath, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock FontStyle="Italic"
Visibility="{Binding DataModelPath, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" />
</TextBlock>
</Grid>
<TextBlock FontStyle="Italic" <TextBlock FontStyle="Italic"
Visibility="{Binding DataModelPath, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}"> Visibility="{Binding IsValid, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" /> « Invalid »
</TextBlock> </TextBlock>
</Grid> </Grid>
<TextBlock FontStyle="Italic" </Button>
Visibility="{Binding IsValid, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"> </StackPanel>
« Invalid »
</TextBlock>
</Grid>
</Button>
</UserControl> </UserControl>

View File

@ -25,6 +25,7 @@ namespace Artemis.UI.Shared.Input
private bool _isDataModelViewModelOpen; private bool _isDataModelViewModelOpen;
private bool _isEnabled = true; private bool _isEnabled = true;
private string _placeholder = "Select a property"; private string _placeholder = "Select a property";
private bool _displaySwitchButton;
internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService) internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService)
{ {
@ -56,6 +57,12 @@ namespace Artemis.UI.Shared.Input
set => SetAndNotify(ref _isEnabled, value); set => SetAndNotify(ref _isEnabled, value);
} }
public bool DisplaySwitchButton
{
get => _displaySwitchButton;
set => SetAndNotify(ref _displaySwitchButton, value);
}
public Type[] FilterTypes public Type[] FilterTypes
{ {
get => _filterTypes; get => _filterTypes;
@ -125,6 +132,13 @@ namespace Artemis.UI.Shared.Input
DataModelPath = dataModelPath != null ? new DataModelPath(dataModelPath) : null; DataModelPath = dataModelPath != null ? new DataModelPath(dataModelPath) : null;
} }
public void SwitchToStatic()
{
ChangeDataModelPath(null);
OnPropertySelected(new DataModelInputDynamicEventArgs(null));
OnSwitchToStaticRequested();
}
private void Initialize() private void Initialize()
{ {
// Get the data models // Get the data models
@ -167,12 +181,18 @@ namespace Artemis.UI.Shared.Input
#region Events #region Events
public event EventHandler<DataModelInputDynamicEventArgs> PropertySelected; public event EventHandler<DataModelInputDynamicEventArgs> PropertySelected;
public event EventHandler SwitchToStaticRequested;
protected virtual void OnPropertySelected(DataModelInputDynamicEventArgs e) protected virtual void OnPropertySelected(DataModelInputDynamicEventArgs e)
{ {
PropertySelected?.Invoke(this, e); PropertySelected?.Invoke(this, e);
} }
protected virtual void OnSwitchToStaticRequested()
{
SwitchToStaticRequested?.Invoke(this, EventArgs.Empty);
}
#endregion #endregion
} }
} }

View File

@ -22,24 +22,39 @@
</UserControl.Resources> </UserControl.Resources>
<Grid Margin="3 -4"> <Grid Margin="3 -4">
<Button Style="{StaticResource DataModelConditionButton}" <StackPanel Orientation="Horizontal" Visibility="{Binding InputViewModel, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
Background="{Binding ButtonBrush}" <Button Style="{StaticResource MaterialDesignFlatDarkBgButton}"
BorderBrush="{Binding ButtonBrush}" Height="22"
Margin="0 4" Padding="0"
Command="{s:Action ActivateInputViewModel}" Width="22"
HorizontalAlignment="Left" FontSize="12"
IsEnabled="{Binding IsEnabled}" materialDesign:ButtonAssist.CornerRadius="2 0 0 2"
Visibility="{Binding InputViewModel, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}"> Margin="0 0 -3 0"
<Grid> HorizontalAlignment="Left"
<StackPanel Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal"> ToolTip="Switch to data model value"
<ContentControl s:View.Model="{Binding DisplayViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" /> Command="{s:Action SwitchToDynamic}">
</StackPanel> <materialDesign:PackIcon Kind="SwapHorizontal" />
</Button>
<Button Style="{StaticResource DataModelConditionButton}"
materialDesign:ButtonAssist.CornerRadius="0 2 2 0"
Background="{Binding ButtonBrush}"
BorderBrush="{Binding ButtonBrush}"
Command="{s:Action ActivateInputViewModel}"
HorizontalAlignment="Left"
IsEnabled="{Binding IsEnabled}"
ToolTip="Click to edit value">
<Grid>
<StackPanel Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
<ContentControl s:View.Model="{Binding DisplayViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</StackPanel>
<TextBlock FontStyle="Italic" Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" />
</TextBlock>
</Grid>
</Button>
</StackPanel>
<TextBlock FontStyle="Italic" Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" />
</TextBlock>
</Grid>
</Button>
<Border BorderBrush="{Binding ButtonBrush}" <Border BorderBrush="{Binding ButtonBrush}"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
Visibility="{Binding InputViewModel, Converter={StaticResource NullToVisibilityConverter}}" Visibility="{Binding InputViewModel, Converter={StaticResource NullToVisibilityConverter}}"

View File

@ -17,11 +17,11 @@ namespace Artemis.UI.Shared.Input
private Brush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188)); private Brush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188));
private DataModelDisplayViewModel _displayViewModel; private DataModelDisplayViewModel _displayViewModel;
private DataModelInputViewModel _inputViewModel; private DataModelInputViewModel _inputViewModel;
private bool _isEnabled;
private string _placeholder = "Enter a value"; private string _placeholder = "Enter a value";
private DataModelPropertyAttribute _targetDescription; private DataModelPropertyAttribute _targetDescription;
private Type _targetType; private Type _targetType;
private object _value; private object _value;
private bool _isEnabled;
internal DataModelStaticViewModel(Type targetType, DataModelPropertyAttribute targetDescription, IDataModelUIService dataModelUIService) internal DataModelStaticViewModel(Type targetType, DataModelPropertyAttribute targetDescription, IDataModelUIService dataModelUIService)
{ {
@ -92,19 +92,6 @@ namespace Artemis.UI.Shared.Input
private set => SetAndNotify(ref _isEnabled, value); private set => SetAndNotify(ref _isEnabled, value);
} }
#region IDisposable
public void Dispose()
{
if (_rootView != null)
{
_rootView.MouseUp -= RootViewOnMouseUp;
_rootView.KeyUp -= RootViewOnKeyUp;
}
}
#endregion
public void ActivateInputViewModel() public void ActivateInputViewModel()
{ {
InputViewModel = _dataModelUIService.GetDataModelInputViewModel( InputViewModel = _dataModelUIService.GetDataModelInputViewModel(
@ -129,12 +116,17 @@ namespace Artemis.UI.Shared.Input
} }
// If the type changed, reset to the default type // If the type changed, reset to the default type
if (Value == null || !target.IsCastableFrom(Value.GetType())) if (Value == null || !TargetType.IsCastableFrom(Value.GetType()))
{
// Force the VM to close if it was open and apply the new value // Force the VM to close if it was open and apply the new value
ApplyFreeInput(target.GetDefault(), true); ApplyFreeInput(TargetType.GetDefault(), true);
} }
public void SwitchToDynamic()
{
InputViewModel?.Cancel();
ApplyFreeInput(TargetType.GetDefault(), true);
OnSwitchToDynamicRequested();
} }
private void ApplyFreeInput(object value, bool submitted) private void ApplyFreeInput(object value, bool submitted)
@ -146,6 +138,19 @@ namespace Artemis.UI.Shared.Input
Value = value; Value = value;
} }
#region IDisposable
public void Dispose()
{
if (_rootView != null)
{
_rootView.MouseUp -= RootViewOnMouseUp;
_rootView.KeyUp -= RootViewOnKeyUp;
}
}
#endregion
#region Event handlers #region Event handlers
private void RootViewOnKeyUp(object sender, KeyEventArgs e) private void RootViewOnKeyUp(object sender, KeyEventArgs e)
@ -173,12 +178,18 @@ namespace Artemis.UI.Shared.Input
#region Events #region Events
public event EventHandler<DataModelInputStaticEventArgs> ValueUpdated; public event EventHandler<DataModelInputStaticEventArgs> ValueUpdated;
public event EventHandler SwitchToDynamicRequested;
protected virtual void OnValueUpdated(DataModelInputStaticEventArgs e) protected virtual void OnValueUpdated(DataModelInputStaticEventArgs e)
{ {
ValueUpdated?.Invoke(this, e); ValueUpdated?.Invoke(this, e);
} }
protected virtual void OnSwitchToDynamicRequested()
{
SwitchToDynamicRequested?.Invoke(this, EventArgs.Empty);
}
#endregion #endregion
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Ninject; using Ninject;
@ -13,7 +14,7 @@ namespace Artemis.UI.Shared.Services
ILayerProperty SelectedDataBinding { get; } ILayerProperty SelectedDataBinding { get; }
TimeSpan CurrentTime { get; set; } TimeSpan CurrentTime { get; set; }
int PixelsPerSecond { get; set; } int PixelsPerSecond { get; set; }
IReadOnlyList<PropertyInputRegistration> RegisteredPropertyEditors { get; } ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors { get; }
IKernel Kernel { get; } IKernel Kernel { get; }
void ChangeSelectedProfile(Profile profile); void ChangeSelectedProfile(Profile profile);
void UpdateSelectedProfile(); void UpdateSelectedProfile();

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
@ -32,7 +33,7 @@ namespace Artemis.UI.Shared.Services
} }
public IKernel Kernel { get; } public IKernel Kernel { get; }
public IReadOnlyList<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly(); public ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly();
public Profile SelectedProfile { get; private set; } public Profile SelectedProfile { get; private set; }
public RenderProfileElement SelectedProfileElement { get; private set; } public RenderProfileElement SelectedProfileElement { get; private set; }
public ILayerProperty SelectedDataBinding { get; private set; } public ILayerProperty SelectedDataBinding { get; private set; }

View File

@ -98,42 +98,9 @@
</Button.Style> </Button.Style>
<Button.ContextMenu> <Button.ContextMenu>
<ContextMenu> <ContextMenu>
<ContextMenu.Resources> <MenuItem Header="Add condition" ToolTip="A condition that compares with another value" Command="{s:Action AddCondition}">
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</ContextMenu.Resources>
<MenuItem Header="Add static condition"
ToolTip="A condition that compares with a static input"
Command="{s:Action AddCondition}"
CommandParameter="Static">
<MenuItem.Icon> <MenuItem.Icon>
<materialDesign:PackIcon Kind="FormTextarea" /> <materialDesign:PackIcon Kind="Equal" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add dynamic condition"
ToolTip="A condition that compares with a data model property"
Command="{s:Action AddCondition}"
CommandParameter="Dynamic">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Link" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add self condition"
ToolTip="A condition that compares with a property contained in the list"
Command="{s:Action AddCondition}"
CommandParameter="DynamicList"
IsEnabled="{Binding Data.DynamicListConditionSupported, Source={StaticResource DataContextProxy}}"
Visibility="{Binding Data.IsListGroup, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Source={StaticResource DataContextProxy}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="UndoVariant" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add list condition"
ToolTip="A condition that evaluates on items in a list"
Command="{s:Action AddCondition}"
CommandParameter="List"
Visibility="{Binding Data.IsListGroup, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Source={StaticResource DataContextProxy}}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormatListBulleted" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}"> <MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}">

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract; using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
using Artemis.UI.Screens.ProfileEditor.DisplayConditions; using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
@ -26,11 +27,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
: base(dataModelConditionGroup) : base(dataModelConditionGroup)
{ {
IsListGroup = isListGroup; IsListGroup = isListGroup;
if (IsListGroup)
DynamicListConditionSupported = !((DataModelConditionList) dataModelConditionGroup.Parent).IsPrimitiveList;
else
DynamicListConditionSupported = false;
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory; _dataModelConditionsVmFactory = dataModelConditionsVmFactory;
@ -44,7 +40,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
} }
public bool IsListGroup { get; } public bool IsListGroup { get; }
public bool DynamicListConditionSupported { get; }
public DataModelConditionGroup DataModelConditionGroup => (DataModelConditionGroup) Model; public DataModelConditionGroup DataModelConditionGroup => (DataModelConditionGroup) Model;
public bool IsRootGroup public bool IsRootGroup
@ -71,26 +66,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
} }
public void AddCondition(string type) public void AddCondition()
{ {
if (type == "Static") if (!IsListGroup)
{ DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
if (!IsListGroup) else
DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Static)); DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
else
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ListRightSideType.Static));
}
else if (type == "Dynamic")
{
if (!IsListGroup)
DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
else
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ListRightSideType.Dynamic));
}
else if (type == "DynamicList" && IsListGroup)
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ListRightSideType.DynamicList));
else if (type == "List" && !IsListGroup)
DataModelConditionGroup.AddChild(new DataModelConditionList(DataModelConditionGroup));
Update(); Update();
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
@ -135,9 +116,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
break; break;
} }
} }
if (viewModels.Any()) if (viewModels.Any())
Items.AddRange(viewModels); Items.AddRange(viewModels);
// Ensure the items are in the same order as on the model
((BindableCollection<DataModelConditionViewModel>) Items).Sort(i => Model.Children.IndexOf(i.Model));
foreach (DataModelConditionViewModel childViewModel in Items) foreach (DataModelConditionViewModel childViewModel in Items)
childViewModel.Update(); childViewModel.Update();
@ -147,6 +132,36 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
OnUpdated(); OnUpdated();
} }
public void ConvertToConditionList(DataModelConditionPredicateViewModel predicateViewModel)
{
// Store the old index and remove the old predicate
int index = DataModelConditionGroup.Children.IndexOf(predicateViewModel.Model);
DataModelConditionGroup.RemoveChild(predicateViewModel.Model);
// Insert a list in the same position
DataModelConditionList list = new DataModelConditionList(DataModelConditionGroup);
list.UpdateList(predicateViewModel.LeftSideSelectionViewModel.DataModelPath);
DataModelConditionGroup.AddChild(list, index);
// Update to switch the VMs
Update();
}
public void ConvertToPredicate(DataModelConditionListViewModel listViewModel)
{
// Store the old index and remove the old predicate
int index = DataModelConditionGroup.Children.IndexOf(listViewModel.Model);
DataModelConditionGroup.RemoveChild(listViewModel.Model);
// Insert a list in the same position
DataModelConditionPredicate predicate = new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic);
predicate.UpdateLeftSide(listViewModel.TargetSelectionViewModel.DataModelPath);
DataModelConditionGroup.AddChild(predicate, index);
// Update to switch the VMs
Update();
}
public event EventHandler Updated; public event EventHandler Updated;
protected virtual void OnUpdated() protected virtual void OnUpdated()

View File

@ -135,39 +135,27 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
SelectedOperator = DataModelConditionListPredicate.Operator; SelectedOperator = DataModelConditionListPredicate.Operator;
if (SelectedOperator == null || !SelectedOperator.SupportsRightSide) if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStaticViewModel();
DisposeRightSideDynamic(); DisposeRightSideDynamicViewModel();
} }
// Ensure the right side has the proper VM // Ensure the right side has the proper VM
ListRightSideType type = DataModelConditionListPredicate.PredicateType; if (DataModelConditionListPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide)
if ((type == ListRightSideType.Dynamic || type == ListRightSideType.DynamicList) && SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStaticViewModel();
if (RightSideSelectionViewModel == null) if (RightSideSelectionViewModel == null)
{ CreateRightSideSelectionViewModel();
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList)
RightSideSelectionViewModel.ChangeDataModel((DataModelPropertiesViewModel) GetListDataModel());
}
RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionListPredicate.RightPath); RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionListPredicate.RightPath);
} }
else if (SelectedOperator.SupportsRightSide) else if (SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideDynamic(); DisposeRightSideDynamicViewModel();
if (RightSideInputViewModel == null) if (RightSideInputViewModel == null)
{ CreateRightSideInputViewModel(leftSideType);
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription());
RightSideInputViewModel.Value = DataModelConditionListPredicate.RightStaticValue;
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
}
RightSideInputViewModel.Value = DataModelConditionListPredicate.RightStaticValue;
if (RightSideInputViewModel.TargetType != leftSideType) if (RightSideInputViewModel.TargetType != leftSideType)
RightSideInputViewModel.UpdateTargetType(leftSideType); RightSideInputViewModel.UpdateTargetType(leftSideType);
} }
@ -184,12 +172,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void ApplyRightSideDynamic() public void ApplyRightSideDynamic()
{ {
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath);
DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath);
else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList)
DataModelConditionListPredicate.UpdateRightSideDynamicList(RightSideSelectionViewModel.DataModelPath);
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
Update(); Update();
} }
@ -232,6 +217,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
ApplyOperator(); ApplyOperator();
} }
#region IDisposable
public void Dispose()
{
if (!_isPrimitiveList)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
}
DisposeRightSideStaticViewModel();
DisposeRightSideDynamicViewModel();
}
#endregion
#region Event handlers
private void LeftSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) private void LeftSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
{ {
ApplyLeftSide(); ApplyLeftSide();
@ -247,36 +250,59 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
ApplyRightSideStatic(e.Value); ApplyRightSideStatic(e.Value);
} }
private void DisposeRightSideStatic() private void RightSideSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e)
{ {
if (RightSideInputViewModel != null) DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Static;
{ Update();
RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered;
RightSideInputViewModel.Dispose();
RightSideInputViewModel = null;
}
} }
private void DisposeRightSideDynamic() private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
{ {
if (RightSideSelectionViewModel != null) DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Dynamic;
{ Update();
RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected;
RightSideSelectionViewModel.Dispose();
RightSideSelectionViewModel = null;
}
} }
public void Dispose() #endregion
{
if (!_isPrimitiveList)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
}
DisposeRightSideDynamic(); #region View model management
DisposeRightSideStatic();
private void CreateRightSideSelectionViewModel()
{
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideSelectionViewModel.DisplaySwitchButton = true;
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
RightSideSelectionViewModel.SwitchToStaticRequested += RightSideSelectionViewModelOnSwitchToStaticRequested;
} }
private void CreateRightSideInputViewModel(Type leftSideType)
{
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription());
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
RightSideInputViewModel.SwitchToDynamicRequested += RightSideInputViewModelOnSwitchToDynamicRequested;
}
private void DisposeRightSideStaticViewModel()
{
if (RightSideInputViewModel == null)
return;
RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered;
RightSideInputViewModel.SwitchToDynamicRequested -= RightSideInputViewModelOnSwitchToDynamicRequested;
RightSideInputViewModel.Dispose();
RightSideInputViewModel = null;
}
private void DisposeRightSideDynamicViewModel()
{
if (RightSideSelectionViewModel == null)
return;
RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected;
RightSideSelectionViewModel.SwitchToStaticRequested -= RightSideSelectionViewModelOnSwitchToStaticRequested;
RightSideSelectionViewModel.Dispose();
RightSideSelectionViewModel = null;
}
#endregion
} }
} }

View File

@ -58,12 +58,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
} }
public void AddCondition(string type) public void AddCondition()
{ {
if (type == "Static") DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Dynamic));
DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Static));
else if (type == "Dynamic")
DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Dynamic));
Update(); Update();
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
@ -86,16 +83,28 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void Initialize() public void Initialize()
{ {
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
TargetSelectionViewModel.FilterTypes = new[] {typeof(IEnumerable<>)}; TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
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));
supportedInputTypes.Add(typeof(IEnumerable<>));
TargetSelectionViewModel.FilterTypes = supportedInputTypes.ToArray();
TargetSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188)); TargetSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188));
TargetSelectionViewModel.Placeholder = "Select a list"; TargetSelectionViewModel.Placeholder = "Select a list";
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
Update(); Update();
} }
public void ApplyList() public void ApplyList()
{ {
if (!TargetSelectionViewModel.DataModelPath.GetPropertyType().IsGenericEnumerable())
{
if (Parent is DataModelConditionGroupViewModel groupViewModel)
groupViewModel.ConvertToPredicate(this);
return;
}
DataModelConditionList.UpdateList(TargetSelectionViewModel.DataModelPath); DataModelConditionList.UpdateList(TargetSelectionViewModel.DataModelPath);
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
@ -125,6 +134,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
viewModel.IsRootGroup = true; viewModel.IsRootGroup = true;
viewModels.Add(viewModel); viewModels.Add(viewModel);
} }
if (viewModels.Any()) if (viewModels.Any())
Items.AddRange(viewModels); Items.AddRange(viewModels);

View File

@ -96,7 +96,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors; IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList(); _supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes)); _supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
_supportedInputTypes.Add(typeof(IEnumerable<>));
Update(); Update();
} }
@ -115,33 +115,25 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
SelectedOperator = DataModelConditionPredicate.Operator; SelectedOperator = DataModelConditionPredicate.Operator;
if (SelectedOperator == null || !SelectedOperator.SupportsRightSide) if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStaticViewModel();
DisposeRightSideDynamic(); DisposeRightSideDynamicViewModel();
} }
// Ensure the right side has the proper VM // Ensure the right side has the proper VM
if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide) if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStaticViewModel();
if (RightSideSelectionViewModel == null) if (RightSideSelectionViewModel == null)
{ CreateRightSideSelectionViewModel();
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
}
RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionPredicate.RightPath); RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionPredicate.RightPath);
RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
} }
else if (SelectedOperator.SupportsRightSide) else if (SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideDynamic(); DisposeRightSideDynamicViewModel();
if (RightSideInputViewModel == null) if (RightSideInputViewModel == null)
{ CreateRightSideInputViewModel(leftSideType);
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription());
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
}
RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue; RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue;
if (RightSideInputViewModel.TargetType != leftSideType) if (RightSideInputViewModel.TargetType != leftSideType)
@ -151,6 +143,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void ApplyLeftSide() public void ApplyLeftSide()
{ {
if (LeftSideSelectionViewModel.DataModelPath.GetPropertyType().IsGenericEnumerable())
{
if (Parent is DataModelConditionGroupViewModel groupViewModel)
groupViewModel.ConvertToConditionList(this);
return;
}
DataModelConditionPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath); DataModelConditionPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath);
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
@ -182,6 +181,75 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
Update(); Update();
} }
private void ExecuteSelectOperatorCommand(object context)
{
if (!(context is ConditionOperator DataModelConditionOperator))
return;
SelectedOperator = DataModelConditionOperator;
ApplyOperator();
}
#region IDisposable
public void Dispose()
{
if (LeftSideSelectionViewModel != null)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
LeftSideSelectionViewModel = null;
}
DisposeRightSideStaticViewModel();
DisposeRightSideDynamicViewModel();
}
#endregion
#region View model creation
private void CreateRightSideSelectionViewModel()
{
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideSelectionViewModel.DisplaySwitchButton = true;
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
RightSideSelectionViewModel.SwitchToStaticRequested += RightSideSelectionViewModelOnSwitchToStaticRequested;
}
private void CreateRightSideInputViewModel(Type leftSideType)
{
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription());
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
RightSideInputViewModel.SwitchToDynamicRequested += RightSideInputViewModelOnSwitchToDynamicRequested;
}
private void DisposeRightSideStaticViewModel()
{
if (RightSideInputViewModel == null)
return;
RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered;
RightSideInputViewModel.SwitchToDynamicRequested -= RightSideInputViewModelOnSwitchToDynamicRequested;
RightSideInputViewModel.Dispose();
RightSideInputViewModel = null;
}
private void DisposeRightSideDynamicViewModel()
{
if (RightSideSelectionViewModel == null)
return;
RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected;
RightSideSelectionViewModel.SwitchToStaticRequested -= RightSideSelectionViewModelOnSwitchToStaticRequested;
RightSideSelectionViewModel.Dispose();
RightSideSelectionViewModel = null;
}
#endregion
#region Event handlers
private void LeftSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) private void LeftSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
{ {
ApplyLeftSide(); ApplyLeftSide();
@ -197,46 +265,19 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
ApplyRightSideStatic(e.Value); ApplyRightSideStatic(e.Value);
} }
private void ExecuteSelectOperatorCommand(object context) private void RightSideSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e)
{ {
if (!(context is ConditionOperator DataModelConditionOperator)) DataModelConditionPredicate.PredicateType = ProfileRightSideType.Static;
return; Update();
SelectedOperator = DataModelConditionOperator;
ApplyOperator();
} }
private void DisposeRightSideStatic()
private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
{ {
if (RightSideInputViewModel != null) DataModelConditionPredicate.PredicateType = ProfileRightSideType.Dynamic;
{ Update();
RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered;
RightSideInputViewModel.Dispose();
RightSideInputViewModel = null;
}
} }
private void DisposeRightSideDynamic() #endregion
{
if (RightSideSelectionViewModel != null)
{
RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected;
RightSideSelectionViewModel.Dispose();
RightSideSelectionViewModel = null;
}
}
public void Dispose()
{
if (LeftSideSelectionViewModel != null)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
LeftSideSelectionViewModel = null;
}
DisposeRightSideStatic();
DisposeRightSideDynamic();
}
} }
} }

View File

@ -56,17 +56,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
#endregion #endregion
public void AddCondition(string type)
{
DataBindingCondition<TLayerProperty, TProperty> condition = ConditionalDataBinding.AddCondition();
// Find the VM of the new condition
DataBindingConditionViewModel<TLayerProperty, TProperty> viewModel = ConditionViewModels.First(c => c.DataBindingCondition == condition);
viewModel.ActiveItem.AddCondition(type);
_profileEditorService.UpdateSelectedProfileElement();
}
private void UpdateConditionViewModels() private void UpdateConditionViewModels()
{ {
_updating = true; _updating = true;

View File

@ -57,7 +57,7 @@
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding SidebarViewModel.IsSidebarOpen}"> <materialDesign:DrawerHost IsLeftDrawerOpen="{Binding SidebarViewModel.IsSidebarOpen}">
<materialDesign:DrawerHost.LeftDrawerContent> <materialDesign:DrawerHost.LeftDrawerContent>
<ContentControl s:View.Model="{Binding SidebarViewModel}" Width="220" ClipToBounds="False" /> <ContentControl s:View.Model="{Binding SidebarViewModel}" Width="280" ClipToBounds="False" />
</materialDesign:DrawerHost.LeftDrawerContent> </materialDesign:DrawerHost.LeftDrawerContent>
<DockPanel> <DockPanel>
<mde:AppBar Type="Dense" <mde:AppBar Type="Dense"

View File

@ -12,17 +12,29 @@
d:DataContext="{d:DesignInstance sidebar:SidebarViewModel}"> d:DataContext="{d:DesignInstance sidebar:SidebarViewModel}">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<!-- no idea why this has to be 0 --> <RowDefinition Height="Auto" />
<RowDefinition Height="0" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Grid.Row="0" Grid.RowSpan="2" Source="/Resources/Images/Sidebar/sidebar-header.png" Stretch="Uniform" VerticalAlignment="Top" /> <Image Grid.Row="0"
<TextBlock Grid.Row="1" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="15" materialDesign:ShadowAssist.ShadowDepth="Depth1" Text="{Binding ActiveModules}" /> Grid.RowSpan="2"
Source="/Resources/Images/Sidebar/sidebar-header.png"
Stretch="None"
VerticalAlignment="Top" Height="120" />
<TextBlock Grid.Row="1"
Style="{StaticResource MaterialDesignHeadline6TextBlock}"
Margin="15"
materialDesign:ShadowAssist.ShadowDepth="Depth1"
Text="{Binding ActiveModules}"
VerticalAlignment="Bottom" />
<controls:SideNavigation Grid.Row="3" Items="{Binding SidebarItems}" SelectedItem="{Binding SelectedItem}" WillSelectNavigationItemCommand="{s:Action SelectItem}" Margin="0 5 0 0" /> <controls:SideNavigation Grid.Row="3"
Items="{Binding SidebarItems}"
SelectedItem="{Binding SelectedItem}"
WillSelectNavigationItemCommand="{s:Action SelectItem}"
Margin="0 5 0 0" />
</Grid> </Grid>
</UserControl> </UserControl>