mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profile editor - Added F5 previewing
Core - Performance fixes
This commit is contained in:
parent
5b183d3010
commit
8c7bbc3f0f
@ -149,9 +149,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
{
|
{
|
||||||
if (TriggerMode == EventTriggerMode.Toggle)
|
if (TriggerMode == EventTriggerMode.Toggle)
|
||||||
{
|
{
|
||||||
if (!IsMet && _wasMet)
|
if (IsMet && !_wasMet)
|
||||||
ProfileElement.Timeline.JumpToEnd();
|
|
||||||
else if (IsMet && !_wasMet)
|
|
||||||
ProfileElement.Timeline.JumpToStart();
|
ProfileElement.Timeline.JumpToStart();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -164,12 +162,13 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
{
|
{
|
||||||
if (OverlapMode == EventOverlapMode.Restart)
|
if (OverlapMode == EventOverlapMode.Restart)
|
||||||
ProfileElement.Timeline.JumpToStart();
|
ProfileElement.Timeline.JumpToStart();
|
||||||
else if (OverlapMode == EventOverlapMode.Copy && ProfileElement is Layer layer)
|
else if (OverlapMode == EventOverlapMode.Copy && ProfileElement is Layer layer && layer.Parent is not Layer)
|
||||||
layer.CreateCopyAsChild();
|
layer.CreateRenderCopy(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileElement.Timeline.Update(TimeSpan.FromSeconds(deltaTime), TriggerMode == EventTriggerMode.Toggle);
|
// Stick to mean segment in toggle mode for as long as the condition is met
|
||||||
|
ProfileElement.Timeline.Update(TimeSpan.FromSeconds(deltaTime), TriggerMode == EventTriggerMode.Toggle && IsMet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -225,10 +224,9 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
INode? existingEventNode = Script.Nodes.FirstOrDefault(n => n.Id == EventDefaultNode.NodeId);
|
INode? existingEventNode = Script.Nodes.FirstOrDefault(n => n.Id == EventDefaultNode.NodeId);
|
||||||
if (existingEventNode != null)
|
if (existingEventNode != null)
|
||||||
_eventNode = (EventDefaultNode) existingEventNode;
|
_eventNode = (EventDefaultNode) existingEventNode;
|
||||||
|
|
||||||
UpdateEventNode();
|
UpdateEventNode();
|
||||||
Script.LoadConnections();
|
Script.LoadConnections();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -190,8 +190,11 @@ namespace Artemis.Core
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.InternalPreProcess(canvas, rendererBounds, layerPaint);
|
{
|
||||||
|
if (!baseLayerEffect.Suspended)
|
||||||
|
baseLayerEffect.InternalPreProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
}
|
||||||
|
|
||||||
// No point rendering if the alpha was set to zero by one of the effects
|
// No point rendering if the alpha was set to zero by one of the effects
|
||||||
if (layerPaint.Color.Alpha == 0)
|
if (layerPaint.Color.Alpha == 0)
|
||||||
@ -204,8 +207,11 @@ namespace Artemis.Core
|
|||||||
for (int index = Children.Count - 1; index > -1; index--)
|
for (int index = Children.Count - 1; index > -1; index--)
|
||||||
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.InternalPostProcess(canvas, rendererBounds, layerPaint);
|
{
|
||||||
|
if (!baseLayerEffect.Suspended)
|
||||||
|
baseLayerEffect.InternalPostProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,6 +16,7 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Layer : RenderProfileElement
|
public sealed class Layer : RenderProfileElement
|
||||||
{
|
{
|
||||||
|
private readonly List<Layer> _renderCopies;
|
||||||
private LayerGeneralProperties _general;
|
private LayerGeneralProperties _general;
|
||||||
private BaseLayerBrush? _layerBrush;
|
private BaseLayerBrush? _layerBrush;
|
||||||
private LayerShape? _layerShape;
|
private LayerShape? _layerShape;
|
||||||
@ -37,6 +38,8 @@ namespace Artemis.Core
|
|||||||
Name = name;
|
Name = name;
|
||||||
Suspended = false;
|
Suspended = false;
|
||||||
|
|
||||||
|
// TODO: move to top
|
||||||
|
_renderCopies = new List<Layer>();
|
||||||
_general = new LayerGeneralProperties();
|
_general = new LayerGeneralProperties();
|
||||||
_transform = new LayerTransformProperties();
|
_transform = new LayerTransformProperties();
|
||||||
|
|
||||||
@ -61,6 +64,8 @@ namespace Artemis.Core
|
|||||||
Profile = profile;
|
Profile = profile;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
|
|
||||||
|
// TODO: move to top
|
||||||
|
_renderCopies = new List<Layer>();
|
||||||
_general = new LayerGeneralProperties();
|
_general = new LayerGeneralProperties();
|
||||||
_transform = new LayerTransformProperties();
|
_transform = new LayerTransformProperties();
|
||||||
|
|
||||||
@ -76,15 +81,15 @@ namespace Artemis.Core
|
|||||||
/// Creates a new instance of the <see cref="Layer" /> class by copying the provided <paramref name="source"/>.
|
/// Creates a new instance of the <see cref="Layer" /> class by copying the provided <paramref name="source"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The layer to copy</param>
|
/// <param name="source">The layer to copy</param>
|
||||||
/// <param name="parent">The parent of the layer</param>
|
private Layer(Layer source) : base(source, source.Profile)
|
||||||
public Layer(Layer source, ProfileElement parent) : base(parent, parent.Profile)
|
|
||||||
{
|
{
|
||||||
LayerEntity = CoreJson.DeserializeObject<LayerEntity>(CoreJson.SerializeObject(source.LayerEntity, true), true) ?? new LayerEntity();
|
LayerEntity = source.LayerEntity;
|
||||||
LayerEntity.Id = Guid.NewGuid();
|
|
||||||
|
|
||||||
Profile = source.Profile;
|
Profile = source.Profile;
|
||||||
Parent = parent;
|
Parent = source;
|
||||||
|
|
||||||
|
// TODO: move to top
|
||||||
|
_renderCopies = new List<Layer>();
|
||||||
_general = new LayerGeneralProperties();
|
_general = new LayerGeneralProperties();
|
||||||
_transform = new LayerTransformProperties();
|
_transform = new LayerTransformProperties();
|
||||||
|
|
||||||
@ -94,6 +99,13 @@ namespace Artemis.Core
|
|||||||
Adapter = new LayerAdapter(this);
|
Adapter = new LayerAdapter(this);
|
||||||
Load();
|
Load();
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
|
Timeline.JumpToStart();
|
||||||
|
AddLeds(source.Leds);
|
||||||
|
Enable();
|
||||||
|
|
||||||
|
// After loading using the source entity create a new entity so the next call to Save won't mess with the source, just in case.
|
||||||
|
LayerEntity = new LayerEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -373,7 +385,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
if (ShouldBeEnabled)
|
if (ShouldBeEnabled)
|
||||||
Enable();
|
Enable();
|
||||||
else if (Timeline.IsFinished && !Children.Any())
|
else if (Timeline.IsFinished && !_renderCopies.Any())
|
||||||
Disable();
|
Disable();
|
||||||
|
|
||||||
if (Timeline.Delta == TimeSpan.Zero)
|
if (Timeline.Delta == TimeSpan.Zero)
|
||||||
@ -383,22 +395,26 @@ namespace Artemis.Core
|
|||||||
Transform.Update(Timeline);
|
Transform.Update(Timeline);
|
||||||
LayerBrush?.InternalUpdate(Timeline);
|
LayerBrush?.InternalUpdate(Timeline);
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.InternalUpdate(Timeline);
|
|
||||||
|
|
||||||
// Remove children that finished their timeline and update the rest
|
|
||||||
for (int index = 0; index < Children.Count; index++)
|
|
||||||
{
|
{
|
||||||
Layer child = (Layer) Children[index];
|
if (!baseLayerEffect.Suspended)
|
||||||
|
baseLayerEffect.InternalUpdate(Timeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove render copies that finished their timeline and update the rest
|
||||||
|
for (int index = 0; index < _renderCopies.Count; index++)
|
||||||
|
{
|
||||||
|
Layer child = _renderCopies[index];
|
||||||
if (!child.Timeline.IsFinished)
|
if (!child.Timeline.IsFinished)
|
||||||
{
|
{
|
||||||
child.Update(deltaTime);
|
child.Update(deltaTime);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
RemoveChild(child);
|
{
|
||||||
child.Dispose();
|
_renderCopies.Remove(child);
|
||||||
index--;
|
child.Dispose();
|
||||||
|
index--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,20 +424,16 @@ namespace Artemis.Core
|
|||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
RenderSelf(canvas, basePosition);
|
RenderLayer(canvas, basePosition);
|
||||||
RenderChildren(canvas, basePosition);
|
RenderCopies(canvas, basePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderSelf(SKCanvas canvas, SKPointI basePosition)
|
private void RenderLayer(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
// Ensure the layer is ready
|
// Ensure the layer is ready
|
||||||
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any())
|
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Render children first so they go below
|
|
||||||
for (int i = Children.Count - 1; i >= 0; i--)
|
|
||||||
Children[i].Render(canvas, basePosition);
|
|
||||||
|
|
||||||
// Ensure the brush is ready
|
// Ensure the brush is ready
|
||||||
if (LayerBrush == null || LayerBrush?.BaseProperties?.PropertiesInitialized == false)
|
if (LayerBrush == null || LayerBrush?.BaseProperties?.PropertiesInitialized == false)
|
||||||
return;
|
return;
|
||||||
@ -432,7 +444,7 @@ namespace Artemis.Core
|
|||||||
SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low};
|
SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low};
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
canvas.Save();
|
using SKAutoCanvasRestore _ = new(canvas);
|
||||||
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||||
using SKPath clipPath = new(Path);
|
using SKPath clipPath = new(Path);
|
||||||
clipPath.Transform(SKMatrix.CreateTranslation(Bounds.Left * -1, Bounds.Top * -1));
|
clipPath.Transform(SKMatrix.CreateTranslation(Bounds.Left * -1, Bounds.Top * -1));
|
||||||
@ -478,18 +490,16 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
canvas.Restore();
|
|
||||||
layerPaint.DisposeSelfAndProperties();
|
layerPaint.DisposeSelfAndProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline.ClearDelta();
|
Timeline.ClearDelta();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderChildren(SKCanvas canvas, SKPointI basePosition)
|
private void RenderCopies(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
// Render children first so they go below
|
for (int i = _renderCopies.Count - 1; i >= 0; i--)
|
||||||
for (int i = Children.Count - 1; i >= 0; i--)
|
_renderCopies[i].Render(canvas, basePosition);
|
||||||
Children[i].Render(canvas, basePosition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -549,23 +559,24 @@ namespace Artemis.Core
|
|||||||
else
|
else
|
||||||
Timeline.JumpToEnd();
|
Timeline.JumpToEnd();
|
||||||
|
|
||||||
while (Children.Any())
|
while (_renderCopies.Any())
|
||||||
{
|
{
|
||||||
Children[0].Dispose();
|
_renderCopies[0].Dispose();
|
||||||
RemoveChild(Children[0]);
|
_renderCopies.RemoveAt(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a copy of this layer as a child and plays it once
|
/// Creates a copy of this layer and renders it alongside this layer for as long as its timeline lasts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CreateCopyAsChild()
|
/// <param name="max">The total maximum of render copies to keep</param>
|
||||||
|
public void CreateRenderCopy(int max)
|
||||||
{
|
{
|
||||||
Layer copy = new(this, this);
|
if (_renderCopies.Count >= max)
|
||||||
copy.AddLeds(Leds);
|
return;
|
||||||
copy.Enable();
|
|
||||||
copy.Timeline.JumpToStart();
|
Layer copy = new(this);
|
||||||
AddChild(copy);
|
_renderCopies.Add(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CalculateRenderProperties()
|
internal void CalculateRenderProperties()
|
||||||
@ -623,26 +634,23 @@ namespace Artemis.Core
|
|||||||
if (LayerBrush == null)
|
if (LayerBrush == null)
|
||||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
canvas.SaveLayer(layerPaint);
|
if (!baseLayerEffect.Suspended)
|
||||||
canvas.ClipPath(renderPath);
|
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
|
||||||
|
|
||||||
// Restore the blend mode before doing the actual render
|
|
||||||
layerPaint.BlendMode = SKBlendMode.SrcOver;
|
|
||||||
|
|
||||||
LayerBrush.InternalRender(canvas, bounds, layerPaint);
|
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
|
||||||
baseLayerEffect.InternalPostProcess(canvas, bounds, layerPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
using SKAutoCanvasRestore _ = new(canvas);
|
||||||
|
canvas.ClipPath(renderPath);
|
||||||
|
|
||||||
|
// Restore the blend mode before doing the actual render
|
||||||
|
layerPaint.BlendMode = SKBlendMode.SrcOver;
|
||||||
|
LayerBrush.InternalRender(canvas, bounds, layerPaint);
|
||||||
|
|
||||||
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||||
{
|
{
|
||||||
canvas.Restore();
|
if (!baseLayerEffect.Suspended)
|
||||||
|
baseLayerEffect.InternalPostProcess(canvas, bounds, layerPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,11 @@ public interface IProfileEditorService : IArtemisSharedUIService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IObservable<int> PixelsPerSecond { get; }
|
IObservable<int> PixelsPerSecond { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an observable of the suspended state.
|
||||||
|
/// </summary>
|
||||||
|
IObservable<bool> SuspendedEditing { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a source list of all available editor tools.
|
/// Gets a source list of all available editor tools.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -87,6 +92,12 @@ public interface IProfileEditorService : IArtemisSharedUIService
|
|||||||
/// <param name="pixelsPerSecond">The new pixels per second.</param>
|
/// <param name="pixelsPerSecond">The new pixels per second.</param>
|
||||||
void ChangePixelsPerSecond(int pixelsPerSecond);
|
void ChangePixelsPerSecond(int pixelsPerSecond);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the current suspended state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="suspend">The new suspended state.</param>
|
||||||
|
void ChangeSuspendedEditing(bool suspend);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects the provided keyframe.
|
/// Selects the provided keyframe.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -62,8 +62,6 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public IObservable<bool> SuspendedEditing { get; }
|
|
||||||
|
|
||||||
private ProfileEditorHistory? GetHistory(ProfileConfiguration? profileConfiguration)
|
private ProfileEditorHistory? GetHistory(ProfileConfiguration? profileConfiguration)
|
||||||
{
|
{
|
||||||
if (profileConfiguration == null)
|
if (profileConfiguration == null)
|
||||||
@ -107,6 +105,7 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
public IObservable<RenderProfileElement?> ProfileElement { get; }
|
public IObservable<RenderProfileElement?> ProfileElement { get; }
|
||||||
public IObservable<ILayerProperty?> LayerProperty { get; }
|
public IObservable<ILayerProperty?> LayerProperty { get; }
|
||||||
public IObservable<ProfileEditorHistory?> History { get; }
|
public IObservable<ProfileEditorHistory?> History { get; }
|
||||||
|
public IObservable<bool> SuspendedEditing { get; }
|
||||||
public IObservable<TimeSpan> Time { get; }
|
public IObservable<TimeSpan> Time { get; }
|
||||||
public IObservable<bool> Playing { get; }
|
public IObservable<bool> Playing { get; }
|
||||||
public IObservable<int> PixelsPerSecond { get; }
|
public IObservable<int> PixelsPerSecond { get; }
|
||||||
@ -180,6 +179,25 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
_timeSubject.OnNext(time);
|
_timeSubject.OnNext(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ChangeSuspendedEditing(bool suspend)
|
||||||
|
{
|
||||||
|
if (_suspendedEditingSubject.Value == suspend)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_suspendedEditingSubject.OnNext(suspend);
|
||||||
|
if (suspend)
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
_profileService.RenderForEditor = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_profileConfigurationSubject.Value != null)
|
||||||
|
_profileService.RenderForEditor = true;
|
||||||
|
Tick(_timeSubject.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SelectKeyframe(ILayerPropertyKeyframe? keyframe, bool expand, bool toggle)
|
public void SelectKeyframe(ILayerPropertyKeyframe? keyframe, bool expand, bool toggle)
|
||||||
{
|
{
|
||||||
if (keyframe == null)
|
if (keyframe == null)
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
xmlns:controls="clr-namespace:Artemis.UI.Controls"
|
xmlns:controls="clr-namespace:Artemis.UI.Controls"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="350"
|
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="350"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.PropertiesView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.PropertiesView"
|
||||||
x:DataType="local:PropertiesViewModel">
|
x:DataType="local:PropertiesViewModel">
|
||||||
|
|||||||
@ -31,6 +31,7 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
|||||||
private ObservableAsPropertyHelper<ILayerProperty?>? _layerProperty;
|
private ObservableAsPropertyHelper<ILayerProperty?>? _layerProperty;
|
||||||
private ObservableAsPropertyHelper<int>? _pixelsPerSecond;
|
private ObservableAsPropertyHelper<int>? _pixelsPerSecond;
|
||||||
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
|
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public PropertiesViewModel(IProfileEditorService profileEditorService,
|
public PropertiesViewModel(IProfileEditorService profileEditorService,
|
||||||
@ -55,6 +56,7 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
|||||||
_profileElement = profileEditorService.ProfileElement.ToProperty(this, vm => vm.ProfileElement).DisposeWith(d);
|
_profileElement = profileEditorService.ProfileElement.ToProperty(this, vm => vm.ProfileElement).DisposeWith(d);
|
||||||
_pixelsPerSecond = profileEditorService.PixelsPerSecond.ToProperty(this, vm => vm.PixelsPerSecond).DisposeWith(d);
|
_pixelsPerSecond = profileEditorService.PixelsPerSecond.ToProperty(this, vm => vm.PixelsPerSecond).DisposeWith(d);
|
||||||
_layerProperty = profileEditorService.LayerProperty.ToProperty(this, vm => vm.LayerProperty).DisposeWith(d);
|
_layerProperty = profileEditorService.LayerProperty.ToProperty(this, vm => vm.LayerProperty).DisposeWith(d);
|
||||||
|
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
|
||||||
Disposable.Create(() =>
|
Disposable.Create(() =>
|
||||||
{
|
{
|
||||||
_settingsService.SaveAllSettings();
|
_settingsService.SaveAllSettings();
|
||||||
@ -94,11 +96,13 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
|||||||
public RenderProfileElement? ProfileElement => _profileElement?.Value;
|
public RenderProfileElement? ProfileElement => _profileElement?.Value;
|
||||||
public Layer? Layer => _profileElement?.Value as Layer;
|
public Layer? Layer => _profileElement?.Value as Layer;
|
||||||
public ILayerProperty? LayerProperty => _layerProperty?.Value;
|
public ILayerProperty? LayerProperty => _layerProperty?.Value;
|
||||||
|
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
|
||||||
|
|
||||||
public int PixelsPerSecond => _pixelsPerSecond?.Value ?? 0;
|
public int PixelsPerSecond => _pixelsPerSecond?.Value ?? 0;
|
||||||
public IObservable<bool> Playing => _profileEditorService.Playing;
|
public IObservable<bool> Playing => _profileEditorService.Playing;
|
||||||
public PluginSetting<double> PropertiesTreeWidth => _settingsService.GetSetting("ProfileEditor.PropertiesTreeWidth", 500.0);
|
public PluginSetting<double> PropertiesTreeWidth => _settingsService.GetSetting("ProfileEditor.PropertiesTreeWidth", 500.0);
|
||||||
|
|
||||||
|
|
||||||
private void UpdatePropertyGroups()
|
private void UpdatePropertyGroups()
|
||||||
{
|
{
|
||||||
if (ProfileElement == null)
|
if (ProfileElement == null)
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<!-- The middle layer contains visualizers -->
|
<!-- The middle layer contains visualizers -->
|
||||||
<ItemsControl Items="{CompiledBinding Visualizers}" ClipToBounds="False">
|
<ItemsControl Items="{CompiledBinding Visualizers}" ClipToBounds="False" IsVisible="{CompiledBinding !SuspendedEditing}">
|
||||||
<ItemsControl.Styles>
|
<ItemsControl.Styles>
|
||||||
<Style Selector="ContentPresenter">
|
<Style Selector="ContentPresenter">
|
||||||
<Setter Property="Canvas.Left" Value="{Binding X}" />
|
<Setter Property="Canvas.Left" Value="{Binding X}" />
|
||||||
@ -74,7 +74,7 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<!-- The top layer contains tools -->
|
<!-- The top layer contains tools -->
|
||||||
<ItemsControl Items="{CompiledBinding Tools}" ClipToBounds="False">
|
<ItemsControl Items="{CompiledBinding Tools}" ClipToBounds="False" IsVisible="{CompiledBinding !SuspendedEditing}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<Grid />
|
<Grid />
|
||||||
|
|||||||
@ -22,6 +22,7 @@ public class VisualEditorViewModel : ActivatableViewModelBase
|
|||||||
private readonly SourceList<IVisualizerViewModel> _visualizers;
|
private readonly SourceList<IVisualizerViewModel> _visualizers;
|
||||||
private readonly IProfileEditorVmFactory _vmFactory;
|
private readonly IProfileEditorVmFactory _vmFactory;
|
||||||
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
||||||
private ReadOnlyObservableCollection<IToolViewModel> _tools;
|
private ReadOnlyObservableCollection<IToolViewModel> _tools;
|
||||||
|
|
||||||
public VisualEditorViewModel(IProfileEditorService profileEditorService, IRgbService rgbService, IProfileEditorVmFactory vmFactory)
|
public VisualEditorViewModel(IProfileEditorService profileEditorService, IRgbService rgbService, IProfileEditorVmFactory vmFactory)
|
||||||
@ -38,12 +39,10 @@ public class VisualEditorViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
_profileConfiguration = profileEditorService.ProfileConfiguration
|
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
|
||||||
.ToProperty(this, vm => vm.ProfileConfiguration)
|
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
|
||||||
.DisposeWith(d);
|
profileEditorService.ProfileConfiguration.Subscribe(CreateVisualizers).DisposeWith(d);
|
||||||
profileEditorService.ProfileConfiguration
|
|
||||||
.Subscribe(CreateVisualizers)
|
|
||||||
.DisposeWith(d);
|
|
||||||
profileEditorService.Tools
|
profileEditorService.Tools
|
||||||
.Connect()
|
.Connect()
|
||||||
.AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected)).Filter(t => t.IsSelected).Bind(out ReadOnlyObservableCollection<IToolViewModel> tools)
|
.AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected)).Filter(t => t.IsSelected).Bind(out ReadOnlyObservableCollection<IToolViewModel> tools)
|
||||||
@ -71,6 +70,7 @@ public class VisualEditorViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
||||||
|
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
|
||||||
|
|
||||||
public ObservableCollection<ArtemisDevice> Devices { get; }
|
public ObservableCollection<ArtemisDevice> Devices { get; }
|
||||||
public ReadOnlyObservableCollection<IVisualizerViewModel> Visualizers { get; }
|
public ReadOnlyObservableCollection<IVisualizerViewModel> Visualizers { get; }
|
||||||
|
|||||||
@ -13,9 +13,19 @@
|
|||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="Border.suspended-editing">
|
||||||
|
<Setter Property="Margin" Value="-10" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SmokeFillColorDefault}" />
|
||||||
|
<Setter Property="IsVisible" Value="{CompiledBinding SuspendedEditing}" />
|
||||||
|
<Setter Property="CornerRadius" Value="{DynamicResource CardCornerRadius}" />
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
<UserControl.KeyBindings>
|
<UserControl.KeyBindings>
|
||||||
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z"></KeyBinding>
|
||||||
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y"></KeyBinding>
|
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y"></KeyBinding>
|
||||||
|
<KeyBinding Command="{CompiledBinding ToggleSuspend}" Gesture="F5"></KeyBinding>
|
||||||
|
<KeyBinding Command="{CompiledBinding ToggleAutoSuspend}" Gesture="Shift+F5"></KeyBinding>
|
||||||
</UserControl.KeyBindings>
|
</UserControl.KeyBindings>
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="GridSplitter.editor-grid-splitter-vertical">
|
<Style Selector="GridSplitter.editor-grid-splitter-vertical">
|
||||||
@ -78,7 +88,23 @@
|
|||||||
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
||||||
|
|
||||||
<Border Grid.Row="2" Classes="card card-condensed" Margin="4" Padding="0" ClipToBounds="True">
|
<Border Grid.Row="2" Classes="card card-condensed" Margin="4" Padding="0" ClipToBounds="True">
|
||||||
<ContentControl Content="{CompiledBinding PropertiesViewModel}" />
|
<Panel>
|
||||||
|
<ContentControl Content="{CompiledBinding PropertiesViewModel}" />
|
||||||
|
<Border Classes="suspended-editing">
|
||||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="16">
|
||||||
|
<avalonia:MaterialIcon Kind="TimerOffOutline" Width="125" Height="125" HorizontalAlignment="Center" />
|
||||||
|
<TextBlock Classes="h4" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 10">
|
||||||
|
Timeline suspended
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center">
|
||||||
|
The profile is currently running in normal mode and the timeline cannot be edited.
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center">
|
||||||
|
Press F5 to switch between editor mode and normal mode. Auto-switching can be disabled in the run menu.
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Panel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@ -91,13 +117,19 @@
|
|||||||
<RowDefinition Height="{CompiledBinding ConditionsHeight.Value, Mode=TwoWay, Converter={StaticResource DoubleToGridLengthConverter}}" />
|
<RowDefinition Height="{CompiledBinding ConditionsHeight.Value, Mode=TwoWay, Converter={StaticResource DoubleToGridLengthConverter}}" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Border Grid.Row="0" Classes="card card-condensed" Margin="4 0 4 4">
|
<Border Grid.Row="0" Classes="card card-condensed" Margin="4 0 4 4">
|
||||||
<ContentControl Content="{CompiledBinding ProfileTreeViewModel}" />
|
<Panel>
|
||||||
|
<ContentControl Content="{CompiledBinding ProfileTreeViewModel}" />
|
||||||
|
<Border Classes="suspended-editing" />
|
||||||
|
</Panel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
||||||
|
|
||||||
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
||||||
<ContentControl Content="{CompiledBinding DisplayConditionScriptViewModel}"></ContentControl>
|
<Panel>
|
||||||
|
<ContentControl Content="{CompiledBinding DisplayConditionScriptViewModel}"></ContentControl>
|
||||||
|
<Border Classes="suspended-editing" />
|
||||||
|
</Panel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
@ -17,9 +18,11 @@ namespace Artemis.UI.Screens.ProfileEditor;
|
|||||||
|
|
||||||
public class ProfileEditorViewModel : MainScreenViewModel
|
public class ProfileEditorViewModel : MainScreenViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
private ObservableAsPropertyHelper<ProfileEditorHistory?>? _history;
|
private ObservableAsPropertyHelper<ProfileEditorHistory?>? _history;
|
||||||
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
||||||
|
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
||||||
private ReadOnlyObservableCollection<IToolViewModel>? _tools;
|
private ReadOnlyObservableCollection<IToolViewModel>? _tools;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -34,6 +37,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
StatusBarViewModel statusBarViewModel)
|
StatusBarViewModel statusBarViewModel)
|
||||||
: base(hostScreen, "profile-editor")
|
: base(hostScreen, "profile-editor")
|
||||||
{
|
{
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
VisualEditorViewModel = visualEditorViewModel;
|
VisualEditorViewModel = visualEditorViewModel;
|
||||||
ProfileTreeViewModel = profileTreeViewModel;
|
ProfileTreeViewModel = profileTreeViewModel;
|
||||||
@ -41,11 +45,12 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
DisplayConditionScriptViewModel = displayConditionScriptViewModel;
|
DisplayConditionScriptViewModel = displayConditionScriptViewModel;
|
||||||
StatusBarViewModel = statusBarViewModel;
|
StatusBarViewModel = statusBarViewModel;
|
||||||
TitleBarViewModel = profileEditorTitleBarViewModel;
|
TitleBarViewModel = profileEditorTitleBarViewModel;
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
|
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
|
||||||
_history = profileEditorService.History.ToProperty(this, vm => vm.History).DisposeWith(d);
|
_history = profileEditorService.History.ToProperty(this, vm => vm.History).DisposeWith(d);
|
||||||
|
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
|
||||||
profileEditorService.Tools.Connect()
|
profileEditorService.Tools.Connect()
|
||||||
.Filter(t => t.ShowInToolbar)
|
.Filter(t => t.ShowInToolbar)
|
||||||
.Sort(SortExpressionComparer<IToolViewModel>.Ascending(vm => vm.Order))
|
.Sort(SortExpressionComparer<IToolViewModel>.Ascending(vm => vm.Order))
|
||||||
@ -54,6 +59,9 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
Tools = tools;
|
Tools = tools;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ToggleSuspend = ReactiveCommand.Create(ExecuteToggleSuspend);
|
||||||
|
ToggleAutoSuspend = ReactiveCommand.Create(ExecuteToggleAutoSuspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualEditorViewModel VisualEditorViewModel { get; }
|
public VisualEditorViewModel VisualEditorViewModel { get; }
|
||||||
@ -70,12 +78,24 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
|
|
||||||
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
||||||
public ProfileEditorHistory? History => _history?.Value;
|
public ProfileEditorHistory? History => _history?.Value;
|
||||||
|
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
|
||||||
public PluginSetting<double> TreeWidth => _settingsService.GetSetting("ProfileEditor.TreeWidth", 350.0);
|
public PluginSetting<double> TreeWidth => _settingsService.GetSetting("ProfileEditor.TreeWidth", 350.0);
|
||||||
public PluginSetting<double> ConditionsHeight => _settingsService.GetSetting("ProfileEditor.ConditionsHeight", 300.0);
|
public PluginSetting<double> ConditionsHeight => _settingsService.GetSetting("ProfileEditor.ConditionsHeight", 300.0);
|
||||||
public PluginSetting<double> PropertiesHeight => _settingsService.GetSetting("ProfileEditor.PropertiesHeight", 300.0);
|
public PluginSetting<double> PropertiesHeight => _settingsService.GetSetting("ProfileEditor.PropertiesHeight", 300.0);
|
||||||
|
public ReactiveCommand<Unit, Unit> ToggleSuspend { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ToggleAutoSuspend { get; }
|
||||||
|
|
||||||
public void OpenUrl(string url)
|
public void OpenUrl(string url)
|
||||||
{
|
{
|
||||||
Utilities.OpenUrl(url);
|
Utilities.OpenUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleSuspend()
|
||||||
|
{
|
||||||
|
_profileEditorService.ChangeSuspendedEditing(!SuspendedEditing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleAutoSuspend()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user