diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs
index 370a72196..315ecac2d 100644
--- a/src/Artemis.Core/Models/Profile/Folder.cs
+++ b/src/Artemis.Core/Models/Profile/Folder.cs
@@ -70,12 +70,12 @@ namespace Artemis.Core.Models.Profile
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
// to it's start
- var timelineDeltaTime = UpdateTimeline(deltaTime);
+ UpdateTimeline(deltaTime);
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
baseLayerEffect.BaseProperties?.Update();
- baseLayerEffect.Update(timelineDeltaTime);
+ baseLayerEffect.Update(deltaTime);
}
// Iterate the children in reverse because that's how they must be rendered too
diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index f5be0698f..99265b4bc 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -70,7 +70,6 @@ namespace Artemis.Core.Models.Profile
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
ApplyRenderElementEntity();
- ApplyRenderElementDefaults();
}
internal LayerEntity LayerEntity { get; set; }
@@ -224,17 +223,17 @@ namespace Artemis.Core.Models.Profile
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
// to it's start
- var timelineDeltaTime = UpdateTimeline(deltaTime);
+ UpdateTimeline(deltaTime);
General.Update();
Transform.Update();
LayerBrush.BaseProperties?.Update();
- LayerBrush.Update(timelineDeltaTime);
+ LayerBrush.Update(deltaTime);
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
baseLayerEffect.BaseProperties?.Update();
- baseLayerEffect.Update(timelineDeltaTime);
+ baseLayerEffect.Update(deltaTime);
}
}
@@ -256,7 +255,10 @@ namespace Artemis.Core.Models.Profile
else
{
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
- TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
+ if (progress > 0)
+ TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
+ else
+ TimelinePosition = StartSegmentLength;
}
}
else
@@ -437,6 +439,39 @@ namespace Artemis.Core.Models.Profile
return position;
}
+ ///
+ /// Excludes the provided path from the translations applied to the layer by applying translations that cancel the
+ /// layer translations out
+ ///
+ ///
+ public void ExcludePathFromTranslation(SKPath path)
+ {
+ var sizeProperty = Transform.Scale.CurrentValue;
+ var rotationProperty = Transform.Rotation.CurrentValue;
+
+ var anchorPosition = GetLayerAnchorPosition(Path);
+ var anchorProperty = Transform.AnchorPoint.CurrentValue;
+
+ // Translation originates from the unscaled center of the shape and is tied to the anchor
+ var x = anchorPosition.X - Bounds.MidX - anchorProperty.X * Bounds.Width;
+ var y = anchorPosition.Y - Bounds.MidY - anchorProperty.Y * Bounds.Height;
+
+ var reversedXScale = 1f / (sizeProperty.Width / 100f);
+ var reversedYScale = 1f / (sizeProperty.Height / 100f);
+
+ if (General.FillType == LayerFillType.Stretch)
+ {
+ path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
+ path.Transform(SKMatrix.MakeScale(reversedXScale, reversedYScale, anchorPosition.X, anchorPosition.Y));
+ path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
+ }
+ else
+ {
+ path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
+ path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
+ }
+ }
+
#endregion
#region LED management
diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
index 4156086be..dd8d7ba26 100644
--- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
+++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
@@ -17,8 +17,7 @@ namespace Artemis.Core.Models.Profile
{
protected void ApplyRenderElementDefaults()
{
- if (MainSegmentLength <= TimeSpan.Zero)
- MainSegmentLength = TimeSpan.FromSeconds(5);
+ MainSegmentLength = TimeSpan.FromSeconds(5);
}
protected void ApplyRenderElementEntity()
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml
index 87a3ed132..f4b699c5d 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml
@@ -172,130 +172,62 @@
-
-
-
-
-
-
-
+
+
-
+
-
-
+
+
-
+
@@ -303,8 +235,8 @@
@@ -409,15 +341,15 @@
+ IsEnabled="{Binding Data.StartTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
+ IsEnabled="{Binding Data.MainTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
+ IsEnabled="{Binding Data.EndTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
index 62e2df39e..c708e5fd1 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
@@ -35,6 +35,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private RenderProfileElement _selectedProfileElement;
private TimelineViewModel _timelineViewModel;
private TreeViewModel _treeViewModel;
+ private TimelineSegmentViewModel _startTimelineSegmentViewModel;
+ private TimelineSegmentViewModel _mainTimelineSegmentViewModel;
+ private TimelineSegmentViewModel _endTimelineSegmentViewModel;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService,
ILayerPropertyVmFactory layerPropertyVmFactory)
@@ -68,10 +71,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public string FormattedCurrentTime => $"{Math.Floor(ProfileEditorService.CurrentTime.TotalSeconds):00}.{ProfileEditorService.CurrentTime.Milliseconds:000}";
- public Thickness TimeCaretPosition
+ public double TimeCaretPosition
{
- get => new Thickness(ProfileEditorService.CurrentTime.TotalSeconds * ProfileEditorService.PixelsPerSecond, 0, 0, 0);
- set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / ProfileEditorService.PixelsPerSecond);
+ get => ProfileEditorService.CurrentTime.TotalSeconds * ProfileEditorService.PixelsPerSecond;
+ set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value / ProfileEditorService.PixelsPerSecond);
}
public int PropertyTreeIndex
@@ -94,8 +97,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
if (!SetAndNotify(ref _selectedProfileElement, value)) return;
NotifyOfPropertyChange(nameof(SelectedLayer));
NotifyOfPropertyChange(nameof(SelectedFolder));
- NotifyOfPropertyChange(nameof(StartSegmentEnabled));
- NotifyOfPropertyChange(nameof(EndSegmentEnabled));
}
}
@@ -127,6 +128,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
set => SetAndNotify(ref _timelineViewModel, value);
}
+ public TimelineSegmentViewModel StartTimelineSegmentViewModel
+ {
+ get => _startTimelineSegmentViewModel;
+ set => SetAndNotify(ref _startTimelineSegmentViewModel, value);
+ }
+
+ public TimelineSegmentViewModel MainTimelineSegmentViewModel
+ {
+ get => _mainTimelineSegmentViewModel;
+ set => SetAndNotify(ref _mainTimelineSegmentViewModel, value);
+ }
+
+ public TimelineSegmentViewModel EndTimelineSegmentViewModel
+ {
+ get => _endTimelineSegmentViewModel;
+ set => SetAndNotify(ref _endTimelineSegmentViewModel, value);
+ }
+
protected override void OnInitialActivate()
{
PopulateProperties(ProfileEditorService.SelectedProfileElement);
@@ -227,11 +246,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
TimelineViewModel?.Dispose();
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
+ StartTimelineSegmentViewModel?.Dispose();
+ StartTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.Start);
+ MainTimelineSegmentViewModel?.Dispose();
+ MainTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.Main);
+ EndTimelineSegmentViewModel?.Dispose();
+ EndTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.End);
ApplyLayerBrush();
ApplyEffects();
}
+
+
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
{
ApplyLayerBrush();
@@ -564,163 +591,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
#endregion
#region Segments
-
- public bool StartSegmentEnabled
- {
- get => SelectedProfileElement?.StartSegmentLength != TimeSpan.Zero;
- set
- {
- SelectedProfileElement.StartSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
- ProfileEditorService.UpdateSelectedProfileElement();
- NotifyOfPropertyChange(nameof(StartSegmentEnabled));
- NotifyOfPropertyChange(nameof(CanAddSegment));
- }
- }
- public bool MainSegmentEnabled
- {
- get => SelectedProfileElement?.MainSegmentLength != TimeSpan.Zero;
- set
- {
- SelectedProfileElement.MainSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
- ProfileEditorService.UpdateSelectedProfileElement();
- NotifyOfPropertyChange(nameof(MainSegmentEnabled));
- NotifyOfPropertyChange(nameof(CanAddSegment));
- }
- }
-
- public bool EndSegmentEnabled
- {
- get => SelectedProfileElement?.EndSegmentLength != TimeSpan.Zero;
- set
- {
- SelectedProfileElement.EndSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
- ProfileEditorService.UpdateSelectedProfileElement();
- NotifyOfPropertyChange(nameof(EndSegmentEnabled));
- NotifyOfPropertyChange(nameof(CanAddSegment));
- }
- }
-
- public bool CanAddSegment => !StartSegmentEnabled || !MainSegmentEnabled || !EndSegmentEnabled;
-
- public bool RepeatMainSegment
- {
- get => SelectedProfileElement?.RepeatMainSegment ?? false;
- set
- {
- SelectedProfileElement.RepeatMainSegment = value;
- ProfileEditorService.UpdateSelectedProfileElement();
- NotifyOfPropertyChange(nameof(RepeatMainSegment));
- }
- }
-
- private bool _draggingStartSegment;
- private bool _draggingMainSegment;
- private bool _draggingEndSegment;
-
- public void DisableSegment(string segment)
- {
- if (segment == "Start")
- StartSegmentEnabled = false;
- else if (segment == "Main")
- MainSegmentEnabled = false;
- else if (segment == "End")
- EndSegmentEnabled = false;
- }
-
public void EnableSegment(string segment)
{
if (segment == "Start")
- StartSegmentEnabled = true;
+ StartTimelineSegmentViewModel.EnableSegment();
else if (segment == "Main")
- MainSegmentEnabled = true;
+ MainTimelineSegmentViewModel.EnableSegment();
else if (segment == "End")
- EndSegmentEnabled = true;
- }
-
- public void StartSegmentMouseDown(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).CaptureMouse();
- _draggingStartSegment = true;
- }
-
- public void StartSegmentMouseUp(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).ReleaseMouseCapture();
- _draggingStartSegment = false;
- }
-
- public void MainSegmentMouseDown(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).CaptureMouse();
- _draggingMainSegment = true;
- }
-
- public void MainSegmentMouseUp(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).ReleaseMouseCapture();
- _draggingMainSegment = false;
- }
-
- public void EndSegmentMouseDown(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).CaptureMouse();
- _draggingEndSegment = true;
- }
-
- public void EndSegmentMouseUp(object sender, MouseButtonEventArgs e)
- {
- ((IInputElement) sender).ReleaseMouseCapture();
- _draggingEndSegment = false;
- }
-
- public void SegmentMouseMove(object sender, MouseEventArgs e)
- {
- if (e.LeftButton == MouseButtonState.Pressed)
- {
- // Get the parent grid, need that for our position
- var parent = (IInputElement) VisualTreeHelper.GetParent((DependencyObject) sender);
- var x = Math.Max(0, e.GetPosition(parent).X);
- var newTime = TimeSpan.FromSeconds(x / ProfileEditorService.PixelsPerSecond);
-
- // Round the time to something that fits the current zoom level
- if (ProfileEditorService.PixelsPerSecond < 200)
- newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 5.0) * 5.0);
- else if (ProfileEditorService.PixelsPerSecond < 500)
- newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 2.0) * 2.0);
- else
- newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds));
-
- // If holding down shift, snap to the closest element on the timeline
- if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
- {
- newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, true);
- }
- // If holding down control, round to the closest 50ms
- else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
- {
- newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
- }
-
- if (_draggingStartSegment)
- {
- if (newTime < TimeSpan.FromMilliseconds(100))
- newTime = TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.StartSegmentLength = newTime;
- }
- else if (_draggingMainSegment)
- {
- if (newTime < SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100))
- newTime = SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.MainSegmentLength = newTime - SelectedProfileElement.StartSegmentLength;
- }
- else if (_draggingEndSegment)
- {
- if (newTime < SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100))
- newTime = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.EndSegmentLength = newTime - SelectedProfileElement.StartSegmentLength - SelectedProfileElement.MainSegmentLength;
- }
- }
+ EndTimelineSegmentViewModel.EnableSegment();
}
#endregion
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentView.xaml
new file mode 100644
index 000000000..56d957874
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentView.xaml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs
new file mode 100644
index 000000000..9175f2b64
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs
@@ -0,0 +1,275 @@
+using System;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using Artemis.Core.Models.Profile;
+using Artemis.UI.Shared.Services.Interfaces;
+using Artemis.UI.Shared.Utilities;
+using Stylet;
+
+namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
+{
+ public class TimelineSegmentViewModel : PropertyChangedBase, IDisposable
+ {
+ private bool _draggingSegment;
+ private bool _showSegmentName;
+ private bool _showRepeatButton;
+ private bool _showDisableButton;
+
+ public TimelineSegmentViewModel(IProfileEditorService profileEditorService, SegmentViewModelType segment)
+ {
+ ProfileEditorService = profileEditorService;
+ Segment = segment;
+ SelectedProfileElement = ProfileEditorService.SelectedProfileElement;
+
+ switch (Segment)
+ {
+ case SegmentViewModelType.Start:
+ ToolTip = "This segment is played when a layer starts displaying because it's conditions are met";
+ break;
+ case SegmentViewModelType.Main:
+ ToolTip = "This segment is played while a condition is met, either once or on a repeating loop";
+ break;
+ case SegmentViewModelType.End:
+ ToolTip = "This segment is played once a condition is no longer met";
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(segment));
+ }
+
+ UpdateDisplay();
+ ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
+ SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
+ }
+
+ public RenderProfileElement SelectedProfileElement { get; }
+
+ public SegmentViewModelType Segment { get; }
+ public IProfileEditorService ProfileEditorService { get; }
+ public string ToolTip { get; }
+
+ public TimeSpan SegmentLength
+ {
+ get
+ {
+ return Segment switch
+ {
+ SegmentViewModelType.Start => SelectedProfileElement?.StartSegmentLength ?? TimeSpan.Zero,
+ SegmentViewModelType.Main => SelectedProfileElement?.MainSegmentLength ?? TimeSpan.Zero,
+ SegmentViewModelType.End => SelectedProfileElement?.EndSegmentLength ?? TimeSpan.Zero,
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
+ }
+
+ public double SegmentWidth => ProfileEditorService.PixelsPerSecond * SegmentLength.TotalSeconds;
+
+ public bool SegmentEnabled => SegmentLength != TimeSpan.Zero;
+ public bool IsMainSegment => Segment == SegmentViewModelType.Main;
+
+ // Only the main segment supports this, for any other segment the getter always returns false and the setter does nothing
+ public bool RepeatSegment
+ {
+ get
+ {
+ if (Segment != SegmentViewModelType.Main)
+ return false;
+
+ return SelectedProfileElement?.RepeatMainSegment ?? false;
+ }
+ set
+ {
+ if (Segment != SegmentViewModelType.Main)
+ return;
+
+ SelectedProfileElement.RepeatMainSegment = value;
+ ProfileEditorService.UpdateSelectedProfileElement();
+ NotifyOfPropertyChange(nameof(RepeatSegment));
+ }
+ }
+
+ public double SegmentStartPosition
+ {
+ get
+ {
+ return Segment switch
+ {
+ SegmentViewModelType.Start => 0,
+ SegmentViewModelType.Main => ProfileEditorService.PixelsPerSecond * SelectedProfileElement.StartSegmentLength.TotalSeconds,
+ SegmentViewModelType.End => ProfileEditorService.PixelsPerSecond * (SelectedProfileElement.StartSegmentLength.TotalSeconds + SelectedProfileElement.MainSegmentLength.TotalSeconds),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
+ }
+
+ public bool ShowSegmentName
+ {
+ get => _showSegmentName;
+ set => SetAndNotify(ref _showSegmentName, value);
+ }
+
+ public bool ShowRepeatButton
+ {
+ get => _showRepeatButton;
+ set => SetAndNotify(ref _showRepeatButton, value);
+ }
+
+ public bool ShowDisableButton
+ {
+ get => _showDisableButton;
+ set => SetAndNotify(ref _showDisableButton, value);
+ }
+
+ public void Dispose()
+ {
+ ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
+ SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
+ }
+
+ public void DisableSegment()
+ {
+ switch (Segment)
+ {
+ case SegmentViewModelType.Start:
+ SelectedProfileElement.StartSegmentLength = TimeSpan.Zero;
+ break;
+ case SegmentViewModelType.Main:
+ SelectedProfileElement.MainSegmentLength = TimeSpan.Zero;
+ break;
+ case SegmentViewModelType.End:
+ SelectedProfileElement.EndSegmentLength = TimeSpan.Zero;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ NotifyOfPropertyChange(nameof(SegmentEnabled));
+ ProfileEditorService.UpdateSelectedProfileElement();
+ }
+
+ public void EnableSegment()
+ {
+ switch (Segment)
+ {
+ case SegmentViewModelType.Start:
+ SelectedProfileElement.StartSegmentLength = TimeSpan.FromSeconds(1);
+ break;
+ case SegmentViewModelType.Main:
+ SelectedProfileElement.MainSegmentLength = TimeSpan.FromSeconds(1);
+ break;
+ case SegmentViewModelType.End:
+ SelectedProfileElement.EndSegmentLength = TimeSpan.FromSeconds(1);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ NotifyOfPropertyChange(nameof(SegmentEnabled));
+ ProfileEditorService.UpdateSelectedProfileElement();
+ }
+
+ public void SegmentMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ ((IInputElement) sender).CaptureMouse();
+ _draggingSegment = true;
+ }
+
+ public void SegmentMouseUp(object sender, MouseButtonEventArgs e)
+ {
+ ((IInputElement) sender).ReleaseMouseCapture();
+ _draggingSegment = false;
+ }
+
+ public void SegmentMouseMove(object sender, MouseEventArgs e)
+ {
+ if (e.LeftButton != MouseButtonState.Pressed || !_draggingSegment)
+ return;
+
+ // Get the parent scroll viewer, need that for our position
+ var parent = VisualTreeUtilities.FindParent((DependencyObject) sender, "TimelineHeaderScrollViewer");
+
+ var x = Math.Max(0, e.GetPosition(parent).X);
+ var newTime = TimeSpan.FromSeconds(x / ProfileEditorService.PixelsPerSecond);
+
+ // Round the time to something that fits the current zoom level
+ if (ProfileEditorService.PixelsPerSecond < 200)
+ newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 5.0) * 5.0);
+ else if (ProfileEditorService.PixelsPerSecond < 500)
+ newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 2.0) * 2.0);
+ else
+ newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds));
+
+ // If holding down shift, snap to the closest element on the timeline
+ if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
+ newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, true);
+ // If holding down control, round to the closest 50ms
+ else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
+ newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
+
+
+ if (Segment == SegmentViewModelType.Start)
+ {
+ if (newTime < TimeSpan.FromMilliseconds(100))
+ newTime = TimeSpan.FromMilliseconds(100);
+ SelectedProfileElement.StartSegmentLength = newTime;
+ }
+ else if (Segment == SegmentViewModelType.Main)
+ {
+ if (newTime < SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100))
+ newTime = SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100);
+ SelectedProfileElement.MainSegmentLength = newTime - SelectedProfileElement.StartSegmentLength;
+ }
+ else if (Segment == SegmentViewModelType.End)
+ {
+ if (newTime < SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100))
+ newTime = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100);
+ SelectedProfileElement.EndSegmentLength = newTime - SelectedProfileElement.StartSegmentLength - SelectedProfileElement.MainSegmentLength;
+ }
+
+ NotifyOfPropertyChange(nameof(SegmentLength));
+ NotifyOfPropertyChange(nameof(SegmentWidth));
+
+ UpdateDisplay();
+ }
+
+ private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(RenderProfileElement.StartSegmentLength) ||
+ e.PropertyName == nameof(RenderProfileElement.MainSegmentLength) ||
+ e.PropertyName == nameof(RenderProfileElement.EndSegmentLength))
+ {
+ NotifyOfPropertyChange(nameof(SegmentStartPosition));
+ NotifyOfPropertyChange(nameof(SegmentWidth));
+ }
+ }
+
+
+ private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
+ {
+ NotifyOfPropertyChange(nameof(SegmentWidth));
+ NotifyOfPropertyChange(nameof(SegmentStartPosition));
+
+ UpdateDisplay();
+ }
+
+ private void UpdateDisplay()
+ {
+ if (!IsMainSegment)
+ ShowSegmentName = SegmentWidth > 60;
+ else
+ ShowSegmentName = SegmentWidth > 80;
+
+ ShowRepeatButton = SegmentWidth > 45 && IsMainSegment;
+ ShowDisableButton = SegmentWidth > 25;
+ }
+ }
+
+ public enum SegmentViewModelType
+ {
+ Start,
+ Main,
+ End
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs
index f20b5635a..5aa063b2f 100644
--- a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs
+++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs
@@ -73,6 +73,19 @@ namespace Artemis.Plugins.LayerBrushes.Noise
var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
CreateBitmap(width, height);
+
+ var clipPath = new SKPath(Layer.Path);
+ Layer.ExcludePathFromTranslation(clipPath);
+ clipPath = new SKPath(clipPath);
+ clipPath.Transform(SKMatrix.MakeTranslation(Layer.Path.Bounds.Left * -1, Layer.Path.Bounds.Top * -1));
+
+ // Fill a canvas matching the final area that will be rendered
+ using var bitmapCanvas = new SKCanvas(_bitmap);
+ using var clipPaint = new SKPaint {Color = new SKColor(0, 0, 0, 255)};
+ bitmapCanvas.Clear();
+ bitmapCanvas.Scale(_renderScale);
+ bitmapCanvas.DrawPath(clipPath, clipPaint);
+
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
@@ -84,6 +97,10 @@ namespace Artemis.Plugins.LayerBrushes.Noise
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
continue;
+ var pixel = _bitmap.GetPixel(x, y);
+ if (pixel.Alpha != 255)
+ continue;
+
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
var amount = Math.Max(0f, Math.Min(1f, v));
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/GeneralDataModel.cs b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/GeneralDataModel.cs
index 3d7453178..6828579e5 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/GeneralDataModel.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/GeneralDataModel.cs
@@ -1,62 +1,9 @@
-using System.Collections.Generic;
-using System.Diagnostics;
-using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
-using Artemis.Plugins.Modules.General.DataModel.Windows;
-using SkiaSharp;
+using Artemis.Plugins.Modules.General.DataModel.Windows;
namespace Artemis.Plugins.Modules.General.DataModel
{
public class GeneralDataModel : Core.Plugins.Abstract.DataModels.DataModel
{
- public TestDataModel TestDataModel { get; set; }
- public WindowsDataModel Windows { get; set; }
-
-
- public GeneralDataModel()
- {
- TestDataModel = new TestDataModel();
- Windows = new WindowsDataModel();
- }
- }
-
- public class TestDataModel
- {
- public TestDataModel()
- {
- PlayerInfo = new PlayerInfo();
- IntsList = new List();
- PlayerInfosList = new List();
- }
-
- [DataModelProperty(Name = "A test string", Description = "This is a test string that's not of any use outside testing!")]
- public string TestString { get; set; }
-
- [DataModelProperty(Name = "A test boolean", Description = "This is a test boolean that's not of any use outside testing!")]
- public bool TestBoolean { get; set; }
-
- public SKColor TestColor { get; set; } = new SKColor(221, 21, 152);
-
- [DataModelProperty(Name = "Player info", Description = "[TEST] Contains information about the player")]
- public PlayerInfo PlayerInfo { get; set; }
-
- public double UpdatesDividedByFour { get; set; }
- public int Updates { get; set; }
-
- public List IntsList { get; set; }
- public List PlayerInfosList { get; set; }
- }
-
- public class PlayerInfo
- {
- [DataModelProperty(Name = "A test string", Description = "This is a test string that's not of any use outside testing!")]
- public string TestString { get; set; }
-
- [DataModelProperty(Name = "A test boolean", Description = "This is a test boolean that's not of any use outside testing!")]
- public bool TestBoolean { get; set; }
-
- [DataModelProperty(Affix = "%", MinValue = 0, MaxValue = 100)]
- public int Health { get; set; }
-
- public SKPoint Position { get; set; }
+ public WindowDataModel ActiveWindow { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowDataModel.cs b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowDataModel.cs
index 128295d79..17e07abd4 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowDataModel.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowDataModel.cs
@@ -16,7 +16,7 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
ProcessName = process.ProcessName;
// Accessing MainModule requires admin privileges, this way does not
- ProgramLocation = WindowMonitor.GetProcessFilename(process);
+ ProgramLocation = WindowUtilities.GetProcessFilename(process);
}
public string WindowTitle { get; set; }
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowsDataModel.cs b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowsDataModel.cs
index e6b100d8b..b42815cb3 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowsDataModel.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/DataModel/Windows/WindowsDataModel.cs
@@ -6,7 +6,6 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
{
public class WindowsDataModel
{
- public WindowDataModel ActiveWindow { get; set; }
- public List OpenWindows { get; set; }
+
}
}
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
index 17062b515..a9e01ffed 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
@@ -1,33 +1,16 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows.Interop;
-using Artemis.Core;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.Abstract.ViewModels;
-using Artemis.Core.Plugins.Models;
using Artemis.Plugins.Modules.General.DataModel;
using Artemis.Plugins.Modules.General.DataModel.Windows;
using Artemis.Plugins.Modules.General.Utilities;
using Artemis.Plugins.Modules.General.ViewModels;
-using SkiaSharp;
namespace Artemis.Plugins.Modules.General
{
public class GeneralModule : ProfileModule
{
- private readonly PluginSettings _settings;
- private readonly Random _rand;
-
-
- public GeneralModule(PluginSettings settings)
- {
- _settings = settings;
- _rand = new Random();
- }
-
public override IEnumerable GetViewModels()
{
return new List {new GeneralViewModel(this)};
@@ -35,19 +18,7 @@ namespace Artemis.Plugins.Modules.General
public override void Update(double deltaTime)
{
- DataModel.TestDataModel.UpdatesDividedByFour += 0.25;
- DataModel.TestDataModel.Updates += 1;
- DataModel.TestDataModel.PlayerInfo.Position = new SKPoint(_rand.Next(100), _rand.Next(100));
- DataModel.TestDataModel.PlayerInfo.Health++;
- if (DataModel.TestDataModel.PlayerInfo.Health > 200)
- DataModel.TestDataModel.PlayerInfo.Health = 0;
-
- DataModel.TestDataModel.IntsList[0] = _rand.Next();
- DataModel.TestDataModel.IntsList[2] = _rand.Next();
-
UpdateCurrentWindow();
- UpdateBackgroundWindows();
-
base.Update(deltaTime);
}
@@ -56,11 +27,6 @@ namespace Artemis.Plugins.Modules.General
DisplayName = "General";
DisplayIcon = "AllInclusive";
ExpandsDataModel = true;
-
- DataModel.TestDataModel.IntsList = new List {_rand.Next(), _rand.Next(), _rand.Next()};
- DataModel.TestDataModel.PlayerInfosList = new List {new PlayerInfo()};
-
- var testSetting = _settings.GetSetting("TestSetting", DateTime.Now);
}
public override void DisablePlugin()
@@ -69,31 +35,11 @@ namespace Artemis.Plugins.Modules.General
#region Open windows
- private DateTime _lastBackgroundWindowsUpdate;
-
public void UpdateCurrentWindow()
{
- var processId = WindowMonitor.GetActiveProcessId();
- if (DataModel.Windows.ActiveWindow == null || DataModel.Windows.ActiveWindow.Process.Id != processId)
- DataModel.Windows.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
- }
-
- public void UpdateBackgroundWindows()
- {
- // This is kinda slow so lets not do it very often and lets do it in a task
- if (DateTime.Now - _lastBackgroundWindowsUpdate < TimeSpan.FromSeconds(5))
- return;
-
- _lastBackgroundWindowsUpdate = DateTime.Now;
- Task.Run(() =>
- {
- // All processes with a main window handle are considered open windows
- DataModel.Windows.OpenWindows = Process.GetProcesses()
- .Where(p => p.MainWindowHandle != IntPtr.Zero)
- .Select(p => new WindowDataModel(p))
- .Where(w => !string.IsNullOrEmpty(w.WindowTitle))
- .ToList();
- });
+ var processId = WindowUtilities.GetActiveProcessId();
+ if (DataModel.ActiveWindow == null || DataModel.ActiveWindow.Process.Id != processId)
+ DataModel.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
}
#endregion
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowMonitor.cs b/src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowUtilities.cs
similarity index 97%
rename from src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowMonitor.cs
rename to src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowUtilities.cs
index 02a4c5377..37267cc4f 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowMonitor.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/Utilities/WindowUtilities.cs
@@ -5,7 +5,7 @@ using System.Text;
namespace Artemis.Plugins.Modules.General.Utilities
{
- public static class WindowMonitor
+ public static class WindowUtilities
{
public static int GetActiveProcessId()
{