1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Data bindings - Highlight current property

Data bindings - Disable data-bound property inputs
Data bindings - Use toggle to indicate data bindings being enabled
This commit is contained in:
SpoinkyNL 2020-09-15 23:18:21 +02:00
parent 0c25d0bbec
commit d788183f25
29 changed files with 295 additions and 58 deletions

View File

@ -27,6 +27,16 @@ namespace Artemis.Core
); );
} }
public static SKColor Sum(this SKColor a, SKColor b)
{
return new SKColor(
ClampToByte(a.Red + b.Red),
ClampToByte(a.Green + b.Green),
ClampToByte(a.Blue + b.Blue),
ClampToByte(a.Alpha + b.Alpha)
);
}
private static byte ClampToByte(float value) private static byte ClampToByte(float value)
{ {
return (byte) Math.Clamp(value, 0, 255); return (byte) Math.Clamp(value, 0, 255);

View File

@ -0,0 +1,20 @@
using SkiaSharp;
namespace Artemis.Core
{
/// <inheritdoc />
public class SKColorDataBindingConverter : DataBindingConverter<SKColor, SKColor>
{
/// <inheritdoc />
public override SKColor Sum(SKColor a, SKColor b)
{
return a.Sum(b);
}
/// <inheritdoc />
public override SKColor Interpolate(SKColor a, SKColor b, double progress)
{
return a.Interpolate(b, (float)progress);
}
}
}

View File

@ -40,12 +40,18 @@ namespace Artemis.Core
/// <para><c>null</c> if the <see cref="PropertyExpression" /> is not a member expression</para> /// <para><c>null</c> if the <see cref="PropertyExpression" /> is not a member expression</para>
/// </summary> /// </summary>
public MemberInfo Member { get; } public MemberInfo Member { get; }
/// <summary> /// <summary>
/// Gets the data binding created using this registration /// Gets the data binding created using this registration
/// </summary> /// </summary>
public DataBinding<TLayerProperty, TProperty> DataBinding { get; internal set; } public DataBinding<TLayerProperty, TProperty> DataBinding { get; internal set; }
/// <inheritdoc />
public IDataBinding GetDataBinding()
{
return DataBinding;
}
/// <inheritdoc /> /// <inheritdoc />
public IDataBinding CreateDataBinding() public IDataBinding CreateDataBinding()
{ {

View File

@ -1,12 +1,17 @@
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary> /// <summary>
/// Represents a data binding registration /// Represents a data binding registration
/// </summary> /// </summary>
public interface IDataBindingRegistration public interface IDataBindingRegistration
{ {
/// <summary> /// <summary>
/// If found, creates a data binding from storage /// Returns the data binding applied using this registration
/// </summary>
public IDataBinding GetDataBinding();
/// <summary>
/// If found, creates a data binding from storage
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
IDataBinding CreateDataBinding(); IDataBinding CreateDataBinding();

View File

@ -13,6 +13,11 @@ namespace Artemis.Core
/// </summary> /// </summary>
public interface ILayerProperty : IStorageModel, IUpdateModel, IDisposable public interface ILayerProperty : IStorageModel, IUpdateModel, IDisposable
{ {
/// <summary>
/// Gets the description attribute applied to this property
/// </summary>
public PropertyDescriptionAttribute PropertyDescription { get; }
/// <summary> /// <summary>
/// Initializes the layer property /// Initializes the layer property
/// <para> /// <para>

View File

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection;
using Artemis.Storage.Entities.Profile; using Artemis.Storage.Entities.Profile;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -28,9 +27,7 @@ namespace Artemis.Core
_keyframes = new List<LayerPropertyKeyframe<T>>(); _keyframes = new List<LayerPropertyKeyframe<T>>();
} }
/// <summary> /// <inheritdoc />
/// Gets the description attribute applied to this property
/// </summary>
public PropertyDescriptionAttribute PropertyDescription { get; internal set; } public PropertyDescriptionAttribute PropertyDescription { get; internal set; }
/// <summary> /// <summary>
@ -49,6 +46,15 @@ namespace Artemis.Core
OnUpdated(); OnUpdated();
} }
/// <inheritdoc />
public void Dispose()
{
_disposed = true;
foreach (var dataBinding in _dataBindings)
dataBinding.Dispose();
}
/// <summary> /// <summary>
/// Returns the type of the property /// Returns the type of the property
/// </summary> /// </summary>
@ -320,6 +326,20 @@ namespace Artemis.Core
/// </summary> /// </summary>
public bool DataBindingsSupported { get; protected internal set; } = true; public bool DataBindingsSupported { get; protected internal set; } = true;
/// <summary>
/// Gets whether the layer has any active data bindings
/// </summary>
public bool HasDataBinding => GetAllDataBindingRegistrations().Any(r => r.GetDataBinding() != null);
/// <summary>
/// Gets a data binding registration by the expression used to register it
/// <para>Note: The expression must exactly match the one used to register the data binding</para>
/// </summary>
public DataBindingRegistration<T, TProperty> GetDataBindingRegistration<TProperty>(Expression<Func<T, TProperty>> propertyExpression)
{
return GetDataBindingRegistration<TProperty>(propertyExpression.ToString());
}
public DataBindingRegistration<T, TProperty> GetDataBindingRegistration<TProperty>(string expression) public DataBindingRegistration<T, TProperty> GetDataBindingRegistration<TProperty>(string expression)
{ {
if (_disposed) if (_disposed)
@ -327,6 +347,7 @@ namespace Artemis.Core
var match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration && var match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration<T, TProperty> registration &&
registration.PropertyExpression.ToString() == expression); registration.PropertyExpression.ToString() == expression);
return (DataBindingRegistration<T, TProperty>) match; return (DataBindingRegistration<T, TProperty>) match;
} }
@ -367,6 +388,7 @@ namespace Artemis.Core
var dataBinding = new DataBinding<T, TProperty>(dataBindingRegistration); var dataBinding = new DataBinding<T, TProperty>(dataBindingRegistration);
_dataBindings.Add(dataBinding); _dataBindings.Add(dataBinding);
OnDataBindingEnabled(new LayerPropertyEventArgs<T>(dataBinding.LayerProperty));
return dataBinding; return dataBinding;
} }
@ -380,6 +402,10 @@ namespace Artemis.Core
throw new ObjectDisposedException("LayerProperty"); throw new ObjectDisposedException("LayerProperty");
_dataBindings.Remove(dataBinding); _dataBindings.Remove(dataBinding);
dataBinding.Registration.DataBinding = null;
dataBinding.Dispose();
OnDataBindingDisabled(new LayerPropertyEventArgs<T>(dataBinding.LayerProperty));
} }
private void UpdateDataBindings(double deltaTime) private void UpdateDataBindings(double deltaTime)
@ -532,6 +558,16 @@ namespace Artemis.Core
/// </summary> /// </summary>
public event EventHandler<LayerPropertyEventArgs<T>> KeyframeRemoved; public event EventHandler<LayerPropertyEventArgs<T>> KeyframeRemoved;
/// <summary>
/// Occurs when a data binding has been enabled
/// </summary>
public event EventHandler<LayerPropertyEventArgs<T>> DataBindingEnabled;
/// <summary>
/// Occurs when a data binding has been disabled
/// </summary>
public event EventHandler<LayerPropertyEventArgs<T>> DataBindingDisabled;
protected virtual void OnUpdated() protected virtual void OnUpdated()
{ {
Updated?.Invoke(this, new LayerPropertyEventArgs<T>(this)); Updated?.Invoke(this, new LayerPropertyEventArgs<T>(this));
@ -562,15 +598,16 @@ namespace Artemis.Core
KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs<T>(this)); KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs<T>(this));
} }
#endregion protected virtual void OnDataBindingEnabled(LayerPropertyEventArgs<T> e)
/// <inheritdoc />
public void Dispose()
{ {
_disposed = true; DataBindingEnabled?.Invoke(this, e);
foreach (var dataBinding in _dataBindings)
dataBinding.Dispose();
} }
protected virtual void OnDataBindingDisabled(LayerPropertyEventArgs<T> e)
{
DataBindingDisabled?.Invoke(this, e);
}
#endregion
} }
} }

View File

@ -7,10 +7,7 @@ namespace Artemis.Core
{ {
internal SKColorLayerProperty() internal SKColorLayerProperty()
{ {
RegisterDataBindingProperty(color => color.Alpha, new SKColorArgbDataBindingConverter(SKColorArgbDataBindingConverter.Channel.Alpha)); RegisterDataBindingProperty(value => value, new SKColorDataBindingConverter());
RegisterDataBindingProperty(color => color.Red, new SKColorArgbDataBindingConverter(SKColorArgbDataBindingConverter.Channel.Red));
RegisterDataBindingProperty(color => color.Green, new SKColorArgbDataBindingConverter(SKColorArgbDataBindingConverter.Channel.Green));
RegisterDataBindingProperty(color => color.Blue, new SKColorArgbDataBindingConverter(SKColorArgbDataBindingConverter.Channel.Blue));
} }
/// <summary> /// <summary>

View File

@ -3,13 +3,28 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:shared="clr-namespace:Artemis.UI.Shared"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Style> <UserControl.Style>
<Style> <Style TargetType="UserControl" >
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}" /> <Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style> </Style>
</UserControl.Style> </UserControl.Style>
<UserControl.Resources>
<Style TargetType="Rectangle" x:Key="RectStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=IsEnabled}" Value="False">
<Setter Property="StrokeDashArray" Value="2 2" />
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid> <Grid>
<!-- Drag handle --> <!-- Drag handle -->
<Border x:Name="DragHandle" BorderThickness="0,0,0,1" Height="19"> <Border x:Name="DragHandle" BorderThickness="0,0,0,1" Height="19">
@ -17,10 +32,12 @@
<VisualBrush> <VisualBrush>
<VisualBrush.Visual> <VisualBrush.Visual>
<Rectangle x:Name="BorderVisual" <Rectangle x:Name="BorderVisual"
Style="{StaticResource RectStyle}"
Stroke="{DynamicResource MaterialDesignTextBoxBorder}" Stroke="{DynamicResource MaterialDesignTextBoxBorder}"
StrokeThickness="1" StrokeThickness="1"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}" /> Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}">
</Rectangle>
</VisualBrush.Visual> </VisualBrush.Visual>
</VisualBrush> </VisualBrush>
</Border.BorderBrush> </Border.BorderBrush>

View File

@ -0,0 +1,26 @@
using System.Windows;
using System.Windows.Controls.Primitives;
namespace Artemis.UI.Shared
{
public class LockableToggleButton : ToggleButton
{
protected override void OnToggle()
{
if (!IsLocked)
{
base.OnToggle();
}
}
public bool IsLocked
{
get { return (bool)GetValue(IsLockedProperty); }
set { SetValue(IsLockedProperty, value); }
}
// Using a DependencyProperty as the backing store for LockToggle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsLockedProperty =
DependencyProperty.Register("IsLocked", typeof(bool), typeof(LockableToggleButton), new UIPropertyMetadata(false));
}
}

View File

@ -16,6 +16,8 @@ namespace Artemis.UI.Shared
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
LayerProperty.Updated += LayerPropertyOnUpdated; LayerProperty.Updated += LayerPropertyOnUpdated;
LayerProperty.BaseValueChanged += LayerPropertyOnUpdated; LayerProperty.BaseValueChanged += LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
UpdateInputValue(); UpdateInputValue();
} }
@ -25,11 +27,14 @@ namespace Artemis.UI.Shared
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
LayerProperty.Updated += LayerPropertyOnUpdated; LayerProperty.Updated += LayerPropertyOnUpdated;
LayerProperty.BaseValueChanged += LayerPropertyOnUpdated; LayerProperty.BaseValueChanged += LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
UpdateInputValue(); UpdateInputValue();
} }
public LayerProperty<T> LayerProperty { get; } public LayerProperty<T> LayerProperty { get; }
public IProfileEditorService ProfileEditorService { get; } public IProfileEditorService ProfileEditorService { get; }
internal override object InternalGuard { get; } = null; internal override object InternalGuard { get; } = null;
public bool InputDragging public bool InputDragging
@ -52,6 +57,8 @@ namespace Artemis.UI.Shared
{ {
LayerProperty.Updated -= LayerPropertyOnUpdated; LayerProperty.Updated -= LayerPropertyOnUpdated;
LayerProperty.BaseValueChanged -= LayerPropertyOnUpdated; LayerProperty.BaseValueChanged -= LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
@ -65,6 +72,10 @@ namespace Artemis.UI.Shared
{ {
} }
protected virtual void OnDataBindingsChanged()
{
}
protected void ApplyInputValue() protected void ApplyInputValue()
{ {
// Force the validator to run // Force the validator to run
@ -123,6 +134,11 @@ namespace Artemis.UI.Shared
ProfileEditorService.UpdateProfilePreview(); ProfileEditorService.UpdateProfilePreview();
} }
private void LayerPropertyOnDataBindingChange(object sender, LayerPropertyEventArgs<T> e)
{
OnDataBindingsChanged();
}
#endregion #endregion
} }

View File

@ -16,7 +16,8 @@
materialDesign:ValidationAssist.UsePopup="True" materialDesign:ValidationAssist.UsePopup="True"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsEnabled}"/>
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" /> <TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -8,9 +8,19 @@ namespace Artemis.UI.PropertyInput
{ {
public class FloatPropertyInputViewModel : PropertyInputViewModel<float> public class FloatPropertyInputViewModel : PropertyInputViewModel<float>
{ {
private readonly DataBindingRegistration<float, float> _registration;
public FloatPropertyInputViewModel(LayerProperty<float> layerProperty, IProfileEditorService profileEditorService, IModelValidator<FloatPropertyInputViewModel> validator) public FloatPropertyInputViewModel(LayerProperty<float> layerProperty, IProfileEditorService profileEditorService, IModelValidator<FloatPropertyInputViewModel> validator)
: base(layerProperty, profileEditorService, validator) : base(layerProperty, profileEditorService, validator)
{ {
_registration = layerProperty.GetDataBindingRegistration(value => value);
}
public bool IsEnabled => _registration.DataBinding == null;
protected override void OnDataBindingsChanged()
{
NotifyOfPropertyChange(nameof(IsEnabled));
} }
} }

View File

@ -16,7 +16,8 @@
materialDesign:ValidationAssist.UsePopup="True" materialDesign:ValidationAssist.UsePopup="True"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsEnabled}"/>
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" /> <TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -8,9 +8,19 @@ namespace Artemis.UI.PropertyInput
{ {
public class IntPropertyInputViewModel : PropertyInputViewModel<int> public class IntPropertyInputViewModel : PropertyInputViewModel<int>
{ {
private readonly DataBindingRegistration<int, int> _registration;
public IntPropertyInputViewModel(LayerProperty<int> layerProperty, IProfileEditorService profileEditorService, IModelValidator<IntPropertyInputViewModel> validator) public IntPropertyInputViewModel(LayerProperty<int> layerProperty, IProfileEditorService profileEditorService, IModelValidator<IntPropertyInputViewModel> validator)
: base(layerProperty, profileEditorService, validator) : base(layerProperty, profileEditorService, validator)
{ {
_registration = layerProperty.GetDataBindingRegistration(value => value);
}
public bool IsEnabled => _registration.DataBinding == null;
protected override void OnDataBindingsChanged()
{
NotifyOfPropertyChange(nameof(IsEnabled));
} }
} }

View File

@ -16,7 +16,8 @@
<artemis:ColorPicker Width="132" <artemis:ColorPicker Width="132"
Margin="0 -2 0 3" Margin="0 -2 0 3"
Padding="0 -1" Padding="0 -1"
Color="{Binding InputValue, Converter={StaticResource SKColorToColorConverter}}" /> Color="{Binding InputValue, Converter={StaticResource SKColorToColorConverter}}"
IsEnabled="{Binding IsEnabled}"/>
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" /> <TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -7,8 +7,18 @@ namespace Artemis.UI.PropertyInput
{ {
public class SKColorPropertyInputViewModel : PropertyInputViewModel<SKColor> public class SKColorPropertyInputViewModel : PropertyInputViewModel<SKColor>
{ {
private readonly DataBindingRegistration<SKColor, SKColor> _registration;
public SKColorPropertyInputViewModel(LayerProperty<SKColor> layerProperty, IProfileEditorService profileEditorService) : base(layerProperty, profileEditorService) public SKColorPropertyInputViewModel(LayerProperty<SKColor> layerProperty, IProfileEditorService profileEditorService) : base(layerProperty, profileEditorService)
{ {
_registration = layerProperty.GetDataBindingRegistration(value => value);
}
public bool IsEnabled => _registration.DataBinding == null;
protected override void OnDataBindingsChanged()
{
NotifyOfPropertyChange(nameof(IsEnabled));
} }
} }
} }

View File

@ -15,13 +15,15 @@
Value="{Binding X}" Value="{Binding X}"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsXEnabled}"/>
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock> <TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
<shared:DraggableFloat ToolTip="Y-coordinate (vertical)" <shared:DraggableFloat ToolTip="Y-coordinate (vertical)"
Value="{Binding Y}" Value="{Binding Y}"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsYEnabled}"/>
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" /> <TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -10,9 +10,14 @@ namespace Artemis.UI.PropertyInput
{ {
public class SKPointPropertyInputViewModel : PropertyInputViewModel<SKPoint> public class SKPointPropertyInputViewModel : PropertyInputViewModel<SKPoint>
{ {
private readonly DataBindingRegistration<SKPoint, float> _xRegistration;
private readonly DataBindingRegistration<SKPoint, float> _yRegistration;
public SKPointPropertyInputViewModel(LayerProperty<SKPoint> layerProperty, IProfileEditorService profileEditorService, public SKPointPropertyInputViewModel(LayerProperty<SKPoint> layerProperty, IProfileEditorService profileEditorService,
IModelValidator<SKPointPropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator) IModelValidator<SKPointPropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
{ {
_xRegistration = layerProperty.GetDataBindingRegistration(point => point.X);
_yRegistration = layerProperty.GetDataBindingRegistration(point => point.Y);
} }
public float X public float X
@ -27,11 +32,20 @@ namespace Artemis.UI.PropertyInput
set => InputValue = new SKPoint(X, value); set => InputValue = new SKPoint(X, value);
} }
public bool IsXEnabled => _xRegistration.DataBinding == null;
public bool IsYEnabled => _yRegistration.DataBinding == null;
protected override void OnInputValueChanged() protected override void OnInputValueChanged()
{ {
NotifyOfPropertyChange(nameof(X)); NotifyOfPropertyChange(nameof(X));
NotifyOfPropertyChange(nameof(Y)); NotifyOfPropertyChange(nameof(Y));
} }
protected override void OnDataBindingsChanged()
{
NotifyOfPropertyChange(nameof(IsXEnabled));
NotifyOfPropertyChange(nameof(IsYEnabled));
}
} }
public class SKPointPropertyInputViewModelValidator : AbstractValidator<SKPointPropertyInputViewModel> public class SKPointPropertyInputViewModelValidator : AbstractValidator<SKPointPropertyInputViewModel>

View File

@ -15,13 +15,15 @@
Value="{Binding Height}" Value="{Binding Height}"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsHeightEnabled}"/>
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock> <TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
<shared:DraggableFloat ToolTip="Width" <shared:DraggableFloat ToolTip="Width"
Value="{Binding Width}" Value="{Binding Width}"
StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}" StepSize="{Binding LayerProperty.PropertyDescription.InputStepSize}"
DragStarted="{s:Action InputDragStarted}" DragStarted="{s:Action InputDragStarted}"
DragEnded="{s:Action InputDragEnded}" /> DragEnded="{s:Action InputDragEnded}"
IsEnabled="{Binding IsWidthEnabled}"/>
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" /> <TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -4,15 +4,22 @@ using Artemis.UI.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using FluentValidation; using FluentValidation;
using SkiaSharp; using SkiaSharp;
using Stylet; // using PropertyChanged; using Stylet;
// using PropertyChanged;
namespace Artemis.UI.PropertyInput namespace Artemis.UI.PropertyInput
{ {
public class SKSizePropertyInputViewModel : PropertyInputViewModel<SKSize> public class SKSizePropertyInputViewModel : PropertyInputViewModel<SKSize>
{ {
private readonly DataBindingRegistration<SKSize, float> _heightRegistration;
private readonly DataBindingRegistration<SKSize, float> _widthRegistration;
public SKSizePropertyInputViewModel(LayerProperty<SKSize> layerProperty, IProfileEditorService profileEditorService, public SKSizePropertyInputViewModel(LayerProperty<SKSize> layerProperty, IProfileEditorService profileEditorService,
IModelValidator<SKSizePropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator) IModelValidator<SKSizePropertyInputViewModel> validator) : base(layerProperty, profileEditorService, validator)
{ {
_widthRegistration = layerProperty.GetDataBindingRegistration(size => size.Width);
_heightRegistration = layerProperty.GetDataBindingRegistration(size => size.Height);
} }
// Since SKSize is immutable we need to create properties that replace the SKSize entirely // Since SKSize is immutable we need to create properties that replace the SKSize entirely
@ -28,11 +35,20 @@ namespace Artemis.UI.PropertyInput
set => InputValue = new SKSize(Width, value); set => InputValue = new SKSize(Width, value);
} }
public bool IsWidthEnabled => _widthRegistration.DataBinding == null;
public bool IsHeightEnabled => _heightRegistration.DataBinding == null;
protected override void OnInputValueChanged() protected override void OnInputValueChanged()
{ {
NotifyOfPropertyChange(nameof(Width)); NotifyOfPropertyChange(nameof(Width));
NotifyOfPropertyChange(nameof(Height)); NotifyOfPropertyChange(nameof(Height));
} }
protected override void OnDataBindingsChanged()
{
NotifyOfPropertyChange(nameof(IsWidthEnabled));
NotifyOfPropertyChange(nameof(IsHeightEnabled));
}
} }
public class SKSizePropertyInputViewModelValidator : AbstractValidator<SKSizePropertyInputViewModel> public class SKSizePropertyInputViewModelValidator : AbstractValidator<SKSizePropertyInputViewModel>

View File

@ -56,14 +56,16 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
public bool ConditionBehaviourEnabled => RenderProfileElement != null; public bool ConditionBehaviourEnabled => RenderProfileElement != null;
protected override void OnActivate() protected override void OnInitialActivate()
{ {
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected; _profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
base.OnInitialActivate();
} }
protected override void OnDeactivate() protected override void OnClose()
{ {
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected; _profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
base.OnClose();
} }
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e) private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)

View File

@ -40,6 +40,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
set => SetAndNotify(ref _isVisible, value); set => SetAndNotify(ref _isVisible, value);
} }
public bool IsHighlighted => false;
public bool IsExpanded public bool IsExpanded
{ {
get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup); get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup);

View File

@ -10,6 +10,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
public class LayerPropertyViewModel : PropertyChangedBase, IDisposable public class LayerPropertyViewModel : PropertyChangedBase, IDisposable
{ {
private bool _isVisible; private bool _isVisible;
private bool _isHighlighted;
private bool _isExpanded;
public LayerPropertyViewModel(ILayerProperty layerProperty, IPropertyVmFactory propertyVmFactory) public LayerPropertyViewModel(ILayerProperty layerProperty, IPropertyVmFactory propertyVmFactory)
{ {
@ -29,8 +31,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
set => SetAndNotify(ref _isVisible, value); set => SetAndNotify(ref _isVisible, value);
} }
public bool IsExpanded => false; public bool IsHighlighted
{
get => _isHighlighted;
set => SetAndNotify(ref _isHighlighted, value);
}
public bool IsExpanded
{
get => _isExpanded;
set => SetAndNotify(ref _isExpanded, value);
}
public void Dispose() public void Dispose()
{ {
TreePropertyViewModel?.Dispose(); TreePropertyViewModel?.Dispose();

View File

@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid Height="22" Margin="-20 0 0 0"> <Grid Height="22" Margin="-20 0 0 0">
@ -43,15 +44,17 @@
</ContentControl.Resources> </ContentControl.Resources>
</ContentControl> </ContentControl>
<ToggleButton Grid.Column="3" <shared:LockableToggleButton Grid.Column="3"
Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}" Style="{StaticResource MaterialDesignFlatToggleButton}"
ToolTip="Change the property's data binding" ToolTip="Change the property's data binding"
Width="20" Width="20"
Height="20" Height="20"
VerticalAlignment="Center" VerticalAlignment="Center"
IsLocked="True"
IsEnabled="{Binding LayerProperty.DataBindingsSupported}" IsEnabled="{Binding LayerProperty.DataBindingsSupported}"
IsChecked="{Binding DataBindingsOpen}"> IsChecked="{Binding HasDataBinding, Mode=OneWay}"
Click="{s:Action ActivateDataBindingViewModel}">
<materialDesign:PackIcon Kind="VectorLink" Height="13" Width="13" /> <materialDesign:PackIcon Kind="VectorLink" Height="13" Width="13" />
</ToggleButton> </shared:LockableToggleButton>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -22,10 +22,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
PropertyInputViewModel = _profileEditorService.CreatePropertyInputViewModel(LayerProperty); PropertyInputViewModel = _profileEditorService.CreatePropertyInputViewModel(LayerProperty);
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged; _profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
LayerProperty.VisibilityChanged += LayerPropertyOnVisibilityChanged; LayerProperty.VisibilityChanged += LayerPropertyOnVisibilityChanged;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden; LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
} }
public LayerProperty<T> LayerProperty { get; } public LayerProperty<T> LayerProperty { get; }
public LayerPropertyViewModel LayerPropertyViewModel { get; } public LayerPropertyViewModel LayerPropertyViewModel { get; }
@ -35,6 +36,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
set => SetAndNotify(ref _propertyInputViewModel, value); set => SetAndNotify(ref _propertyInputViewModel, value);
} }
public bool HasDataBinding => LayerProperty.HasDataBinding;
public bool HasPropertyInputViewModel => PropertyInputViewModel != null; public bool HasPropertyInputViewModel => PropertyInputViewModel != null;
public bool KeyframesEnabled public bool KeyframesEnabled
@ -43,10 +46,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
set => ApplyKeyframesEnabled(value); set => ApplyKeyframesEnabled(value);
} }
public bool DataBindingsOpen public void ActivateDataBindingViewModel()
{ {
get => _profileEditorService.SelectedDataBinding == LayerProperty; if (_profileEditorService.SelectedDataBinding == LayerProperty)
set => _profileEditorService.ChangeSelectedDataBinding(value ? LayerProperty : null); _profileEditorService.ChangeSelectedDataBinding(null);
else
_profileEditorService.ChangeSelectedDataBinding(LayerProperty);
} }
#region IDisposable #region IDisposable
@ -56,6 +61,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
_propertyInputViewModel?.Dispose(); _propertyInputViewModel?.Dispose();
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged; _profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
LayerProperty.VisibilityChanged -= LayerPropertyOnVisibilityChanged; LayerProperty.VisibilityChanged -= LayerPropertyOnVisibilityChanged;
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
} }
#endregion #endregion
@ -85,7 +92,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e) private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
{ {
NotifyOfPropertyChange(nameof(DataBindingsOpen)); LayerPropertyViewModel.IsHighlighted = _profileEditorService.SelectedDataBinding == LayerProperty;
} }
private void LayerPropertyOnVisibilityChanged(object? sender, LayerPropertyEventArgs<T> e) private void LayerPropertyOnVisibilityChanged(object? sender, LayerPropertyEventArgs<T> e)
@ -93,12 +100,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden; LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
} }
private void LayerPropertyOnDataBindingChange(object? sender, LayerPropertyEventArgs<T> e)
{
NotifyOfPropertyChange(nameof(HasDataBinding));
}
#endregion #endregion
} }
public interface ITreePropertyViewModel : IScreen, INotifyPropertyChanged, IDisposable public interface ITreePropertyViewModel : IScreen, IDisposable
{ {
bool HasPropertyInputViewModel { get; } bool HasPropertyInputViewModel { get; }
bool DataBindingsOpen { get; set; } bool HasDataBinding { get; }
} }
} }

View File

@ -96,7 +96,7 @@
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" /> <Setter Property="Visibility" Value="{Binding IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding TreePropertyViewModel.DataBindingsOpen}" Value="True"> <DataTrigger Binding="{Binding IsHighlighted, Mode=OneWay}" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" /> <Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>

View File

@ -234,7 +234,7 @@ namespace Artemis.UI.Screens.ProfileEditor
_snackbarMessageQueue.Enqueue("Redid profile update", "UNDO", Undo); _snackbarMessageQueue.Enqueue("Redid profile update", "UNDO", Undo);
} }
protected override void OnActivate() protected override void OnInitialActivate()
{ {
LoadWorkspaceSettings(); LoadWorkspaceSettings();
Module.IsProfileUpdatingDisabled = true; Module.IsProfileUpdatingDisabled = true;
@ -246,10 +246,10 @@ namespace Artemis.UI.Screens.ProfileEditor
SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId); SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId);
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(Module); }); Task.Run(async () => { await _moduleService.SetActiveModuleOverride(Module); });
base.OnActivate(); base.OnInitialActivate();
} }
protected override void OnDeactivate() protected override void OnClose()
{ {
SaveWorkspaceSettings(); SaveWorkspaceSettings();
Module.IsProfileUpdatingDisabled = false; Module.IsProfileUpdatingDisabled = false;
@ -257,7 +257,7 @@ namespace Artemis.UI.Screens.ProfileEditor
_profileEditorService.ChangeSelectedProfile(null); _profileEditorService.ChangeSelectedProfile(null);
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(null); }); Task.Run(async () => { await _moduleService.SetActiveModuleOverride(null); });
base.OnDeactivate(); base.OnClose();
} }
private void RemoveProfile(ProfileDescriptor profileDescriptor) private void RemoveProfile(ProfileDescriptor profileDescriptor)

View File

@ -96,16 +96,16 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
ActiveItem?.AddLayer(); ActiveItem?.AddLayer();
} }
protected override void OnActivate() protected override void OnInitialActivate()
{ {
Subscribe(); Subscribe();
base.OnActivate(); base.OnInitialActivate();
} }
protected override void OnDeactivate() protected override void OnClose()
{ {
Unsubscribe(); Unsubscribe();
base.OnDeactivate(); base.OnClose();
} }
private void CreateRootFolderViewModel() private void CreateRootFolderViewModel()

View File

@ -173,7 +173,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
.ToList(); .ToList();
} }
protected override void OnActivate() protected override void OnInitialActivate()
{ {
ApplyActiveProfile(); ApplyActiveProfile();
@ -186,10 +186,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
_profileEditorService.ProfileElementSelected += OnProfileElementSelected; _profileEditorService.ProfileElementSelected += OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated; _profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
base.OnActivate(); base.OnInitialActivate();
} }
protected override void OnDeactivate() protected override void OnClose()
{ {
HighlightSelectedLayer.SettingChanged -= HighlightSelectedLayerOnSettingChanged; HighlightSelectedLayer.SettingChanged -= HighlightSelectedLayerOnSettingChanged;
_surfaceService.ActiveSurfaceConfigurationSelected -= OnActiveSurfaceConfigurationSelected; _surfaceService.ActiveSurfaceConfigurationSelected -= OnActiveSurfaceConfigurationSelected;
@ -206,7 +206,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
canvasViewModel.Dispose(); canvasViewModel.Dispose();
CanvasViewModels.Clear(); CanvasViewModels.Clear();
base.OnDeactivate(); base.OnClose();
} }
private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e) private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e)