using System; using Avalonia.Data; using Avalonia.Interactivity; using Avalonia.Input; using Avalonia.Layout; using Avalonia.Threading; using Avalonia.Controls.Metadata; using Avalonia.Automation.Peers; namespace Avalonia.Controls.Primitives { public class ScrollEventArgs : EventArgs { public ScrollEventArgs(ScrollEventType eventType, double newValue) { ScrollEventType = eventType; NewValue = newValue; } public double NewValue { get; private set; } public ScrollEventType ScrollEventType { get; private set; } } /// /// A scrollbar control. /// [TemplatePart("PART_LineDownButton", typeof(Button))] [TemplatePart("PART_LineUpButton", typeof(Button))] [TemplatePart("PART_PageDownButton", typeof(Button))] [TemplatePart("PART_PageUpButton", typeof(Button))] [PseudoClasses(":vertical", ":horizontal")] public class ScrollBar : RangeBase { /// /// Defines the property. /// public static readonly StyledProperty ViewportSizeProperty = AvaloniaProperty.Register(nameof(ViewportSize), defaultValue: double.NaN); /// /// Defines the property. /// public static readonly StyledProperty VisibilityProperty = AvaloniaProperty.Register(nameof(Visibility), ScrollBarVisibility.Visible); /// /// Defines the property. /// public static readonly StyledProperty OrientationProperty = AvaloniaProperty.Register(nameof(Orientation), Orientation.Vertical); /// /// Defines the property. /// public static readonly DirectProperty IsExpandedProperty = AvaloniaProperty.RegisterDirect( nameof(IsExpanded), o => o.IsExpanded); /// /// Defines the property. /// public static readonly StyledProperty AllowAutoHideProperty = AvaloniaProperty.Register(nameof(AllowAutoHide), true); /// /// Defines the property. /// public static readonly StyledProperty HideDelayProperty = AvaloniaProperty.Register(nameof(HideDelay), TimeSpan.FromSeconds(2)); /// /// Defines the property. /// public static readonly StyledProperty ShowDelayProperty = AvaloniaProperty.Register(nameof(ShowDelay), TimeSpan.FromSeconds(0.5)); private Button? _lineUpButton; private Button? _lineDownButton; private Button? _pageUpButton; private Button? _pageDownButton; private DispatcherTimer? _timer; private bool _isExpanded; /// /// Initializes static members of the class. /// static ScrollBar() { Thumb.DragDeltaEvent.AddClassHandler((x, e) => x.OnThumbDragDelta(e), RoutingStrategies.Bubble); Thumb.DragCompletedEvent.AddClassHandler((x, e) => x.OnThumbDragComplete(e), RoutingStrategies.Bubble); } /// /// Initializes a new instance of the class. /// public ScrollBar() { UpdatePseudoClasses(Orientation); } /// /// Gets or sets the amount of the scrollable content that is currently visible. /// public double ViewportSize { get { return GetValue(ViewportSizeProperty); } set { SetValue(ViewportSizeProperty, value); } } /// /// Gets or sets a value that indicates whether the scrollbar should hide itself when it /// is not needed. /// public ScrollBarVisibility Visibility { get { return GetValue(VisibilityProperty); } set { SetValue(VisibilityProperty, value); } } /// /// Gets or sets the orientation of the scrollbar. /// public Orientation Orientation { get { return GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } /// /// Gets a value that indicates whether the scrollbar is expanded. /// public bool IsExpanded { get => _isExpanded; private set => SetAndRaise(IsExpandedProperty, ref _isExpanded, value); } /// /// Gets a value that indicates whether the scrollbar can hide itself when user is not interacting with it. /// public bool AllowAutoHide { get => GetValue(AllowAutoHideProperty); set => SetValue(AllowAutoHideProperty, value); } /// /// Gets a value that determines how long will be the hide delay after user stops interacting with the scrollbar. /// public TimeSpan HideDelay { get => GetValue(HideDelayProperty); set => SetValue(HideDelayProperty, value); } /// /// Gets a value that determines how long will be the show delay when user starts interacting with the scrollbar. /// public TimeSpan ShowDelay { get => GetValue(ShowDelayProperty); set => SetValue(ShowDelayProperty, value); } public event EventHandler? Scroll; /// /// Calculates and updates whether the scrollbar should be visible. /// private void UpdateIsVisible() { var isVisible = Visibility switch { ScrollBarVisibility.Visible => true, ScrollBarVisibility.Disabled => false, ScrollBarVisibility.Hidden => false, ScrollBarVisibility.Auto => (double.IsNaN(ViewportSize) || Maximum > 0), _ => throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.") }; SetValue(IsVisibleProperty, isVisible); } protected override void OnKeyDown(KeyEventArgs e) { if (e.Key == Key.PageUp) { LargeDecrement(); e.Handled = true; } else if (e.Key == Key.PageDown) { LargeIncrement(); e.Handled = true; } } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == OrientationProperty) { UpdatePseudoClasses(change.GetNewValue()); } else if (change.Property == AllowAutoHideProperty) { UpdateIsExpandedState(); } else { if (change.Property == MinimumProperty || change.Property == MaximumProperty || change.Property == ViewportSizeProperty || change.Property == VisibilityProperty) { UpdateIsVisible(); } } } protected override void OnPointerEntered(PointerEventArgs e) { base.OnPointerEntered(e); if (AllowAutoHide) { ExpandAfterDelay(); } } protected override void OnPointerExited(PointerEventArgs e) { base.OnPointerExited(e); if (AllowAutoHide) { CollapseAfterDelay(); } } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { if (_lineUpButton != null) { _lineUpButton.Click -= LineUpClick; } if (_lineDownButton != null) { _lineDownButton.Click -= LineDownClick; } if (_pageUpButton != null) { _pageUpButton.Click -= PageUpClick; } if (_pageDownButton != null) { _pageDownButton.Click -= PageDownClick; } _lineUpButton = e.NameScope.Find