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; } }