mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Core - Refactored effects
Profile editor - Added effect creation
This commit is contained in:
1 parent
e5ba48c7f4
commit
2bf36fbf20
61 files changed
+1005
-763
No files matched your search
@@ -0,0 +1,64 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:layerEffects="clr-namespace:Artemis.Core.LayerEffects;assembly=Artemis.Core"
|
||||
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Dialogs"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Dialogs.AddEffectView"
|
||||
x:DataType="dialogs:AddEffectViewModel"
|
||||
Width="500">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<TextBox Name="SearchBox" Text="{CompiledBinding SearchText}" Margin="0 0 0 15" Watermark="Search"></TextBox>
|
||||
<ListBox Name="EffectDescriptorsList"
|
||||
Grid.Row="1"
|
||||
Items="{CompiledBinding LayerEffectDescriptors}"
|
||||
IsVisible="{CompiledBinding LayerEffectDescriptors.Count}"
|
||||
Height="300">
|
||||
|
||||
<ListBox.DataTemplates>
|
||||
<DataTemplate DataType="{x:Type layerEffects:LayerEffectDescriptor}">
|
||||
<Grid RowDefinitions="Auto,*"
|
||||
ColumnDefinitions="Auto,Auto"
|
||||
Background="Transparent"
|
||||
PointerReleased="InputElement_OnPointerReleased"
|
||||
Margin="0 4"
|
||||
VerticalAlignment="Center">
|
||||
<shared:ArtemisIcon Grid.Column="0"
|
||||
Grid.RowSpan="2"
|
||||
Icon="{CompiledBinding Icon}"
|
||||
Width="24"
|
||||
Height="24"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 15 0" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
Classes="BodyStrongTextBlockStyle"
|
||||
Text="{CompiledBinding DisplayName}"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="450"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Foreground="{DynamicResource TextFillColorSecondary}"
|
||||
Text="{CompiledBinding Description}"
|
||||
VerticalAlignment="Top"
|
||||
Width="450"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.DataTemplates>
|
||||
</ListBox>
|
||||
<Grid Grid.Row="1" Height="300">
|
||||
<StackPanel VerticalAlignment="Center"
|
||||
Spacing="20"
|
||||
IsVisible="{CompiledBinding !LayerEffectDescriptors.Count}">
|
||||
<avalonia:MaterialIcon Kind="CloseCircle" Width="32" Height="32"></avalonia:MaterialIcon>
|
||||
<TextBlock Classes="h5" TextAlignment="Center">None of the effects match your search</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Avalonia;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
||||
|
||||
public class AddEffectView : ReactiveUserControl<AddEffectViewModel>
|
||||
{
|
||||
public AddEffectView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (sender is not IDataContextProvider {DataContext: LayerEffectDescriptor descriptor} || ViewModel == null)
|
||||
return;
|
||||
|
||||
ViewModel?.AddLayerEffect(descriptor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
||||
|
||||
public class AddEffectViewModel : ContentDialogViewModelBase
|
||||
{
|
||||
private readonly RenderProfileElement _renderProfileElement;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private string? _searchText;
|
||||
|
||||
public AddEffectViewModel(RenderProfileElement renderProfileElement, IProfileEditorService profileEditorService, ILayerEffectService layerEffectService)
|
||||
{
|
||||
_renderProfileElement = renderProfileElement;
|
||||
_profileEditorService = profileEditorService;
|
||||
|
||||
SourceList<LayerEffectDescriptor> layerEffectSourceList = new();
|
||||
layerEffectSourceList.AddRange(layerEffectService.GetLayerEffects());
|
||||
IObservable<Func<LayerEffectDescriptor, bool>> layerEffectFilter = this.WhenAnyValue(vm => vm.SearchText).Select(CreatePredicate);
|
||||
|
||||
layerEffectSourceList.Connect()
|
||||
.Filter(layerEffectFilter)
|
||||
.Bind(out ReadOnlyObservableCollection<LayerEffectDescriptor> layerEffectDescriptors)
|
||||
.Subscribe();
|
||||
LayerEffectDescriptors = layerEffectDescriptors;
|
||||
}
|
||||
|
||||
public ReadOnlyObservableCollection<LayerEffectDescriptor> LayerEffectDescriptors { get; }
|
||||
|
||||
public string? SearchText
|
||||
{
|
||||
get => _searchText;
|
||||
set => this.RaiseAndSetIfChanged(ref _searchText, value);
|
||||
}
|
||||
|
||||
public void AddLayerEffect(LayerEffectDescriptor descriptor)
|
||||
{
|
||||
BaseLayerEffect layerEffect = descriptor.CreateInstance(_renderProfileElement, null);
|
||||
_profileEditorService.ExecuteCommand(new AddLayerEffect(_renderProfileElement, layerEffect));
|
||||
ContentDialog?.Hide();
|
||||
}
|
||||
|
||||
private Func<LayerEffectDescriptor, bool> CreatePredicate(string? search)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(search))
|
||||
return _ => true;
|
||||
|
||||
search = search.Trim();
|
||||
return data => data.DisplayName.Contains(search, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
data.Description.Contains(search, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<StyleInclude Source="/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml" />
|
||||
</UserControl.Styles>
|
||||
<UserControl.Resources>
|
||||
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
||||
<converters:DoubleToGridLengthConverter x:Key="DoubleToGridLengthConverter"></converters:DoubleToGridLengthConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid Name="ContainerGrid">
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -29,13 +29,22 @@
|
||||
Name="TreeScrollViewer"
|
||||
Offset="{CompiledBinding #TimelineScrollViewer.Offset, Mode=OneWay}"
|
||||
Background="{DynamicResource CardStrokeColorDefaultSolidBrush}">
|
||||
<ItemsControl Items="{CompiledBinding PropertyGroupViewModels}" Padding="0 0 8 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<TreeDataTemplate DataType="{x:Type local:PropertyGroupViewModel}" ItemsSource="{CompiledBinding Children}">
|
||||
<ContentControl Content="{CompiledBinding TreeGroupViewModel}" />
|
||||
</TreeDataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<ItemsControl Items="{CompiledBinding PropertyGroupViewModels}" Padding="0 0 8 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<TreeDataTemplate DataType="{x:Type local:PropertyGroupViewModel}" ItemsSource="{CompiledBinding Children}">
|
||||
<ContentControl Content="{CompiledBinding TreeGroupViewModel}" />
|
||||
</TreeDataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Button Grid.Row="1"
|
||||
Command="{CompiledBinding AddEffect}"
|
||||
Margin="4"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right">
|
||||
Add new effect
|
||||
</Button>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
@@ -45,12 +54,12 @@
|
||||
Background="Transparent"
|
||||
Margin="0 0 -5 0" />
|
||||
|
||||
<ContentControl Grid.Column="2"
|
||||
<ContentControl Grid.Column="2"
|
||||
IsVisible="{CompiledBinding DataBindingViewModel, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
Content="{CompiledBinding DataBindingViewModel}"/>
|
||||
Content="{CompiledBinding DataBindingViewModel}" />
|
||||
|
||||
<!-- Horizontal scrolling -->
|
||||
<ScrollViewer Grid.Column="2"
|
||||
<!-- Horizontal scrolling -->
|
||||
<ScrollViewer Grid.Column="2"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
IsVisible="{CompiledBinding DataBindingViewModel, Converter={x:Static ObjectConverters.IsNull}}">
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.LayerBrushes;
|
||||
using Artemis.Core.LayerEffects;
|
||||
@@ -12,8 +13,12 @@ using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.Playback;
|
||||
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
||||
using Artemis.UI.Screens.ProfileEditor.Properties.Dialogs;
|
||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
||||
using Artemis.UI.Screens.Sidebar;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Builders;
|
||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||
using ReactiveUI;
|
||||
|
||||
@@ -23,6 +28,8 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly Dictionary<LayerPropertyGroup, PropertyGroupViewModel> _cachedPropertyViewModels;
|
||||
private readonly IDataBindingVmFactory _dataBindingVmFactory;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly ILayerEffectService _layerEffectService;
|
||||
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
@@ -38,18 +45,22 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
ISettingsService settingsService,
|
||||
ILayerPropertyVmFactory layerPropertyVmFactory,
|
||||
IDataBindingVmFactory dataBindingVmFactory,
|
||||
IWindowService windowService,
|
||||
ILayerEffectService layerEffectService,
|
||||
PlaybackViewModel playbackViewModel)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_settingsService = settingsService;
|
||||
_layerPropertyVmFactory = layerPropertyVmFactory;
|
||||
_dataBindingVmFactory = dataBindingVmFactory;
|
||||
_windowService = windowService;
|
||||
_layerEffectService = layerEffectService;
|
||||
_cachedPropertyViewModels = new Dictionary<LayerPropertyGroup, PropertyGroupViewModel>();
|
||||
|
||||
PropertyGroupViewModels = new ObservableCollection<PropertyGroupViewModel>();
|
||||
PlaybackViewModel = playbackViewModel;
|
||||
TimelineViewModel = layerPropertyVmFactory.TimelineViewModel(PropertyGroupViewModels);
|
||||
|
||||
AddEffect = ReactiveCommand.CreateFromTask(ExecuteAddEffect);
|
||||
// React to service profile element changes as long as the VM is active
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
@@ -86,6 +97,7 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
public ObservableCollection<PropertyGroupViewModel> PropertyGroupViewModels { get; }
|
||||
public PlaybackViewModel PlaybackViewModel { get; }
|
||||
public TimelineViewModel TimelineViewModel { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddEffect { get; }
|
||||
|
||||
public DataBindingViewModel? DataBindingViewModel
|
||||
{
|
||||
@@ -102,6 +114,17 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
public IObservable<bool> Playing => _profileEditorService.Playing;
|
||||
public PluginSetting<double> PropertiesTreeWidth => _settingsService.GetSetting("ProfileEditor.PropertiesTreeWidth", 500.0);
|
||||
|
||||
private async Task ExecuteAddEffect()
|
||||
{
|
||||
if (ProfileElement == null)
|
||||
return;
|
||||
|
||||
await _windowService.CreateContentDialog()
|
||||
.WithTitle("Add layer effect")
|
||||
.WithViewModel(out AddEffectViewModel _, ("renderProfileElement", ProfileElement))
|
||||
.WithCloseButtonText("Cancel")
|
||||
.ShowAsync();
|
||||
}
|
||||
|
||||
private void UpdatePropertyGroups()
|
||||
{
|
||||
|
||||
@@ -38,18 +38,36 @@ public class PropertyGroupViewModel : ViewModelBase, IDisposable
|
||||
PopulateChildren();
|
||||
}
|
||||
|
||||
public PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, ILayerPropertyVmFactory layerPropertyVmFactory, IPropertyInputService propertyInputService,
|
||||
BaseLayerBrush layerBrush)
|
||||
: this(layerPropertyGroup, layerPropertyVmFactory, propertyInputService)
|
||||
public PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, ILayerPropertyVmFactory layerPropertyVmFactory, IPropertyInputService propertyInputService, BaseLayerBrush layerBrush)
|
||||
{
|
||||
_layerPropertyVmFactory = layerPropertyVmFactory;
|
||||
_propertyInputService = propertyInputService;
|
||||
LayerBrush = layerBrush;
|
||||
Children = new ObservableCollection<ViewModelBase>();
|
||||
LayerPropertyGroup = layerPropertyGroup;
|
||||
TreeGroupViewModel = layerPropertyVmFactory.TreeGroupViewModel(this);
|
||||
TimelineGroupViewModel = layerPropertyVmFactory.TimelineGroupViewModel(this);
|
||||
|
||||
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
|
||||
_isVisible = !LayerPropertyGroup.IsHidden;
|
||||
|
||||
PopulateChildren();
|
||||
}
|
||||
|
||||
public PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, ILayerPropertyVmFactory layerPropertyVmFactory, IPropertyInputService propertyInputService,
|
||||
BaseLayerEffect layerEffect)
|
||||
: this(layerPropertyGroup, layerPropertyVmFactory, propertyInputService)
|
||||
public PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, ILayerPropertyVmFactory layerPropertyVmFactory, IPropertyInputService propertyInputService, BaseLayerEffect layerEffect)
|
||||
{
|
||||
_layerPropertyVmFactory = layerPropertyVmFactory;
|
||||
_propertyInputService = propertyInputService;
|
||||
LayerEffect = layerEffect;
|
||||
Children = new ObservableCollection<ViewModelBase>();
|
||||
LayerPropertyGroup = layerPropertyGroup;
|
||||
TreeGroupViewModel = layerPropertyVmFactory.TreeGroupViewModel(this);
|
||||
TimelineGroupViewModel = layerPropertyVmFactory.TimelineGroupViewModel(this);
|
||||
|
||||
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
|
||||
_isVisible = !LayerPropertyGroup.IsHidden;
|
||||
|
||||
PopulateChildren();
|
||||
}
|
||||
|
||||
public ObservableCollection<ViewModelBase> Children { get; }
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0 5"
|
||||
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.General}}">
|
||||
<avalonia:MaterialIcon Kind="HammerWrench" Margin="0 -1 5 0" />
|
||||
<avalonia:MaterialIcon Kind="HammerWrench" Margin="0 0 5 0" />
|
||||
<TextBlock ToolTip.Tip="{Binding LayerPropertyGroup.GroupDescription.Description}">General</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
@@ -61,22 +61,23 @@
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0 5"
|
||||
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.Transform}}">
|
||||
<avalonia:MaterialIcon Kind="TransitConnectionVariant" Margin="0 -1 5 0" />
|
||||
<avalonia:MaterialIcon Kind="TransitConnectionVariant" Margin="0 0 5 0" />
|
||||
<TextBlock ToolTip.Tip="{Binding LayerPropertyGroup.GroupDescription.Description}">Transform</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Type: LayerBrushRoot -->
|
||||
<Grid IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerBrushRoot}}"
|
||||
Height="29"
|
||||
ColumnDefinitions="Auto,Auto,Auto,*">
|
||||
<shared:ArtemisIcon Grid.Column="0"
|
||||
Icon="{Binding LayerBrush.Descriptor.Icon}"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0 5 5 0" />
|
||||
Margin="0 0 5 0" />
|
||||
<TextBlock Grid.Column="1"
|
||||
ToolTip.Tip="{Binding LayerBrush.Descriptor.Description}"
|
||||
Margin="0 5 0 0">
|
||||
Brush - 
|
||||
Margin="0 5 5 0">
|
||||
Brush -
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding LayerBrush.Descriptor.DisplayName}"
|
||||
@@ -101,8 +102,8 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Type: LayerEffectRoot -->
|
||||
<Grid Height="24"
|
||||
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerEffectRoot}}"
|
||||
<Grid IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerEffectRoot}}"
|
||||
Height="29"
|
||||
ColumnDefinitions="Auto,Auto,Auto,Auto,*,Auto">
|
||||
<shared:ArtemisIcon
|
||||
Grid.Column="0"
|
||||
@@ -110,7 +111,7 @@
|
||||
Icon="{Binding LayerEffect.Descriptor.Icon}"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0 5 5 0"
|
||||
Margin="0 0 5 0"
|
||||
Background="Transparent" />
|
||||
<TextBlock Grid.Column="1" ToolTip.Tip="{Binding LayerEffect.Descriptor.Description}" Margin="0 5 0 0">
|
||||
Effect
|
||||
@@ -133,18 +134,23 @@
|
||||
Margin="0 5"
|
||||
IsVisible="{Binding LayerEffect.Name, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
|
||||
<StackPanel Grid.Column="5" Orientation="Horizontal">
|
||||
<ToggleButton
|
||||
Classes="icon-button"
|
||||
ToolTip.Tip="Toggle suspended state"
|
||||
Width="18"
|
||||
Height="18"
|
||||
IsChecked="{Binding !LayerEffect.Suspended}"
|
||||
VerticalAlignment="Center" Padding="-25"
|
||||
Margin="5 0"
|
||||
Command="{Binding SuspendedToggled}">
|
||||
<avalonia:MaterialIcon Kind="Eye" Height="13" Width="13" />
|
||||
</ToggleButton>
|
||||
<StackPanel Grid.Column="5" Orientation="Horizontal" Spacing="2">
|
||||
<Button Classes="icon-button"
|
||||
ToolTip.Tip="Toggle suspended state"
|
||||
Width="24"
|
||||
Height="24"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SuspendedToggled}">
|
||||
<avalonia:MaterialIcon Kind="EyeOff" Height="16" Width="16" IsVisible="True" />
|
||||
</Button>
|
||||
<Button Classes="icon-button"
|
||||
ToolTip.Tip="Toggle suspended state"
|
||||
Width="24"
|
||||
Height="24"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SuspendedToggled}">
|
||||
<avalonia:MaterialIcon Kind="Eye" Height="16" Width="16" IsVisible="True" />
|
||||
</Button>
|
||||
<Button Classes="icon-button"
|
||||
ToolTip.Tip="Rename"
|
||||
Width="24"
|
||||
|
||||
Reference in new issue
Block a user