mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Data bindings - Rewrote data binding system to fully leverage nodes
This commit is contained in:
1 parent
7933bf7ee9
commit
0bb93f2ebd
63 files changed
+654
-1533
No files matched your search
-167
@@ -1,167 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DataBindingView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.50*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<materialDesign:Card Grid.Column="0"
|
||||
UniformCornerRadius="0"
|
||||
materialDesign:ShadowAssist.ShadowDepth="Depth3"
|
||||
materialDesign:ShadowAssist.ShadowEdges="Right"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
Panel.ZIndex="2">
|
||||
<Grid Margin="10 5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<CheckBox Grid.Row="0" Margin="0 10" IsChecked="{Binding IsDataBindingEnabled}">Enable data binding</CheckBox>
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Margin="0 5"
|
||||
Text="{Binding EasingTime}"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
materialDesign:TextFieldAssist.SuffixText="ms"
|
||||
materialDesign:HintAssist.Hint="Easing time"
|
||||
IsEnabled="{Binding IsDataBindingEnabled}" />
|
||||
|
||||
<ComboBox Grid.Row="2"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
Margin="0 5"
|
||||
materialDesign:HintAssist.Hint="Easing type"
|
||||
MinWidth="128"
|
||||
IsEnabled="{Binding IsEasingTimeEnabled}"
|
||||
SelectedItem="{Binding SelectedEasingViewModel}"
|
||||
ItemsSource="{Binding EasingViewModels}">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Polyline Stroke="{DynamicResource MaterialDesignBody}"
|
||||
StrokeThickness="1"
|
||||
Points="{Binding EasingPoints}"
|
||||
Stretch="Uniform"
|
||||
Width="14"
|
||||
Height="14"
|
||||
Margin="0 0 10 0" />
|
||||
<TextBlock Text="{Binding Description}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<materialDesign:Card Grid.Row="3" Grid.ColumnSpan="2" Margin="0 5 0 0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Margin="10 10 0 0">
|
||||
Result
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0 10 10 0"
|
||||
Visibility="{Binding AlwaysApplyDataBindings.Value, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"
|
||||
ToolTip="Check 'Apply data bindings in editor'"
|
||||
Cursor="Help">
|
||||
Other bindings not updating?
|
||||
</TextBlock>
|
||||
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignLightSeparator}" Margin="0" />
|
||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="10 4 10 10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Margin="0 2" Visibility="{Binding ActiveItem.SupportsTestValue, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">Input</TextBlock>
|
||||
<ContentControl Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Visibility="{Binding ActiveItem.SupportsTestValue, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||
s:View.Model="{Binding TestInputValue}"
|
||||
Margin="0 2"
|
||||
FontFamily="Consolas"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Right" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0 2">Output</TextBlock>
|
||||
<ContentControl Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
s:View.Model="{Binding TestResultValue}"
|
||||
Margin="0 2"
|
||||
FontFamily="Consolas"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<Grid Grid.Row="4" VerticalAlignment="Bottom" Margin="0 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignRaisedAccentButton}"
|
||||
Margin="0 0 5 0"
|
||||
ToolTip="Copy the entire data binding"
|
||||
Command="{s:Action CopyDataBinding}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="ContentCopy" />
|
||||
<TextBlock Text="COPY" Margin="8 0 0 0" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignRaisedAccentButton}"
|
||||
Margin="5 0 0 0"
|
||||
ToolTip="Paste the entire data binding"
|
||||
Command="{s:Action PasteDataBinding}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="ContentPaste" />
|
||||
<TextBlock Text="PASTE" Margin="8 0 0 0" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card Grid.Column="1" UniformCornerRadius="0" Background="{DynamicResource MaterialDesignToolBarBackground}" Panel.ZIndex="1">
|
||||
<controls:VisualScriptEditor Script="{Binding Script}" AvailableNodes="{Binding AvailableNodes}"></controls:VisualScriptEditor>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DataBindingView.xaml
|
||||
/// </summary>
|
||||
public partial class DataBindingView : UserControl
|
||||
{
|
||||
public DataBindingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
-251
@@ -1,251 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
{
|
||||
public sealed class DataBindingViewModel<TLayerProperty, TProperty> : Screen, IDataBindingViewModel
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private int _easingTime;
|
||||
private bool _isDataBindingEnabled;
|
||||
private bool _isEasingTimeEnabled;
|
||||
private DateTime _lastUpdate;
|
||||
private TimelineEasingViewModel _selectedEasingViewModel;
|
||||
|
||||
private bool _updating;
|
||||
private bool _updatingTestResult;
|
||||
|
||||
public DataBindingViewModel(DataBindingRegistration<TLayerProperty, TProperty> registration,
|
||||
ICoreService coreService,
|
||||
ISettingsService settingsService,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
INodeService nodeService)
|
||||
{
|
||||
Registration = registration;
|
||||
_coreService = coreService;
|
||||
_profileEditorService = profileEditorService;
|
||||
|
||||
DisplayName = Registration.DisplayName.ToUpper();
|
||||
AlwaysApplyDataBindings = settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true);
|
||||
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
||||
AvailableNodes = nodeService.AvailableNodes;
|
||||
TestInputValue = dataModelUIService.GetDataModelDisplayViewModel(typeof(TProperty), null, true);
|
||||
TestResultValue = dataModelUIService.GetDataModelDisplayViewModel(typeof(TProperty), null, true);
|
||||
}
|
||||
|
||||
public DataBindingRegistration<TLayerProperty, TProperty> Registration { get; }
|
||||
public NodeScript<TProperty> Script => Registration.DataBinding?.Script;
|
||||
|
||||
public PluginSetting<bool> AlwaysApplyDataBindings { get; }
|
||||
public BindableCollection<TimelineEasingViewModel> EasingViewModels { get; }
|
||||
public IEnumerable<NodeData> AvailableNodes { get; }
|
||||
public DataModelDisplayViewModel TestInputValue { get; }
|
||||
public DataModelDisplayViewModel TestResultValue { get; }
|
||||
|
||||
|
||||
public bool IsDataBindingEnabled
|
||||
{
|
||||
get => _isDataBindingEnabled;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isDataBindingEnabled, value);
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
EnableDataBinding();
|
||||
else
|
||||
DisableDataBinding();
|
||||
}
|
||||
}
|
||||
|
||||
public TimelineEasingViewModel SelectedEasingViewModel
|
||||
{
|
||||
get => _selectedEasingViewModel;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedEasingViewModel, value)) return;
|
||||
ApplyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public int EasingTime
|
||||
{
|
||||
get => _easingTime;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _easingTime, value)) return;
|
||||
ApplyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEasingTimeEnabled
|
||||
{
|
||||
get => _isEasingTimeEnabled;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _isEasingTimeEnabled, value)) return;
|
||||
ApplyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyDataBinding()
|
||||
{
|
||||
if (Registration.DataBinding != null)
|
||||
JsonClipboard.SetObject(Registration.DataBinding.Entity);
|
||||
}
|
||||
|
||||
public void PasteDataBinding()
|
||||
{
|
||||
if (Registration.DataBinding == null)
|
||||
Registration.LayerProperty.EnableDataBinding(Registration);
|
||||
if (Registration.DataBinding == null)
|
||||
throw new ArtemisUIException("Failed to create a data binding in order to paste");
|
||||
|
||||
DataBindingEntity dataBindingEntity = JsonClipboard.GetData<DataBindingEntity>();
|
||||
if (dataBindingEntity == null)
|
||||
return;
|
||||
|
||||
Registration.DataBinding.EasingTime = dataBindingEntity.EasingTime;
|
||||
Registration.DataBinding.EasingFunction = (Easings.Functions) dataBindingEntity.EasingFunction;
|
||||
|
||||
// TODO - Paste visual script
|
||||
|
||||
Update();
|
||||
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
Initialize();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(v => new TimelineEasingViewModel(v, false)));
|
||||
|
||||
_lastUpdate = DateTime.Now;
|
||||
_coreService.FrameRendered += OnFrameRendered;
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
if (Registration.DataBinding == null)
|
||||
{
|
||||
IsDataBindingEnabled = false;
|
||||
IsEasingTimeEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_updating = true;
|
||||
|
||||
EasingTime = (int) Registration.DataBinding.EasingTime.TotalMilliseconds;
|
||||
SelectedEasingViewModel = EasingViewModels.First(vm => vm.EasingFunction == Registration.DataBinding.EasingFunction);
|
||||
IsDataBindingEnabled = true;
|
||||
IsEasingTimeEnabled = EasingTime > 0;
|
||||
|
||||
_updating = false;
|
||||
}
|
||||
|
||||
private void ApplyChanges()
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
if (Registration.DataBinding != null)
|
||||
{
|
||||
Registration.DataBinding.EasingTime = TimeSpan.FromMilliseconds(EasingTime);
|
||||
Registration.DataBinding.EasingFunction = SelectedEasingViewModel?.EasingFunction ?? Easings.Functions.Linear;
|
||||
}
|
||||
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
Update();
|
||||
}
|
||||
|
||||
private void UpdateTestResult()
|
||||
{
|
||||
if (_updating || _updatingTestResult)
|
||||
return;
|
||||
|
||||
_updatingTestResult = true;
|
||||
|
||||
if (Registration.DataBinding == null)
|
||||
{
|
||||
TestInputValue.UpdateValue(default);
|
||||
TestResultValue.UpdateValue(default);
|
||||
_updatingTestResult = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// If always update is disabled, do constantly update the data binding as long as the view model is open
|
||||
// If always update is enabled, this is done for all data bindings in ProfileViewModel
|
||||
if (!AlwaysApplyDataBindings.Value)
|
||||
{
|
||||
Registration.DataBinding.UpdateWithDelta(DateTime.Now - _lastUpdate);
|
||||
_profileEditorService.UpdateProfilePreview();
|
||||
}
|
||||
|
||||
TProperty currentValue = Registration.Converter.ConvertFromObject(Registration.DataBinding.Script.Result ?? default(TProperty));
|
||||
TestInputValue.UpdateValue(currentValue);
|
||||
TestResultValue.UpdateValue(Registration.DataBinding != null ? Registration.DataBinding.GetValue(currentValue) : default);
|
||||
|
||||
_updatingTestResult = false;
|
||||
}
|
||||
|
||||
private void EnableDataBinding()
|
||||
{
|
||||
if (Registration.DataBinding != null)
|
||||
return;
|
||||
|
||||
Registration.LayerProperty.EnableDataBinding(Registration);
|
||||
NotifyOfPropertyChange(nameof(Script));
|
||||
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void DisableDataBinding()
|
||||
{
|
||||
if (Registration.DataBinding == null)
|
||||
return;
|
||||
|
||||
Registration.LayerProperty.DisableDataBinding(Registration.DataBinding);
|
||||
NotifyOfPropertyChange(nameof(Script));
|
||||
Update();
|
||||
|
||||
_profileEditorService.SaveSelectedProfileElement();
|
||||
}
|
||||
|
||||
private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
UpdateTestResult();
|
||||
_lastUpdate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_coreService.FrameRendered -= OnFrameRendered;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDataBindingViewModel : IScreen, IDisposable
|
||||
{
|
||||
}
|
||||
}
|
||||
+43
-15
@@ -4,20 +4,48 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
||||
xmlns:layerProperties="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<TabControl ItemsSource="{Binding Items}"
|
||||
SelectedIndex="{Binding SelectedItemIndex}"
|
||||
Style="{StaticResource MaterialDesignTabControl}" >
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" TextElement.Foreground="{DynamicResource MaterialDesignBody}" />
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
<TabControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Margin="-12 0" Text="{Binding DisplayName}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</TabControl.ItemTemplate>
|
||||
</TabControl>
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type layerProperties:DataBindingsViewModel}}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="48" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="15 0"
|
||||
Text="{Binding DataBinding.BaseLayerProperty.PropertyDescription.Name}" />
|
||||
<CheckBox Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding DataBindingEnabled}">
|
||||
Enable data binding
|
||||
</CheckBox>
|
||||
</Grid>
|
||||
|
||||
<controls:VisualScriptPresenter Grid.Row="1" AvailableNodes="{Binding AvailableNodes}" Script="{Binding DataBinding.Script}" />
|
||||
<Border Grid.Row="1" Background="{StaticResource MaterialDesignToolBarBackground}"
|
||||
Visibility="{Binding DataBindingEnabled, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="16">
|
||||
<materialDesign:PackIcon Kind="TransitConnectionVariant" Width="100" Height="100" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
|
||||
Enable this data binding to use nodes!
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center">
|
||||
When you enable data bindings you can no longer use keyframes or normal values for this property. <LineBreak />
|
||||
Instead you'll be using our node scripting system to set a value based on the data model or values of other layers/folders.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
+28
-55
@@ -1,88 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
{
|
||||
public class DataBindingsViewModel : Conductor<IDataBindingViewModel>.Collection.AllActive
|
||||
public class DataBindingsViewModel : Screen
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private ILayerProperty _selectedDataBinding;
|
||||
private int _selectedItemIndex;
|
||||
private bool _updating;
|
||||
private IDataBinding _dataBinding;
|
||||
|
||||
public DataBindingsViewModel(IProfileEditorService profileEditorService, IDataBindingsVmFactory dataBindingsVmFactory)
|
||||
public DataBindingsViewModel(IProfileEditorService profileEditorService, INodeService nodeService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataBindingsVmFactory = dataBindingsVmFactory;
|
||||
AvailableNodes = nodeService.AvailableNodes.ToList();
|
||||
}
|
||||
|
||||
public int SelectedItemIndex
|
||||
public List<NodeData> AvailableNodes { get; }
|
||||
|
||||
public IDataBinding DataBinding
|
||||
{
|
||||
get => _selectedItemIndex;
|
||||
set => SetAndNotify(ref _selectedItemIndex, value);
|
||||
get => _dataBinding;
|
||||
set => SetAndNotify(ref _dataBinding, value);
|
||||
}
|
||||
|
||||
private void CreateDataBindingViewModels()
|
||||
public bool DataBindingEnabled
|
||||
{
|
||||
int oldIndex = SelectedItemIndex;
|
||||
Items.Clear();
|
||||
|
||||
ILayerProperty layerProperty = _profileEditorService.SelectedDataBinding;
|
||||
if (layerProperty == null)
|
||||
return;
|
||||
|
||||
List<IDataBindingRegistration> registrations = layerProperty.GetAllDataBindingRegistrations();
|
||||
|
||||
// Create a data binding VM for each data bindable property. These VMs will be responsible for retrieving
|
||||
// and creating the actual data bindings
|
||||
Items.AddRange(registrations.Select(registration => _dataBindingsVmFactory.DataBindingViewModel(registration)));
|
||||
|
||||
SelectedItemIndex = Items.Count < oldIndex ? 0 : oldIndex;
|
||||
get => _dataBinding?.IsEnabled ?? false;
|
||||
set
|
||||
{
|
||||
if (_dataBinding != null)
|
||||
_dataBinding.IsEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
|
||||
{
|
||||
CreateDataBindingViewModels();
|
||||
SubscribeToSelectedDataBinding();
|
||||
|
||||
SelectedItemIndex = 0;
|
||||
}
|
||||
|
||||
private void SubscribeToSelectedDataBinding()
|
||||
{
|
||||
if (_selectedDataBinding != null)
|
||||
if (DataBinding != null)
|
||||
{
|
||||
_selectedDataBinding.DataBindingPropertyRegistered -= DataBindingRegistrationsChanged;
|
||||
_selectedDataBinding.DataBindingPropertiesCleared -= DataBindingRegistrationsChanged;
|
||||
DataBinding.DataBindingEnabled -= DataBindingOnDataBindingToggled;
|
||||
DataBinding.DataBindingDisabled -= DataBindingOnDataBindingToggled;
|
||||
}
|
||||
|
||||
_selectedDataBinding = _profileEditorService.SelectedDataBinding;
|
||||
if (_selectedDataBinding != null)
|
||||
DataBinding = _profileEditorService.SelectedDataBinding;
|
||||
if (DataBinding != null)
|
||||
{
|
||||
_selectedDataBinding.DataBindingPropertyRegistered += DataBindingRegistrationsChanged;
|
||||
_selectedDataBinding.DataBindingPropertiesCleared += DataBindingRegistrationsChanged;
|
||||
DataBinding.DataBindingEnabled += DataBindingOnDataBindingToggled;
|
||||
DataBinding.DataBindingDisabled += DataBindingOnDataBindingToggled;
|
||||
|
||||
OnPropertyChanged(nameof(DataBindingEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
private void DataBindingRegistrationsChanged(object sender, LayerPropertyEventArgs e)
|
||||
private void DataBindingOnDataBindingToggled(object? sender, DataBindingEventArgs e)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
_updating = true;
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
await Task.Delay(200);
|
||||
CreateDataBindingViewModels();
|
||||
_updating = false;
|
||||
});
|
||||
OnPropertyChanged(nameof(DataBindingEnabled));
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
@@ -90,17 +70,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
CreateDataBindingViewModels();
|
||||
SubscribeToSelectedDataBinding();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
SelectedItemIndex = 0;
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
|
||||
@@ -156,7 +156,6 @@
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
<!-- Properties tree -->
|
||||
<materialDesign:DialogHost Identifier="PropertyTreeDialogHost" DialogTheme="Inherit" CloseOnClickAway="True" Grid.Row="1">
|
||||
<materialDesign:Transitioner x:Name="PropertyTreeTransitioner" SelectedIndex="{Binding PropertyTreeIndex}" DefaultTransitionOrigin="0.9, 0.9" AutoApplyTransitionOrigins="True">
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
|
||||
public void ActivateDataBindingViewModel()
|
||||
{
|
||||
if (_profileEditorService.SelectedDataBinding == LayerProperty)
|
||||
if (_profileEditorService.SelectedDataBinding == LayerProperty.DataBinding)
|
||||
_profileEditorService.ChangeSelectedDataBinding(null);
|
||||
else
|
||||
_profileEditorService.ChangeSelectedDataBinding(LayerProperty);
|
||||
_profileEditorService.ChangeSelectedDataBinding(LayerProperty.DataBinding);
|
||||
}
|
||||
|
||||
public void ResetToDefault()
|
||||
@@ -92,8 +92,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
{
|
||||
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
LayerProperty.VisibilityChanged += LayerPropertyOnVisibilityChanged;
|
||||
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBinding.DataBindingEnabled += LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBinding.DataBindingDisabled += LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled;
|
||||
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
|
||||
base.OnInitialActivate();
|
||||
@@ -104,8 +104,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
{
|
||||
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
LayerProperty.VisibilityChanged -= LayerPropertyOnVisibilityChanged;
|
||||
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBinding.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.DataBinding.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
|
||||
LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled;
|
||||
base.OnClose();
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
|
||||
{
|
||||
LayerPropertyViewModel.IsHighlighted = _profileEditorService.SelectedDataBinding == LayerProperty;
|
||||
LayerPropertyViewModel.IsHighlighted = _profileEditorService.SelectedDataBinding == LayerProperty.DataBinding;
|
||||
}
|
||||
|
||||
private void LayerPropertyOnVisibilityChanged(object sender, LayerPropertyEventArgs e)
|
||||
@@ -124,7 +124,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
|
||||
}
|
||||
|
||||
private void LayerPropertyOnDataBindingChange(object sender, LayerPropertyEventArgs e)
|
||||
private void LayerPropertyOnDataBindingChange(object sender, DataBindingEventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(HasDataBinding));
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
private bool _canSelectEditTool;
|
||||
private BindableCollection<ArtemisDevice> _devices;
|
||||
private BindableCollection<ArtemisLed> _highlightedLeds;
|
||||
private DateTime _lastUpdate;
|
||||
private PanZoomViewModel _panZoomViewModel;
|
||||
private Layer _previousSelectedLayer;
|
||||
private int _previousTool;
|
||||
@@ -138,7 +137,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
|
||||
ApplyActiveProfile();
|
||||
|
||||
_lastUpdate = DateTime.Now;
|
||||
_coreService.FrameRendered += OnFrameRendered;
|
||||
|
||||
_rgbService.DeviceAdded += RgbServiceOnDevicesModified;
|
||||
@@ -232,7 +230,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
if (CanSelectEditTool == false && ActiveToolIndex == 1)
|
||||
ActivateToolByIndex(2);
|
||||
}
|
||||
|
||||
|
||||
#region Buttons
|
||||
|
||||
private void ActivateToolByIndex(int value)
|
||||
@@ -307,19 +305,32 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
|
||||
private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
TimeSpan delta = DateTime.Now - _lastUpdate;
|
||||
_lastUpdate = DateTime.Now;
|
||||
|
||||
if (SuspendedEditing || !_settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true).Value || _profileEditorService.SelectedProfile == null)
|
||||
if (SuspendedEditing || _profileEditorService.Playing || _profileEditorService.SelectedProfile == null)
|
||||
return;
|
||||
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _profileEditorService.SelectedProfile.GetAllRenderElements()
|
||||
.SelectMany(f => f.GetAllLayerProperties(), (f, p) => p)
|
||||
.SelectMany(p => p.GetAllDataBindingRegistrations()))
|
||||
dataBindingRegistration.GetDataBinding()?.UpdateWithDelta(delta);
|
||||
|
||||
// TODO: Only update when there are data bindings
|
||||
if (!_profileEditorService.Playing)
|
||||
bool hasEnabledDataBindings = false;
|
||||
|
||||
// Always update the currently selected data binding
|
||||
if (_profileEditorService.SelectedDataBinding != null && _profileEditorService.SelectedDataBinding.IsEnabled)
|
||||
{
|
||||
hasEnabledDataBindings = true;
|
||||
_profileEditorService.SelectedDataBinding.BaseLayerProperty.UpdateDataBinding();
|
||||
}
|
||||
|
||||
// Update all other data bindings if the user enabled this
|
||||
if (_settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true).Value)
|
||||
{
|
||||
foreach (ILayerProperty layerProperty in _profileEditorService.SelectedProfile.GetAllRenderElements().SelectMany(f => f.GetAllLayerProperties(), (_, p) => p))
|
||||
{
|
||||
if (layerProperty.BaseDataBinding != _profileEditorService.SelectedDataBinding && layerProperty.BaseDataBinding.IsEnabled)
|
||||
{
|
||||
hasEnabledDataBindings = true;
|
||||
layerProperty.UpdateDataBinding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasEnabledDataBindings)
|
||||
_profileEditorService.UpdateProfilePreview();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user