Pārlūkot izejas kodu

Added SelectableStrip highlight animation

Krzysztof Krysiński 1 mēnesi atpakaļ
vecāks
revīzija
a7b82a5039

+ 151 - 0
src/PixiEditor.UI.Common/Controls/SelectableStrip.cs

@@ -0,0 +1,151 @@
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Animation.Easings;
+using Avalonia.Controls;
+using Avalonia.Layout;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Avalonia.VisualTree;
+
+namespace PixiEditor.UI.Common.Controls;
+
+public class SelectableStrip : Panel
+{
+    public static readonly AttachedProperty<bool> IsStripSelectedProperty =
+        AvaloniaProperty.RegisterAttached<Control, bool>("IsStripSelected", typeof(SelectableStrip));
+
+    public static void SetIsStripSelected(AvaloniaObject obj, bool value) =>
+        obj.SetValue(IsStripSelectedProperty, value);
+
+    public static bool GetIsStripSelected(AvaloniaObject obj) =>
+        obj.GetValue(IsStripSelectedProperty);
+
+    public double HighlightX
+    {
+        get => GetValue(HighlightXProperty);
+        set => SetValue(HighlightXProperty, value);
+    }
+
+    public static readonly StyledProperty<double> HighlightXProperty =
+        AvaloniaProperty.Register<SelectableStrip, double>(nameof(HighlightX));
+
+    private Border _highlight;
+
+    static SelectableStrip()
+    {
+        HighlightXProperty.Changed.AddClassHandler<SelectableStrip>((strip, e) =>
+        {
+            if (e.Property != HighlightXProperty)
+                return;
+
+            if (strip._highlight.RenderTransform is TranslateTransform transform)
+            {
+                transform.X = (double)e.NewValue;
+            }
+        });
+
+        IsStripSelectedProperty.Changed.AddClassHandler<Control>(OnSelectionChanged);
+    }
+
+    public SelectableStrip()
+    {
+        IBrush border = Brushes.Red;
+        IBrush background = Brushes.Transparent;
+        if (Application.Current.Styles.TryGetResource("ThemeBorderMidBrush", null, out object resource))
+        {
+            border = resource as IBrush;
+        }
+
+        if (Application.Current.Styles.TryGetResource("ThemeBorderLowBrush", null, out object bgResource))
+        {
+            background = bgResource as IBrush;
+        }
+
+        _highlight = new Border
+        {
+            Background = background, CornerRadius = new CornerRadius(4), ZIndex = -1,
+            BorderBrush = border, BorderThickness = new Thickness(1),
+        };
+
+        _highlight.RenderTransform = new TranslateTransform();
+        Transitions = new Transitions()
+        {
+            new DoubleTransition
+            {
+                Property = HighlightXProperty,
+                Duration = TimeSpan.FromMilliseconds(160),
+                Easing = new CubicEaseOut(),
+            }
+        };
+    }
+
+    public override void ApplyTemplate()
+    {
+        base.ApplyTemplate();
+        if (!Children.Contains(_highlight))
+        {
+            Children.Insert(0, _highlight);
+        }
+    }
+
+    private static void OnSelectionChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
+    {
+        if (e.Property != IsStripSelectedProperty)
+            return;
+
+        var control = e.Sender as Control;
+        if (control is null || !GetIsStripSelected(control))
+            return;
+
+        var strip = control.GetVisualParent();
+        while (strip != null && strip is not SelectableStrip)
+        {
+            strip = strip.GetVisualParent();
+        }
+
+        if (strip is not SelectableStrip selectableStrip)
+            return;
+
+        var pos = control.TranslatePoint(new Point(0, 0), selectableStrip) ?? new Point();
+        selectableStrip.HighlightX = pos.X;
+    }
+
+    protected override Size ArrangeOverride(Size finalSize)
+    {
+        double x = 0;
+        foreach (var child in Children)
+        {
+            if (child == _highlight)
+            {
+                child.Arrange(new Rect(new Point(0, 0), new Size(finalSize.Height, finalSize.Height)));
+                continue;
+            }
+
+            child.Arrange(new Rect(new Point(x, 0), new Size(child.DesiredSize.Width, finalSize.Height)));
+
+            x += child.DesiredSize.Width;
+        }
+
+        return finalSize;
+    }
+
+    override protected Size MeasureOverride(Size availableSize)
+    {
+        double totalWidth = 0;
+        double maxHeight = 0;
+
+        foreach (var child in Children)
+        {
+            if (child == _highlight)
+            {
+                continue;
+            }
+
+            child.Measure(availableSize);
+            totalWidth += child.DesiredSize.Width;
+            maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
+        }
+
+        return new Size(totalWidth, maxHeight);
+    }
+}

+ 14 - 3
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/BrushToolbar.cs

@@ -73,8 +73,15 @@ internal class BrushToolbar : Toolbar, IBrushToolbar
         setting.ValueChanged += (_, _) => OnPropertyChanged(nameof(ToolSize));
         AddSetting(setting);
         AddSetting(new BrushSettingViewModel(nameof(Brush), "BRUSH_SETTING") { IsExposed = true });
-        AddSetting(new EnumSettingViewModel<StabilizationMode>(nameof(StabilizationMode), "STABILIZATION_MODE_SETTING") { IsExposed = true, PickerType = EnumSettingPickerType.IconButtons, IsLabelVisible = false});
-        AddSetting(new SizeSettingViewModel(nameof(Stabilization), "STABILIZATION_SETTING", 0, min: 0, max: 128) { IsExposed = true });
+        AddSetting(new EnumSettingViewModel<StabilizationMode>(nameof(StabilizationMode), "STABILIZATION_MODE_SETTING")
+            { IsExposed = true, PickerType = EnumSettingPickerType.IconButtons, IsLabelVisible = false});
+        var stabilizationSetting = new SizeSettingViewModel(nameof(Stabilization), "STABILIZATION_SETTING", 10, min: 0, max: 128)
+        {
+            IsExposed = false,
+            IsLabelVisible = false
+        };
+
+        AddSetting(stabilizationSetting);
 
         foreach (var aSetting in Settings)
         {
@@ -90,7 +97,11 @@ internal class BrushToolbar : Toolbar, IBrushToolbar
 
             if (aSetting.Name == "StabilizationMode")
             {
-                aSetting.ValueChanged += (_, _) => OnPropertyChanged(nameof(StabilizationMode));
+                aSetting.ValueChanged += (_, _) =>
+                {
+                    stabilizationSetting.IsExposed = StabilizationMode != StabilizationMode.None;
+                    OnPropertyChanged(nameof(StabilizationMode));
+                };
             }
         }
     }

+ 34 - 34
src/PixiEditor/Views/Tools/ToolSettings/Settings/EnumSettingView.axaml

@@ -8,6 +8,7 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:settings1="clr-namespace:PixiEditor.Views.Tools.ToolSettings.Settings"
              xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+             xmlns:controls="clr-namespace:PixiEditor.UI.Common.Controls;assembly=PixiEditor.UI.Common"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PixiEditor.Views.Tools.ToolSettings.Settings.EnumSettingView" Name="uc">
     <Design.DataContext>
@@ -34,47 +35,46 @@
                 </DataTemplate>
             </ComboBox.ItemTemplate>
         </ComboBox>
-        <ItemsControl IsVisible="{Binding PickerIsIconButtons}"
-                      Name="iconButtonsPicker"
-                      ItemsSource="{Binding EnumValues}"
-                      HorizontalAlignment="Center">
+        <Border Background="{DynamicResource ThemeControlLowBrush}" CornerRadius="4">
+            <ItemsControl IsVisible="{Binding PickerIsIconButtons}"
+                          Name="iconButtonsPicker"
+                          ItemsSource="{Binding EnumValues}"
+                          HorizontalAlignment="Center">
                 <ItemsControl.Styles>
-                    <Style Selector="ContentPresenter:nth-last-child(1) ToggleButton">
-                        <Setter Property="CornerRadius" Value="0,4,4,0"/>
-                        <Setter Property="BorderThickness" Value="0,1,1,1"/>
-                    </Style>
-                    <Style Selector="ContentPresenter.first ToggleButton">
-                        <Setter Property="CornerRadius" Value="4,0,0,4"/>
-                        <Setter Property="BorderThickness" Value="1,1,0,1"/>
-                    </Style>
                     <Style Selector="ToggleButton">
-                        <Setter Property="CornerRadius" Value="0"/>
-                        <Setter Property="BorderThickness" Value="0, 1"/>
+                        <Setter Property="CornerRadius" Value="0" />
+                        <Setter Property="BorderThickness" Value="0, 0" />
+                        <Setter Property="Background" Value="Transparent" />
                     </Style>
                     <Style Selector="ToggleButton:unchecked">
-                        <Setter Property="Background" Value="{DynamicResource ThemeControlLowBrush}"/>
+                        <Setter Property="Background" Value="Transparent" />
+                    </Style>
+                    <Style Selector="ToggleButton:checked">
+                        <Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
+                        <Setter Property="Background" Value="Transparent" />
                     </Style>
                 </ItemsControl.Styles>
-            <ItemsControl.ItemsPanel>
-                <ItemsPanelTemplate>
-                    <StackPanel Orientation="Horizontal"
-                                HorizontalAlignment="Center" />
-                </ItemsPanelTemplate>
-            </ItemsControl.ItemsPanel>
-            <ItemsControl.ItemTemplate>
-                <DataTemplate>
-                    <ToggleButton Padding="4"
-                                  behaviours:ToggleGroupBehavior.GroupName="PickerMode"
-                                  behaviours:ToggleGroupBehavior.Value="{Binding .}"
-                                  behaviours:ToggleGroupBehavior.SelectedValue="{Binding DataContext.Value,
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <controls:SelectableStrip />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <ToggleButton Padding="4"
+                                      controls:SelectableStrip.IsStripSelected="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
+                                      behaviours:ToggleGroupBehavior.GroupName="PickerMode"
+                                      behaviours:ToggleGroupBehavior.Value="{Binding .}"
+                                      behaviours:ToggleGroupBehavior.SelectedValue="{Binding DataContext.Value,
                               RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}"
-                                  localization:Translator.TooltipKey="{Binding ., Converter={converters:EnumToLocalizedStringConverter}}">
-
-                        <TextBlock FontSize="20" Classes="pixi-icon" Text="{Binding ., Converter={converters:EnumToIconConverter}}"/>
-                    </ToggleButton>
-                </DataTemplate>
-            </ItemsControl.ItemTemplate>
+                                      localization:Translator.TooltipKey="{Binding ., Converter={converters:EnumToLocalizedStringConverter}}">
 
-        </ItemsControl>
+                            <TextBlock FontSize="20" Classes="pixi-icon" Name="iconTextBlock"
+                                       Text="{Binding ., Converter={converters:EnumToIconConverter}}"/>
+                        </ToggleButton>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+        </Border>
     </Panel>
 </UserControl>

+ 0 - 20
src/PixiEditor/Views/Tools/ToolSettings/Settings/EnumSettingView.axaml.cs

@@ -14,25 +14,5 @@ public partial class EnumSettingView : UserControl
     {
         InitializeComponent();
     }
-
-    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
-    {
-        base.OnAttachedToVisualTree(e);
-        iconButtonsPicker.ContainerPrepared += IconButtonsPickerOnContainerPrepared;
-    }
-
-    override protected void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
-    {
-        base.OnDetachedFromVisualTree(e);
-        iconButtonsPicker.ContainerPrepared -= IconButtonsPickerOnContainerPrepared;
-    }
-
-    private void IconButtonsPickerOnContainerPrepared(object? sender, ContainerPreparedEventArgs e)
-    {
-        if (e.Index == 0)
-        {
-            e.Container.Classes.Add("first");
-        }
-    }
 }