ShadowView.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #nullable enable
  2. using Microsoft.VisualBasic;
  3. using System.Diagnostics;
  4. namespace Terminal.Gui;
  5. /// <summary>
  6. /// Draws a shadow on the right or bottom of the view. Used internally by <see cref="Margin"/>.
  7. /// </summary>
  8. internal class ShadowView : View
  9. {
  10. private ShadowStyle _shadowStyle;
  11. /// <inheritdoc/>
  12. public override Attribute GetNormalColor ()
  13. {
  14. if (SuperView is not Adornment adornment)
  15. {
  16. return base.GetNormalColor ();
  17. }
  18. var attr = Attribute.Default;
  19. if (adornment.Parent?.SuperView is { })
  20. {
  21. attr = adornment.Parent.SuperView.GetNormalColor ();
  22. }
  23. else if (Application.Top is { })
  24. {
  25. attr = Application.Top.GetNormalColor ();
  26. }
  27. return new (
  28. new Attribute (
  29. ShadowStyle == ShadowStyle.Opaque ? Color.Black : attr.Foreground.GetDarkerColor (),
  30. ShadowStyle == ShadowStyle.Opaque ? attr.Background : attr.Background.GetDarkerColor ()));
  31. }
  32. /// <inheritdoc />
  33. /// <inheritdoc />
  34. protected override bool OnDrawingText ()
  35. {
  36. return true;
  37. }
  38. /// <inheritdoc />
  39. protected override bool OnClearingViewport ()
  40. {
  41. // Prevent clearing (so we can have transparency)
  42. return true;
  43. }
  44. /// <inheritdoc/>
  45. protected override bool OnDrawingContent ()
  46. {
  47. SetAttribute (GetNormalColor ());
  48. switch (ShadowStyle)
  49. {
  50. case ShadowStyle.Opaque:
  51. if (Orientation == Orientation.Vertical)
  52. {
  53. DrawVerticalShadowOpaque (Viewport);
  54. }
  55. else
  56. {
  57. DrawHorizontalShadowOpaque (Viewport);
  58. }
  59. break;
  60. case ShadowStyle.Transparent:
  61. //Attribute prevAttr = Driver.GetAttribute ();
  62. //var attr = new Attribute (prevAttr.Foreground, prevAttr.Background);
  63. //SetAttribute (attr);
  64. if (Orientation == Orientation.Vertical)
  65. {
  66. DrawVerticalShadowTransparent (Viewport);
  67. }
  68. else
  69. {
  70. DrawHorizontalShadowTransparent (Viewport);
  71. }
  72. //SetAttribute (prevAttr);
  73. break;
  74. }
  75. return true;
  76. }
  77. /// <summary>
  78. /// Gets or sets the orientation of the shadow.
  79. /// </summary>
  80. public Orientation Orientation { get; set; }
  81. public override ShadowStyle ShadowStyle
  82. {
  83. get => _shadowStyle;
  84. set
  85. {
  86. Visible = value != ShadowStyle.None;
  87. _shadowStyle = value;
  88. }
  89. }
  90. private void DrawHorizontalShadowOpaque (Rectangle rectangle)
  91. {
  92. // Draw the start glyph
  93. AddRune (0, 0, Glyphs.ShadowHorizontalStart);
  94. // Fill the rest of the rectangle with the glyph - note we skip the last since vertical will draw it
  95. for (var i = 1; i < rectangle.Width - 1; i++)
  96. {
  97. AddRune (i, 0, Glyphs.ShadowHorizontal);
  98. }
  99. // Last is special
  100. AddRune (rectangle.Width - 1, 0, Glyphs.ShadowHorizontalEnd);
  101. }
  102. private void DrawHorizontalShadowTransparent (Rectangle viewport)
  103. {
  104. Rectangle screen = ViewportToScreen (Viewport);
  105. for (int r = Math.Max (0, screen.Y); r < screen.Y + screen.Height; r++)
  106. {
  107. for (int c = Math.Max (0, screen.X + 1); c < screen.X + screen.Width; c++)
  108. {
  109. Driver?.Move (c, r);
  110. if (c < Driver?.Contents!.GetLength (1) && r < Driver?.Contents?.GetLength (0))
  111. {
  112. Driver.AddRune (Driver.Contents [r, c].Rune);
  113. }
  114. }
  115. }
  116. }
  117. private void DrawVerticalShadowOpaque (Rectangle viewport)
  118. {
  119. // Draw the start glyph
  120. AddRune (0, 0, Glyphs.ShadowVerticalStart);
  121. // Fill the rest of the rectangle with the glyph
  122. for (var i = 1; i < viewport.Height - 1; i++)
  123. {
  124. AddRune (0, i, Glyphs.ShadowVertical);
  125. }
  126. }
  127. private void DrawVerticalShadowTransparent (Rectangle viewport)
  128. {
  129. Rectangle screen = ViewportToScreen (Viewport);
  130. // Fill the rest of the rectangle
  131. for (int c = Math.Max (0, screen.X); c < screen.X + screen.Width; c++)
  132. {
  133. for (int r = Math.Max (0, screen.Y); r < screen.Y + viewport.Height; r++)
  134. {
  135. Driver?.Move (c, r);
  136. if (Driver?.Contents is { } && screen.X < Driver.Contents.GetLength (1) && r < Driver.Contents.GetLength (0))
  137. {
  138. Driver.AddRune (Driver.Contents [r, c].Rune);
  139. }
  140. }
  141. }
  142. }
  143. }