ViewAdornments.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. namespace Terminal.Gui;
  2. public partial class View
  3. {
  4. /// <summary>
  5. /// Initializes the Adornments of the View. Called by the constructor.
  6. /// </summary>
  7. private void SetupAdornments ()
  8. {
  9. //// TODO: Move this to Adornment as a static factory method
  10. if (this is not Adornment)
  11. {
  12. Margin = new (this);
  13. Border = new (this);
  14. Padding = new (this);
  15. }
  16. }
  17. private void BeginInitAdornments ()
  18. {
  19. Margin?.BeginInit ();
  20. Border?.BeginInit ();
  21. Padding?.BeginInit ();
  22. }
  23. private void EndInitAdornments ()
  24. {
  25. Margin?.EndInit ();
  26. Border?.EndInit ();
  27. Padding?.EndInit ();
  28. }
  29. private void DisposeAdornments ()
  30. {
  31. Margin?.Dispose ();
  32. Margin = null;
  33. Border?.Dispose ();
  34. Border = null;
  35. Padding?.Dispose ();
  36. Padding = null;
  37. }
  38. /// <summary>
  39. /// The <see cref="Adornment"/> that enables separation of a View from other SubViews of the same
  40. /// SuperView. The margin offsets the <see cref="Viewport"/> from the <see cref="Frame"/>.
  41. /// </summary>
  42. /// <remarks>
  43. /// <para>
  44. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  45. /// View's content and are not clipped by the View's Clip Area.
  46. /// </para>
  47. /// <para>
  48. /// Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  49. /// change the size of <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
  50. /// <see cref="SuperView"/> and its <see cref="Subviews"/>.
  51. /// </para>
  52. /// </remarks>
  53. public Margin Margin { get; private set; }
  54. /// <summary>
  55. /// The <see cref="Adornment"/> that offsets the <see cref="Viewport"/> from the <see cref="Margin"/>.
  56. /// The Border provides the space for a visual border (drawn using
  57. /// line-drawing glyphs) and the Title. The Border expands inward; in other words if `Border.Thickness.Top == 2` the
  58. /// border and title will take up the first row and the second row will be filled with spaces.
  59. /// </summary>
  60. /// <remarks>
  61. /// <para><see cref="BorderStyle"/> provides a simple helper for turning a simple border frame on or off.</para>
  62. /// <para>
  63. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  64. /// View's content and are not clipped by the View's Clip Area.
  65. /// </para>
  66. /// <para>
  67. /// Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  68. /// change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
  69. /// <see cref="SuperView"/> and its <see cref="Subviews"/>.
  70. /// </para>
  71. /// </remarks>
  72. public Border Border { get; private set; }
  73. /// <summary>Gets or sets whether the view has a one row/col thick border.</summary>
  74. /// <remarks>
  75. /// <para>
  76. /// This is a helper for manipulating the view's <see cref="Border"/>. Setting this property to any value other
  77. /// than <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  78. /// <see cref="Adornment.Thickness"/> to `1` and <see cref="BorderStyle"/> to the value.
  79. /// </para>
  80. /// <para>
  81. /// Setting this property to <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
  82. /// <see cref="Adornment.Thickness"/> to `0` and <see cref="BorderStyle"/> to <see cref="LineStyle.None"/>.
  83. /// </para>
  84. /// <para>For more advanced customization of the view's border, manipulate see <see cref="Border"/> directly.</para>
  85. /// </remarks>
  86. public LineStyle BorderStyle
  87. {
  88. get => Border?.LineStyle ?? LineStyle.Single;
  89. set
  90. {
  91. if (Border is null)
  92. {
  93. return;
  94. }
  95. if (value != LineStyle.None)
  96. {
  97. if (Border.Thickness == Thickness.Empty)
  98. {
  99. Border.Thickness = new (1);
  100. }
  101. }
  102. else
  103. {
  104. Border.Thickness = new (0);
  105. }
  106. Border.LineStyle = value;
  107. LayoutAdornments ();
  108. SetNeedsLayout ();
  109. }
  110. }
  111. /// <summary>
  112. /// The <see cref="Adornment"/> inside of the view that offsets the <see cref="Viewport"/>
  113. /// from the <see cref="Border"/>.
  114. /// </summary>
  115. /// <remarks>
  116. /// <para>
  117. /// The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the
  118. /// View's content and are not clipped by the View's Clip Area.
  119. /// </para>
  120. /// <para>
  121. /// Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
  122. /// change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
  123. /// <see cref="SuperView"/> and its <see cref="Subviews"/>.
  124. /// </para>
  125. /// </remarks>
  126. public Padding Padding { get; private set; }
  127. /// <summary>
  128. /// <para>Gets the thickness describing the sum of the Adornments' thicknesses.</para>
  129. /// </summary>
  130. /// <remarks>
  131. /// <para>
  132. /// The <see cref="Viewport"/> is offset from the <see cref="Frame"/> by the thickness returned by this method.
  133. /// </para>
  134. /// </remarks>
  135. /// <returns>A thickness that describes the sum of the Adornments' thicknesses.</returns>
  136. public Thickness GetAdornmentsThickness ()
  137. {
  138. if (Margin is null)
  139. {
  140. return Thickness.Empty;
  141. }
  142. return Margin.Thickness + Border.Thickness + Padding.Thickness;
  143. }
  144. /// <summary>Lays out the Adornments of the View.</summary>
  145. /// <remarks>
  146. /// Overriden by <see cref="Adornment"/> to do nothing, as <see cref="Adornment"/> does not have adornments.
  147. /// </remarks>
  148. internal virtual void LayoutAdornments ()
  149. {
  150. if (Margin is null)
  151. {
  152. return; // CreateAdornments () has not been called yet
  153. }
  154. if (Margin.Frame.Size != Frame.Size)
  155. {
  156. Margin.SetFrame (Rectangle.Empty with { Size = Frame.Size });
  157. Margin.X = 0;
  158. Margin.Y = 0;
  159. Margin.Width = Frame.Size.Width;
  160. Margin.Height = Frame.Size.Height;
  161. }
  162. Margin.SetNeedsLayout ();
  163. Margin.SetNeedsDisplay ();
  164. if (IsInitialized)
  165. {
  166. Margin.LayoutSubviews ();
  167. }
  168. Rectangle border = Margin.Thickness.GetInside (Margin.Frame);
  169. if (border != Border.Frame)
  170. {
  171. Border.SetFrame (border);
  172. Border.X = border.Location.X;
  173. Border.Y = border.Location.Y;
  174. Border.Width = border.Size.Width;
  175. Border.Height = border.Size.Height;
  176. }
  177. Border.SetNeedsLayout ();
  178. Border.SetNeedsDisplay ();
  179. if (IsInitialized)
  180. {
  181. Border.LayoutSubviews ();
  182. }
  183. Rectangle padding = Border.Thickness.GetInside (Border.Frame);
  184. if (padding != Padding.Frame)
  185. {
  186. Padding.SetFrame (padding);
  187. Padding.X = padding.Location.X;
  188. Padding.Y = padding.Location.Y;
  189. Padding.Width = padding.Size.Width;
  190. Padding.Height = padding.Size.Height;
  191. }
  192. Padding.SetNeedsLayout ();
  193. Padding.SetNeedsDisplay ();
  194. if (IsInitialized)
  195. {
  196. Padding.LayoutSubviews ();
  197. }
  198. }
  199. }