Skip to content

Commit

Permalink
Merge pull request #3376 from tig/v2_2144-3D-effect
Browse files Browse the repository at this point in the history
Fixes #2114. Adds `View.ShadowStyle` - Enabled but not turned on by default
  • Loading branch information
tig authored Jun 26, 2024
2 parents f24a0f8 + de92ea3 commit 61699d6
Show file tree
Hide file tree
Showing 44 changed files with 1,469 additions and 377 deletions.
1 change: 1 addition & 0 deletions Terminal.Gui/Application/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,7 @@ public static void RunIteration (ref RunState state, ref bool firstIteration)

if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ())
{
state.Toplevel.SetNeedsDisplay();
state.Toplevel.Draw ();
Driver.UpdateScreen ();

Expand Down
2 changes: 2 additions & 0 deletions Terminal.Gui/Configuration/ConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.Versioning;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand Down Expand Up @@ -49,6 +50,7 @@ namespace Terminal.Gui;
/// Lowest Precedence.
/// </para>
/// </summary>
[ComponentGuarantees (ComponentGuaranteesOptions.None)]
public static class ConfigurationManager
{
/// <summary>
Expand Down
9 changes: 5 additions & 4 deletions Terminal.Gui/Drawing/Cell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
/// Represents a single row/column in a Terminal.Gui rendering surface (e.g. <see cref="LineCanvas"/> and
/// <see cref="ConsoleDriver"/>).
/// </summary>
public class Cell
public record struct Cell ()
{
private Rune _rune;

/// <summary>The attributes to use when drawing the Glyph.</summary>
public Attribute? Attribute { get; set; }
public Attribute? Attribute { get; set; } = null;

/// <summary>
/// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.Cell"/> has been modified since the
/// last time it was drawn.
/// </summary>
public bool IsDirty { get; set; }
public bool IsDirty { get; set; } = false;

private Rune _rune = default;

/// <summary>The character to display. If <see cref="Rune"/> is <see langword="null"/>, then <see cref="Rune"/> is ignored.</summary>
public Rune Rune
Expand Down
21 changes: 21 additions & 0 deletions Terminal.Gui/Drawing/Color.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,27 @@ public Color GetHighlightColor ()

}

/// <summary>
/// Gets a color that is the same hue as the current color, but with a different lightness.
/// </summary>
/// <returns></returns>
public Color GetDarkerColor ()
{
// TODO: This is a temporary implementation; just enough to show how it could work.
var hsl = ColorHelper.ColorConverter.RgbToHsl (new RGB (R, G, B));

var amount = .3;
if (hsl.L <= 5)
{
return DarkGray;
}
hsl.L = (byte)(hsl.L * amount);

var rgb = ColorHelper.ColorConverter.HslToRgb (hsl);
return new (rgb.R, rgb.G, rgb.B);

}

#region Legacy Color Names

/// <summary>The black color.</summary>
Expand Down
20 changes: 20 additions & 0 deletions Terminal.Gui/Drawing/Glyphs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -437,4 +437,24 @@ public class GlyphDefinitions
public Rune CrossHv { get; set; } = (Rune)'╋';

#endregion

#region ----------------- ShadowStyle -----------------


/// <summary>Shadow - Vertical Start - Left Half Block - ▌ U+0258c</summary>
public Rune ShadowVerticalStart { get; set; } = (Rune)'▌'; // Half: '\u2596' ▖;

/// <summary>Shadow - Vertical - Left Half Block - ▌ U+0258c</summary>
public Rune ShadowVertical { get; set; } = (Rune)'▌';

/// <summary>Shadow - Horizontal Start - Upper Half Block - ▀ U+02580</summary>
public Rune ShadowHorizontalStart { get; set; } = (Rune)'▀'; // Half: ▝ U+0259d;

/// <summary>Shadow - Horizontal - Upper Half Block - ▀ U+02580</summary>
public Rune ShadowHorizontal { get; set; } = (Rune)'▀';

/// <summary>Shadow - Horizontal End - Quadrant Upper Left - ▘ U+02598</summary>
public Rune ShadowHorizontalEnd { get; set; } = (Rune)'▘';

#endregion
}
4 changes: 2 additions & 2 deletions Terminal.Gui/Drawing/LineCanvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ public void Clear ()
/// intersection symbols.
/// </summary>
/// <returns>A map of all the points within the canvas.</returns>
public Dictionary<Point, Cell> GetCellMap ()
public Dictionary<Point, Cell?> GetCellMap ()
{
Dictionary<Point, Cell> map = new ();
Dictionary<Point, Cell?> map = new ();

// walk through each pixel of the bitmap
for (int y = Viewport.Y; y < Viewport.Y + Viewport.Height; y++)
Expand Down
4 changes: 4 additions & 0 deletions Terminal.Gui/Resources/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"Application.AlternateBackwardKey": "Ctrl+PageUp",
"Application.AlternateForwardKey": "Ctrl+PageDown",
"Application.QuitKey": "Esc",

"Theme": "Default",
"Themes": [
{
Expand All @@ -28,6 +29,9 @@
"Dialog.DefaultButtonAlignmentModes": "AddSpaceBetweenItems",
"FrameView.DefaultBorderStyle": "Single",
"Window.DefaultBorderStyle": "Single",
"Dialog.DefaultBorderStyle": "Single",
"MessageBox.DefaultBorderStyle": "Double",
"Button.DefaultShadow": "None",
"ColorSchemes": [
{
"TopLevel": {
Expand Down
187 changes: 184 additions & 3 deletions Terminal.Gui/View/Adornment/Margin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
namespace Terminal.Gui;
#nullable enable

using System.Drawing;

namespace Terminal.Gui;

/// <summary>The Margin for a <see cref="View"/>.</summary>
/// <remarks>
Expand All @@ -15,6 +19,102 @@ public Margin ()
public Margin (View parent) : base (parent)
{
/* Do nothing; View.CreateAdornment requires a constructor that takes a parent */

HighlightStyle |= HighlightStyle.Pressed;
Highlight += Margin_Highlight;
LayoutStarted += Margin_LayoutStarted;

// Margin should not be focusable
CanFocus = false;
}

private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
{
// Adjust the shadow such that it is drawn aligned with the Border
if (ShadowStyle != Gui.ShadowStyle.None && _rightShadow is { } && _bottomShadow is { })
{
_rightShadow.Y = Parent.Border.Thickness.Top > 0 ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.ShowTitle ? 1 : 0) : 1;
_bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1;
}
}

private bool _pressed;
private void Margin_Highlight (object? sender, HighlightEventArgs e)
{
if (ShadowStyle != Gui.ShadowStyle.None)
{
if (_pressed && e.HighlightStyle == HighlightStyle.None)
{
Thickness = new (Thickness.Left - 1, Thickness.Top, Thickness.Right + 1, Thickness.Bottom);

if (_rightShadow is { })
{
_rightShadow.Visible = true;
}

if (_bottomShadow is { })
{
_bottomShadow.Visible = true;
}

_pressed = false;
return;
}

if (!_pressed && (e.HighlightStyle.HasFlag (HighlightStyle.Pressed) /*|| e.HighlightStyle.HasFlag (HighlightStyle.PressedOutside)*/))
{
Thickness = new (Thickness.Left + 1, Thickness.Top, Thickness.Right - 1, Thickness.Bottom);
_pressed = true;
if (_rightShadow is { })
{
_rightShadow.Visible = false;
}

if (_bottomShadow is { })
{
_bottomShadow.Visible = false;
}
}
}

}

/// <inheritdoc />
public override void OnDrawContent (Rectangle viewport)
{
Rectangle screen = ViewportToScreen (viewport);
Attribute normalAttr = GetNormalColor ();

Driver?.SetAttribute (normalAttr);


// This just draws/clears the thickness, not the insides.
if (ShadowStyle != ShadowStyle.None)
{
screen = Rectangle.Inflate (screen, -1, -1);
}
Thickness.Draw (screen, ToString ());

if (Subviews.Count > 0)
{
// Draw subviews
// TODO: Implement OnDrawSubviews (cancelable);
if (Subviews is { } && SubViewNeedsDisplay)
{
IEnumerable<View> subviewsNeedingDraw = Subviews.Where (
view => view.Visible
&& (view.NeedsDisplay || view.SubViewNeedsDisplay || view.LayoutNeeded)
);
foreach (View view in subviewsNeedingDraw)
{
if (view.LayoutNeeded)
{
view.LayoutSubviews ();
}
view.Draw ();
}
}
}
}

/// <summary>
Expand All @@ -30,12 +130,93 @@ public override ColorScheme ColorScheme
return base.ColorScheme;
}

return Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"];
return (Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"])!;
}
set
{
base.ColorScheme = value;
Parent?.SetNeedsDisplay ();
}
}
}

/// <inheritdoc />
public override ShadowStyle ShadowStyle
{
get => base.ShadowStyle;
set
{
base.ShadowStyle = SetShadow (value);
}
}

/// <summary>
/// Sets whether the Margin includes a shadow effect. The shadow is drawn on the right and bottom sides of the
/// Margin.
/// </summary>
public ShadowStyle SetShadow (ShadowStyle style)
{
if (ShadowStyle == style)
{
// return style;
}

if (ShadowStyle != ShadowStyle.None)
{
// Turn off shadow
Thickness = new (Thickness.Left, Thickness.Top, Thickness.Right - 1, Thickness.Bottom - 1);
}

if (style != ShadowStyle.None)
{
// Turn on shadow
Thickness = new (Thickness.Left, Thickness.Top, Thickness.Right + 1, Thickness.Bottom + 1);
}

if (_rightShadow is { })
{
_rightShadow.ShadowStyle = style;
}

if (_bottomShadow is { })
{
_bottomShadow.ShadowStyle = style;
}
return style;
}

private ShadowView? _bottomShadow;
private ShadowView? _rightShadow;

/// <inheritdoc/>
public override void BeginInit ()
{
base.BeginInit ();

if (Parent is null)
{
return;
}

ShadowStyle = base.ShadowStyle;
Add (
_rightShadow = new ShadowView
{
X = Pos.AnchorEnd (1),
Y = 0,
Width = 1,
Height = Dim.Fill (),
ShadowStyle = ShadowStyle,
Orientation = Orientation.Vertical
},
_bottomShadow = new ShadowView
{
X = 0,
Y = Pos.AnchorEnd (1),
Width = Dim.Fill (),
Height = 1,
ShadowStyle = ShadowStyle,
Orientation = Orientation.Horizontal
}
);
}
}
22 changes: 22 additions & 0 deletions Terminal.Gui/View/Adornment/ShadowStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Terminal.Gui;

/// <summary>
/// Defines the style of shadow to be drawn on the right and bottom sides of the <see cref="View"/>.
/// </summary>
public enum ShadowStyle
{
/// <summary>
/// No shadow.
/// </summary>
None,

/// <summary>
/// A shadow that is drawn using block elements. Ideal for smaller views such as buttons.
/// </summary>
Opaque,

/// <summary>
/// A shadow that is drawn using the underlying text with a darker background. Ideal for larger views such as windows.
/// </summary>
Transparent
}
Loading

0 comments on commit 61699d6

Please sign in to comment.