Profile editor - Integrated visual scripting

This commit is contained in:
Robert committed 2022-04-03 22:21:56 +02:00
1 parent 372991a69b
commit 66ea718316
96 files changed
+2413 -238

No files matched your search

@@ -8,7 +8,7 @@ using Artemis.Core.Modules;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Events;
using Artemis.UI.Shared.Extensions;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using Artemis.Core;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.DataModelVisualization
{
@@ -3,7 +3,6 @@ using System.Linq;
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared
@@ -1,6 +1,5 @@
using System;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared
@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared
@@ -2,7 +2,6 @@
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared
@@ -2,7 +2,6 @@
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared
@@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services;
using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared;
@@ -0,0 +1,31 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:display="clr-namespace:Artemis.UI.Shared.DefaultTypes.DataModel.Display"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Shared.DefaultTypes.DataModel.Display.SKColorDataModelDisplayView"
x:DataType="display:SKColorDataModelDisplayViewModel">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock x:Name="HexDisplay"
Text="{CompiledBinding DisplayValue, Converter={StaticResource SKColorToStringConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch" />
<Border Margin="5 0 0 0"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
BorderThickness="1"
MinWidth="18"
MinHeight="18"
Background="{DynamicResource CheckerboardBrush}"
BorderBrush="{DynamicResource ColorPickerButtonOutline}"
CornerRadius="4"
ClipToBounds="True">
<Border CornerRadius="4">
<Border.Background>
<SolidColorBrush Color="{CompiledBinding DisplayValue, Converter={StaticResource SKColorToColorConverter}}" />
</Border.Background>
</Border>
</Border>
</StackPanel>
</UserControl>
@@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
{
public partial class SKColorDataModelDisplayView : UserControl
{
public SKColorDataModelDisplayView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
@@ -0,0 +1,11 @@
using Artemis.UI.Shared.DataModelVisualization;
using SkiaSharp;
namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display;
/// <summary>
/// Represents a data model display view model used to display <see cref="SKColor" /> values.
/// </summary>
public class SKColorDataModelDisplayViewModel : DataModelDisplayViewModel<SKColor>
{
}
@@ -1,5 +1,5 @@
using System;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services;
using Ninject.Extensions.Conventions;
using Ninject.Modules;
@@ -1,5 +1,4 @@
using Artemis.Core.ScriptingProviders;
using ReactiveUI;
namespace Artemis.UI.Shared.ScriptingProviders
{
@@ -8,7 +8,6 @@ using Artemis.Core.Services;
using Artemis.UI.Shared.DataModelVisualization;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.DefaultTypes.DataModel.Display;
using Artemis.UI.Shared.Services.Interfaces;
using Ninject;
using Ninject.Parameters;
@@ -1,6 +1,4 @@
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared.Services;
public class GradientPickerService : IGradientPickerService
{
@@ -1,4 +1,4 @@
namespace Artemis.UI.Shared.Services.Interfaces
namespace Artemis.UI.Shared.Services
{
/// <summary>
/// Represents a service provided by the Artemis Shared UI library
@@ -5,7 +5,7 @@ using Artemis.Core.Modules;
using Artemis.UI.Shared.DataModelVisualization;
using Artemis.UI.Shared.DataModelVisualization.Shared;
namespace Artemis.UI.Shared.Services.Interfaces
namespace Artemis.UI.Shared.Services
{
/// <summary>
/// A service for UI related data model tasks
@@ -1,6 +1,6 @@
using Artemis.UI.Shared.Services.Builders;
namespace Artemis.UI.Shared.Services.Interfaces
namespace Artemis.UI.Shared.Services
{
/// <summary>
/// A service that can be used to create notifications in either the application or on the desktop.
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
using Artemis.UI.Shared.Services.Builders;
using Avalonia.Controls;
namespace Artemis.UI.Shared.Services.Interfaces
namespace Artemis.UI.Shared.Services
{
/// <summary>
/// A service that can be used to show windows and dialogs.
@@ -1,5 +1,4 @@
using System;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services.MainWindow
{
@@ -1,6 +1,5 @@
using System;
using Artemis.Core;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services.ProfileEditor;
namespace Artemis.UI.Shared.Services.NodeEditor;
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Artemis.Core;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services.NodeEditor.Commands;
namespace Artemis.UI.Shared.Services.NodeEditor;
@@ -1,5 +1,4 @@
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.Interfaces;
using Avalonia.Controls;
namespace Artemis.UI.Shared.Services
@@ -0,0 +1,53 @@
using System;
using Artemis.Core;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to change the condition type of a profile element.
/// </summary>
public class ChangeConditionType : IProfileEditorCommand, IDisposable
{
private readonly RenderProfileElement _profileElement;
private readonly ICondition? _condition;
private readonly ICondition? _oldCondition;
private bool _executed;
/// <summary>
/// Creates a new instance of the <see cref="ChangeConditionType" /> class.
/// </summary>
/// <param name="profileElement">The profile element whose condition type to change.</param>
/// <param name="condition">The new condition type.</param>
public ChangeConditionType(RenderProfileElement profileElement, ICondition? condition)
{
_profileElement = profileElement;
_condition = condition;
_oldCondition = _profileElement.DisplayCondition;
}
/// <inheritdoc />
public string DisplayName => "Change element display condition type";
/// <inheritdoc />
public void Execute()
{
_profileElement.DisplayCondition = _condition;
_executed = true;
}
/// <inheritdoc />
public void Undo()
{
_profileElement.DisplayCondition = _oldCondition;
_executed = false;
}
/// <inheritdoc />
public void Dispose()
{
if (_executed)
_oldCondition?.Dispose();
else
_condition?.Dispose();
}
}
@@ -0,0 +1,40 @@
using Artemis.Core;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to enable or disable data bindings on a layer property.
/// </summary>
public class ChangeDataBindingEnabled : IProfileEditorCommand
{
private readonly bool _enabled;
private readonly ILayerProperty _layerProperty;
private readonly bool _originalEnabled;
/// <summary>
/// Creates a new instance of the <see cref="ChangeDataBindingEnabled" /> class.
/// </summary>
/// <param name="layerProperty">The layer property to enable or disable data bindings on.</param>
/// <param name="enabled">Whether to enable or disable data bindings.</param>
public ChangeDataBindingEnabled(ILayerProperty layerProperty, bool enabled)
{
_layerProperty = layerProperty;
_enabled = enabled;
_originalEnabled = _layerProperty.BaseDataBinding.IsEnabled;
}
/// <inheritdoc />
public string DisplayName => _enabled ? "Enable data binding" : "Disable data binding";
/// <inheritdoc />
public void Execute()
{
_layerProperty.BaseDataBinding.IsEnabled = _enabled;
}
/// <inheritdoc />
public void Undo()
{
_layerProperty.BaseDataBinding.IsEnabled = _originalEnabled;
}
}
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Shared.Services.Interfaces;
using DynamicData;
namespace Artemis.UI.Shared.Services.ProfileEditor;
@@ -22,6 +21,11 @@ public interface IProfileEditorService : IArtemisSharedUIService
/// </summary>
IObservable<RenderProfileElement?> ProfileElement { get; }
/// <summary>
/// Gets an observable of the currently selected layer property.
/// </summary>
IObservable<ILayerProperty?> LayerProperty { get; }
/// <summary>
/// Gets an observable of the current editor history.
/// </summary>
@@ -65,6 +69,12 @@ public interface IProfileEditorService : IArtemisSharedUIService
/// <param name="renderProfileElement">The profile element to select.</param>
void ChangeCurrentProfileElement(RenderProfileElement? renderProfileElement);
/// <summary>
/// Change the selected layer property.
/// </summary>
/// <param name="layerProperty">The layer property to select.</param>
void ChangeCurrentLayerProperty(ILayerProperty? layerProperty);
/// <summary>
/// Changes the current profile preview playback time.
/// </summary>
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using Serilog;
@@ -18,6 +15,7 @@ namespace Artemis.UI.Shared.Services.ProfileEditor;
internal class ProfileEditorService : IProfileEditorService
{
private readonly BehaviorSubject<ILayerProperty?> _layerPropertySubject = new(null);
private readonly ILogger _logger;
private readonly IModuleService _moduleService;
private readonly BehaviorSubject<int> _pixelsPerSecondSubject = new(120);
@@ -41,6 +39,7 @@ internal class ProfileEditorService : IProfileEditorService
ProfileConfiguration = _profileConfigurationSubject.AsObservable();
ProfileElement = _profileElementSubject.AsObservable();
LayerProperty = _layerPropertySubject.AsObservable();
History = Observable.Defer(() => Observable.Return(GetHistory(_profileConfigurationSubject.Value))).Concat(ProfileConfiguration.Select(GetHistory));
Time = _timeSubject.AsObservable();
Playing = _playingSubject.AsObservable();
@@ -55,24 +54,15 @@ internal class ProfileEditorService : IProfileEditorService
// Disable all others if the changed one is selected and exclusive
if (changed.IsSelected && changed.IsExclusive)
{
Tools.Edit(list =>
{
foreach (IToolViewModel toolViewModel in list.Where(t => t.IsExclusive && t != changed))
toolViewModel.IsSelected = false;
});
}
});
}
public IObservable<bool> SuspendedEditing { get; }
public IObservable<ProfileConfiguration?> ProfileConfiguration { get; }
public IObservable<RenderProfileElement?> ProfileElement { get; }
public IObservable<ProfileEditorHistory?> History { get; }
public IObservable<TimeSpan> Time { get; }
public IObservable<bool> Playing { get; }
public IObservable<int> PixelsPerSecond { get; }
public SourceList<IToolViewModel> Tools { get; }
private ProfileEditorHistory? GetHistory(ProfileConfiguration? profileConfiguration)
{
@@ -114,6 +104,15 @@ internal class ProfileEditorService : IProfileEditorService
}
}
public IObservable<ProfileConfiguration?> ProfileConfiguration { get; }
public IObservable<RenderProfileElement?> ProfileElement { get; }
public IObservable<ILayerProperty?> LayerProperty { get; }
public IObservable<ProfileEditorHistory?> History { get; }
public IObservable<TimeSpan> Time { get; }
public IObservable<bool> Playing { get; }
public IObservable<int> PixelsPerSecond { get; }
public SourceList<IToolViewModel> Tools { get; }
public IObservable<IChangeSet<ILayerPropertyKeyframe>> ConnectToKeyframes()
{
return _selectedKeyframes.Connect();
@@ -167,6 +166,13 @@ internal class ProfileEditorService : IProfileEditorService
{
_selectedKeyframes.Clear();
_profileElementSubject.OnNext(renderProfileElement);
ChangeCurrentLayerProperty(null);
}
/// <inheritdoc />
public void ChangeCurrentLayerProperty(ILayerProperty? layerProperty)
{
_layerPropertySubject.OnNext(layerProperty);
}
public void ChangeTime(TimeSpan time)
@@ -1,7 +1,6 @@
using System;
using System.Collections.ObjectModel;
using Artemis.Core;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services.PropertyInput;
@@ -1,7 +1,6 @@
using System;
using System.Threading.Tasks;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.Interfaces;
using Avalonia;
using Avalonia.Layout;
@@ -2,7 +2,6 @@
using System.Linq;
using System.Threading.Tasks;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.Interfaces;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
+29
View File
@@ -39,6 +39,11 @@
<Button Classes="title-bar-button">
<avalonia:MaterialIcon Kind="WindowMinimize" />
</Button>
<TextBlock Margin="0 5 0 0">ToggleButton.window-button</TextBlock>
<ToggleButton Classes="icon-button">
<avalonia:MaterialIcon Kind="BlockChain" />
</ToggleButton>
</StackPanel>
</Border>
</Design.PreviewWith>
@@ -100,4 +105,28 @@
<Style Selector="Button.title-bar-button:pointerover">
<Setter Property="Background" Value="Red"></Setter>
</Style>
<Style Selector="ToggleButton:checked:pointerover /template/ Border#BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedPointerOver}" />
</Style>
<Style Selector="ToggleButton:checked:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedPointerOver}" />
</Style>
<Style Selector="ToggleButton:checked:pressed /template/ Border#BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedPressed}" />
</Style>
<Style Selector="ToggleButton:checked:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedPressed}" />
</Style>
<Style Selector="ToggleButton:checked:disabled /template/ Border#BorderElement">
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedDisabled}" />
</Style>
<Style Selector="ToggleButton:checked:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedDisabled}" />
</Style>
</Styles>
@@ -32,6 +32,8 @@
BorderBrush="{TemplateBinding BorderBrush}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
HorizontalContentAlignment="Stretch">
<Grid ColumnDefinitions="*,Auto" HorizontalAlignment="Stretch">
<TextBlock Name="MainButtonLabel"