namespace Terminal.Gui.Views;
///
/// Draws a single line using the specified by .
///
///
///
/// is a that renders a single horizontal or vertical line
/// using the system. integrates with the LineCanvas
/// to enable proper box-drawing character selection and line intersection handling.
///
///
/// The line's appearance is controlled by the property, which supports
/// various line styles including Single, Double, Heavy, Rounded, Dashed, and Dotted.
///
///
/// Use the property to control the extent of the line regardless of its
/// . For horizontal lines, Length controls Width; for vertical lines,
/// it controls Height. The perpendicular dimension is always 1.
///
///
/// When multiple instances or other LineCanvas-aware views (like )
/// intersect, the LineCanvas automatically selects the appropriate box-drawing characters for corners,
/// T-junctions, and crosses.
///
///
/// sets to ,
/// 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.
///
///
///
///
/// // 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 };
///
///
public class Line : View, IOrientation
{
private readonly OrientationHelper _orientationHelper;
private LineStyle _style = LineStyle.Single;
private Dim _length = Dim.Fill ();
///
/// Constructs a new instance of the class with horizontal orientation.
///
///
/// By default, a horizontal line fills the available width and has a height of 1.
/// The line style defaults to .
///
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;
}
///
/// Gets or sets the length of the line along its orientation.
///
///
///
/// 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.
///
///
/// 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.
///
///
/// This property provides a cleaner API for controlling the line's extent
/// without needing to know whether to use Width or Height.
///
///
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;
}
}
}
///
/// Gets or sets the style of the line. This controls the visual appearance of the line.
///
///
/// Supports various line styles including Single, Double, Heavy, Rounded, Dashed, and Dotted.
/// Note: This is separate from to avoid conflicts with the View's Border.
///
public LineStyle Style
{
get => _style;
set
{
if (_style != value)
{
_style = value;
SetNeedsDraw ();
}
}
}
#region IOrientation members
///
/// The direction of the line.
///
///
///
/// When orientation changes, the appropriate dimension is set to
/// and the perpendicular dimension is set to 1.
///
///
/// For object initializers where dimensions are set before orientation:
/// new Line { Height = 9, Orientation = Orientation.Vertical }
/// 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.
///
///
public Orientation Orientation
{
get => _orientationHelper.Orientation;
set => _orientationHelper.Orientation = value;
}
#pragma warning disable CS0067 // The event is never used
///
public event EventHandler>? OrientationChanging;
///
public event EventHandler>? OrientationChanged;
#pragma warning restore CS0067 // The event is never used
///
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;
}
}
///
protected override bool OnWidthChanging (ValueChangingEventArgs 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);
}
///
protected override bool OnHeightChanging (ValueChangingEventArgs 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
///
///
/// This method adds the line to the LineCanvas for rendering.
/// The actual rendering is performed by the parent view through .
///
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;
}
}