Layers - Seperated activation and removal of layers/effects

Effects - Added effects UI, order is still a bit messed up and reordering is missed
Effects - Added renaming of effects on the layer
This commit is contained in:
SpoinkyNL committed 2020-06-13 22:23:33 +02:00
1 parent 692cf806b7
commit 18593853d8
39 files changed
+691 -334

No files matched your search

+5 -1
View File
@@ -8,7 +8,7 @@
<Product>Artemis</Product>
<NeutralLanguage>en-US</NeutralLanguage>
<Description>Adds third-party support for RGB keyboards to games.</Description>
<Copyright>Copyright © Robert Beekman - 2019</Copyright>
<Copyright>Copyright © Robert Beekman - 2020</Copyright>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>2.0.0.0</FileVersion>
<Prefer32Bit>true</Prefer32Bit>
@@ -117,6 +117,10 @@
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.4.1" />
<PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="Fody" Version="6.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="gong-wpf-dragdrop" Version="2.2.0" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf.NetCore" Version="1.0.10" />
<PackageReference Include="Humanizer.Core" Version="2.8.11" />
@@ -0,0 +1,39 @@
using System.Windows;
using System.Windows.Input;
namespace Artemis.UI.Behaviors
{
public class MouseBehaviour
{
public static readonly DependencyProperty MouseUpCommandProperty =
DependencyProperty.RegisterAttached("MouseUpCommand", typeof(ICommand),
typeof(MouseBehaviour), new FrameworkPropertyMetadata(
MouseUpCommandChanged));
public static void SetMouseUpCommand(UIElement element, ICommand value)
{
element.SetValue(MouseUpCommandProperty, value);
}
public static ICommand GetMouseUpCommand(UIElement element)
{
return (ICommand) element.GetValue(MouseUpCommandProperty);
}
private static void MouseUpCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = (FrameworkElement) d;
element.MouseUp += element_MouseUp;
}
private static void element_MouseUp(object sender, MouseButtonEventArgs e)
{
var element = (FrameworkElement) sender;
var command = GetMouseUpCommand(element);
command.Execute(e);
}
}
}
@@ -1,11 +1,18 @@
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.Abstract;
using Artemis.UI.Screens.Module;
using Artemis.UI.Screens.Module.ProfileEditor;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem;
using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
using Artemis.UI.Screens.Settings.Tabs.Devices;
using Stylet;
namespace Artemis.UI.Ninject.Factories
{
@@ -43,4 +50,14 @@ namespace Artemis.UI.Ninject.Factories
{
ProfileLayerViewModel Create(Layer layer);
}
public interface ILayerPropertyVmFactory : IVmFactory
{
LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription);
TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel);
TimelineViewModel TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
TreePropertyGroupViewModel TreePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel);
TimelinePropertyGroupViewModel TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel);
}
}
@@ -1,57 +0,0 @@
<UserControl x:Class="Artemis.UI.PropertyInput.EffectPropertyInputView"
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:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
xmlns:layerEffect="clr-namespace:Artemis.Core.Plugins.LayerEffect;assembly=Artemis.Core"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type propertyInput:EffectPropertyInputViewModel}}">
<UserControl.Resources>
<ControlTemplate x:Key="SimpleTemplate">
<StackPanel d:DataContext="{d:DesignInstance {x:Type layerEffect:LayerEffectDescriptor}}" Orientation="Horizontal">
<materialDesign:PackIcon Kind="{Binding Icon}" Height="13" Width="13" Margin="0 1 3 0" />
<TextBlock Text="{Binding DisplayName}" />
</StackPanel>
</ControlTemplate>
<ControlTemplate x:Key="ExtendedTemplate">
<Grid d:DataContext="{d:DesignInstance {x:Type layerEffect:LayerEffectDescriptor}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<materialDesign:PackIcon Grid.Row="0" Grid.RowSpan="2" Kind="{Binding Icon}" Height="20" Width="20" Margin="-5 -2 10 0" VerticalAlignment="Center"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding DisplayName}" TextWrapping="Wrap" MaxWidth="350"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}" TextWrapping="Wrap" MaxWidth="350" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
</Grid>
</ControlTemplate>
<DataTemplate x:Key="DescriptorTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputPrefix}" />
<ComboBox Width="132"
Margin="0 2"
Padding="0 -1"
Height="15"
materialDesign:ComboBoxAssist.ClassicMode="True"
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ItemsSource="{Binding Path=Descriptors}"
SelectedValue="{Binding Path=SelectedDescriptor}"
ItemTemplate="{StaticResource DescriptorTemplate}" />
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
</StackPanel>
</UserControl>
@@ -1,68 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Events;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.LayerEffect;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Shared.PropertyInput;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.PropertyInput
{
public class EffectPropertyInputViewModel : PropertyInputViewModel<LayerEffectReference>
{
private readonly ILayerService _layerService;
private readonly IPluginService _pluginService;
public EffectPropertyInputViewModel(LayerProperty<LayerEffectReference> layerProperty, IProfileEditorService profileEditorService,
ILayerService layerService, IPluginService pluginService) : base(layerProperty, profileEditorService)
{
_layerService = layerService;
_pluginService = pluginService;
_pluginService.PluginEnabled += PluginServiceOnPluginLoaded;
_pluginService.PluginDisabled += PluginServiceOnPluginLoaded;
UpdateEnumValues();
}
public List<LayerEffectDescriptor> Descriptors { get; set; }
public LayerEffectDescriptor SelectedDescriptor
{
get => Descriptors.FirstOrDefault(d => d.LayerEffectProvider.PluginInfo.Guid == InputValue?.EffectPluginGuid && d.LayerEffectType.Name == InputValue?.EffectType);
set => SetEffectByDescriptor(value);
}
public void UpdateEnumValues()
{
var layerEffectProviders = _pluginService.GetPluginsOfType<LayerEffectProvider>();
Descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList();
NotifyOfPropertyChange(nameof(SelectedDescriptor));
}
public override void Dispose()
{
_pluginService.PluginEnabled -= PluginServiceOnPluginLoaded;
_pluginService.PluginDisabled -= PluginServiceOnPluginLoaded;
base.Dispose();
}
protected override void OnInputValueApplied()
{
_layerService.InstantiateLayerEffect(LayerProperty.Layer);
}
private void SetEffectByDescriptor(LayerEffectDescriptor value)
{
InputValue = new LayerEffectReference {EffectPluginGuid = value.LayerEffectProvider.PluginInfo.Guid, EffectType = value.LayerEffectType.Name};
}
private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e)
{
UpdateEnumValues();
}
}
}
@@ -1,4 +1,4 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Dialogs.ProfileElementRenameView"
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Dialogs.RenameView"
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"
@@ -9,7 +9,8 @@
d:DesignHeight="213.053" d:DesignWidth="254.425">
<StackPanel Margin="16">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
Rename profile element
<Run Text="Rename"></Run>
<Run Text="{Binding Subject, Mode=OneWay}"></Run>
</TextBlock>
<TextBox materialDesign:HintAssist.Hint="Element name"
@@ -5,11 +5,11 @@ using System.Windows.Input;
namespace Artemis.UI.Screens.Module.ProfileEditor.Dialogs
{
/// <summary>
/// Interaction logic for ProfileElementRenameView.xaml
/// Interaction logic for RenameView.xaml
/// </summary>
public partial class ProfileElementRenameView : UserControl
public partial class RenameView : UserControl
{
public ProfileElementRenameView()
public RenameView()
{
InitializeComponent();
}
@@ -6,13 +6,15 @@ using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.Dialogs
{
public class ProfileElementRenameViewModel : DialogViewModelBase
public class RenameViewModel : DialogViewModelBase
{
public ProfileElementRenameViewModel(IModelValidator<ProfileElementRenameViewModel> validator, ProfileElement profileElement) : base(validator)
public RenameViewModel(IModelValidator<RenameViewModel> validator, string subject, string currentName) : base(validator)
{
ElementName = profileElement.Name;
Subject = subject;
ElementName = currentName;
}
public string Subject { get; }
public string ElementName { get; set; }
public async Task Accept()
@@ -31,7 +33,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Dialogs
}
}
public class ProfileElementRenameViewModelValidator : AbstractValidator<ProfileElementRenameViewModel>
public class ProfileElementRenameViewModelValidator : AbstractValidator<RenameViewModel>
{
public ProfileElementRenameViewModelValidator()
{
@@ -0,0 +1,51 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects.EffectsView"
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:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:layerEffect="clr-namespace:Artemis.Core.Plugins.LayerEffect;assembly=Artemis.Core"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:EffectsViewModel}">
<Grid Background="{DynamicResource MaterialDesignCardBackground}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16"
Visibility="{Binding HasLayerEffectDescriptors, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}">
<materialDesign:PackIcon Kind="AutoAwesome" Width="80" Height="80" HorizontalAlignment="Center" />
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 15">
Looks like you have no effects installed or enabled!
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignCaptionTextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center">
Effects will apply some sort of post- or pre-processing to layers or even entire folders. <LineBreak />
Think of things like blur, black &amp; white but also audio visualization etc.
</TextBlock>
</StackPanel>
<ListBox ItemsSource="{Binding LayerEffectDescriptors}" SelectedItem="{Binding SelectedLayerEffectDescriptor}" HorizontalContentAlignment="Stretch"
Visibility="{Binding HasLayerEffectDescriptors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type layerEffect:LayerEffectDescriptor}">
<Border Padding="8" BorderThickness="0 0 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}" VerticalAlignment="Stretch"
behaviors:MouseBehaviour.MouseUpCommand="{x:Static materialDesign:Transitioner.MoveFirstCommand}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon Kind="{Binding Icon}" Width="20" Height="20" VerticalAlignment="Center" />
<StackPanel Margin="8 0 0 0" Grid.Column="1" VerticalAlignment="Stretch">
<TextBlock FontWeight="Bold" Text="{Binding DisplayName}" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
@@ -0,0 +1,50 @@
using System.Linq;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.LayerEffect;
using Artemis.Core.Services.Interfaces;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects
{
public class EffectsViewModel : PropertyChangedBase
{
private readonly ILayerService _layerService;
private readonly IPluginService _pluginService;
public EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IPluginService pluginService, ILayerService layerService)
{
_pluginService = pluginService;
_layerService = layerService;
LayerPropertiesViewModel = layerPropertiesViewModel;
LayerEffectDescriptors = new BindableCollection<LayerEffectDescriptor>();
}
public LayerPropertiesViewModel LayerPropertiesViewModel { get; }
public BindableCollection<LayerEffectDescriptor> LayerEffectDescriptors { get; set; }
public bool HasLayerEffectDescriptors => LayerEffectDescriptors.Any();
public LayerEffectDescriptor SelectedLayerEffectDescriptor
{
get => null;
set => AddLayerEffect(value);
}
public void PopulateDescriptors()
{
var layerBrushProviders = _pluginService.GetPluginsOfType<LayerEffectProvider>();
if (LayerEffectDescriptors.Any())
LayerEffectDescriptors.Clear();
LayerEffectDescriptors.AddRange(layerBrushProviders.SelectMany(l => l.LayerEffectDescriptors));
NotifyOfPropertyChange(nameof(HasLayerEffectDescriptors));
}
private void AddLayerEffect(LayerEffectDescriptor value)
{
if (LayerPropertiesViewModel.SelectedLayer != null && value != null)
_layerService.AddLayerEffect(LayerPropertiesViewModel.SelectedLayer, value);
}
}
}
@@ -1,21 +1,21 @@
<UserControl
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:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:timeline="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerPropertiesView"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:LayerPropertiesViewModel}}"
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True">
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:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:timeline="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerPropertiesView"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:LayerPropertiesViewModel}}"
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True">
<UserControl.Resources>
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<Style x:Key="SvStyle" TargetType="{x:Type ScrollViewer}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
@@ -125,14 +125,24 @@
<!-- Properties tree -->
<materialDesign:DialogHost Identifier="PropertyTreeDialogHost" DialogTheme="Inherit" CloseOnClickAway="True" Grid.Row="1">
<ScrollViewer x:Name="PropertyTreeScrollViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
ScrollChanged="TimelineScrollChanged">
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource MaterialDesignDivider}">
<ContentControl s:View.Model="{Binding TreeViewModel}" />
</Border>
</ScrollViewer>
<materialDesign:Transitioner SelectedIndex="{Binding PropertyTreeIndex}" DefaultTransitionOrigin="0.9, 1" AutoApplyTransitionOrigins="True">
<ScrollViewer x:Name="PropertyTreeScrollViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
ScrollChanged="TimelineScrollChanged">
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource MaterialDesignDivider}">
<ContentControl s:View.Model="{Binding TreeViewModel}" />
</Border>
</ScrollViewer>
<materialDesign:TransitionerSlide >
<materialDesign:TransitionerSlide.BackwardWipe>
<materialDesign:CircleWipe />
</materialDesign:TransitionerSlide.BackwardWipe>
<ContentControl s:View.Model="{Binding EffectsViewModel}" />
</materialDesign:TransitionerSlide>
</materialDesign:Transitioner>
</materialDesign:DialogHost>
</Grid>
@@ -206,10 +216,10 @@
<Grid Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
Orientation="Horizontal"
Margin="6"
Visibility="{Binding SelectedLayer, Converter={StaticResource NullToVisibilityConverter}}">
<materialDesign:PackIcon Kind="Layers" Width="16" />
@@ -218,11 +228,11 @@
Margin="5 0 0 0"
ToolTip="{Binding SelectedLayer.LayerBrush.Descriptor.DisplayName, Mode=OneWay}"
Background="Transparent"
Visibility="{Binding SelectedLayer.LayerBrush, Converter={StaticResource NullToVisibilityConverter}}"/>
Visibility="{Binding SelectedLayer.LayerBrush, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock Text="{Binding SelectedLayer.Name}" Margin="5 0 0 0" />
</StackPanel>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
Orientation="Horizontal"
Margin="6"
Visibility="{Binding SelectedFolder, Converter={StaticResource NullToVisibilityConverter}}">
<materialDesign:PackIcon Kind="Folder" Width="16" />
@@ -235,9 +245,11 @@
Height="20"
Width="82"
ToolTip="Change the property's data binding"
VerticalAlignment="Center">
<TextBlock FontSize="10"><Run Text="ADD EFFECT"/></TextBlock>
VerticalAlignment="Center"
Command="{s:Action ToggleAddEffect}">
<TextBlock FontSize="10">
<Run Text="ADD EFFECT" />
</TextBlock>
</Button>
</Grid>
@@ -11,6 +11,8 @@ using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Plugins.LayerBrush.Abstract;
using Artemis.Core.Services;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
using Artemis.UI.Shared.Events;
@@ -21,10 +23,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
{
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private LayerPropertyGroupViewModel _brushPropertyGroup;
private DateTime _lastToggle;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService)
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService,
ILayerPropertyVmFactory layerPropertyVmFactory)
{
_layerPropertyVmFactory = layerPropertyVmFactory;
ProfileEditorService = profileEditorService;
CoreService = coreService;
SettingsService = settingsService;
@@ -46,11 +53,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / ProfileEditorService.PixelsPerSecond);
}
public int PropertyTreeIndex { get; set; }
public Layer SelectedLayer { get; set; }
public Folder SelectedFolder { get; set; }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
public TreeViewModel TreeViewModel { get; set; }
public EffectsViewModel EffectsViewModel { get; set; }
public TimelineViewModel TimelineViewModel { get; set; }
protected override void OnInitialActivate()
@@ -110,9 +119,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
SelectedFolder = null;
}
if (SelectedLayer != null)
{
SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
SelectedLayer.LayerEffectsUpdated -= SelectedLayerOnLayerEffectsUpdated;
SelectedLayer = null;
}
@@ -129,6 +140,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
SelectedLayer = layer;
SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated;
SelectedLayer.LayerEffectsUpdated += SelectedLayerOnLayerEffectsUpdated;
// Add the built-in root groups of the layer
var generalAttribute = Attribute.GetCustomAttribute(
@@ -139,16 +151,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
layer.GetType().GetProperty(nameof(layer.Transform)),
typeof(PropertyGroupDescriptionAttribute)
);
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(ProfileEditorService, layer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(ProfileEditorService, layer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
}
else
SelectedLayer = null;
TreeViewModel = new TreeViewModel(this, LayerPropertyGroups);
TimelineViewModel = new TimelineViewModel(this, LayerPropertyGroups);
TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, LayerPropertyGroups);
EffectsViewModel = _layerPropertyVmFactory.EffectsViewModel(this);
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
ApplyLayerBrush();
ApplyLayerEffects();
}
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
@@ -156,6 +170,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
ApplyLayerBrush();
}
private void SelectedLayerOnLayerEffectsUpdated(object sender, EventArgs e)
{
ApplyLayerEffects();
}
public void ApplyLayerBrush()
{
if (SelectedLayer == null)
@@ -183,13 +202,42 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
Name = SelectedLayer.LayerBrush.Descriptor.DisplayName,
Description = SelectedLayer.LayerBrush.Descriptor.Description
};
_brushPropertyGroup = new LayerPropertyGroupViewModel(ProfileEditorService, SelectedLayer.LayerBrush.BaseProperties, brushDescription);
_brushPropertyGroup = _layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.LayerBrush.BaseProperties, brushDescription);
LayerPropertyGroups.Add(_brushPropertyGroup);
}
TimelineViewModel.UpdateKeyframes();
}
private void ApplyLayerEffects()
{
if (SelectedLayer == null)
return;
// Remove VMs of effects no longer applied on the layer
var toRemove = LayerPropertyGroups.Where(l => l.LayerPropertyGroup.LayerEffect != null && !SelectedLayer.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)).ToList();
LayerPropertyGroups.RemoveRange(toRemove);
foreach (var layerPropertyGroupViewModel in toRemove)
layerPropertyGroupViewModel.Dispose();
foreach (var layerEffect in SelectedLayer.LayerEffects)
{
if (LayerPropertyGroups.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect))
continue;
// Add the rout group of the brush
// The root group of the brush has no attribute so let's pull one out of our sleeve
var brushDescription = new PropertyGroupDescriptionAttribute
{
Name = layerEffect.Descriptor.DisplayName,
Description = layerEffect.Descriptor.Description
};
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerEffect.BaseProperties, brushDescription));
}
TimelineViewModel.UpdateKeyframes();
}
#endregion
#region Controls
@@ -341,5 +389,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
}
#endregion
#region Effects
public void ToggleAddEffect()
{
if (DateTime.Now - _lastToggle < TimeSpan.FromMilliseconds(500))
return;
_lastToggle = DateTime.Now;
PropertyTreeIndex = PropertyTreeIndex == 0 ? 1 : 0;
if (PropertyTreeIndex == 1)
EffectsViewModel.PopulateDescriptors();
}
#endregion
}
}
@@ -4,6 +4,7 @@ using System.Linq;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
@@ -24,16 +25,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
None
}
public LayerPropertyGroupViewModel(IProfileEditorService profileEditorService, LayerPropertyGroup layerPropertyGroup,
PropertyGroupDescriptionAttribute propertyGroupDescription)
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription,
IProfileEditorService profileEditorService, ILayerPropertyVmFactory layerPropertyVmFactory)
{
_layerPropertyVmFactory = layerPropertyVmFactory;
ProfileEditorService = profileEditorService;
LayerPropertyGroup = layerPropertyGroup;
PropertyGroupDescription = propertyGroupDescription;
TreePropertyGroupViewModel = new TreePropertyGroupViewModel(this);
TimelinePropertyGroupViewModel = new TimelinePropertyGroupViewModel(this);
TreePropertyGroupViewModel = _layerPropertyVmFactory.TreePropertyGroupViewModel(this);
TimelinePropertyGroupViewModel = _layerPropertyVmFactory.TimelinePropertyGroupViewModel(this);
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
PopulateChildren();
@@ -123,7 +127,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
}
// Create VMs for child groups on this group, resulting in a nested structure
else if (groupAttribute != null && value is LayerPropertyGroup layerPropertyGroup)
Children.Add(new LayerPropertyGroupViewModel(ProfileEditorService, layerPropertyGroup, groupAttribute));
Children.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerPropertyGroup, groupAttribute));
}
}
@@ -10,7 +10,7 @@ using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class TimelineViewModel
public class TimelineViewModel : PropertyChangedBase
{
private readonly LayerPropertiesViewModel _layerPropertiesViewModel;
@@ -34,7 +34,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
layerPropertyGroupViewModel.TimelinePropertyGroupViewModel.TimelineViewModel = this;
layerPropertyGroupViewModel.TimelinePropertyGroupViewModel.UpdateKeyframes();
foreach (var layerPropertyBaseViewModel in layerPropertyGroupViewModel.GetAllChildren())
{
if (layerPropertyBaseViewModel is LayerPropertyViewModel layerPropertyViewModel)
@@ -5,9 +5,14 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:TreePropertyGroupViewModel}"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
</UserControl.Resources>
<StackPanel>
<!-- Type: None -->
<TextBlock
@@ -78,12 +83,15 @@
</StackPanel>
<!-- Type: LayerEffectRoot -->
<Grid Height="22">
<Grid Height="24">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
@@ -96,24 +104,47 @@
</Style>
</Grid.Style>
<materialDesign:PackIcon Grid.Column="0" Kind="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Icon}" Margin="0 5 5 0" />
<TextBlock Grid.Column="1" ToolTip="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Description}" Margin="0 5">
Effect -&#160;
<TextBlock Grid.Column="1" ToolTip="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Description}" Margin="0 5 0 0">
Effect
</TextBlock>
<TextBlock Grid.Column="2"
ToolTip="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Description}"
Margin="3 5">
-
</TextBlock>
<!-- Show either the descriptors display name or, if set, the effect name -->
<TextBlock Grid.Column="3"
Text="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.DisplayName}"
ToolTip="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Description}"
Margin="0 5" />
Margin="0 5"
Visibility="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
<TextBlock Grid.Column="4"
Text="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name}"
ToolTip="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Description}"
Margin="0 5"
Visibility="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name, Converter={StaticResource NullToVisibilityConverter}}" />
<Button Grid.Column="3"
Style="{StaticResource MaterialDesignOutlinedButton}"
Margin="0 1"
Padding="0"
Width="80"
Height="20"
ToolTip="Change the property's data binding"
VerticalAlignment="Center">
<TextBlock FontSize="10">DELETE EFFECT</TextBlock>
<Button Grid.Column="5"
Style="{StaticResource MaterialDesignIconButton}"
ToolTip="Rename"
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{s:Action RenameEffect}">
<materialDesign:PackIcon Kind="RenameBox" Height="16" Width="16" />
</Button>
<Button Grid.Column="6"
Style="{StaticResource MaterialDesignIconButton}"
ToolTip="Remove"
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{s:Action DeleteEffect}">
<materialDesign:PackIcon Kind="TrashCan" Height="16" Width="16" />
</Button>
</Grid>
</StackPanel>
</UserControl>
@@ -1,14 +1,50 @@
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using System.Collections.Generic;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
{
public class TreePropertyGroupViewModel
{
public TreePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
private readonly IProfileEditorService _profileEditorService;
private readonly ILayerService _layerService;
private readonly IDialogService _dialogService;
public TreePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel,
IProfileEditorService profileEditorService, ILayerService layerService, IDialogService dialogService)
{
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel)layerPropertyBaseViewModel;
_profileEditorService = profileEditorService;
_layerService = layerService;
_dialogService = dialogService;
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel;
}
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
public async void RenameEffect()
{
var result = await _dialogService.ShowDialogAt<RenameViewModel>(
"PropertyTreeDialogHost",
new Dictionary<string, object>
{
{"subject", "effect"},
{"currentName", LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name}
}
);
if (result is string newName)
{
LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name = newName;
LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.HasBeenRenamed = true;
_profileEditorService.UpdateSelectedProfile(true);
}
}
public void DeleteEffect()
{
_layerService.RemoveLayerEffect(LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect);
_profileEditorService.UpdateSelectedProfile(true);
}
}
}
@@ -1,12 +1,11 @@
using System.Linq;
using System.Windows;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
{
public class TreeViewModel
public class TreeViewModel : PropertyChangedBase
{
private readonly LayerPropertiesViewModel _layerPropertiesViewModel;
@@ -130,8 +130,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
// ReSharper disable once UnusedMember.Global - Called from view
public async Task RenameElement()
{
var result = await _dialogService.ShowDialog<ProfileElementRenameViewModel>(
new Dictionary<string, object> {{"profileElement", ProfileElement}}
var result = await _dialogService.ShowDialog<RenameViewModel>(
new Dictionary<string, object>
{
{"subject", ProfileElement is Folder ? "folder" : "layer"},
{"currentName", ProfileElement.Name}
}
);
if (result is string newName)
{
@@ -30,7 +30,6 @@ namespace Artemis.UI.Services
{
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(BrushPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(ColorGradientPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(EffectPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(FloatPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(IntPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(SKColorPropertyInputViewModel));