#nullable enable
using System.ComponentModel;
namespace Terminal.Gui;
/// A proportional scroll bar that can be oriented either horizontally or vertically.
///
///
/// indicates the current location between zero and .
///
/// If the scrollbar is larger than three cells, arrow indicators are drawn.
///
public class ScrollBar : View
{
///
public ScrollBar ()
{
_scroll = new ();
_decrease = new ();
_increase = new () { NavigationDirection = NavigationDirection.Forward };
Add (_scroll, _decrease, _increase);
CanFocus = false;
Orientation = Orientation.Vertical;
Width = Dim.Auto (DimAutoStyle.Content, 1);
Height = Dim.Auto (DimAutoStyle.Content, 1);
_scroll.PositionChanging += Scroll_PositionChanging;
_scroll.PositionChanged += Scroll_PositionChanged;
_scroll.SizeChanged += _scroll_SizeChanged;
}
private readonly Scroll _scroll;
private readonly ScrollButton _decrease;
private readonly ScrollButton _increase;
private bool _autoHide = true;
private bool _showScrollIndicator = 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;
AdjustAll ();
}
}
}
/// 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;
}
/// Gets or sets if a scrollbar is vertical or horizontal.
public Orientation Orientation
{
get => _scroll.Orientation;
set
{
Resize (value);
_scroll.Orientation = value;
}
}
/// Gets or sets the position, relative to , to set the scrollbar at.
/// The position.
public int Position
{
get => _scroll.Position;
set
{
_scroll.Position = value;
AdjustAll ();
}
}
/// Raised when the has changed.
public event EventHandler>? PositionChanged;
///
/// Raised when the is changing. Set to
/// to prevent the position from being changed.
///
public event EventHandler>? PositionChanging;
/// Gets or sets the visibility for the vertical or horizontal scroll indicator.
/// true if show vertical or horizontal scroll indicator; otherwise, false.
public bool ShowScrollIndicator
{
get => Visible;
set
{
if (value == _showScrollIndicator)
{
return;
}
_showScrollIndicator = value;
if (IsInitialized)
{
SetNeedsLayout ();
if (value)
{
Visible = true;
}
else
{
Visible = false;
Position = 0;
}
AdjustAll ();
}
}
}
///
/// 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;
AdjustAll ();
}
}
/// Raised when has changed.
public event EventHandler>? SizeChanged;
///
internal override void OnLayoutComplete (LayoutEventArgs args)
{
base.OnLayoutComplete (args);
AdjustAll ();
}
private void _scroll_SizeChanged (object? sender, EventArgs e) { SizeChanged?.Invoke (this, e); }
private void AdjustAll ()
{
CheckVisibility ();
_scroll.AdjustScroll ();
_decrease.AdjustButton ();
_increase.AdjustButton ();
}
private bool CheckVisibility ()
{
if (!AutoHide)
{
if (Visible != _showScrollIndicator)
{
Visible = _showScrollIndicator;
SetNeedsDisplay ();
}
return _showScrollIndicator;
}
int barSize = Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width;
if (barSize == 0 || barSize >= Size)
{
if (Visible)
{
Visible = false;
SetNeedsDisplay ();
return false;
}
}
else
{
if (!Visible)
{
Visible = true;
SetNeedsDisplay ();
}
}
return true;
}
private void Resize (Orientation orientation)
{
switch (orientation)
{
case Orientation.Horizontal:
break;
case Orientation.Vertical:
break;
default:
throw new ArgumentOutOfRangeException (nameof (orientation), orientation, null);
}
}
private void Scroll_PositionChanged (object? sender, EventArgs e) { PositionChanged?.Invoke (this, e); }
private void Scroll_PositionChanging (object? sender, CancelEventArgs e) { PositionChanging?.Invoke (this, e); }
}