View.ScrollBars.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. public partial class View
  4. {
  5. private Lazy<ScrollBar> _horizontalScrollBar;
  6. private Lazy<ScrollBar> _verticalScrollBar;
  7. /// <summary>
  8. /// Initializes the ScrollBars of the View. Called by the constructor.
  9. /// </summary>
  10. private void SetupScrollBars ()
  11. {
  12. if (this is Adornment)
  13. {
  14. return;
  15. }
  16. _verticalScrollBar = new (() => ScrollBarFactory (Orientation.Vertical));
  17. _horizontalScrollBar = new (() => ScrollBarFactory (Orientation.Horizontal));
  18. ViewportChanged += (_, _) =>
  19. {
  20. if (_verticalScrollBar.IsValueCreated)
  21. {
  22. _verticalScrollBar.Value.VisibleContentSize = Viewport.Height;
  23. _verticalScrollBar.Value.Position = Viewport.Y;
  24. }
  25. if (_horizontalScrollBar.IsValueCreated)
  26. {
  27. _horizontalScrollBar.Value.VisibleContentSize = Viewport.Width;
  28. _horizontalScrollBar.Value.Position = Viewport.X;
  29. }
  30. };
  31. ContentSizeChanged += (_, _) =>
  32. {
  33. if (_verticalScrollBar.IsValueCreated)
  34. {
  35. _verticalScrollBar.Value.ScrollableContentSize = GetContentSize ().Height;
  36. }
  37. if (_horizontalScrollBar.IsValueCreated)
  38. {
  39. _horizontalScrollBar.Value.ScrollableContentSize = GetContentSize ().Width;
  40. }
  41. };
  42. }
  43. private ScrollBar ScrollBarFactory (Orientation orientation)
  44. {
  45. var scrollBar = new ScrollBar
  46. {
  47. Orientation = orientation,
  48. AutoHide = true
  49. };
  50. if (orientation == Orientation.Vertical)
  51. {
  52. scrollBar.X = Pos.AnchorEnd ();
  53. // Ensure the scrollbar's length accomodates for the opposite scrollbar's visibility
  54. scrollBar.Height = Dim.Fill (
  55. Dim.Func (
  56. () =>
  57. {
  58. if (_horizontalScrollBar.IsValueCreated)
  59. {
  60. return _horizontalScrollBar.Value.Visible ? 1 : 0;
  61. }
  62. return 0;
  63. }));
  64. scrollBar.ScrollableContentSize = GetContentSize ().Height;
  65. }
  66. else
  67. {
  68. scrollBar.Y = Pos.AnchorEnd ();
  69. // Ensure the scrollbar's length accomodates for the opposite scrollbar's visibility
  70. scrollBar.Width = Dim.Fill (
  71. Dim.Func (
  72. () =>
  73. {
  74. if (_verticalScrollBar.IsValueCreated)
  75. {
  76. return _verticalScrollBar.Value.Visible ? 1 : 0;
  77. }
  78. return 0;
  79. }));
  80. scrollBar.ScrollableContentSize = GetContentSize ().Width;
  81. }
  82. Padding?.Add (scrollBar);
  83. scrollBar.Initialized += OnScrollBarOnInitialized;
  84. return scrollBar;
  85. void OnScrollBarOnInitialized (object? o, EventArgs eventArgs)
  86. {
  87. if (orientation == Orientation.Vertical)
  88. {
  89. Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0 };
  90. scrollBar.PositionChanged += (_, args) =>
  91. {
  92. Viewport = Viewport with
  93. {
  94. Y = Math.Min (
  95. args.CurrentValue,
  96. GetContentSize ().Height - Viewport.Height)
  97. };
  98. };
  99. scrollBar.VisibleChanged += (_, _) =>
  100. {
  101. Padding.Thickness = Padding.Thickness with
  102. {
  103. Right = scrollBar.Visible
  104. ? Padding.Thickness.Right + 1
  105. : Padding.Thickness.Right - 1
  106. };
  107. };
  108. }
  109. else
  110. {
  111. Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0 };
  112. scrollBar.PositionChanged += (_, args) =>
  113. {
  114. Viewport = Viewport with
  115. {
  116. X = Math.Min (
  117. args.CurrentValue,
  118. GetContentSize ().Width - Viewport.Width)
  119. };
  120. };
  121. scrollBar.VisibleChanged += (_, _) =>
  122. {
  123. Padding.Thickness = Padding.Thickness with
  124. {
  125. Bottom = scrollBar.Visible
  126. ? Padding.Thickness.Bottom + 1
  127. : Padding.Thickness.Bottom - 1
  128. };
  129. };
  130. }
  131. }
  132. }
  133. /// <summary>
  134. /// </summary>
  135. public ScrollBar HorizontalScrollBar => _horizontalScrollBar.Value;
  136. /// <summary>
  137. /// </summary>
  138. public ScrollBar VerticalScrollBar => _verticalScrollBar.Value;
  139. /// <summary>
  140. /// Clean up the ScrollBars of the View. Called by View.Dispose.
  141. /// </summary>
  142. private void DisposeScrollBars ()
  143. {
  144. if (this is Adornment)
  145. {
  146. return;
  147. }
  148. if (_horizontalScrollBar.IsValueCreated)
  149. {
  150. Padding?.Remove (_horizontalScrollBar.Value);
  151. _horizontalScrollBar.Value.Dispose ();
  152. }
  153. if (_verticalScrollBar.IsValueCreated)
  154. {
  155. Padding?.Remove (_verticalScrollBar.Value);
  156. _verticalScrollBar.Value.Dispose ();
  157. }
  158. }
  159. private void SetScrollBarsKeepContentInAllViewport (ViewportSettings viewportSettings)
  160. {
  161. if (viewportSettings == ViewportSettings.None)
  162. {
  163. _horizontalScrollBar.Value.KeepContentInAllViewport = true;
  164. _verticalScrollBar.Value.KeepContentInAllViewport = true;
  165. }
  166. else if (viewportSettings.HasFlag (ViewportSettings.AllowNegativeX))
  167. {
  168. _horizontalScrollBar.Value.AutoHide = false;
  169. }
  170. else if (viewportSettings.HasFlag (ViewportSettings.AllowNegativeY))
  171. {
  172. _verticalScrollBar.Value.AutoHide = false;
  173. }
  174. else if (viewportSettings.HasFlag (ViewportSettings.AllowNegativeLocation))
  175. {
  176. _horizontalScrollBar.Value.AutoHide = false;
  177. _verticalScrollBar.Value.AutoHide = false;
  178. }
  179. else if (viewportSettings.HasFlag (ViewportSettings.AllowXGreaterThanContentWidth))
  180. {
  181. _horizontalScrollBar.Value.KeepContentInAllViewport = false;
  182. }
  183. else if (viewportSettings.HasFlag (ViewportSettings.AllowYGreaterThanContentHeight))
  184. {
  185. _verticalScrollBar.Value.KeepContentInAllViewport = false;
  186. }
  187. else if (viewportSettings.HasFlag (ViewportSettings.AllowLocationGreaterThanContentSize))
  188. {
  189. _horizontalScrollBar.Value.KeepContentInAllViewport = false;
  190. _verticalScrollBar.Value.KeepContentInAllViewport = false;
  191. }
  192. }
  193. }