#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;
}
}