diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs index 8e7e2d039..82fb7d75f 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -21,68 +21,82 @@ namespace Artemis.Core.Models.Profile.LayerProperties Name = name; Description = description; Type = type; + CanUseKeyframes = true; Children = new List(); BaseKeyframes = new List(); } /// - /// The layer this property applies to + /// Gets the layer this property applies to /// public Layer Layer { get; } /// - /// The parent property of this property. + /// Gets the parent property of this property. /// public BaseLayerProperty Parent { get; } /// - /// The child properties of this property. + /// Gets or sets the child properties of this property. /// If the layer has children it cannot contain a value or keyframes. /// public List Children { get; set; } /// - /// A unique identifier for this property, a layer may not contain two properties with the same ID. + /// Gets or sets a unique identifier for this property, a layer may not contain two properties with the same ID. /// public string Id { get; set; } /// - /// The user-friendly name for this property, shown in the UI. + /// Gets or sets the user-friendly name for this property, shown in the UI. /// public string Name { get; set; } /// - /// The user-friendly description for this property, shown in the UI. + /// Gets or sets the user-friendly description for this property, shown in the UI. /// public string Description { get; set; } /// - /// Whether to expand this property by default, this is useful for important parent properties. + /// Gets or sets whether to expand this property by default, this is useful for important parent properties. /// public bool ExpandByDefault { get; set; } /// - /// An optional input prefix to show before input elements in the UI. + /// Gets or sets the an optional input prefix to show before input elements in the UI. /// public string InputPrefix { get; set; } /// - /// An optional input affix to show behind input elements in the UI. + /// Gets or sets an optional input affix to show behind input elements in the UI. /// public string InputAffix { get; set; } /// - /// The type of value this layer property contains. + /// Gets or sets whether this property can use keyframes, True by default. /// - public Type Type { get; set; } + public bool CanUseKeyframes { get; set; } /// - /// A list of keyframes defining different values of the property in time, this list contains the untyped + /// Gets or sets whether this property is using keyframes. + /// + public bool IsUsingKeyframes { get; set; } + + /// + /// Gets the type of value this layer property contains. + /// + public Type Type { get; protected set; } + + /// + /// Gets a list of keyframes defining different values of the property in time, this list contains the untyped /// . /// public IReadOnlyCollection UntypedKeyframes => BaseKeyframes.AsReadOnly(); + /// + /// Gets or sets the keyframe engine instance of this property + /// public KeyframeEngine KeyframeEngine { get; set; } protected List BaseKeyframes { get; set; } @@ -113,6 +127,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties propertyEntity.ValueType = Type.Name; propertyEntity.Value = JsonConvert.SerializeObject(BaseValue); + propertyEntity.IsUsingKeyframes = IsUsingKeyframes; propertyEntity.KeyframeEntities.Clear(); foreach (var baseKeyframe in BaseKeyframes) @@ -129,6 +144,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties internal void ApplyToProperty(PropertyEntity propertyEntity) { BaseValue = DeserializePropertyValue(propertyEntity.Value); + IsUsingKeyframes = propertyEntity.IsUsingKeyframes; BaseKeyframes.Clear(); foreach (var keyframeEntity in propertyEntity.KeyframeEntities.OrderBy(e => e.Position)) @@ -170,6 +186,33 @@ namespace Artemis.Core.Models.Profile.LayerProperties BaseKeyframes.Clear(); } + /// + /// Gets the current value using the regular value or keyframes. + /// + /// The value to set. + /// + /// An optional time to set the value add, if provided and property is using keyframes the value will be set to an new + /// or existing keyframe. + /// + public void SetCurrentValue(object value, TimeSpan? time) + { + if (value != null && value.GetType() != Type) + throw new ArtemisCoreException($"Cannot set value of type {value.GetType()} on property {this}, expected type is {Type}."); + + if (time == null || !CanUseKeyframes || !IsUsingKeyframes) + BaseValue = value; + else + { + // If on a keyframe, update the keyframe + var currentKeyframe = UntypedKeyframes.FirstOrDefault(k => k.Position == time.Value); + // Create a new keyframe if none found + if (currentKeyframe == null) + currentKeyframe = CreateNewKeyframe(time.Value); + + currentKeyframe.BaseValue = value; + } + } + internal void SortKeyframes() { BaseKeyframes = BaseKeyframes.OrderBy(k => k.Position).ToList(); diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index 5614cbb38..34900c9bc 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Linq; namespace Artemis.Core.Models.Profile.LayerProperties @@ -10,7 +11,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties } /// - /// The value of the property without any keyframes applied + /// Gets or sets the value of the property without any keyframes applied /// public T Value { @@ -19,12 +20,12 @@ namespace Artemis.Core.Models.Profile.LayerProperties } /// - /// The value of the property with keyframes applied + /// Gets the value of the property with keyframes applied /// public T CurrentValue => KeyframeEngine != null ? (T) KeyframeEngine.GetCurrentValue() : Value; /// - /// A list of keyframes defining different values of the property in time, this list contains the strongly typed + /// Gets a list of keyframes defining different values of the property in time, this list contains the strongly typed /// /// public ReadOnlyCollection> Keyframes => BaseKeyframes.Cast>().ToList().AsReadOnly(); @@ -50,7 +51,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties } /// - /// Gets the current value using the keyframes + /// Gets the current value using the regular value or if present, keyframes /// /// public T GetCurrentValue() diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs b/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs index 98b7654fc..fa5e217d7 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using Artemis.Storage.Entities.Profile; using SkiaSharp; @@ -41,13 +42,14 @@ namespace Artemis.Core.Models.Profile.LayerShapes /// /// Updates Position and Size using the provided unscaled rectangle /// - /// An unscaled rectangle where 1px = 1mm - public void SetFromUnscaledRectangle(SKRect rect) + /// An unscaled rectangle which is relative to the layer (1.0 being full width/height, 0.5 being half). + /// An optional timespan to indicate where to set the properties, if null the properties' base values will be used. + public void SetFromUnscaledRectangle(SKRect rect, TimeSpan? time) { if (!Layer.Leds.Any()) { - Layer.PositionProperty.Value = SKPoint.Empty; - Layer.SizeProperty.Value = SKSize.Empty; + Layer.PositionProperty.SetCurrentValue(SKPoint.Empty, time); + Layer.SizeProperty.SetCurrentValue(SKSize.Empty, time); return; } @@ -56,10 +58,9 @@ namespace Artemis.Core.Models.Profile.LayerShapes var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x; var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y; - Layer.PositionProperty.Value = new SKPoint((float) (100f / width * (rect.Left - x)) / 100f, (float) (100f / height * (rect.Top - y)) / 100f); - Layer.SizeProperty.Value = new SKSize((float) (100f / width * rect.Width) / 100f, (float) (100f / height * rect.Height) / 100f); + Layer.PositionProperty.SetCurrentValue(new SKPoint((float) (100f / width * (rect.Left - x)) / 100f, (float) (100f / height * (rect.Top - y)) / 100f), time); + Layer.SizeProperty.SetCurrentValue(new SKSize((float) (100f / width * rect.Width) / 100f, (float) (100f / height * rect.Height) / 100f), time); - // TODO: Update keyframes CalculateRenderProperties(Layer.PositionProperty.CurrentValue, Layer.SizeProperty.CurrentValue); } diff --git a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs index b19bfcd47..2f450633d 100644 --- a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs @@ -13,6 +13,7 @@ namespace Artemis.Storage.Entities.Profile public string Id { get; set; } public string ValueType { get; set; } public string Value { get; set; } + public bool IsUsingKeyframes { get; set; } public List KeyframeEntities { get; set; } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml index cc2ac125c..4fd802767 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml @@ -40,25 +40,25 @@ - - - - - - diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs index be0ef884a..f11559423 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs @@ -19,7 +19,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { _kernel = kernel; _profileEditorService = profileEditorService; - _keyframesEnabled = layerProperty.UntypedKeyframes.Any(); + _keyframesEnabled = layerProperty.IsUsingKeyframes; LayerProperty = layerProperty; Parent = parent; @@ -56,6 +56,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties LayerProperty.ClearKeyframes(); // Force the keyframe engine to update, the new keyframe is the current keyframe + LayerProperty.IsUsingKeyframes = _keyframesEnabled; LayerProperty.KeyframeEngine.Update(0); _profileEditorService.UpdateSelectedProfileElement(); diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs index 452b31514..e7029aaee 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs @@ -15,7 +15,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P public float FloatInputValue { - get => (float) InputValue; + get => (float?) InputValue ?? 0f; set => InputValue = value; } @@ -23,17 +23,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P { NotifyOfPropertyChange(() => FloatInputValue); } - - protected override void UpdateBaseValue(object value) - { - var layerProperty = (LayerProperty) LayerPropertyViewModel.LayerProperty; - layerProperty.Value = (float) value; - } - - protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value) - { - var keyframe = (Keyframe) baseKeyframe; - keyframe.Value = (float) value; - } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs index 185703805..d8e74e8a4 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs @@ -15,7 +15,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P public int IntInputValue { - get => (int) InputValue; + get => (int?) InputValue ?? 0; set => InputValue = value; } @@ -23,17 +23,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P { NotifyOfPropertyChange(() => IntInputValue); } - - protected override void UpdateBaseValue(object value) - { - var layerProperty = (LayerProperty) LayerPropertyViewModel.LayerProperty; - layerProperty.Value = (int) value; - } - - protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value) - { - var keyframe = (Keyframe) baseKeyframe; - keyframe.Value = (int) value; - } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs index 16c1179ef..6ccfbefa0 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.Models.Profile.LayerProperties; using Artemis.UI.Exceptions; using Artemis.UI.Services.Interfaces; using Stylet; @@ -43,29 +42,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P private void UpdateInputValue(object value) { - // If keyframes are disabled, update the base value - if (!LayerPropertyViewModel.KeyframesEnabled) - { - UpdateBaseValue(value); - return; - } - - // If on a keyframe, update the keyframe - var currentKeyframe = LayerPropertyViewModel.LayerProperty.UntypedKeyframes.FirstOrDefault(k => k.Position == ProfileEditorService.CurrentTime); - // Create a new keyframe if none found - if (currentKeyframe == null) - currentKeyframe = LayerPropertyViewModel.LayerProperty.CreateNewKeyframe(ProfileEditorService.CurrentTime); - - UpdateKeyframeValue(currentKeyframe, value); + LayerPropertyViewModel.LayerProperty.SetCurrentValue(value, ProfileEditorService.CurrentTime); // Force the keyframe engine to update, the edited keyframe might affect the current keyframe progress LayerPropertyViewModel.LayerProperty.KeyframeEngine.Update(0); ProfileEditorService.UpdateSelectedProfileElement(); - } public abstract void Update(); - protected abstract void UpdateBaseValue(object value); - protected abstract void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs index 7a0616b60..26924df6c 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs @@ -19,14 +19,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P [DependsOn(nameof(InputValue))] public float X { - get => ((SKPoint) InputValue).X; + get => ((SKPoint?) InputValue)?.X ?? 0; set => InputValue = new SKPoint(value, Y); } [DependsOn(nameof(InputValue))] public float Y { - get => ((SKPoint) InputValue).Y; + get => ((SKPoint?)InputValue)?.Y ?? 0; set => InputValue = new SKPoint(X, value); } @@ -35,17 +35,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P NotifyOfPropertyChange(() => X); NotifyOfPropertyChange(() => Y); } - - protected override void UpdateBaseValue(object value) - { - var layerProperty = (LayerProperty) LayerPropertyViewModel.LayerProperty; - layerProperty.Value = (SKPoint) value; - } - - protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value) - { - var keyframe = (Keyframe) baseKeyframe; - keyframe.Value = (SKPoint) value; - } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs index 593214f35..abeebc1cd 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs @@ -19,14 +19,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P [DependsOn(nameof(InputValue))] public float Width { - get => ((SKSize) InputValue).Width; + get => ((SKSize?) InputValue)?.Width ?? 0; set => InputValue = new SKSize(value, Height); } [DependsOn(nameof(InputValue))] public float Height { - get => ((SKSize) InputValue).Height; + get => ((SKSize?)InputValue)?.Height ?? 0; set => InputValue = new SKSize(Width, value); } @@ -35,17 +35,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P NotifyOfPropertyChange(() => Width); NotifyOfPropertyChange(() => Height); } - - protected override void UpdateBaseValue(object value) - { - var layerProperty = (LayerProperty) LayerPropertyViewModel.LayerProperty; - layerProperty.Value = (SKSize) value; - } - - protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value) - { - var keyframe = (Keyframe) baseKeyframe; - keyframe.Value = (SKSize) value; - } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderViewModel.cs index 3ba3e3db2..1b09bd69a 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderViewModel.cs @@ -1,4 +1,5 @@ using Artemis.Core.Models.Profile; +using Artemis.Core.Services.Interfaces; using Artemis.UI.Ninject.Factories; using Artemis.UI.Services.Interfaces; @@ -10,9 +11,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem public FolderViewModel(ProfileElement folder, IProfileEditorService profileEditorService, IDialogService dialogService, + ILayerService layerService, IFolderViewModelFactory folderViewModelFactory, ILayerViewModelFactory layerViewModelFactory) : - base(null, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory) + base(null, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory) { } @@ -20,9 +22,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem ProfileElement folder, IProfileEditorService profileEditorService, IDialogService dialogService, + ILayerService layerService, IFolderViewModelFactory folderViewModelFactory, ILayerViewModelFactory layerViewModelFactory) : - base(parent, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory) + base(parent, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory) { } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerViewModel.cs index 7be6ebf61..d132dff0f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerViewModel.cs @@ -1,4 +1,5 @@ using Artemis.Core.Models.Profile; +using Artemis.Core.Services.Interfaces; using Artemis.UI.Ninject.Factories; using Artemis.UI.Services.Interfaces; @@ -10,9 +11,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem ProfileElement folder, IProfileEditorService profileEditorService, IDialogService dialogService, + ILayerService layerService, IFolderViewModelFactory folderViewModelFactory, ILayerViewModelFactory layerViewModelFactory) : - base(parent, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory) + base(parent, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory) { } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs index f0efe6155..0fff6175f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Artemis.Core.Models.Profile; +using Artemis.Core.Services.Interfaces; using Artemis.UI.Exceptions; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Module.ProfileEditor.Dialogs; @@ -13,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem public abstract class TreeItemViewModel : PropertyChangedBase { private readonly IDialogService _dialogService; + private readonly ILayerService _layerService; private readonly IFolderViewModelFactory _folderViewModelFactory; private readonly ILayerViewModelFactory _layerViewModelFactory; private readonly IProfileEditorService _profileEditorService; @@ -21,11 +23,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem ProfileElement profileElement, IProfileEditorService profileEditorService, IDialogService dialogService, + ILayerService layerService, IFolderViewModelFactory folderViewModelFactory, ILayerViewModelFactory layerViewModelFactory) { _profileEditorService = profileEditorService; _dialogService = dialogService; + _layerService = layerService; _folderViewModelFactory = folderViewModelFactory; _layerViewModelFactory = layerViewModelFactory; @@ -117,7 +121,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem if (!SupportsChildren) throw new ArtemisUIException("Cannot add a layer to a profile element of type " + ProfileElement.GetType().Name); - ProfileElement.AddChild(new Layer(ProfileElement.Profile, ProfileElement, "New layer")); + var layer = new Layer(ProfileElement.Profile, ProfileElement, "New layer"); + foreach (var baseLayerProperty in layer.Properties) + _layerService.InstantiateKeyframeEngine(baseLayerProperty); + ProfileElement.AddChild(layer); UpdateProfileElements(); _profileEditorService.UpdateSelectedProfile(); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs index a0331ebaf..20bcf559c 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs @@ -28,9 +28,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated; _profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged; _profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated; - _profileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged; + _profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated; } + public Layer Layer { get; } public Geometry LayerGeometry { get; set; } @@ -102,8 +103,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization } var skRect = Layer.LayerShape.GetUnscaledRectangle(); - var rect = new Rect(skRect.Left, skRect.Top, Math.Max(0, skRect.Width), Math.Max(0,skRect.Height)); - + var rect = new Rect(skRect.Left, skRect.Top, Math.Max(0, skRect.Width), Math.Max(0, skRect.Height)); + var shapeGeometry = Geometry.Empty; switch (Layer.LayerShape) { @@ -189,7 +190,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization { Layer.RenderPropertiesUpdated -= LayerOnRenderPropertiesUpdated; } - + #region Event handlers private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e) @@ -208,7 +209,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization Update(); } - private void ProfileEditorServiceOnCurrentTimeChanged(object sender, EventArgs e) + private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e) { if (!IsSelected) return; diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolView.xaml index fdf497ff6..cc499c36f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolView.xaml @@ -9,15 +9,20 @@ d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance {x:Type local:EditToolViewModel}}"> - + + StrokeDashArray="2 2" + Cursor="Hand" + MouseDown="{s:Action ShapeEditMouseDown}" + MouseUp="{s:Action ShapeEditMouseUp}" + MouseMove="{s:Action Move}"/> diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs index 7076a08fd..7ea715376 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs @@ -10,7 +10,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools { public class EditToolViewModel : VisualizationToolViewModel { - private bool _mouseDown; + private bool _isDragging; + private double _dragOffsetY; + private double _dragOffsetX; public EditToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService) { @@ -19,7 +21,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools profileEditorService.SelectedProfileChanged += (sender, args) => Update(); profileEditorService.SelectedProfileElementUpdated += (sender, args) => Update(); - profileEditorService.CurrentTimeChanged += (sender, args) => Update(); + profileEditorService.ProfilePreviewUpdated += (sender, args) => Update(); } private void Update() @@ -34,41 +36,64 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools public void ShapeEditMouseDown(object sender, MouseButtonEventArgs e) { + if (_isDragging) + return; + ((IInputElement) sender).CaptureMouse(); - _mouseDown = true; + if (ProfileEditorService.SelectedProfileElement is Layer layer) + { + var dragStartPosition = GetRelativePosition(sender, e); + var skRect = layer.LayerShape.GetUnscaledRectangle(); + _dragOffsetX = skRect.Left - dragStartPosition.X; + _dragOffsetY = skRect.Top - dragStartPosition.Y; + } + + _isDragging = true; e.Handled = true; } public void ShapeEditMouseUp(object sender, MouseButtonEventArgs e) { ((IInputElement) sender).ReleaseMouseCapture(); - _mouseDown = false; + ProfileEditorService.UpdateSelectedProfileElement(); + + _isDragging = false; e.Handled = true; } + public void Move(object sender, MouseEventArgs e) + { + if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer)) + return; + + var position = GetRelativePosition(sender, e); + var skRect = layer.LayerShape.GetUnscaledRectangle(); + layer.LayerShape.SetFromUnscaledRectangle( + SKRect.Create((float) (position.X + _dragOffsetX), (float) (position.Y + _dragOffsetY), skRect.Width, skRect.Height), + ProfileEditorService.CurrentTime + ); + ProfileEditorService.UpdateProfilePreview(); + } + public void TopLeftRotate(object sender, MouseEventArgs e) { } public void TopLeftResize(object sender, MouseEventArgs e) { - } public void TopCenterResize(object sender, MouseEventArgs e) { - if (!_mouseDown) - return; - if (!(ProfileEditorService.SelectedProfileElement is Layer layer)) + if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer)) return; var position = GetRelativePosition(sender, e); var skRect = layer.LayerShape.GetUnscaledRectangle(); skRect.Top = (float) Math.Min(position.Y, skRect.Bottom); - layer.LayerShape.SetFromUnscaledRectangle(skRect); - - ProfileEditorService.UpdateSelectedProfileElement(); + layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime); + ProfileEditorService.UpdateProfilePreview(); } public void TopRightRotate(object sender, MouseEventArgs e) @@ -81,18 +106,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools public void CenterRightResize(object sender, MouseEventArgs e) { - if (!_mouseDown) - return; - if (!(ProfileEditorService.SelectedProfileElement is Layer layer)) + if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer)) return; var position = GetRelativePosition(sender, e); var skRect = layer.LayerShape.GetUnscaledRectangle(); skRect.Right = (float) Math.Max(position.X, skRect.Left); - layer.LayerShape.SetFromUnscaledRectangle(skRect); - - ProfileEditorService.UpdateSelectedProfileElement(); + layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime); + ProfileEditorService.UpdateProfilePreview(); } private Point GetRelativePosition(object sender, MouseEventArgs mouseEventArgs) @@ -111,18 +133,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools public void BottomCenterResize(object sender, MouseEventArgs e) { - if (!_mouseDown) - return; - if (!(ProfileEditorService.SelectedProfileElement is Layer layer)) + if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer)) return; var position = GetRelativePosition(sender, e); var skRect = layer.LayerShape.GetUnscaledRectangle(); skRect.Bottom = (float) Math.Max(position.Y, skRect.Top); - layer.LayerShape.SetFromUnscaledRectangle(skRect); - - ProfileEditorService.UpdateSelectedProfileElement(); + layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime); + ProfileEditorService.UpdateProfilePreview(); } public void BottomLeftRotate(object sender, MouseEventArgs e) @@ -135,18 +154,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools public void CenterLeftResize(object sender, MouseEventArgs e) { - if (!_mouseDown) - return; - if (!(ProfileEditorService.SelectedProfileElement is Layer layer)) + if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer)) return; var position = GetRelativePosition(sender, e); var skRect = layer.LayerShape.GetUnscaledRectangle(); skRect.Left = (float) Math.Min(position.X, skRect.Right); - layer.LayerShape.SetFromUnscaledRectangle(skRect); - - ProfileEditorService.UpdateSelectedProfileElement(); + layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime); + ProfileEditorService.UpdateProfilePreview(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs index 8130a360b..b5666c6b4 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs @@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.LayerShape = new Ellipse(layer); // Apply the drag rectangle - layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect()); + layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect(), ProfileEditorService.CurrentTime); ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs index 25363d5b2..84682ccaf 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs @@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.LayerShape = new Rectangle(layer); // Apply the drag rectangle - layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect()); + layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect(), ProfileEditorService.CurrentTime); ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs index 33f2554a7..fe2d1bf5a 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs @@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.AddLeds(selectedLeds); // Restore the saved size if (layer.LayerShape != null) - layer.LayerShape.SetFromUnscaledRectangle(shapeSize); + layer.LayerShape.SetFromUnscaledRectangle(shapeSize, ProfileEditorService.CurrentTime); ProfileEditorService.UpdateSelectedProfileElement(); } diff --git a/src/Artemis.UI/Services/Interfaces/IProfileEditorService.cs b/src/Artemis.UI/Services/Interfaces/IProfileEditorService.cs index 90837eddd..bb9dda6bf 100644 --- a/src/Artemis.UI/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI/Services/Interfaces/IProfileEditorService.cs @@ -1,5 +1,6 @@ using System; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; namespace Artemis.UI.Services.Interfaces { @@ -13,6 +14,7 @@ namespace Artemis.UI.Services.Interfaces void UpdateSelectedProfile(); void ChangeSelectedProfileElement(ProfileElement profileElement); void UpdateSelectedProfileElement(); + void UpdateProfilePreview(); /// /// Occurs when a new profile is selected @@ -38,5 +40,10 @@ namespace Artemis.UI.Services.Interfaces /// Occurs when the current editor time is changed /// event EventHandler CurrentTimeChanged; + + /// + /// Occurs when the profile preview has been updated + /// + event EventHandler ProfilePreviewUpdated; } } \ No newline at end of file diff --git a/src/Artemis.UI/Services/ProfileEditorService.cs b/src/Artemis.UI/Services/ProfileEditorService.cs index c20af3a57..35ba8e0f6 100644 --- a/src/Artemis.UI/Services/ProfileEditorService.cs +++ b/src/Artemis.UI/Services/ProfileEditorService.cs @@ -60,7 +60,7 @@ namespace Artemis.UI.Services } - private void UpdateProfilePreview() + public void UpdateProfilePreview() { if (SelectedProfile == null) return; @@ -78,6 +78,7 @@ namespace Artemis.UI.Services } _lastUpdateTime = CurrentTime; + OnProfilePreviewUpdated(); } public event EventHandler SelectedProfileChanged; @@ -85,6 +86,7 @@ namespace Artemis.UI.Services public event EventHandler SelectedProfileElementChanged; public event EventHandler SelectedProfileElementUpdated; public event EventHandler CurrentTimeChanged; + public event EventHandler ProfilePreviewUpdated; protected virtual void OnSelectedProfileElementUpdated() { @@ -110,5 +112,10 @@ namespace Artemis.UI.Services { CurrentTimeChanged?.Invoke(this, EventArgs.Empty); } + + protected virtual void OnProfilePreviewUpdated() + { + ProfilePreviewUpdated?.Invoke(this, EventArgs.Empty); + } } } \ No newline at end of file