1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-01 18:23:32 +00:00

Profile editor - Fixed new elements not rendering while paused

Profile editor - Use default brush on new layers
Profile tree - Implement drag & drop
This commit is contained in:
Robert 2022-03-09 00:10:41 +01:00
parent f5a902f5a5
commit 376a9142d3
14 changed files with 335 additions and 229 deletions

View File

@ -27,5 +27,7 @@ namespace Artemis.Core.Services
/// Returns the descriptor of the default layer brush /// Returns the descriptor of the default layer brush
/// </summary> /// </summary>
LayerBrushDescriptor? GetDefaultLayerBrush(); LayerBrushDescriptor? GetDefaultLayerBrush();
void ApplyDefaultBrush(Layer layer);
} }
} }

View File

@ -46,5 +46,13 @@ namespace Artemis.Core.Services
defaultReference.Value.BrushType ??= "SolidBrush"; defaultReference.Value.BrushType ??= "SolidBrush";
return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor; return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor;
} }
/// <inheritdoc />
public void ApplyDefaultBrush(Layer layer)
{
LayerBrushDescriptor? brush = GetDefaultLayerBrush();
if (brush != null)
layer.ChangeLayerBrush(brush.CreateInstance(layer, null));
}
} }
} }

View File

@ -47,6 +47,8 @@ public class AddProfileElement : IProfileEditorCommand, IDisposable
{ {
_isAdded = true; _isAdded = true;
_target.AddChild(_subject, _index); _target.AddChild(_subject, _index);
_subject.Enable();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -134,7 +134,7 @@ public abstract class PropertyInputViewModel<T> : PropertyInputViewModel
return; return;
if (_preview.DiscardPreview() && _preview.PreviewValue != null) if (_preview.DiscardPreview() && _preview.PreviewValue != null)
ProfileEditorService.ExecuteCommand(new UpdateLayerProperty<T>(LayerProperty, _inputValue, _preview.PreviewValue, Time)); ProfileEditorService.ExecuteCommand(new UpdateLayerProperty<T>(LayerProperty, _inputValue, _preview.OriginalValue, Time));
_preview = null; _preview = null;
} }

View File

@ -0,0 +1,23 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
using Avalonia.Media;
namespace Artemis.UI.Converters;
public class ColorOpacityConverter : IValueConverter
{
/// <inheritdoc />
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Color color && double.TryParse(parameter?.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double multiplier))
return new Color((byte) (color.A * multiplier), color.R, color.G, color.B);
return value;
}
/// <inheritdoc />
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value;
}
}

View File

@ -55,7 +55,9 @@
</TextBox> </TextBox>
<controls:ColorPickerButton Classes="contained-color-picker-button" <controls:ColorPickerButton Classes="contained-color-picker-button"
Color="{CompiledBinding InputValue, Converter={StaticResource SKColorToColor2Converter}}" Color="{CompiledBinding InputValue, Converter={StaticResource SKColorToColor2Converter}}"
ShowAcceptDismissButtons="False" /> ShowAcceptDismissButtons="False"
FlyoutOpened="ColorPickerButton_OnFlyoutOpened"
FlyoutClosed="ColorPickerButton_OnFlyoutClosed" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,8 +1,10 @@
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using FluentAvalonia.UI.Controls;
namespace Artemis.UI.DefaultTypes.PropertyInput namespace Artemis.UI.DefaultTypes.PropertyInput
{ {
@ -17,5 +19,15 @@ namespace Artemis.UI.DefaultTypes.PropertyInput
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private void ColorPickerButton_OnFlyoutOpened(ColorPickerButton sender, EventArgs args)
{
ViewModel?.StartPreview();
}
private void ColorPickerButton_OnFlyoutClosed(ColorPickerButton sender, EventArgs args)
{
ViewModel?.ApplyPreview();
}
} }
} }

View File

@ -1,15 +1,11 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Generators; using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Xaml.Interactions.DragAndDrop; using Avalonia.Xaml.Interactions.DragAndDrop;
@ -34,7 +30,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
if (sender is ItemsControl itemsControl) if (sender is ItemsControl itemsControl)
{ {
foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(itemsControl)) foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(itemsControl))
SetDraggingPseudoClasses(treeViewItem, TreeDropType.After, false); SetDraggingPseudoClasses(treeViewItem, TreeDropType.None);
} }
return result; return result;
@ -42,8 +38,11 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
public override void Cancel(object? sender, RoutedEventArgs e) public override void Cancel(object? sender, RoutedEventArgs e)
{ {
if (e.Source is IControl control && control.FindAncestorOfType<TreeViewItem>() != null) if (sender is ItemsControl itemsControl)
SetDraggingPseudoClasses(control.FindAncestorOfType<TreeViewItem>(), TreeDropType.After, false); {
foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(itemsControl))
SetDraggingPseudoClasses(treeViewItem, TreeDropType.None);
}
base.Cancel(sender, e); base.Cancel(sender, e);
} }
@ -102,6 +101,9 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
if (e.DragEffects != DragDropEffects.Move) if (e.DragEffects != DragDropEffects.Move)
return false; return false;
foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(treeView))
SetDraggingPseudoClasses(treeViewItem, TreeDropType.None);
if (bExecute) if (bExecute)
{ {
if (dropType == TreeDropType.Into) if (dropType == TreeDropType.Into)
@ -118,7 +120,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
} }
else else
{ {
SetDraggingPseudoClasses((IControl) targetVisual, dropType, true); SetDraggingPseudoClasses((IControl) targetVisual, dropType);
} }
return true; return true;
@ -130,7 +132,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
foreach (ItemContainerInfo containerInfo in currentNode.ItemContainerGenerator.Containers) foreach (ItemContainerInfo containerInfo in currentNode.ItemContainerGenerator.Containers)
{ {
if (containerInfo.ContainerControl is TreeViewItem treeViewItem && containerInfo.Item is TreeItemViewModel viewModel) if (containerInfo.ContainerControl is TreeViewItem treeViewItem && containerInfo.Item is TreeItemViewModel)
{ {
result.Add(treeViewItem); result.Add(treeViewItem);
if (treeViewItem.ItemContainerGenerator.Containers.Any()) if (treeViewItem.ItemContainerGenerator.Containers.Any())
@ -141,9 +143,16 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
return result; return result;
} }
private void SetDraggingPseudoClasses(IControl control, TreeDropType type, bool isDragging) private void SetDraggingPseudoClasses(IControl control, TreeDropType type)
{ {
if (isDragging) if (type == TreeDropType.None)
{
((IPseudoClasses) control.Classes).Remove(":dragging");
((IPseudoClasses) control.Classes).Remove(":dragging-before");
((IPseudoClasses) control.Classes).Remove(":dragging-after");
((IPseudoClasses) control.Classes).Remove(":dragging-into");
}
else
{ {
((IPseudoClasses) control.Classes).Add(":dragging"); ((IPseudoClasses) control.Classes).Add(":dragging");
if (type == TreeDropType.Before) if (type == TreeDropType.Before)
@ -165,19 +174,13 @@ public class ProfileTreeViewDropHandler : DropHandlerBase
((IPseudoClasses) control.Classes).Add(":dragging-into"); ((IPseudoClasses) control.Classes).Add(":dragging-into");
} }
} }
else
{
((IPseudoClasses) control.Classes).Remove(":dragging");
((IPseudoClasses) control.Classes).Remove(":dragging-before");
((IPseudoClasses) control.Classes).Remove(":dragging-after");
((IPseudoClasses) control.Classes).Remove(":dragging-into");
}
} }
private enum TreeDropType private enum TreeDropType
{ {
Before, Before,
After, After,
Into Into,
None
} }
} }

View File

@ -8,8 +8,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{ {
public class FolderTreeItemViewModel : TreeItemViewModel public class FolderTreeItemViewModel : TreeItemViewModel
{ {
public FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, IRgbService rgbService) public FolderTreeItemViewModel(TreeItemViewModel? parent,
: base(parent, folder, windowService, profileEditorService, rgbService, profileEditorVmFactory) Folder folder,
IWindowService windowService,
IProfileEditorService profileEditorService,
ILayerBrushService layerBrushService,
IProfileEditorVmFactory profileEditorVmFactory,
IRgbService rgbService)
: base(parent, folder, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
{ {
Folder = folder; Folder = folder;
} }

View File

@ -8,8 +8,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{ {
public class LayerTreeItemViewModel : TreeItemViewModel public class LayerTreeItemViewModel : TreeItemViewModel
{ {
public LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, IRgbService rgbService) public LayerTreeItemViewModel(TreeItemViewModel? parent,
: base(parent, layer, windowService, profileEditorService, rgbService, profileEditorVmFactory) Layer layer,
IWindowService windowService,
IProfileEditorService profileEditorService,
IRgbService rgbService,
ILayerBrushService layerBrushService,
IProfileEditorVmFactory profileEditorVmFactory)
: base(parent, layer, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
{ {
Layer = layer; Layer = layer;
} }

View File

@ -6,9 +6,13 @@
xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree" xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree"
xmlns:profileBehaviors="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Behaviors" xmlns:profileBehaviors="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Behaviors"
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors" xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.ProfileTreeView" x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.ProfileTreeView"
x:DataType="profileTree:ProfileTreeViewModel"> x:DataType="profileTree:ProfileTreeViewModel">
<UserControl.Resources>
<converters:ColorOpacityConverter x:Key="ColorOpacityConverter" />
</UserControl.Resources>
<UserControl.Styles> <UserControl.Styles>
<StyleInclude Source="avares://Avalonia.Xaml.Interactions/Draggable/Styles.axaml" /> <StyleInclude Source="avares://Avalonia.Xaml.Interactions/Draggable/Styles.axaml" />
<Style Selector="TreeView#ProfileTreeView"> <Style Selector="TreeView#ProfileTreeView">
@ -36,17 +40,49 @@
</Style> </Style>
<Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-before"> <Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-before">
<Setter Property="Background" Value="DarkOrange" /> <Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,28">
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.0" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.05" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.05" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.25" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style> </Style>
<Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-into"> <Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-into">
<Setter Property="Background" Value="Blue" /> <Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,28">
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.0" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.05" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.05" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.25" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.75" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.95" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.95" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style> </Style>
<Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-after"> <Style Selector="TreeView#ProfileTreeView TreeViewItem:dragging-after">
<Setter Property="Background" Value="Green" /> <Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,28">
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0}" Offset="0.75" />
<GradientStop Color="{Binding Source={StaticResource SystemAccentColorLight3}, Converter={StaticResource ColorOpacityConverter}, ConverterParameter=0.25}" Offset="0.95" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="0.95" />
<GradientStop Color="{StaticResource SystemAccentColorLight3}" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style> </Style>
</UserControl.Styles> </UserControl.Styles>
<Grid RowDefinitions="*,Auto"> <Grid RowDefinitions="*,Auto">
<TreeView Name="ProfileTreeView" Classes="no-right-margin draggable" Items="{CompiledBinding Children}" SelectedItem="{CompiledBinding SelectedChild}" SelectionChanged="ProfileTreeView_OnSelectionChanged"> <TreeView Name="ProfileTreeView" Classes="no-right-margin draggable" Items="{CompiledBinding Children}" SelectedItem="{CompiledBinding SelectedChild}"
SelectionChanged="ProfileTreeView_OnSelectionChanged">
<TreeView.Styles> <TreeView.Styles>
<Style Selector="TreeViewItem"> <Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />

View File

@ -15,13 +15,15 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
{ {
public class ProfileTreeViewModel : TreeItemViewModel public class ProfileTreeViewModel : TreeItemViewModel
{ {
private readonly IProfileEditorService _profileEditorService;
private TreeItemViewModel? _selectedChild; private TreeItemViewModel? _selectedChild;
public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, IRgbService rgbService) public ProfileTreeViewModel(IWindowService windowService,
: base(null, null, windowService, profileEditorService, rgbService, profileEditorVmFactory) IProfileEditorService profileEditorService,
ILayerBrushService layerBrushService,
IProfileEditorVmFactory profileEditorVmFactory,
IRgbService rgbService)
: base(null, null, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory)
{ {
_profileEditorService = profileEditorService;
this.WhenActivated(d => this.WhenActivated(d =>
{ {
profileEditorService.ProfileConfiguration.WhereNotNull().Subscribe(configuration => profileEditorService.ProfileConfiguration.WhereNotNull().Subscribe(configuration =>
@ -46,7 +48,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
profileEditorService.ChangeCurrentProfileElement(renderProfileElement); profileEditorService.ChangeCurrentProfileElement(renderProfileElement);
}); });
ClearSelection = ReactiveCommand.Create(() => _profileEditorService.ChangeCurrentProfileElement(null)); ClearSelection = ReactiveCommand.Create(() => profileEditorService.ChangeCurrentProfileElement(null));
} }
public ReactiveCommand<Unit, Unit> ClearSelection { get; } public ReactiveCommand<Unit, Unit> ClearSelection { get; }

View File

@ -8,7 +8,6 @@ using System.Reactive.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Exceptions;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.Interfaces; using Artemis.UI.Shared.Services.Interfaces;
@ -16,20 +15,24 @@ using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands; using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree namespace Artemis.UI.Screens.ProfileEditor.ProfileTree;
{
public abstract class TreeItemViewModel : ActivatableViewModelBase public abstract class TreeItemViewModel : ActivatableViewModelBase
{ {
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileEditorVmFactory _profileEditorVmFactory; private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IWindowService _windowService; private readonly IWindowService _windowService;
private readonly IProfileEditorService _profileEditorService; private RenderProfileElement? _currentProfileElement;
private bool _isExpanded; private bool _isExpanded;
private ProfileElement? _profileElement; private ProfileElement? _profileElement;
private RenderProfileElement? _currentProfileElement;
private bool _renaming;
private string? _renameValue; private string? _renameValue;
private bool _renaming;
protected TreeItemViewModel(TreeItemViewModel? parent, ProfileElement? profileElement, IWindowService windowService, IProfileEditorService profileEditorService, IRgbService rgbService, protected TreeItemViewModel(TreeItemViewModel? parent, ProfileElement? profileElement,
IWindowService windowService,
IProfileEditorService profileEditorService,
IRgbService rgbService,
ILayerBrushService layerBrushService,
IProfileEditorVmFactory profileEditorVmFactory) IProfileEditorVmFactory profileEditorVmFactory)
{ {
_windowService = windowService; _windowService = windowService;
@ -44,12 +47,16 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
if (ProfileElement is Layer targetLayer) if (ProfileElement is Layer targetLayer)
{ {
Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName()); Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName());
layerBrushService.ApplyDefaultBrush(layer);
layer.AddLeds(rgbService.EnabledDevices.SelectMany(d => d.Leds)); layer.AddLeds(rgbService.EnabledDevices.SelectMany(d => d.Leds));
profileEditorService.ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order)); profileEditorService.ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order));
} }
else if (ProfileElement != null) else if (ProfileElement != null)
{ {
Layer layer = new(ProfileElement, ProfileElement.GetNewLayerName()); Layer layer = new(ProfileElement, ProfileElement.GetNewLayerName());
layerBrushService.ApplyDefaultBrush(layer);
layer.AddLeds(rgbService.EnabledDevices.SelectMany(d => d.Leds)); layer.AddLeds(rgbService.EnabledDevices.SelectMany(d => d.Leds));
profileEditorService.ExecuteCommand(new AddProfileElement(layer, ProfileElement, 0)); profileEditorService.ExecuteCommand(new AddProfileElement(layer, ProfileElement, 0));
} }
@ -230,6 +237,3 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
} }
} }
} }
}