Browse Source

Scroll Bar Context Menu V1

pull/19413/head
Tim Miller 8 months ago
parent
commit
40b5aacbc7
  1. 212
      src/Avalonia.Controls/Primitives/ScrollBar.cs

212
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -1,14 +1,18 @@
using System;
using System.Linq;
using System.Windows.Input;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Reactive;
using Avalonia.Threading;
using Avalonia.Controls.Metadata;
using Avalonia.Automation.Peers;
using Avalonia.VisualTree;
using Avalonia.Reactive;
using System.Linq;
namespace Avalonia.Controls.Primitives
{
@ -33,6 +37,7 @@ namespace Avalonia.Controls.Primitives
[PseudoClasses(":vertical", ":horizontal")]
public class ScrollBar : RangeBase
{
/// <summary>
/// Defines the <see cref="ViewportSize"/> property.
/// </summary>
@ -85,6 +90,7 @@ namespace Avalonia.Controls.Primitives
private bool _isExpanded;
private CompositeDisposable? _ownerSubscriptions;
private ScrollViewer? _owner;
private Point _lastRightClickPosition;
/// <summary>
/// Initializes static members of the <see cref="ScrollBar"/> class.
@ -103,6 +109,7 @@ namespace Avalonia.Controls.Primitives
public ScrollBar()
{
UpdatePseudoClasses(Orientation);
ContextRequested += OnContextRequested;
}
/// <summary>
@ -506,5 +513,200 @@ namespace Avalonia.Controls.Primitives
PseudoClasses.Set(":vertical", o == Orientation.Vertical);
PseudoClasses.Set(":horizontal", o == Orientation.Horizontal);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
if (e.GetCurrentPoint(this).Properties.IsRightButtonPressed)
{
_lastRightClickPosition = e.GetPosition(this);
}
}
private void OnContextRequested(object? sender, ContextRequestedEventArgs e)
{
if (e.TryGetPosition(this, out var position))
{
_lastRightClickPosition = position;
}
if (Orientation == Orientation.Vertical)
{
SetCurrentValue(ContextMenuProperty, CreateVerticalContextMenu());
}
else
{
var visualRoot = this.GetVisualRoot() as Visual;
var flowDirection = visualRoot?.FlowDirection ?? FlowDirection.LeftToRight;
SetCurrentValue(ContextMenuProperty, flowDirection == FlowDirection.LeftToRight
? CreateHorizontalContextMenuLTR()
: CreateHorizontalContextMenuRTL());
}
}
private ContextMenu CreateVerticalContextMenu()
{
var contextMenu = new ContextMenu();
contextMenu.Items.Add(CreateMenuItem("Scroll Here", "ScrollHere", () => ScrollHereAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Top", "Top", () => ScrollToTopAction(this)));
contextMenu.Items.Add(CreateMenuItem("Bottom", "Bottom", () => ScrollToBottomAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Page Up", "PageUp", () => PageUpAction(this)));
contextMenu.Items.Add(CreateMenuItem("Page Down", "PageDown", () => PageDownAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Scroll Up", "ScrollUp", () => LineUpAction(this)));
contextMenu.Items.Add(CreateMenuItem("Scroll Down", "ScrollDown", () => LineDownAction(this)));
return contextMenu;
}
private ContextMenu CreateHorizontalContextMenuLTR()
{
var contextMenu = new ContextMenu();
contextMenu.Items.Add(CreateMenuItem("Scroll Here", "ScrollHere", () => ScrollHereAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Left Edge", "LeftEdge", () => ScrollToLeftEndAction(this)));
contextMenu.Items.Add(CreateMenuItem("Right Edge", "RightEdge", () => ScrollToRightEndAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Page Left", "PageLeft", () => PageLeftAction(this)));
contextMenu.Items.Add(CreateMenuItem("Page Right", "PageRight", () => PageRightAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Scroll Left", "ScrollLeft", () => LineLeftAction(this)));
contextMenu.Items.Add(CreateMenuItem("Scroll Right", "ScrollRight", () => LineRightAction(this)));
return contextMenu;
}
private ContextMenu CreateHorizontalContextMenuRTL()
{
var contextMenu = new ContextMenu();
contextMenu.Items.Add(CreateMenuItem("Scroll Here", "ScrollHere", () => ScrollHereAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Right Edge", "RightEdge", () => ScrollToRightEndAction(this)));
contextMenu.Items.Add(CreateMenuItem("Left Edge", "LeftEdge", () => ScrollToLeftEndAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Page Right", "PageRight", () => PageRightAction(this)));
contextMenu.Items.Add(CreateMenuItem("Page Left", "PageLeft", () => PageLeftAction(this)));
contextMenu.Items.Add(new Separator());
contextMenu.Items.Add(CreateMenuItem("Scroll Right", "ScrollRight", () => LineRightAction(this)));
contextMenu.Items.Add(CreateMenuItem("Scroll Left", "ScrollLeft", () => LineLeftAction(this)));
return contextMenu;
}
private static MenuItem CreateMenuItem(string header, string automationId, Action action)
{
var menuItem = new MenuItem
{
Header = header,
Command = new SimpleCommand(action)
};
AutomationProperties.SetAutomationId(menuItem, automationId);
return menuItem;
}
private static void ScrollHereAction(ScrollBar scrollBar)
{
if (scrollBar.Track != null)
{
var track = scrollBar.Track;
var trackLength = scrollBar.Orientation == Orientation.Vertical ? track.Bounds.Height : track.Bounds.Width;
var thumbLength = scrollBar.Orientation == Orientation.Vertical ? track.Thumb?.Bounds.Height ?? 0 : track.Thumb?.Bounds.Width ?? 0;
var clickPosition = scrollBar.Orientation == Orientation.Vertical ? scrollBar._lastRightClickPosition.Y : scrollBar._lastRightClickPosition.X;
if (trackLength > thumbLength)
{
var ratio = clickPosition / trackLength;
var range = scrollBar.Maximum - scrollBar.Minimum;
var value = scrollBar.Minimum + (ratio * range);
scrollBar.SetCurrentValue(ValueProperty, Math.Max(scrollBar.Minimum, Math.Min(scrollBar.Maximum, value)));
scrollBar.OnScroll(ScrollEventType.ThumbTrack);
}
}
}
private static void ScrollToTopAction(ScrollBar scrollBar)
{
scrollBar.SetCurrentValue(ValueProperty, scrollBar.Minimum);
scrollBar.OnScroll(ScrollEventType.SmallDecrement);
}
private static void ScrollToBottomAction(ScrollBar scrollBar)
{
scrollBar.SetCurrentValue(ValueProperty, scrollBar.Maximum);
scrollBar.OnScroll(ScrollEventType.SmallIncrement);
}
private static void ScrollToLeftEndAction(ScrollBar scrollBar)
{
scrollBar.SetCurrentValue(ValueProperty, scrollBar.Minimum);
scrollBar.OnScroll(ScrollEventType.SmallDecrement);
}
private static void ScrollToRightEndAction(ScrollBar scrollBar)
{
scrollBar.SetCurrentValue(ValueProperty, scrollBar.Maximum);
scrollBar.OnScroll(ScrollEventType.SmallIncrement);
}
private static void PageUpAction(ScrollBar scrollBar)
{
scrollBar.LargeDecrement();
}
private static void PageDownAction(ScrollBar scrollBar)
{
scrollBar.LargeIncrement();
}
private static void PageLeftAction(ScrollBar scrollBar)
{
scrollBar.LargeDecrement();
}
private static void PageRightAction(ScrollBar scrollBar)
{
scrollBar.LargeIncrement();
}
private static void LineUpAction(ScrollBar scrollBar)
{
scrollBar.SmallDecrement();
}
private static void LineDownAction(ScrollBar scrollBar)
{
scrollBar.SmallIncrement();
}
private static void LineLeftAction(ScrollBar scrollBar)
{
scrollBar.SmallDecrement();
}
private static void LineRightAction(ScrollBar scrollBar)
{
scrollBar.SmallIncrement();
}
private Track? Track => this.GetTemplateChildren().OfType<Track>().FirstOrDefault();
private class SimpleCommand : ICommand
{
private readonly Action _action;
public SimpleCommand(Action action)
{
_action = action;
}
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? parameter) => true;
public void Execute(object? parameter)
{
_action();
}
}
}
}

Loading…
Cancel
Save