From 879d19e4ea8e73fb3ce35736aefb5a9a9b83dffe Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 13 Oct 2020 20:51:53 +0200 Subject: [PATCH] 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 --- .../Abstract/DataModelConditionPart.cs | 12 +- .../DataModelConditionListPredicate.cs | 96 ++++-------- .../Modes/ConditionalDataBinding.cs | 3 +- .../DataBindings/Modes/DirectDataBinding.cs | 3 +- .../Profile/LayerProperties/LayerProperty.cs | 3 +- .../Input/DataModelDynamicView.xaml | 95 +++++++----- .../Input/DataModelDynamicViewModel.cs | 20 +++ .../Input/DataModelStaticView.xaml | 49 +++--- .../Input/DataModelStaticViewModel.cs | 59 +++++--- .../Interfaces/IProfileEditorService.cs | 3 +- .../Services/ProfileEditorService.cs | 3 +- .../DataModelConditionGroupView.xaml | 37 +---- .../DataModelConditionGroupViewModel.cs | 65 ++++---- ...ataModelConditionListPredicateViewModel.cs | 122 +++++++++------ .../DataModelConditionListViewModel.cs | 26 +++- .../DataModelConditionPredicateViewModel.cs | 141 +++++++++++------- .../ConditionalDataBindingModeViewModel.cs | 11 -- src/Artemis.UI/Screens/RootView.xaml | 2 +- .../Screens/Sidebar/SidebarView.xaml | 22 ++- 19 files changed, 439 insertions(+), 333 deletions(-) diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs index f16df9e7d..bca0ebc4d 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPart.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Artemis.Core.Services; +using System.Collections.ObjectModel; using Artemis.Storage.Entities.Profile.Abstract; namespace Artemis.Core @@ -20,18 +20,22 @@ namespace Artemis.Core /// /// Gets the children of this part /// - public IReadOnlyList Children => _children.AsReadOnly(); + public ReadOnlyCollection Children => _children.AsReadOnly(); /// /// Adds a child to the display condition part's collection /// /// - public void AddChild(DataModelConditionPart dataModelConditionPart) + /// An optional index at which to insert the condition + public void AddChild(DataModelConditionPart dataModelConditionPart, int? index = null) { if (!_children.Contains(dataModelConditionPart)) { dataModelConditionPart.Parent = this; - _children.Add(dataModelConditionPart); + if (index != null) + _children.Insert(index.Value, dataModelConditionPart); + else + _children.Add(dataModelConditionPart); } } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs index baabcf6be..cf35171cf 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs @@ -17,7 +17,7 @@ namespace Artemis.Core /// /// /// - public DataModelConditionListPredicate(DataModelConditionPart parent, ListRightSideType predicateType) + public DataModelConditionListPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType) { Parent = parent; PredicateType = predicateType; @@ -32,7 +32,7 @@ namespace Artemis.Core { Parent = parent; Entity = entity; - PredicateType = (ListRightSideType) entity.PredicateType; + PredicateType = (ProfileRightSideType) entity.PredicateType; DataModelConditionList = null!; ApplyParentList(); @@ -42,7 +42,7 @@ namespace Artemis.Core /// /// Gets or sets the predicate type /// - public ListRightSideType PredicateType { get; set; } + public ProfileRightSideType PredicateType { get; set; } /// /// Gets the operator @@ -66,7 +66,7 @@ namespace Artemis.Core /// /// Gets the right static value, only used it is - /// + /// /// public object? RightStaticValue { get; private set; } @@ -92,11 +92,10 @@ namespace Artemis.Core } /// - /// Updates the right side of the predicate using a path to a value inside the list item, makes the predicate dynamic - /// and re-compiles the expression + /// Updates the right side of the predicate using a path and makes the predicate dynamic /// - /// The path pointing to the right side value inside the list - public void UpdateRightSideDynamicList(DataModelPath? path) + /// The path pointing to the right side value + public void UpdateRightSideDynamic(DataModelPath? path) { if (path != null && !path.IsValid) throw new ArtemisCoreException("Cannot update right side of predicate to an invalid path"); @@ -104,20 +103,7 @@ namespace Artemis.Core RightPath?.Dispose(); RightPath = path != null ? new DataModelPath(path) : null; - PredicateType = ListRightSideType.DynamicList; - } - - /// - /// 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 - /// - /// The path pointing to the right side value inside the list - public void UpdateRightSideDynamic(DataModelPath? path) - { - RightPath?.Dispose(); - RightPath = path; - - PredicateType = ListRightSideType.Dynamic; + PredicateType = ProfileRightSideType.Dynamic; } /// @@ -126,7 +112,7 @@ namespace Artemis.Core /// The right side value to use public void UpdateRightSideStatic(object? staticValue) { - PredicateType = ListRightSideType.Static; + PredicateType = ProfileRightSideType.Static; RightPath?.Dispose(); RightPath = null; @@ -214,7 +200,7 @@ namespace Artemis.Core return false; // Compare with a static value - if (PredicateType == ListRightSideType.Static) + if (PredicateType == ProfileRightSideType.Static) { object? leftSideValue = GetListPathValue(LeftPath, target); if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null) @@ -227,10 +213,13 @@ namespace Artemis.Core return false; // 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()); - if (PredicateType == ListRightSideType.DynamicList) - return Operator.Evaluate(GetListPathValue(LeftPath, target), GetListPathValue(RightPath, target)); + } return false; } @@ -317,17 +306,22 @@ namespace Artemis.Core } // Right side dynamic - if (PredicateType == ListRightSideType.Dynamic && Entity.RightPath != null) - RightPath = new DataModelPath(null, Entity.RightPath); - // Right side dynamic inside the list - else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPath != null) + if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null) { - RightPath = DataModelConditionList.ListType != null - ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), 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) + { + 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 - else if (PredicateType == ListRightSideType.Static && Entity.RightStaticValue != null) + else if (PredicateType == ProfileRightSideType.Static && Entity.RightStaticValue != null) try { if (LeftPath != null && LeftPath.IsValid) @@ -374,7 +368,7 @@ namespace Artemis.Core private void ValidateRightSide() { Type? leftType = LeftPath?.GetPropertyType(); - if (PredicateType == ListRightSideType.Dynamic) + if (PredicateType == ProfileRightSideType.Dynamic) { if (RightPath == null || !RightPath.IsValid) return; @@ -383,15 +377,6 @@ namespace Artemis.Core if (leftType != null && !leftType.IsCastableFrom(rightSideType)) 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 { if (RightStaticValue != null && (leftType == null || leftType.IsCastableFrom(RightStaticValue.GetType()))) @@ -455,25 +440,4 @@ namespace Artemis.Core #endregion } - - /// - /// An enum defining the right side type of a profile entity - /// - public enum ListRightSideType - { - /// - /// A static right side value - /// - Static, - - /// - /// A dynamic right side value based on a path in a data model - /// - Dynamic, - - /// - /// A dynamic right side value based on a path in the list - /// - DynamicList - } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs index d4b4e046b..7b4e26a5b 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Artemis.Storage.Entities.Profile.DataBindings; @@ -25,7 +26,7 @@ namespace Artemis.Core /// /// Gets a list of conditions applied to this data binding /// - public IReadOnlyList> Conditions => _conditions.AsReadOnly(); + public ReadOnlyCollection> Conditions => _conditions.AsReadOnly(); /// public DataBinding DataBinding { get; } diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs index f22ee61d5..9907f1175 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using Artemis.Storage.Entities.Profile.DataBindings; namespace Artemis.Core @@ -28,7 +29,7 @@ namespace Artemis.Core /// /// Gets a list of modifiers applied to this data binding /// - public IReadOnlyList> Modifiers => _modifiers.AsReadOnly(); + public ReadOnlyCollection> Modifiers => _modifiers.AsReadOnly(); internal DirectDataBindingEntity Entity { get; } diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index 9338d25ac..910ca1324 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; using Artemis.Storage.Entities.Profile; @@ -215,7 +216,7 @@ namespace Artemis.Core /// /// Gets a read-only list of all the keyframes on this layer property /// - public IReadOnlyList> Keyframes => _keyframes.AsReadOnly(); + public ReadOnlyCollection> Keyframes => _keyframes.AsReadOnly(); /// /// Gets the current keyframe in the timeline according to the current progress diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml index d2b351696..829f89485 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml @@ -6,6 +6,7 @@ xmlns:shared="clr-namespace:Artemis.UI.Shared" xmlns:input="clr-namespace:Artemis.UI.Shared.Input" xmlns:s="https://github.com/canton7/Stylet" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance input:DataModelDynamicViewModel}"> @@ -24,45 +25,71 @@ + - + + + + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs index 79f00613b..8e8b9dadc 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs @@ -25,6 +25,7 @@ namespace Artemis.UI.Shared.Input private bool _isDataModelViewModelOpen; private bool _isEnabled = true; private string _placeholder = "Select a property"; + private bool _displaySwitchButton; internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService) { @@ -56,6 +57,12 @@ namespace Artemis.UI.Shared.Input set => SetAndNotify(ref _isEnabled, value); } + public bool DisplaySwitchButton + { + get => _displaySwitchButton; + set => SetAndNotify(ref _displaySwitchButton, value); + } + public Type[] FilterTypes { get => _filterTypes; @@ -125,6 +132,13 @@ namespace Artemis.UI.Shared.Input DataModelPath = dataModelPath != null ? new DataModelPath(dataModelPath) : null; } + public void SwitchToStatic() + { + ChangeDataModelPath(null); + OnPropertySelected(new DataModelInputDynamicEventArgs(null)); + OnSwitchToStaticRequested(); + } + private void Initialize() { // Get the data models @@ -167,12 +181,18 @@ namespace Artemis.UI.Shared.Input #region Events public event EventHandler PropertySelected; + public event EventHandler SwitchToStaticRequested; protected virtual void OnPropertySelected(DataModelInputDynamicEventArgs e) { PropertySelected?.Invoke(this, e); } + protected virtual void OnSwitchToStaticRequested() + { + SwitchToStaticRequested?.Invoke(this, EventArgs.Empty); + } + #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticView.xaml b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticView.xaml index 6bc1c6987..1e78b80e0 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticView.xaml +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticView.xaml @@ -22,24 +22,39 @@ - + + + + + + + + _buttonBrush; set => SetAndNotify(ref _buttonBrush, value); } - + public DataModelDisplayViewModel DisplayViewModel { get => _displayViewModel; @@ -92,19 +92,6 @@ namespace Artemis.UI.Shared.Input private set => SetAndNotify(ref _isEnabled, value); } - #region IDisposable - - public void Dispose() - { - if (_rootView != null) - { - _rootView.MouseUp -= RootViewOnMouseUp; - _rootView.KeyUp -= RootViewOnKeyUp; - } - } - - #endregion - public void ActivateInputViewModel() { InputViewModel = _dataModelUIService.GetDataModelInputViewModel( @@ -127,16 +114,21 @@ namespace Artemis.UI.Shared.Input ApplyFreeInput(null, true); return; } - - // If the type changed, reset to the default type - if (Value == null || !target.IsCastableFrom(Value.GetType())) - { - // Force the VM to close if it was open and apply the new value - ApplyFreeInput(target.GetDefault(), true); - } + // If the type changed, reset to the default type + if (Value == null || !TargetType.IsCastableFrom(Value.GetType())) + // Force the VM to close if it was open and apply the new value + ApplyFreeInput(TargetType.GetDefault(), true); } - + + public void SwitchToDynamic() + { + InputViewModel?.Cancel(); + ApplyFreeInput(TargetType.GetDefault(), true); + + OnSwitchToDynamicRequested(); + } + private void ApplyFreeInput(object value, bool submitted) { if (submitted) @@ -146,6 +138,19 @@ namespace Artemis.UI.Shared.Input Value = value; } + #region IDisposable + + public void Dispose() + { + if (_rootView != null) + { + _rootView.MouseUp -= RootViewOnMouseUp; + _rootView.KeyUp -= RootViewOnKeyUp; + } + } + + #endregion + #region Event handlers private void RootViewOnKeyUp(object sender, KeyEventArgs e) @@ -173,12 +178,18 @@ namespace Artemis.UI.Shared.Input #region Events public event EventHandler ValueUpdated; + public event EventHandler SwitchToDynamicRequested; protected virtual void OnValueUpdated(DataModelInputStaticEventArgs e) { ValueUpdated?.Invoke(this, e); } + protected virtual void OnSwitchToDynamicRequested() + { + SwitchToDynamicRequested?.Invoke(this, EventArgs.Empty); + } + #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs index 85cf152e0..8cb46338d 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using Artemis.Core; using Artemis.Core.Modules; using Ninject; @@ -13,7 +14,7 @@ namespace Artemis.UI.Shared.Services ILayerProperty SelectedDataBinding { get; } TimeSpan CurrentTime { get; set; } int PixelsPerSecond { get; set; } - IReadOnlyList RegisteredPropertyEditors { get; } + ReadOnlyCollection RegisteredPropertyEditors { get; } IKernel Kernel { get; } void ChangeSelectedProfile(Profile profile); void UpdateSelectedProfile(); diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index a637b7049..f1dedc4c3 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Artemis.Core; using Artemis.Core.Modules; @@ -32,7 +33,7 @@ namespace Artemis.UI.Shared.Services } public IKernel Kernel { get; } - public IReadOnlyList RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly(); + public ReadOnlyCollection RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly(); public Profile SelectedProfile { get; private set; } public RenderProfileElement SelectedProfileElement { get; private set; } public ILayerProperty SelectedDataBinding { get; private set; } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml index 56350154b..51db5e501 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml @@ -98,42 +98,9 @@ - - - - + - - - - - - - - - - - - - - - - + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs index bad970ea8..48dbb28b9 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Artemis.Core; +using Artemis.UI.Extensions; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract; using Artemis.UI.Screens.ProfileEditor.DisplayConditions; @@ -26,11 +27,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions : base(dataModelConditionGroup) { IsListGroup = isListGroup; - if (IsListGroup) - DynamicListConditionSupported = !((DataModelConditionList) dataModelConditionGroup.Parent).IsPrimitiveList; - else - DynamicListConditionSupported = false; - _profileEditorService = profileEditorService; _dataModelConditionsVmFactory = dataModelConditionsVmFactory; @@ -44,7 +40,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions } public bool IsListGroup { get; } - public bool DynamicListConditionSupported { get; } public DataModelConditionGroup DataModelConditionGroup => (DataModelConditionGroup) Model; public bool IsRootGroup @@ -71,26 +66,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions _profileEditorService.UpdateSelectedProfileElement(); } - public void AddCondition(string type) + public void AddCondition() { - if (type == "Static") - { - if (!IsListGroup) - DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Static)); - 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)); + if (!IsListGroup) + DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic)); + else + DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic)); Update(); _profileEditorService.UpdateSelectedProfileElement(); @@ -135,9 +116,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions break; } } + if (viewModels.Any()) Items.AddRange(viewModels); + // Ensure the items are in the same order as on the model + ((BindableCollection) Items).Sort(i => Model.Children.IndexOf(i.Model)); + foreach (DataModelConditionViewModel childViewModel in Items) childViewModel.Update(); @@ -147,6 +132,36 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions 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; protected virtual void OnUpdated() diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs index 7f8563952..bb6b3945f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs @@ -135,39 +135,27 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions SelectedOperator = DataModelConditionListPredicate.Operator; if (SelectedOperator == null || !SelectedOperator.SupportsRightSide) { - DisposeRightSideStatic(); - DisposeRightSideDynamic(); + DisposeRightSideStaticViewModel(); + DisposeRightSideDynamicViewModel(); } // Ensure the right side has the proper VM - ListRightSideType type = DataModelConditionListPredicate.PredicateType; - if ((type == ListRightSideType.Dynamic || type == ListRightSideType.DynamicList) && SelectedOperator.SupportsRightSide) + if (DataModelConditionListPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide) { - DisposeRightSideStatic(); + DisposeRightSideStaticViewModel(); if (RightSideSelectionViewModel == null) - { - RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); - RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush"); - RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected; - - if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) - RightSideSelectionViewModel.ChangeDataModel((DataModelPropertiesViewModel) GetListDataModel()); - } + CreateRightSideSelectionViewModel(); RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionListPredicate.RightPath); } else if (SelectedOperator.SupportsRightSide) { - DisposeRightSideDynamic(); + DisposeRightSideDynamicViewModel(); if (RightSideInputViewModel == null) - { - RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription()); - RightSideInputViewModel.Value = DataModelConditionListPredicate.RightStaticValue; - RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush"); - RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered; - } + CreateRightSideInputViewModel(leftSideType); + RightSideInputViewModel.Value = DataModelConditionListPredicate.RightStaticValue; if (RightSideInputViewModel.TargetType != leftSideType) RightSideInputViewModel.UpdateTargetType(leftSideType); } @@ -184,12 +172,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void ApplyRightSideDynamic() { - if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) - DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath); - else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) - DataModelConditionListPredicate.UpdateRightSideDynamicList(RightSideSelectionViewModel.DataModelPath); - + DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath); _profileEditorService.UpdateSelectedProfileElement(); + Update(); } @@ -232,6 +217,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions 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) { ApplyLeftSide(); @@ -247,36 +250,59 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions ApplyRightSideStatic(e.Value); } - private void DisposeRightSideStatic() + private void RightSideSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e) { - if (RightSideInputViewModel != null) - { - RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered; - RightSideInputViewModel.Dispose(); - RightSideInputViewModel = null; - } + DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Static; + Update(); } - private void DisposeRightSideDynamic() + private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e) { - if (RightSideSelectionViewModel != null) - { - RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected; - RightSideSelectionViewModel.Dispose(); - RightSideSelectionViewModel = null; - } + DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Dynamic; + Update(); } - public void Dispose() - { - if (!_isPrimitiveList) - { - LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected; - LeftSideSelectionViewModel.Dispose(); - } + #endregion - DisposeRightSideDynamic(); - DisposeRightSideStatic(); + #region View model management + + 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 } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs index 29fb3a4a6..ba875de53 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs @@ -58,12 +58,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions _profileEditorService.UpdateSelectedProfileElement(); } - public void AddCondition(string type) + public void AddCondition() { - if (type == "Static") - DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Static)); - else if (type == "Dynamic") - DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Dynamic)); + DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Dynamic)); Update(); _profileEditorService.UpdateSelectedProfileElement(); @@ -86,16 +83,28 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void Initialize() { TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); - TargetSelectionViewModel.FilterTypes = new[] {typeof(IEnumerable<>)}; + TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected; + + IReadOnlyCollection editors = _dataModelUIService.RegisteredDataModelEditors; + List 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.Placeholder = "Select a list"; - TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected; Update(); } public void ApplyList() { + if (!TargetSelectionViewModel.DataModelPath.GetPropertyType().IsGenericEnumerable()) + { + if (Parent is DataModelConditionGroupViewModel groupViewModel) + groupViewModel.ConvertToPredicate(this); + return; + } DataModelConditionList.UpdateList(TargetSelectionViewModel.DataModelPath); _profileEditorService.UpdateSelectedProfileElement(); @@ -109,7 +118,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions // Remove VMs of effects no longer applied on the layer Items.RemoveRange(Items.Where(c => !DataModelConditionList.Children.Contains(c.Model)).ToList()); - + if (DataModelConditionList.ListPath == null || !DataModelConditionList.ListPath.IsValid) return; @@ -125,6 +134,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions viewModel.IsRootGroup = true; viewModels.Add(viewModel); } + if (viewModels.Any()) Items.AddRange(viewModels); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs index 9129116e8..fbc90b37b 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs @@ -96,7 +96,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions IReadOnlyCollection editors = _dataModelUIService.RegisteredDataModelEditors; _supportedInputTypes = editors.Select(e => e.SupportedType).ToList(); _supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes)); - + _supportedInputTypes.Add(typeof(IEnumerable<>)); Update(); } @@ -115,33 +115,25 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions SelectedOperator = DataModelConditionPredicate.Operator; if (SelectedOperator == null || !SelectedOperator.SupportsRightSide) { - DisposeRightSideStatic(); - DisposeRightSideDynamic(); + DisposeRightSideStaticViewModel(); + DisposeRightSideDynamicViewModel(); } // Ensure the right side has the proper VM if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide) { - DisposeRightSideStatic(); + DisposeRightSideStaticViewModel(); if (RightSideSelectionViewModel == null) - { - RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); - RightSideSelectionViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush"); - RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected; - } + CreateRightSideSelectionViewModel(); RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionPredicate.RightPath); RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; } else if (SelectedOperator.SupportsRightSide) { - DisposeRightSideDynamic(); + DisposeRightSideDynamicViewModel(); if (RightSideInputViewModel == null) - { - RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription()); - RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush"); - RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered; - } + CreateRightSideInputViewModel(leftSideType); RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue; if (RightSideInputViewModel.TargetType != leftSideType) @@ -151,6 +143,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void ApplyLeftSide() { + if (LeftSideSelectionViewModel.DataModelPath.GetPropertyType().IsGenericEnumerable()) + { + if (Parent is DataModelConditionGroupViewModel groupViewModel) + groupViewModel.ConvertToConditionList(this); + return; + } + DataModelConditionPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath); _profileEditorService.UpdateSelectedProfileElement(); @@ -182,6 +181,75 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions 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) { ApplyLeftSide(); @@ -197,46 +265,19 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions ApplyRightSideStatic(e.Value); } - private void ExecuteSelectOperatorCommand(object context) + private void RightSideSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e) { - if (!(context is ConditionOperator DataModelConditionOperator)) - return; - - SelectedOperator = DataModelConditionOperator; - ApplyOperator(); + DataModelConditionPredicate.PredicateType = ProfileRightSideType.Static; + Update(); } - private void DisposeRightSideStatic() + + private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e) { - if (RightSideInputViewModel != null) - { - RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered; - RightSideInputViewModel.Dispose(); - RightSideInputViewModel = null; - } + DataModelConditionPredicate.PredicateType = ProfileRightSideType.Dynamic; + Update(); } - private void DisposeRightSideDynamic() - { - 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(); - } + #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/ConditionalDataBinding/ConditionalDataBindingModeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/ConditionalDataBinding/ConditionalDataBindingModeViewModel.cs index 680107b7f..49b36682a 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/ConditionalDataBinding/ConditionalDataBindingModeViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/ConditionalDataBinding/ConditionalDataBindingModeViewModel.cs @@ -56,17 +56,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio #endregion - public void AddCondition(string type) - { - DataBindingCondition condition = ConditionalDataBinding.AddCondition(); - - // Find the VM of the new condition - DataBindingConditionViewModel viewModel = ConditionViewModels.First(c => c.DataBindingCondition == condition); - viewModel.ActiveItem.AddCondition(type); - - _profileEditorService.UpdateSelectedProfileElement(); - } - private void UpdateConditionViewModels() { _updating = true; diff --git a/src/Artemis.UI/Screens/RootView.xaml b/src/Artemis.UI/Screens/RootView.xaml index b59cd308e..7cd6ac604 100644 --- a/src/Artemis.UI/Screens/RootView.xaml +++ b/src/Artemis.UI/Screens/RootView.xaml @@ -57,7 +57,7 @@ - + - - + - - + + - + \ No newline at end of file