From 5b4188ed1205d2f6e7ec6641c7ba327d72f6d5e9 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 8 Sep 2021 21:00:06 +0200 Subject: [PATCH] Display conditions - Events UI WIP --- .../Controls/DataModelPicker.xaml.cs | 25 +- .../DisplayConditionEventView.xaml | 150 ++++++ .../DisplayConditionEventViewModel.cs | 13 + .../DisplayConditionsView.xaml | 484 +++++++++--------- .../DisplayConditionsViewModel.cs | 7 +- src/Artemis.UI/packages.lock.json | 1 + .../Artemis.VisualScripting.csproj | 3 + .../Editor/Controls/VisualScriptPresenter.cs | 49 +- .../DataModelEventNodeCustomViewModel.cs | 74 +++ .../DataModelNodeCustomViewModel.cs | 0 .../DataModelEventNodeCustomView.xaml | 22 + .../CustomViews/DataModelNodeCustomView.xaml | 0 .../Nodes/DataModelEventNode.cs | 51 ++ .../Nodes/DataModelNode.cs | 2 +- 14 files changed, 591 insertions(+), 290 deletions(-) create mode 100644 src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventView.xaml create mode 100644 src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventViewModel.cs create mode 100644 src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs rename src/Artemis.VisualScripting/Nodes/{ => DataModel}/CustomViewModels/DataModelNodeCustomViewModel.cs (100%) create mode 100644 src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml rename src/Artemis.VisualScripting/Nodes/{ => DataModel}/CustomViews/DataModelNodeCustomView.xaml (100%) create mode 100644 src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs diff --git a/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml.cs b/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml.cs index 5975109f4..306728c42 100644 --- a/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml.cs +++ b/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; @@ -58,8 +59,8 @@ namespace Artemis.UI.Shared.Controls /// A list of extra modules to show data models of /// public static readonly DependencyProperty ModulesProperty = DependencyProperty.Register( - nameof(Modules), typeof(BindableCollection), typeof(DataModelPicker), - new FrameworkPropertyMetadata(new BindableCollection(), FrameworkPropertyMetadataOptions.None, ModulesPropertyChangedCallback) + nameof(Modules), typeof(ObservableCollection), typeof(DataModelPicker), + new FrameworkPropertyMetadata(new ObservableCollection(), FrameworkPropertyMetadataOptions.None, ModulesPropertyChangedCallback) ); /// @@ -74,16 +75,16 @@ namespace Artemis.UI.Shared.Controls /// A list of data model view models to show /// public static readonly DependencyProperty ExtraDataModelViewModelsProperty = DependencyProperty.Register( - nameof(ExtraDataModelViewModels), typeof(BindableCollection), typeof(DataModelPicker), - new FrameworkPropertyMetadata(new BindableCollection(), FrameworkPropertyMetadataOptions.None, ExtraDataModelViewModelsPropertyChangedCallback) + nameof(ExtraDataModelViewModels), typeof(ObservableCollection), typeof(DataModelPicker), + new FrameworkPropertyMetadata(new ObservableCollection(), FrameworkPropertyMetadataOptions.None, ExtraDataModelViewModelsPropertyChangedCallback) ); /// /// A list of data model view models to show /// public static readonly DependencyProperty FilterTypesProperty = DependencyProperty.Register( - nameof(FilterTypes), typeof(BindableCollection), typeof(DataModelPicker), - new FrameworkPropertyMetadata(new BindableCollection()) + nameof(FilterTypes), typeof(ObservableCollection), typeof(DataModelPicker), + new FrameworkPropertyMetadata(new ObservableCollection()) ); public DataModelPicker() @@ -143,9 +144,9 @@ namespace Artemis.UI.Shared.Controls /// /// Gets or sets a list of extra modules to show data models of /// - public BindableCollection? Modules + public ObservableCollection? Modules { - get => (BindableCollection) GetValue(ModulesProperty); + get => (ObservableCollection) GetValue(ModulesProperty); set => SetValue(ModulesProperty, value); } @@ -161,18 +162,18 @@ namespace Artemis.UI.Shared.Controls /// /// Gets or sets a list of data model view models to show /// - public BindableCollection? ExtraDataModelViewModels + public ObservableCollection? ExtraDataModelViewModels { - get => (BindableCollection) GetValue(ExtraDataModelViewModelsProperty); + get => (ObservableCollection) GetValue(ExtraDataModelViewModelsProperty); set => SetValue(ExtraDataModelViewModelsProperty, value); } /// /// Gets or sets the types of properties this view model will allow to be selected /// - public BindableCollection? FilterTypes + public ObservableCollection? FilterTypes { - get => (BindableCollection) GetValue(FilterTypesProperty); + get => (ObservableCollection) GetValue(FilterTypesProperty); set => SetValue(FilterTypesProperty, value); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventView.xaml new file mode 100644 index 000000000..bcae0117a --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventView.xaml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Click to edit script + + + + + + + + + + + + Configure how the layer should act when the event(s) trigger + + + + + + + + + + + + + + + + + RESTART + + + + + Stop the current run and restart the timeline + + + + + + + + TOGGLE + + + + + Repeat the timeline until the event fires again + + + + + + + + IGNORE + + + + + Ignore subsequent event fires until the timeline finishes + + + + + + + + COPY + + + + + Play another copy of the timeline on top of the current run + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventViewModel.cs new file mode 100644 index 000000000..0c0a97b2c --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionEventViewModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Stylet; + +namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions +{ + public class DisplayConditionEventViewModel : Screen + { + } +} diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml index 44bbe92a3..abaa2d145 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml @@ -25,269 +25,253 @@ - + Display conditions - - Not applied during editing - + + + + + + + + + + + + A condition that constantly checks and is either 'on' or 'off' + + + + + + CONSTANT + + + + + + + A condition that checks whenever one or more events fire and acts in a configurable way + + + + + + EVENTS + + + + - - - - - - - - - - - - - - - - Click to edit script - - - - - - - + - - - - - - - - - - - - - - Configure how the layer should act while the conditions above are met - - - - - - - - - - - - - - - Continue repeating the main segment of the timeline while the condition is met - - - - - - REPEAT - - - - - - - Only play the timeline once when the condition is met - - - - - - ONCE - - - - - - - - - - - Configure how the layer should act when the conditions above are no longer met - - - - - - - - - - - - - - - When conditions are no longer met, finish the the current run of the main timeline - - - - - - FINISH - - - - - - - When conditions are no longer met, skip to the end segment of the timeline - - - - - - SKIP TO END - - - - - - - - - - + + - - - - - - Configure how the layer should act when the event(s) trigger + + + + + + + + + + + + + + + + Click to edit script - - - - - - - - - - - - - - - RESTART - - - - - Stop the current run and restart the timeline - - - - - - - - TOGGLE - - - - - Repeat the timeline until the event fires again - - - - - - - - IGNORE - - - - - Ignore subsequent event fires until the timeline finishes - - - - - - - - COPY - - - - - Play another copy of the timeline on top of the current run - - - - - - + + + + + + + + + + + + + + + + + + + + Configure how the layer should act while the conditions above are met + + + + + + + + + + + + + + + Continue repeating the main segment of the timeline while the condition is met + + + + + + REPEAT + + + + + + + Only play the timeline once when the condition is met + + + + + + ONCE + + + + + + + + + + + Configure how the layer should act when the conditions above are no longer met + + + + + + + + + + + + + + + When conditions are no longer met, finish the the current run of the main timeline + + + + + + FINISH + + + + + + + When conditions are no longer met, skip to the end segment of the timeline + + + + + + SKIP TO END + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs index 72f4bfb91..640d283cd 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs @@ -8,7 +8,7 @@ using Stylet; namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions { - public class DisplayConditionsViewModel : Screen, IProfileEditorPanelViewModel + public class DisplayConditionsViewModel : Conductor.Collection.OneActive, IProfileEditorPanelViewModel { private readonly INodeVmFactory _nodeVmFactory; private readonly IProfileEditorService _profileEditorService; @@ -21,6 +21,11 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions _profileEditorService = profileEditorService; _windowManager = windowManager; _nodeVmFactory = nodeVmFactory; + + Items.Add(new DisplayConditionEventViewModel() { DisplayName = "Event 1"}); + Items.Add(new DisplayConditionEventViewModel() { DisplayName = "Event 2"}); + Items.Add(new DisplayConditionEventViewModel() { DisplayName = "Event 3"}); + Items.Add(new DisplayConditionEventViewModel() { DisplayName = "Event 4"}); } public bool IsEventCondition diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json index 0845176f7..53f59c83c 100644 --- a/src/Artemis.UI/packages.lock.json +++ b/src/Artemis.UI/packages.lock.json @@ -1492,6 +1492,7 @@ "Artemis.Core": "1.0.0", "Artemis.UI.Shared": "2.0.0", "JetBrains.Annotations": "2021.1.0", + "MaterialDesignThemes": "4.1.0", "Ninject": "3.3.4", "NoStringEvaluating": "2.2.1", "SkiaSharp": "2.80.3", diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj index da0811361..215c601ae 100644 --- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj +++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj @@ -62,6 +62,9 @@ $(DefaultXamlRuntime) Designer + + $(DefaultXamlRuntime) + $(DefaultXamlRuntime) diff --git a/src/Artemis.VisualScripting/Editor/Controls/VisualScriptPresenter.cs b/src/Artemis.VisualScripting/Editor/Controls/VisualScriptPresenter.cs index 1e75ba72e..3860f1ebb 100644 --- a/src/Artemis.VisualScripting/Editor/Controls/VisualScriptPresenter.cs +++ b/src/Artemis.VisualScripting/Editor/Controls/VisualScriptPresenter.cs @@ -198,8 +198,6 @@ namespace Artemis.VisualScripting.Editor.Controls _canvas.RenderTransform = _canvasViewPortTransform = new TranslateTransform(0, 0); _canvas.MouseLeftButtonDown += OnCanvasMouseLeftButtonDown; _canvas.MouseLeftButtonUp += OnCanvasMouseLeftButtonUp; - _canvas.MouseRightButtonDown += OnCanvasMouseRightButtonDown; - _canvas.MouseRightButtonUp += OnCanvasMouseRightButtonUp; _canvas.PreviewMouseRightButtonDown += OnCanvasPreviewMouseRightButtonDown; _canvas.MouseMove += OnCanvasMouseMove; _canvas.MouseWheel += OnCanvasMouseWheel; @@ -292,6 +290,27 @@ namespace Artemis.VisualScripting.Editor.Controls private void OnCanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs args) { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + if (AutoFitScript) + { + args.Handled = true; + return; + } + + _dragCanvas = true; + _dragCanvasStartLocation = args.GetPosition(this); + _dragCanvasStartOffset = _viewportCenter; + + _movedDuringDrag = false; + + _canvas.CaptureMouse(); + + args.Handled = true; + + return; + } + VisualScript.DeselectAllNodes(); _boxSelect = true; @@ -317,29 +336,7 @@ namespace Artemis.VisualScripting.Editor.Controls SelectWithinRectangle(new Rect(Canvas.GetLeft(_selectionBorder), Canvas.GetTop(_selectionBorder), _selectionBorder.Width, _selectionBorder.Height)); args.Handled = _movedDuringDrag; } - } - private void OnCanvasMouseRightButtonDown(object sender, MouseButtonEventArgs args) - { - if (AutoFitScript) - { - args.Handled = true; - return; - } - - _dragCanvas = true; - _dragCanvasStartLocation = args.GetPosition(this); - _dragCanvasStartOffset = _viewportCenter; - - _movedDuringDrag = false; - - _canvas.CaptureMouse(); - - args.Handled = true; - } - - private void OnCanvasMouseRightButtonUp(object sender, MouseButtonEventArgs args) - { if (_dragCanvas) { _dragCanvas = false; @@ -353,7 +350,7 @@ namespace Artemis.VisualScripting.Editor.Controls { if (_dragCanvas) { - if (args.RightButton == MouseButtonState.Pressed) + if (args.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) { Vector newLocation = _dragCanvasStartOffset - (((args.GetPosition(this) - _dragCanvasStartLocation)) * (1.0 / Scale)); CenterAt(newLocation); @@ -541,7 +538,7 @@ namespace Artemis.VisualScripting.Editor.Controls List pins = node.Pins.ToList(); pins.AddRange(node.PinCollections.SelectMany(c => c)); pins = pins.Where(p => p.Type == typeof(object) || p.Type == SourcePin.Pin.Type).OrderBy(p => p.Type != typeof(object)).ToList(); - + IPin preferredPin = SourcePin.Pin.Direction == PinDirection.Input ? pins.FirstOrDefault(p => p.Direction == PinDirection.Output) : pins.FirstOrDefault(p => p.Direction == PinDirection.Input); diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs new file mode 100644 index 000000000..0057dcbea --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs @@ -0,0 +1,74 @@ +using System; +using System.ComponentModel; +using Artemis.Core; +using Artemis.Core.Modules; +using Artemis.Core.Services; +using Stylet; + +namespace Artemis.VisualScripting.Nodes.CustomViewModels +{ + public class DataModelEventNodeCustomViewModel : CustomNodeViewModel + { + private readonly DataModelEventNode _node; + private BindableCollection _modules; + + public DataModelEventNodeCustomViewModel(DataModelEventNode node, ISettingsService settingsService) : base(node) + { + _node = node; + + ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true); + ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); + } + + public PluginSetting ShowFullPaths { get; } + public PluginSetting ShowDataModelValues { get; } + public BindableCollection FilterTypes { get; } = new() { typeof(DataModelEvent) }; + + public BindableCollection Modules + { + get => _modules; + set => SetAndNotify(ref _modules, value); + } + + public DataModelPath DataModelPath + { + get => _node.DataModelPath; + set + { + if (ReferenceEquals(_node.DataModelPath, value)) + return; + + _node.DataModelPath?.Dispose(); + _node.DataModelPath = value; + _node.DataModelPath.Save(); + + _node.Storage = _node.DataModelPath.Entity; + } + } + + public override void OnActivate() + { + if (Modules != null) + return; + + Modules = new BindableCollection(); + if (_node.Script.Context is Profile scriptProfile && scriptProfile.Configuration.Module != null) + Modules.Add(scriptProfile.Configuration.Module); + else if (_node.Script.Context is ProfileConfiguration profileConfiguration && profileConfiguration.Module != null) + Modules.Add(profileConfiguration.Module); + + _node.PropertyChanged += NodeOnPropertyChanged; + } + + public override void OnDeactivate() + { + _node.PropertyChanged -= NodeOnPropertyChanged; + } + + private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(DataModelNode.DataModelPath)) + OnPropertyChanged(nameof(DataModelPath)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs similarity index 100% rename from src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs rename to src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml new file mode 100644 index 000000000..52708c600 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml similarity index 100% rename from src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml rename to src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml diff --git a/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs b/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs new file mode 100644 index 000000000..26c981864 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs @@ -0,0 +1,51 @@ +using System; +using Artemis.Core; +using Artemis.Storage.Entities.Profile; +using Artemis.VisualScripting.Nodes.CustomViewModels; + +namespace Artemis.VisualScripting.Nodes +{ + [Node("Data Model-Event", "Responds to a data model event trigger", "External", OutputType = typeof(bool))] + public class DataModelEventNode : Node, IDisposable + { + private DataModelPath _dataModelPath; + + public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger") + { + Output = CreateOutputPin(); + } + + public OutputPin Output { get; } + public INodeScript Script { get; set; } + + public DataModelPath DataModelPath + { + get => _dataModelPath; + set => SetAndNotify(ref _dataModelPath, value); + } + + public override void Initialize(INodeScript script) + { + Script = script; + + if (Storage is not DataModelPathEntity pathEntity) + return; + + DataModelPath = new DataModelPath(null, pathEntity); + DataModelPath.PathValidated += DataModelPathOnPathValidated; + } + + public override void Evaluate() + { + } + + private void DataModelPathOnPathValidated(object sender, EventArgs e) + { + } + + /// + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs b/src/Artemis.VisualScripting/Nodes/DataModelNode.cs index ee40fea9f..155420fc4 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModelNode.cs @@ -84,7 +84,7 @@ namespace Artemis.VisualScripting.Nodes /// public void Dispose() { - DataModelPath.Dispose(); + DataModelPath?.Dispose(); } #endregion