#nullable enable namespace Terminal.Gui; public partial class View { private Lazy _horizontalScrollBar = null!; /// /// Gets the horizontal . This property is lazy-loaded and will not be created until it is accessed. /// /// /// /// See for more information on how to use the ScrollBar. /// /// public ScrollBar HorizontalScrollBar => _horizontalScrollBar.Value; private Lazy _verticalScrollBar = null!; /// /// Gets the vertical . This property is lazy-loaded and will not be created until it is accessed. /// /// /// /// See for more information on how to use the ScrollBar. /// /// public ScrollBar VerticalScrollBar => _verticalScrollBar.Value; /// /// Initializes the ScrollBars of the View. Called by the View constructor. /// private void SetupScrollBars () { if (this is Adornment) { return; } _verticalScrollBar = new (() => CreateScrollBar (Orientation.Vertical)); _horizontalScrollBar = new (() => CreateScrollBar (Orientation.Horizontal)); } private ScrollBar CreateScrollBar (Orientation orientation) { var scrollBar = new ScrollBar { Orientation = orientation, Visible = false // Initially hidden until needed }; if (orientation == Orientation.Vertical) { ConfigureVerticalScrollBar (scrollBar); } else { ConfigureHorizontalScrollBar (scrollBar); } scrollBar.Initialized += OnScrollBarInitialized; // Add after setting Initialized event! Padding?.Add (scrollBar); return scrollBar; } private void ConfigureVerticalScrollBar (ScrollBar scrollBar) { scrollBar.X = Pos.AnchorEnd (); scrollBar.Height = Dim.Fill ( Dim.Func ( () => { if (_horizontalScrollBar.IsValueCreated) { return _horizontalScrollBar.Value.Visible ? 1 : 0; } return 0; })); scrollBar.ScrollableContentSize = GetContentSize ().Height; ViewportChanged += (_, _) => { scrollBar.Position = Viewport.Y; }; ContentSizeChanged += (_, _) => { scrollBar.ScrollableContentSize = GetContentSize ().Height; }; } private void ConfigureHorizontalScrollBar (ScrollBar scrollBar) { scrollBar.Y = Pos.AnchorEnd (); scrollBar.Width = Dim.Fill ( Dim.Func ( () => { if (_verticalScrollBar.IsValueCreated) { return _verticalScrollBar.Value.Visible ? 1 : 0; } return 0; })); scrollBar.ScrollableContentSize = GetContentSize ().Width; ViewportChanged += (_, _) => { scrollBar.Position = Viewport.X; }; ContentSizeChanged += (_, _) => { scrollBar.ScrollableContentSize = GetContentSize ().Width; }; } private void OnScrollBarInitialized (object? sender, EventArgs e) { var scrollBar = (ScrollBar)sender!; if (scrollBar.Orientation == Orientation.Vertical) { ConfigureVerticalScrollBarEvents (scrollBar); } else { ConfigureHorizontalScrollBarEvents (scrollBar); } } private void ConfigureVerticalScrollBarEvents (ScrollBar scrollBar) { Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0 }; scrollBar.PositionChanged += (_, args) => { Viewport = Viewport with { Y = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize) }; }; scrollBar.VisibleChanged += (_, _) => { Padding.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : Padding.Thickness.Right - 1 }; }; } private void ConfigureHorizontalScrollBarEvents (ScrollBar scrollBar) { Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0 }; scrollBar.PositionChanged += (_, args) => { Viewport = Viewport with { X = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize) }; }; scrollBar.VisibleChanged += (_, _) => { Padding.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : Padding.Thickness.Bottom - 1 }; }; } /// /// Clean up the ScrollBars of the View. Called by View.Dispose. /// private void DisposeScrollBars () { if (this is Adornment) { return; } if (_horizontalScrollBar.IsValueCreated) { Padding?.Remove (_horizontalScrollBar.Value); _horizontalScrollBar.Value.Dispose (); } if (_verticalScrollBar.IsValueCreated) { Padding?.Remove (_verticalScrollBar.Value); _verticalScrollBar.Value.Dispose (); } } }