mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
241 lines
8.4 KiB
C#
241 lines
8.4 KiB
C#
#nullable enable
|
|
|
|
namespace Terminal.Gui.Views;
|
|
|
|
/// <summary>
|
|
/// Draws a single line using the <see cref="LineStyle"/> specified by <see cref="Line.Style"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <see cref="Line"/> is a <see cref="View"/> that renders a single horizontal or vertical line
|
|
/// using the <see cref="LineCanvas"/> system. <see cref="Line"/> integrates with the LineCanvas
|
|
/// to enable proper box-drawing character selection and line intersection handling.
|
|
/// </para>
|
|
/// <para>
|
|
/// The line's appearance is controlled by the <see cref="Style"/> property, which supports
|
|
/// various line styles including Single, Double, Heavy, Rounded, Dashed, and Dotted.
|
|
/// </para>
|
|
/// <para>
|
|
/// Use the <see cref="Length"/> property to control the extent of the line regardless of its
|
|
/// <see cref="Orientation"/>. For horizontal lines, Length controls Width; for vertical lines,
|
|
/// it controls Height. The perpendicular dimension is always 1.
|
|
/// </para>
|
|
/// <para>
|
|
/// When multiple <see cref="Line"/> instances or other LineCanvas-aware views (like <see cref="Border"/>)
|
|
/// intersect, the LineCanvas automatically selects the appropriate box-drawing characters for corners,
|
|
/// T-junctions, and crosses.
|
|
/// </para>
|
|
/// <para>
|
|
/// <see cref="Line"/> sets <see cref="View.SuperViewRendersLineCanvas"/> to <see langword="true"/>,
|
|
/// meaning its parent view is responsible for rendering the line. This allows for proper intersection
|
|
/// handling when multiple views contribute lines to the same canvas.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // Create a horizontal line
|
|
/// var hLine = new Line { Y = 5 };
|
|
///
|
|
/// // Create a vertical line with specific length
|
|
/// var vLine = new Line { X = 10, Orientation = Orientation.Vertical, Length = 15 };
|
|
///
|
|
/// // Create a double-line style horizontal line
|
|
/// var doubleLine = new Line { Y = 10, Style = LineStyle.Double };
|
|
/// </code>
|
|
/// </example>
|
|
public class Line : View, IOrientation
|
|
{
|
|
private readonly OrientationHelper _orientationHelper;
|
|
private LineStyle _style = LineStyle.Single;
|
|
private Dim _length = Dim.Fill ();
|
|
|
|
/// <summary>
|
|
/// Constructs a new instance of the <see cref="Line"/> class with horizontal orientation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// By default, a horizontal line fills the available width and has a height of 1.
|
|
/// The line style defaults to <see cref="LineStyle.Single"/>.
|
|
/// </remarks>
|
|
public Line ()
|
|
{
|
|
CanFocus = false;
|
|
base.SuperViewRendersLineCanvas = true;
|
|
|
|
_orientationHelper = new (this);
|
|
_orientationHelper.Orientation = Orientation.Horizontal;
|
|
|
|
// Set default dimensions for horizontal orientation
|
|
// Set Height first (this will update _length, but we'll override it next)
|
|
Height = 1;
|
|
|
|
// Now set Width and _length to Fill
|
|
_length = Dim.Fill ();
|
|
Width = _length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the length of the line along its orientation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This is the "source of truth" for the line's primary dimension.
|
|
/// For a horizontal line, Length controls Width.
|
|
/// For a vertical line, Length controls Height.
|
|
/// </para>
|
|
/// <para>
|
|
/// When Width or Height is set directly, Length is updated to match the primary dimension.
|
|
/// When Orientation changes, the appropriate dimension is set to Length and the perpendicular
|
|
/// dimension is set to 1.
|
|
/// </para>
|
|
/// <para>
|
|
/// This property provides a cleaner API for controlling the line's extent
|
|
/// without needing to know whether to use Width or Height.
|
|
/// </para>
|
|
/// </remarks>
|
|
public Dim Length
|
|
{
|
|
get => Orientation == Orientation.Horizontal ? Width : Height;
|
|
set
|
|
{
|
|
_length = value;
|
|
|
|
// Update the appropriate dimension based on current orientation
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
Width = _length;
|
|
}
|
|
else
|
|
{
|
|
Height = _length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the style of the line. This controls the visual appearance of the line.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Supports various line styles including Single, Double, Heavy, Rounded, Dashed, and Dotted.
|
|
/// Note: This is separate from <see cref="View.BorderStyle"/> to avoid conflicts with the View's Border.
|
|
/// </remarks>
|
|
public LineStyle Style
|
|
{
|
|
get => _style;
|
|
set
|
|
{
|
|
if (_style != value)
|
|
{
|
|
_style = value;
|
|
SetNeedsDraw ();
|
|
}
|
|
}
|
|
}
|
|
|
|
#region IOrientation members
|
|
|
|
/// <summary>
|
|
/// The direction of the line.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// When orientation changes, the appropriate dimension is set to <see cref="Length"/>
|
|
/// and the perpendicular dimension is set to 1.
|
|
/// </para>
|
|
/// <para>
|
|
/// For object initializers where dimensions are set before orientation:
|
|
/// <code>new Line { Height = 9, Orientation = Orientation.Vertical }</code>
|
|
/// Setting Height=9 updates Length to 9 (since default orientation is Horizontal and Height is perpendicular).
|
|
/// Then when Orientation is set to Vertical, Height is set to Length (9) and Width is set to 1,
|
|
/// resulting in the expected Width=1, Height=9.
|
|
/// </para>
|
|
/// </remarks>
|
|
public Orientation Orientation
|
|
{
|
|
get => _orientationHelper.Orientation;
|
|
set => _orientationHelper.Orientation = value;
|
|
}
|
|
|
|
#pragma warning disable CS0067 // The event is never used
|
|
/// <inheritdoc/>
|
|
public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
|
|
|
|
/// <inheritdoc/>
|
|
public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
|
|
#pragma warning restore CS0067 // The event is never used
|
|
|
|
/// <summary>
|
|
/// Called when <see cref="Orientation"/> has changed.
|
|
/// </summary>
|
|
/// <param name="newOrientation">The new orientation value.</param>
|
|
public void OnOrientationChanged (Orientation newOrientation)
|
|
{
|
|
// Set dimensions based on new orientation:
|
|
// - Primary dimension (along orientation) = Length
|
|
// - Perpendicular dimension = 1
|
|
if (newOrientation == Orientation.Horizontal)
|
|
{
|
|
Width = _length;
|
|
Height = 1;
|
|
}
|
|
else
|
|
{
|
|
Height = _length;
|
|
Width = 1;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override bool OnWidthChanging (ValueChangingEventArgs<Dim> e)
|
|
{
|
|
// If horizontal, allow width changes and update _length
|
|
_length = e.NewValue;
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
return base.OnWidthChanging (e);
|
|
}
|
|
|
|
// If vertical, keep width at 1 (don't allow changes to perpendicular dimension)
|
|
e.NewValue = 1;
|
|
|
|
return base.OnWidthChanging (e);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override bool OnHeightChanging (ValueChangingEventArgs<Dim> e)
|
|
{
|
|
// If vertical, allow height changes and update _length
|
|
_length = e.NewValue;
|
|
if (Orientation == Orientation.Vertical)
|
|
{
|
|
return base.OnHeightChanging (e);
|
|
}
|
|
|
|
e.NewValue = 1;
|
|
|
|
return base.OnHeightChanging (e);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <inheritdoc/>
|
|
/// <remarks>
|
|
/// This method adds the line to the LineCanvas for rendering.
|
|
/// The actual rendering is performed by the parent view through <see cref="View.RenderLineCanvas"/>.
|
|
/// </remarks>
|
|
protected override bool OnDrawingContent ()
|
|
{
|
|
Point pos = ViewportToScreen (Viewport).Location;
|
|
int length = Orientation == Orientation.Horizontal ? Frame.Width : Frame.Height;
|
|
|
|
LineCanvas.AddLine (
|
|
pos,
|
|
length,
|
|
Orientation,
|
|
Style,
|
|
GetAttributeForRole(VisualRole.Normal)
|
|
);
|
|
|
|
return true;
|
|
}
|
|
}
|