| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- namespace Terminal.Gui.ViewBase;
- /// <summary>
- /// Draws a shadow on the right or bottom of the view. Used internally by <see cref="Margin"/>.
- /// </summary>
- internal class ShadowView : View
- {
- private ShadowStyle _shadowStyle;
- /// <inheritdoc/>
- protected override bool OnDrawingText () { return true; }
- /// <inheritdoc/>
- protected override bool OnClearingViewport ()
- {
- // Prevent clearing (so we can have transparency)
- return true;
- }
- /// <inheritdoc/>
- protected override bool OnDrawingContent ()
- {
- switch (ShadowStyle)
- {
- case ShadowStyle.Opaque:
- if (Orientation == Orientation.Vertical)
- {
- DrawVerticalShadowOpaque (Viewport);
- }
- else
- {
- DrawHorizontalShadowOpaque (Viewport);
- }
- break;
- case ShadowStyle.Transparent:
- if (Orientation == Orientation.Vertical)
- {
- DrawVerticalShadowTransparent (Viewport);
- }
- else
- {
- DrawHorizontalShadowTransparent (Viewport);
- }
- break;
- }
- return true;
- }
- /// <summary>
- /// Gets or sets the orientation of the shadow.
- /// </summary>
- public Orientation Orientation { get; set; }
- public override ShadowStyle ShadowStyle
- {
- get => _shadowStyle;
- set
- {
- Visible = value != ShadowStyle.None;
- _shadowStyle = value;
- ViewportSettings |= ViewportSettingsFlags.TransparentMouse;
- }
- }
- private void DrawHorizontalShadowOpaque (Rectangle rectangle)
- {
- // Draw the start glyph
- SetAttribute (GetAttributeUnderLocation (ViewportToScreen (new Point (0, 0))));
- AddRune (0, 0, Glyphs.ShadowHorizontalStart);
- // Fill the rest of the rectangle with the glyph - note we skip the last since vertical will draw it
- for (var i = 1; i < rectangle.Width - 1; i++)
- {
- SetAttribute (GetAttributeUnderLocation (ViewportToScreen (new Point (i, 0))));
- AddRune (i, 0, Glyphs.ShadowHorizontal);
- }
- // Last is special
- SetAttribute (GetAttributeUnderLocation (ViewportToScreen (new Point (rectangle.Width - 1, 0))));
- AddRune (rectangle.Width - 1, 0, Glyphs.ShadowHorizontalEnd);
- }
- private void DrawHorizontalShadowTransparent (Rectangle viewport)
- {
- Rectangle screen = ViewportToScreen (Viewport);
- for (int r = Math.Max (0, screen.Y); r < screen.Y + screen.Height; r++)
- {
- for (int c = Math.Max (0, screen.X + 1); c < screen.X + screen.Width; c++)
- {
- Driver?.Move (c, r);
- SetAttribute (GetAttributeUnderLocation (new (c, r)));
- if (c < ScreenContents?.GetLength (1) && r < ScreenContents?.GetLength (0))
- {
- AddStr (ScreenContents [r, c].Grapheme);
- }
- }
- }
- }
- private void DrawVerticalShadowOpaque (Rectangle viewport)
- {
- // Draw the start glyph
- SetAttribute (GetAttributeUnderLocation (ViewportToScreen (new Point (0, 0))));
- AddRune (0, 0, Glyphs.ShadowVerticalStart);
- // Fill the rest of the rectangle with the glyph
- for (var i = 1; i < viewport.Height - 1; i++)
- {
- SetAttribute (GetAttributeUnderLocation (ViewportToScreen (new Point (0, i))));
- AddRune (0, i, Glyphs.ShadowVertical);
- }
- }
- private void DrawVerticalShadowTransparent (Rectangle viewport)
- {
- Rectangle screen = ViewportToScreen (Viewport);
- // Fill in the rest of the rectangle
- for (int c = Math.Max (0, screen.X); c < screen.X + screen.Width; c++)
- {
- for (int r = Math.Max (0, screen.Y); r < screen.Y + viewport.Height; r++)
- {
- Driver?.Move (c, r);
- SetAttribute (GetAttributeUnderLocation (new (c, r)));
- if (ScreenContents is { } && screen.X < ScreenContents.GetLength (1) && r < ScreenContents.GetLength (0))
- {
- AddStr (ScreenContents [r, c].Grapheme);
- }
- }
- }
- }
- private Attribute GetAttributeUnderLocation (Point location)
- {
- if (SuperView is not Adornment
- || location.X < 0
- || location.X >= App?.Screen.Width
- || location.Y < 0
- || location.Y >= App?.Screen.Height)
- {
- return Attribute.Default;
- }
- if (ScreenContents == null ||
- location.Y < 0 || location.Y >= ScreenContents.GetLength (0) ||
- location.X < 0 || location.X >= ScreenContents.GetLength (1))
- {
- return Attribute.Default;
- }
- Attribute attr = ScreenContents [location.Y, location.X].Attribute!.Value;
- var newAttribute =
- new Attribute (
- ShadowStyle == ShadowStyle.Opaque ? Color.Black : attr.Foreground.GetDimColor (),
- ShadowStyle == ShadowStyle.Opaque ? attr.Background : attr.Background.GetDimColor (0.05),
- attr.Style);
- // If the BG is DarkGray, GetDimColor gave up. Instead of using the attribute in the Driver under the shadow,
- // use the Normal attribute from the View under the shadow.
- if (newAttribute.Background == Color.DarkGray)
- {
- List<View?> currentViewsUnderMouse = GetViewsUnderLocation (location, ViewportSettingsFlags.Transparent);
- View? underView = currentViewsUnderMouse.LastOrDefault ();
- attr = underView?.GetAttributeForRole (VisualRole.Normal) ?? Attribute.Default;
- newAttribute = new (
- ShadowStyle == ShadowStyle.Opaque ? Color.Black : attr.Background.GetDimColor (),
- ShadowStyle == ShadowStyle.Opaque ? attr.Background : attr.Foreground.GetDimColor (0.25),
- attr.Style);
- }
- return newAttribute;
- }
- }
|