Margin.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #nullable enable
  2. using System.Drawing;
  3. namespace Terminal.Gui;
  4. /// <summary>The Margin for a <see cref="View"/>.</summary>
  5. /// <remarks>
  6. /// <para>See the <see cref="Adornment"/> class.</para>
  7. /// </remarks>
  8. public class Margin : Adornment
  9. {
  10. /// <inheritdoc/>
  11. public Margin ()
  12. { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */
  13. }
  14. /// <inheritdoc/>
  15. public Margin (View parent) : base (parent)
  16. {
  17. /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */
  18. HighlightStyle |= HighlightStyle.Pressed;
  19. Highlight += Margin_Highlight;
  20. LayoutStarted += Margin_LayoutStarted;
  21. // Margin should not be focusable
  22. CanFocus = false;
  23. }
  24. private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
  25. {
  26. // Adjust the shadow such that it is drawn aligned with the Border
  27. if (ShadowStyle != Gui.ShadowStyle.None && _rightShadow is { } && _bottomShadow is { })
  28. {
  29. _rightShadow.Y = Parent.Border.Thickness.Top > 0 ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.ShowTitle ? 1 : 0) : 1;
  30. _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1;
  31. }
  32. }
  33. private bool _pressed;
  34. private void Margin_Highlight (object? sender, CancelEventArgs<HighlightStyle> e)
  35. {
  36. if (ShadowStyle != Gui.ShadowStyle.None)
  37. {
  38. if (_pressed && e.CurrentValue == HighlightStyle.None)
  39. {
  40. Thickness = new (Thickness.Left - 1, Thickness.Top, Thickness.Right + 1, Thickness.Bottom);
  41. if (_rightShadow is { })
  42. {
  43. _rightShadow.Visible = true;
  44. }
  45. if (_bottomShadow is { })
  46. {
  47. _bottomShadow.Visible = true;
  48. }
  49. _pressed = false;
  50. return;
  51. }
  52. if (!_pressed && (e.CurrentValue.HasFlag (HighlightStyle.Pressed) /*|| e.HighlightStyle.HasFlag (HighlightStyle.PressedOutside)*/))
  53. {
  54. Thickness = new (Thickness.Left + 1, Thickness.Top, Thickness.Right - 1, Thickness.Bottom);
  55. _pressed = true;
  56. if (_rightShadow is { })
  57. {
  58. _rightShadow.Visible = false;
  59. }
  60. if (_bottomShadow is { })
  61. {
  62. _bottomShadow.Visible = false;
  63. }
  64. }
  65. }
  66. }
  67. /// <inheritdoc />
  68. public override void OnDrawContent (Rectangle viewport)
  69. {
  70. Rectangle screen = ViewportToScreen (viewport);
  71. Attribute normalAttr = GetNormalColor ();
  72. Driver?.SetAttribute (normalAttr);
  73. // This just draws/clears the thickness, not the insides.
  74. if (ShadowStyle != ShadowStyle.None)
  75. {
  76. screen = Rectangle.Inflate (screen, -1, -1);
  77. }
  78. Thickness.Draw (screen, ToString ());
  79. if (Subviews.Count > 0)
  80. {
  81. // Draw subviews
  82. // TODO: Implement OnDrawSubviews (cancelable);
  83. if (Subviews is { } && SubViewNeedsDisplay)
  84. {
  85. IEnumerable<View> subviewsNeedingDraw = Subviews.Where (
  86. view => view.Visible
  87. && (view.NeedsDisplay || view.SubViewNeedsDisplay || view.LayoutNeeded)
  88. );
  89. foreach (View view in subviewsNeedingDraw)
  90. {
  91. if (view.LayoutNeeded)
  92. {
  93. view.LayoutSubviews ();
  94. }
  95. view.Draw ();
  96. }
  97. }
  98. }
  99. }
  100. /// <summary>
  101. /// The color scheme for the Margin. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/>'s
  102. /// <see cref="View.SuperView"/> scheme. color scheme.
  103. /// </summary>
  104. public override ColorScheme ColorScheme
  105. {
  106. get
  107. {
  108. if (base.ColorScheme is { })
  109. {
  110. return base.ColorScheme;
  111. }
  112. return (Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"])!;
  113. }
  114. set
  115. {
  116. base.ColorScheme = value;
  117. Parent?.SetNeedsDisplay ();
  118. }
  119. }
  120. /// <inheritdoc />
  121. public override ShadowStyle ShadowStyle
  122. {
  123. get => base.ShadowStyle;
  124. set
  125. {
  126. base.ShadowStyle = SetShadow (value);
  127. }
  128. }
  129. /// <summary>
  130. /// Sets whether the Margin includes a shadow effect. The shadow is drawn on the right and bottom sides of the
  131. /// Margin.
  132. /// </summary>
  133. public ShadowStyle SetShadow (ShadowStyle style)
  134. {
  135. if (ShadowStyle == style)
  136. {
  137. // return style;
  138. }
  139. if (ShadowStyle != ShadowStyle.None)
  140. {
  141. // Turn off shadow
  142. Thickness = new (Thickness.Left, Thickness.Top, Thickness.Right - 1, Thickness.Bottom - 1);
  143. }
  144. if (style != ShadowStyle.None)
  145. {
  146. // Turn on shadow
  147. Thickness = new (Thickness.Left, Thickness.Top, Thickness.Right + 1, Thickness.Bottom + 1);
  148. }
  149. if (_rightShadow is { })
  150. {
  151. _rightShadow.ShadowStyle = style;
  152. }
  153. if (_bottomShadow is { })
  154. {
  155. _bottomShadow.ShadowStyle = style;
  156. }
  157. return style;
  158. }
  159. private ShadowView? _bottomShadow;
  160. private ShadowView? _rightShadow;
  161. /// <inheritdoc/>
  162. public override void BeginInit ()
  163. {
  164. base.BeginInit ();
  165. if (Parent is null)
  166. {
  167. return;
  168. }
  169. ShadowStyle = base.ShadowStyle;
  170. Add (
  171. _rightShadow = new ShadowView
  172. {
  173. X = Pos.AnchorEnd (1),
  174. Y = 0,
  175. Width = 1,
  176. Height = Dim.Fill (),
  177. ShadowStyle = ShadowStyle,
  178. Orientation = Orientation.Vertical
  179. },
  180. _bottomShadow = new ShadowView
  181. {
  182. X = 0,
  183. Y = Pos.AnchorEnd (1),
  184. Width = Dim.Fill (),
  185. Height = 1,
  186. ShadowStyle = ShadowStyle,
  187. Orientation = Orientation.Horizontal
  188. }
  189. );
  190. }
  191. }