View.ScrollBars.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. public partial class View
  4. {
  5. private Lazy<ScrollBar> _horizontalScrollBar = null!;
  6. /// <summary>
  7. /// Gets the horizontal <see cref="ScrollBar"/>. This property is lazy-loaded and will not be created until it is accessed.
  8. /// </summary>
  9. /// <remarks>
  10. /// <para>
  11. /// See <see cref="ScrollBar"/> for more information on how to use the ScrollBar.
  12. /// </para>
  13. /// </remarks>
  14. public ScrollBar HorizontalScrollBar => _horizontalScrollBar.Value;
  15. private Lazy<ScrollBar> _verticalScrollBar = null!;
  16. /// <summary>
  17. /// Gets the vertical <see cref="ScrollBar"/>. This property is lazy-loaded and will not be created until it is accessed.
  18. /// </summary>
  19. /// <remarks>
  20. /// <para>
  21. /// See <see cref="ScrollBar"/> for more information on how to use the ScrollBar.
  22. /// </para>
  23. /// </remarks>
  24. public ScrollBar VerticalScrollBar => _verticalScrollBar.Value;
  25. /// <summary>
  26. /// Initializes the ScrollBars of the View. Called by the View constructor.
  27. /// </summary>
  28. private void SetupScrollBars ()
  29. {
  30. if (this is Adornment)
  31. {
  32. return;
  33. }
  34. _verticalScrollBar = new (() => CreateScrollBar (Orientation.Vertical));
  35. _horizontalScrollBar = new (() => CreateScrollBar (Orientation.Horizontal));
  36. }
  37. private ScrollBar CreateScrollBar (Orientation orientation)
  38. {
  39. var scrollBar = new ScrollBar
  40. {
  41. Orientation = orientation,
  42. Visible = false // Initially hidden until needed
  43. };
  44. if (orientation == Orientation.Vertical)
  45. {
  46. ConfigureVerticalScrollBar (scrollBar);
  47. }
  48. else
  49. {
  50. ConfigureHorizontalScrollBar (scrollBar);
  51. }
  52. scrollBar.Initialized += OnScrollBarInitialized;
  53. // Add after setting Initialized event!
  54. Padding?.Add (scrollBar);
  55. return scrollBar;
  56. }
  57. private void ConfigureVerticalScrollBar (ScrollBar scrollBar)
  58. {
  59. scrollBar.X = Pos.AnchorEnd ();
  60. scrollBar.Height = Dim.Fill (
  61. Dim.Func (
  62. () =>
  63. {
  64. if (_horizontalScrollBar.IsValueCreated)
  65. {
  66. return _horizontalScrollBar.Value.Visible ? 1 : 0;
  67. }
  68. return 0;
  69. }));
  70. scrollBar.ScrollableContentSize = GetContentSize ().Height;
  71. ViewportChanged += (_, _) =>
  72. {
  73. scrollBar.Position = Viewport.Y;
  74. };
  75. ContentSizeChanged += (_, _) => { scrollBar.ScrollableContentSize = GetContentSize ().Height; };
  76. }
  77. private void ConfigureHorizontalScrollBar (ScrollBar scrollBar)
  78. {
  79. scrollBar.Y = Pos.AnchorEnd ();
  80. scrollBar.Width = Dim.Fill (
  81. Dim.Func (
  82. () =>
  83. {
  84. if (_verticalScrollBar.IsValueCreated)
  85. {
  86. return _verticalScrollBar.Value.Visible ? 1 : 0;
  87. }
  88. return 0;
  89. }));
  90. scrollBar.ScrollableContentSize = GetContentSize ().Width;
  91. ViewportChanged += (_, _) =>
  92. {
  93. scrollBar.Position = Viewport.X;
  94. };
  95. ContentSizeChanged += (_, _) => { scrollBar.ScrollableContentSize = GetContentSize ().Width; };
  96. }
  97. private void OnScrollBarInitialized (object? sender, EventArgs e)
  98. {
  99. var scrollBar = (ScrollBar)sender!;
  100. if (scrollBar.Orientation == Orientation.Vertical)
  101. {
  102. ConfigureVerticalScrollBarEvents (scrollBar);
  103. }
  104. else
  105. {
  106. ConfigureHorizontalScrollBarEvents (scrollBar);
  107. }
  108. }
  109. private void ConfigureVerticalScrollBarEvents (ScrollBar scrollBar)
  110. {
  111. Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0 };
  112. scrollBar.PositionChanged += (_, args) =>
  113. {
  114. Viewport = Viewport with
  115. {
  116. Y = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
  117. };
  118. };
  119. scrollBar.VisibleChanged += (_, _) =>
  120. {
  121. Padding.Thickness = Padding.Thickness with
  122. {
  123. Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : Padding.Thickness.Right - 1
  124. };
  125. };
  126. }
  127. private void ConfigureHorizontalScrollBarEvents (ScrollBar scrollBar)
  128. {
  129. Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0 };
  130. scrollBar.PositionChanged += (_, args) =>
  131. {
  132. Viewport = Viewport with
  133. {
  134. X = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
  135. };
  136. };
  137. scrollBar.VisibleChanged += (_, _) =>
  138. {
  139. Padding.Thickness = Padding.Thickness with
  140. {
  141. Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : Padding.Thickness.Bottom - 1
  142. };
  143. };
  144. }
  145. /// <summary>
  146. /// Clean up the ScrollBars of the View. Called by View.Dispose.
  147. /// </summary>
  148. private void DisposeScrollBars ()
  149. {
  150. if (this is Adornment)
  151. {
  152. return;
  153. }
  154. if (_horizontalScrollBar.IsValueCreated)
  155. {
  156. Padding?.Remove (_horizontalScrollBar.Value);
  157. _horizontalScrollBar.Value.Dispose ();
  158. }
  159. if (_verticalScrollBar.IsValueCreated)
  160. {
  161. Padding?.Remove (_verticalScrollBar.Value);
  162. _verticalScrollBar.Value.Dispose ();
  163. }
  164. }
  165. }