#nullable enable using System.ComponentModel; namespace Terminal.Gui; /// /// Provides a visual indicator that content can be scrolled. ScrollBars consist of two buttons, one each for scrolling /// forward or backwards, a that can be dragged /// to scroll continuously. ScrollBars can be oriented either horizontally or vertically and support the user dragging /// and clicking with the mouse to scroll. /// /// /// /// indicates the number of rows or columns the Scroll has moved from 0. /// /// public class ScrollBar : View, IOrientation, IDesignable { private readonly Scroll _scroll; private readonly Button _decreaseButton; private readonly Button _increaseButton; /// public ScrollBar () { CanFocus = false; _scroll = new (); _scroll.SliderPositionChanging += OnScrollOnSliderPositionChanging; _scroll.SliderPositionChanged += OnScrollOnSliderPositionChanged; _scroll.ContentPositionChanging += OnScrollOnContentPositionChanging; _scroll.ContentPositionChanged += OnScrollOnContentPositionChanged; _scroll.SizeChanged += OnScrollOnSizeChanged; _decreaseButton = new () { CanFocus = false, NoDecorations = true, NoPadding = true, ShadowStyle = ShadowStyle.None, WantContinuousButtonPressed = true }; _decreaseButton.Accepting += OnDecreaseButtonOnAccept; _increaseButton = new () { CanFocus = false, NoDecorations = true, NoPadding = true, ShadowStyle = ShadowStyle.None, WantContinuousButtonPressed = true }; _increaseButton.Accepting += OnIncreaseButtonOnAccept; Add (_decreaseButton, _scroll, _increaseButton); _orientationHelper = new (this); // Do not use object initializer! _orientationHelper.Orientation = Orientation.Vertical; _orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e); _orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e); // This sets the width/height etc... OnOrientationChanged (Orientation); return; void OnDecreaseButtonOnAccept (object? s, CommandEventArgs e) { ContentPosition -= Increment; e.Cancel = true; } void OnIncreaseButtonOnAccept (object? s, CommandEventArgs e) { ContentPosition += Increment; e.Cancel = true; } } #region IOrientation members private readonly OrientationHelper _orientationHelper; /// public Orientation Orientation { get => _orientationHelper.Orientation; set => _orientationHelper.Orientation = value; } /// public event EventHandler>? OrientationChanging; /// public event EventHandler>? OrientationChanged; /// public void OnOrientationChanged (Orientation newOrientation) { TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom; TextAlignment = Alignment.Center; VerticalTextAlignment = Alignment.Center; if (Orientation == Orientation.Vertical) { Width = 1; Height = Dim.Fill (); } else { Width = Dim.Fill (); Height = 1; } _scroll.Orientation = newOrientation; } #endregion private bool _autoHide = true; /// /// Gets or sets whether will be set to if the dimension of the /// scroll bar is greater than or equal to . /// public bool AutoHide { get => _autoHide; set { if (_autoHide != value) { _autoHide = value; if (!AutoHide) { Visible = true; } SetNeedsLayout (); } } } /// protected override void OnFrameChanged (in Rectangle frame) { ShowHide (); } private void ShowHide () { if (!AutoHide || !IsInitialized) { return; } if (Orientation == Orientation.Vertical) { Visible = Frame.Height - (_decreaseButton.Frame.Height + _increaseButton.Frame.Height) < Size; } else { Visible = Frame.Width - (_decreaseButton.Frame.Width + _increaseButton.Frame.Width) < Size; } } /// /// Gets or sets whether the Scroll will show the percentage the slider /// takes up within the . /// public bool ShowPercent { get => _scroll.ShowPercent; set => _scroll.ShowPercent = value; } /// Get or sets if the view-port is kept in all visible area of this . public bool KeepContentInAllViewport { //get => _scroll.KeepContentInAllViewport; //set => _scroll.KeepContentInAllViewport = value; get; set; } /// Gets or sets the position of the slider within the ScrollBar's Viewport. /// The position. public int SliderPosition { get => _scroll.SliderPosition; set => _scroll.SliderPosition = value; } private void OnScrollOnSliderPositionChanging (object? sender, CancelEventArgs e) { SliderPositionChanging?.Invoke (this, e); } private void OnScrollOnSliderPositionChanged (object? sender, EventArgs e) { SliderPositionChanged?.Invoke (this, e); } /// /// Raised when the is changing. Set to /// to prevent the position from being changed. /// public event EventHandler>? SliderPositionChanging; /// Raised when the has changed. public event EventHandler>? SliderPositionChanged; /// /// Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through. /// public int Size { get => _scroll.Size; set => _scroll.Size = value; } /// /// Gets or sets the position of the ScrollSlider within the range of 0.... /// public int ContentPosition { get => _scroll.ContentPosition; set => _scroll.ContentPosition = value; } private void OnScrollOnContentPositionChanging (object? sender, CancelEventArgs e) { ContentPositionChanging?.Invoke (this, e); } private void OnScrollOnContentPositionChanged (object? sender, EventArgs e) { ContentPositionChanged?.Invoke (this, e); } /// /// Raised when the is changing. Set to /// to prevent the position from being changed. /// public event EventHandler>? ContentPositionChanging; /// Raised when the has changed. public event EventHandler>? ContentPositionChanged; /// Raised when has changed. public event EventHandler>? SizeChanged; private void OnScrollOnSizeChanged (object? sender, EventArgs e) { ShowHide (); SizeChanged?.Invoke (this, e); } /// /// Gets or sets the amount each click of the increment/decrement buttons and each /// mouse wheel event will incremenet/decrement the . /// /// /// The default is 1. /// public int Increment { get => _scroll.Increment; set => _scroll.Increment = value; } /// protected override void OnSubviewLayout (LayoutEventArgs args) { PositionSubviews (); } private void PositionSubviews () { if (Orientation == Orientation.Vertical) { _decreaseButton.Y = 0; _decreaseButton.X = 0; _decreaseButton.Width = Dim.Fill (); _decreaseButton.Height = 1; _decreaseButton.Title = Glyphs.UpArrow.ToString (); _increaseButton.Y = Pos.Bottom (_scroll); _increaseButton.X = 0; _increaseButton.Width = Dim.Fill (); _increaseButton.Height = 1; _increaseButton.Title = Glyphs.DownArrow.ToString (); _scroll.X = 0; _scroll.Y = Pos.Bottom (_decreaseButton); _scroll.Height = Dim.Fill (1); _scroll.Width = Dim.Fill (); } else { _decreaseButton.Y = 0; _decreaseButton.X = 0; _decreaseButton.Width = 1; _decreaseButton.Height = Dim.Fill (); _decreaseButton.Title = Glyphs.LeftArrow.ToString (); _increaseButton.Y = 0; _increaseButton.X = Pos.Right (_scroll); _increaseButton.Width = 1; _increaseButton.Height = Dim.Fill (); _increaseButton.Title = Glyphs.RightArrow.ToString (); _scroll.Y = 0; _scroll.X = Pos.Right (_decreaseButton); _scroll.Width = Dim.Fill (1); _scroll.Height = Dim.Fill (); } } /// public bool EnableForDesign () { OrientationChanged += (sender, args) => { if (args.CurrentValue == Orientation.Vertical) { Width = 1; Height = Dim.Fill (); } else { Width = Dim.Fill (); Height = 1; } }; Width = 1; Height = Dim.Fill (); Size = 200; SliderPosition = 10; //ShowPercent = true; return true; } }