View.Adornments.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. 
  2. namespace Terminal.Gui.ViewBase;
  3. public partial class View // Adornments
  4. {
  5. /// <summary>
  6. /// Initializes the Adornments of the View. Called by the constructor.
  7. /// </summary>
  8. private void SetupAdornments ()
  9. {
  10. // TODO: Move this to Adornment as a static factory method
  11. if (this is not Adornment)
  12. {
  13. // TODO: Make the Adornments Lazy and only create them when needed
  14. Margin = new (this);
  15. Border = new (this);
  16. Padding = new (this);
  17. }
  18. }
  19. private void BeginInitAdornments ()
  20. {
  21. Margin?.BeginInit ();
  22. Border?.BeginInit ();
  23. Padding?.BeginInit ();
  24. }
  25. private void EndInitAdornments ()
  26. {
  27. Margin?.EndInit ();
  28. Border?.EndInit ();
  29. Padding?.EndInit ();
  30. }
  31. private void DisposeAdornments ()
  32. {
  33. Margin?.Dispose ();
  34. Margin = null;
  35. Border?.Dispose ();
  36. Border = null;
  37. Padding?.Dispose ();
  38. Padding = null;
  39. }
  40. /// <summary>
  41. /// The <see cref="Adornment"/> that enables separation of a View from other SubViews of the same
  42. /// SuperView. The margin offsets the <see cref="Viewport"/> from the <see cref="Frame"/>.
  43. /// </summary>
  44. /// <remarks>
  45. /// <para>
  46. /// The margin is typically transparent. This can be overriden by explicitly setting <see cref="Scheme"/>.
  47. /// </para>
  48. /// <para>
  49. /// Enabling <see cref="ShadowStyle"/> will change the Thickness of the Margin to include the shadow.
  50. /// </para>
  51. /// <para>
  52. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  53. /// View's content and are not clipped by the View's Clip Area.
  54. /// </para>
  55. /// <para>
  56. /// Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  57. /// change the size of <see cref="Frame"/> which will call <see cref="SetNeedsLayout"/> to update the layout of the
  58. /// <see cref="SuperView"/> and its <see cref="SubViews"/>.
  59. /// </para>
  60. /// </remarks>
  61. public Margin? Margin { get; private set; }
  62. private ShadowStyle _shadowStyle;
  63. /// <summary>
  64. /// Gets or sets whether the View is shown with a shadow effect. The shadow is drawn on the right and bottom sides of
  65. /// the
  66. /// Margin.
  67. /// </summary>
  68. /// <remarks>
  69. /// Setting this property to <see langword="true"/> will add a shadow to the right and bottom sides of the Margin.
  70. /// The View 's <see cref="Frame"/> will be expanded to include the shadow.
  71. /// </remarks>
  72. public virtual ShadowStyle ShadowStyle
  73. {
  74. get => _shadowStyle;
  75. set
  76. {
  77. if (_shadowStyle == value)
  78. {
  79. return;
  80. }
  81. _shadowStyle = value;
  82. if (Margin is { })
  83. {
  84. Margin.ShadowStyle = value;
  85. }
  86. }
  87. }
  88. /// <summary>
  89. /// The <see cref="Adornment"/> that offsets the <see cref="Viewport"/> from the <see cref="Margin"/>.
  90. /// <para>
  91. /// The Border provides the space for a visual border (drawn using
  92. /// line-drawing glyphs) and the Title. The Border expands inward; in other words if `Border.Thickness.Top == 2`
  93. /// the
  94. /// border and title will take up the first row and the second row will be filled with spaces.
  95. /// </para>
  96. /// <para>
  97. /// The Border provides the UI for mouse and keyboard arrangement of the View. See <see cref="Arrangement"/>.
  98. /// </para>
  99. /// </summary>
  100. /// <remarks>
  101. /// <para><see cref="BorderStyle"/> provides a simple helper for turning a simple border frame on or off.</para>
  102. /// <para>
  103. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  104. /// View's content and are not clipped by the View's Clip Area.
  105. /// </para>
  106. /// <para>
  107. /// Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  108. /// change the size of <see cref="Frame"/> which will call <see cref="SetNeedsLayout"/> to update the layout of the
  109. /// <see cref="SuperView"/> and its <see cref="SubViews"/>.
  110. /// </para>
  111. /// </remarks>
  112. public Border? Border { get; private set; }
  113. // TODO: Make BorderStyle nullable https://github.com/gui-cs/Terminal.Gui/issues/4021
  114. /// <summary>Gets or sets whether the view has a one row/col thick border.</summary>
  115. /// <remarks>
  116. /// <para>
  117. /// This is a helper for manipulating the view's <see cref="Border"/>. Setting this property to any value other
  118. /// than <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  119. /// <see cref="Adornment.Thickness"/> to `1` and <see cref="BorderStyle"/> to the value.
  120. /// </para>
  121. /// <para>
  122. /// Setting this property to <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  123. /// <see cref="Adornment.Thickness"/> to `0` and <see cref="BorderStyle"/> to <see cref="LineStyle.None"/>.
  124. /// </para>
  125. /// <para>
  126. /// Raises <see cref="OnBorderStyleChanged"/> and raises <see cref="BorderStyleChanged"/>, which allows change
  127. /// to be cancelled.
  128. /// </para>
  129. /// <para>For more advanced customization of the view's border, manipulate see <see cref="Border"/> directly.</para>
  130. /// </remarks>
  131. public LineStyle BorderStyle
  132. {
  133. get => Border?.LineStyle ?? LineStyle.Single;
  134. set
  135. {
  136. if (Border is null)
  137. {
  138. return;
  139. }
  140. SetBorderStyle (value);
  141. OnBorderStyleChanged ();
  142. BorderStyleChanged?.Invoke (this, EventArgs.Empty);
  143. }
  144. }
  145. /// <summary>
  146. /// Called when the <see cref="BorderStyle"/> has changed.
  147. /// </summary>
  148. protected virtual bool OnBorderStyleChanged () { return false; }
  149. /// <summary>
  150. /// Fired when the <see cref="BorderStyle"/> has changed.
  151. /// </summary>
  152. public event EventHandler<EventArgs>? BorderStyleChanged;
  153. /// <summary>
  154. /// Sets the <see cref="BorderStyle"/> of the view to the specified value.
  155. /// </summary>
  156. /// <remarks>
  157. /// <para>
  158. /// <see cref="BorderStyle"/> is a helper for manipulating the view's <see cref="Border"/>. Setting this property
  159. /// to any value other
  160. /// than <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  161. /// <see cref="Adornment.Thickness"/> to `1` and <see cref="BorderStyle"/> to the value.
  162. /// </para>
  163. /// <para>
  164. /// Setting this property to <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  165. /// <see cref="Adornment.Thickness"/> to `0` and <see cref="BorderStyle"/> to <see cref="LineStyle.None"/>.
  166. /// </para>
  167. /// <para>For more advanced customization of the view's border, manipulate see <see cref="Border"/> directly.</para>
  168. /// </remarks>
  169. /// <param name="style"></param>
  170. internal void SetBorderStyle (LineStyle style)
  171. {
  172. if (style != LineStyle.None)
  173. {
  174. if (Border!.Thickness == Thickness.Empty)
  175. {
  176. Border.Thickness = new (1);
  177. }
  178. }
  179. else
  180. {
  181. Border!.Thickness = new (0);
  182. }
  183. Border.LineStyle = style;
  184. SetAdornmentFrames ();
  185. SetNeedsLayout ();
  186. }
  187. /// <summary>
  188. /// The <see cref="Adornment"/> inside of the view that offsets the <see cref="Viewport"/>
  189. /// from the <see cref="Border"/>.
  190. /// </summary>
  191. /// <remarks>
  192. /// <para>
  193. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  194. /// View's content and are not clipped by the View's Clip Area.
  195. /// </para>
  196. /// <para>
  197. /// Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  198. /// change the size of <see cref="Frame"/> which will call <see cref="SetNeedsLayout"/> to update the layout of the
  199. /// <see cref="SuperView"/> and its <see cref="SubViews"/>.
  200. /// </para>
  201. /// </remarks>
  202. public Padding? Padding { get; private set; }
  203. /// <summary>
  204. /// <para>Gets the thickness describing the sum of the Adornments' thicknesses.</para>
  205. /// </summary>
  206. /// <remarks>
  207. /// <para>
  208. /// The <see cref="Viewport"/> is offset from the <see cref="Frame"/> by the thickness returned by this method.
  209. /// </para>
  210. /// </remarks>
  211. /// <returns>A thickness that describes the sum of the Adornments' thicknesses.</returns>
  212. public Thickness GetAdornmentsThickness ()
  213. {
  214. Thickness result = Thickness.Empty;
  215. if (Margin is { })
  216. {
  217. result += Margin.Thickness;
  218. }
  219. if (Border is { })
  220. {
  221. result += Border.Thickness;
  222. }
  223. if (Padding is { })
  224. {
  225. result += Padding.Thickness;
  226. }
  227. return result;
  228. }
  229. /// <summary>Sets the Frame's of the Margin, Border, and Padding.</summary>
  230. internal void SetAdornmentFrames ()
  231. {
  232. if (this is Adornment)
  233. {
  234. // Adornments do not have Adornments
  235. return;
  236. }
  237. if (Margin is { })
  238. {
  239. Margin!.Frame = Rectangle.Empty with { Size = Frame.Size };
  240. }
  241. if (Border is { } && Margin is { })
  242. {
  243. Border!.Frame = Margin!.Thickness.GetInside (Margin!.Frame);
  244. }
  245. if (Padding is { } && Border is { })
  246. {
  247. Padding!.Frame = Border!.Thickness.GetInside (Border!.Frame);
  248. }
  249. }
  250. }