From d102536017e009660a41b3861e0c7355213c36bf Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Thu, 12 Jan 2023 11:40:35 +0000 Subject: [PATCH] implement IScrollSnapPointInfo in StackPanel --- src/Avalonia.Controls/StackPanel.cs | 178 +++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs index 964a1055df..89afb50b38 100644 --- a/src/Avalonia.Controls/StackPanel.cs +++ b/src/Avalonia.Controls/StackPanel.cs @@ -4,7 +4,11 @@ // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation. using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Controls.Primitives; using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Layout; namespace Avalonia.Controls @@ -12,7 +16,7 @@ namespace Avalonia.Controls /// /// A panel which lays out its children horizontally or vertically. /// - public class StackPanel : Panel, INavigableContainer + public class StackPanel : Panel, INavigableContainer, IScrollSnapPointsInfo { /// /// Defines the property. @@ -26,6 +30,34 @@ namespace Avalonia.Controls public static readonly StyledProperty OrientationProperty = StackLayout.OrientationProperty.AddOwner(); + /// + /// Defines the property. + /// + public static readonly StyledProperty AreHorizontalSnapPointsRegularProperty = + AvaloniaProperty.Register(nameof(AreHorizontalSnapPointsRegular)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty AreVerticalSnapPointsRegularProperty = + AvaloniaProperty.Register(nameof(AreVerticalSnapPointsRegular)); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent HorizontalSnapPointsChangedEvent = + RoutedEvent.Register( + nameof(HorizontalSnapPointsChanged), + RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent VerticalSnapPointsChangedEvent = + RoutedEvent.Register( + nameof(VerticalSnapPointsChanged), + RoutingStrategies.Bubble); + /// /// Initializes static members of the class. /// @@ -53,6 +85,31 @@ namespace Avalonia.Controls set { SetValue(OrientationProperty, value); } } + public event EventHandler? HorizontalSnapPointsChanged + { + add => AddHandler(HorizontalSnapPointsChangedEvent, value); + remove => RemoveHandler(HorizontalSnapPointsChangedEvent, value); + } + + + public event EventHandler? VerticalSnapPointsChanged + { + add => AddHandler(VerticalSnapPointsChangedEvent, value); + remove => RemoveHandler(VerticalSnapPointsChangedEvent, value); + } + + public bool AreHorizontalSnapPointsRegular + { + get { return GetValue(AreHorizontalSnapPointsRegularProperty); } + set { SetValue(AreHorizontalSnapPointsRegularProperty, value); } + } + + public bool AreVerticalSnapPointsRegular + { + get { return GetValue(AreVerticalSnapPointsRegularProperty); } + set { SetValue(AreVerticalSnapPointsRegularProperty, value); } + } + /// /// Gets the next control in the specified direction. /// @@ -274,6 +331,8 @@ namespace Avalonia.Controls ArrangeChild(child, rcChild, finalSize, Orientation); } + RaiseEvent(new RoutedEventArgs(Orientation == Orientation.Horizontal ? HorizontalSnapPointsChangedEvent : VerticalSnapPointsChangedEvent)); + return finalSize; } @@ -285,5 +344,122 @@ namespace Avalonia.Controls { child.Arrange(rect); } + + public IReadOnlyList GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment) + { + var snapPoints = new List(); + + switch (orientation) + { + case Orientation.Horizontal: + if (AreHorizontalSnapPointsRegular) + throw new InvalidOperationException(); + if (Orientation == Orientation.Horizontal) + { + foreach(var child in VisualChildren) + { + double snapPoint = 0; + + switch (snapPointsAlignment) + { + case SnapPointsAlignment.Near: + snapPoint = child.Bounds.Left; + break; + case SnapPointsAlignment.Center: + snapPoint = child.Bounds.Center.X; + break; + case SnapPointsAlignment.Far: + snapPoint = child.Bounds.Right; + break; + } + + snapPoints.Add(snapPoint); + } + } + break; + case Orientation.Vertical: + if (AreVerticalSnapPointsRegular) + throw new InvalidOperationException(); + if (Orientation == Orientation.Vertical) + { + foreach (var child in VisualChildren) + { + double snapPoint = 0; + + switch (snapPointsAlignment) + { + case SnapPointsAlignment.Near: + snapPoint = child.Bounds.Top; + break; + case SnapPointsAlignment.Center: + snapPoint = child.Bounds.Center.Y; + break; + case SnapPointsAlignment.Far: + snapPoint = child.Bounds.Bottom; + break; + } + + snapPoints.Add(snapPoint); + } + } + break; + } + + return snapPoints; + } + + public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset) + { + offset = 0f; + var firstChild = VisualChildren.FirstOrDefault(); + + if(firstChild == null) + { + return 0; + } + + double snapPoint = 0; + + switch (Orientation) + { + case Orientation.Horizontal: + if (!AreHorizontalSnapPointsRegular) + throw new InvalidOperationException(); + + snapPoint = firstChild.Bounds.Width; + switch (snapPointsAlignment) + { + case SnapPointsAlignment.Near: + offset = firstChild.Bounds.Left; + break; + case SnapPointsAlignment.Center: + offset = firstChild.Bounds.Center.X; + break; + case SnapPointsAlignment.Far: + offset = firstChild.Bounds.Right; + break; + } + break; + case Orientation.Vertical: + if (!AreVerticalSnapPointsRegular) + throw new InvalidOperationException(); + snapPoint = firstChild.Bounds.Height; + switch (snapPointsAlignment) + { + case SnapPointsAlignment.Near: + offset = firstChild.Bounds.Top; + break; + case SnapPointsAlignment.Center: + offset = firstChild.Bounds.Center.Y; + break; + case SnapPointsAlignment.Far: + offset = firstChild.Bounds.Bottom; + break; + } + break; + } + + return snapPoint; + } } }