#nullable enable namespace Terminal.Gui; public partial class View // Adornments { /// /// Initializes the Adornments of the View. Called by the constructor. /// private void SetupAdornments () { // TODO: Move this to Adornment as a static factory method if (this is not Adornment) { // TODO: Make the Adornments Lazy and only create them when needed Margin = new (this); Border = new (this); Padding = new (this); } } private void BeginInitAdornments () { Margin?.BeginInit (); Border?.BeginInit (); Padding?.BeginInit (); } private void EndInitAdornments () { Margin?.EndInit (); Border?.EndInit (); Padding?.EndInit (); } private void DisposeAdornments () { Margin?.Dispose (); Margin = null; Border?.Dispose (); Border = null; Padding?.Dispose (); Padding = null; } /// /// The that enables separation of a View from other SubViews of the same /// SuperView. The margin offsets the from the . /// /// /// /// The margin is typically transparent. This can be overriden by explicitly setting . /// /// /// Enabling will change the Thickness of the Margin to include the shadow. /// /// /// The adornments (, , and ) are not part of the /// View's content and are not clipped by the View's Clip Area. /// /// /// Changing the size of an adornment (, , or ) will /// change the size of which will call to update the layout of the /// and its . /// /// public Margin? Margin { get; private set; } private ShadowStyle _shadowStyle; /// /// Gets or sets whether the View is shown with a shadow effect. The shadow is drawn on the right and bottom sides of /// the /// Margin. /// /// /// Setting this property to will add a shadow to the right and bottom sides of the Margin. /// The View 's will be expanded to include the shadow. /// public virtual ShadowStyle ShadowStyle { get => _shadowStyle; set { if (_shadowStyle == value) { return; } _shadowStyle = value; if (Margin is { }) { Margin.ShadowStyle = value; } } } /// /// The that offsets the from the . /// /// The Border provides the space for a visual border (drawn using /// line-drawing glyphs) and the Title. The Border expands inward; in other words if `Border.Thickness.Top == 2` /// the /// border and title will take up the first row and the second row will be filled with spaces. /// /// /// The Border provides the UI for mouse and keyboard arrangement of the View. See . /// /// /// /// provides a simple helper for turning a simple border frame on or off. /// /// The adornments (, , and ) are not part of the /// View's content and are not clipped by the View's Clip Area. /// /// /// Changing the size of an adornment (, , or ) will /// change the size of which will call to update the layout of the /// and its . /// /// public Border? Border { get; private set; } /// Gets or sets whether the view has a one row/col thick border. /// /// /// This is a helper for manipulating the view's . Setting this property to any value other /// than is equivalent to setting 's /// to `1` and to the value. /// /// /// Setting this property to is equivalent to setting 's /// to `0` and to . /// /// /// Calls and raises , which allows change /// to be cancelled. /// /// For more advanced customization of the view's border, manipulate see directly. /// public LineStyle BorderStyle { get => Border?.LineStyle ?? LineStyle.Single; set { if (Border is null) { return; } LineStyle old = Border?.LineStyle ?? LineStyle.None; // It's tempting to try to optimize this by checking that old != value and returning. // Do not. CancelEventArgs e = new (ref old, ref value); if (OnBorderStyleChanging (e) || e.Cancel) { return; } BorderStyleChanging?.Invoke (this, e); if (e.Cancel) { return; } SetBorderStyle (e.NewValue); SetAdornmentFrames (); SetNeedsLayout (); } } /// /// Called when the is changing. /// /// /// Set e.Cancel to true to prevent the from changing. /// /// protected virtual bool OnBorderStyleChanging (CancelEventArgs e) { return false; } /// /// Fired when the is changing. Allows the event to be cancelled. /// public event EventHandler>? BorderStyleChanging; /// /// Sets the of the view to the specified value. /// /// /// /// is a helper for manipulating the view's . Setting this property /// to any value other /// than is equivalent to setting 's /// to `1` and to the value. /// /// /// Setting this property to is equivalent to setting 's /// to `0` and to . /// /// For more advanced customization of the view's border, manipulate see directly. /// /// public virtual void SetBorderStyle (LineStyle value) { if (value != LineStyle.None) { if (Border!.Thickness == Thickness.Empty) { Border.Thickness = new (1); } } else { Border!.Thickness = new (0); } Border.LineStyle = value; } /// /// The inside of the view that offsets the /// from the . /// /// /// /// The adornments (, , and ) are not part of the /// View's content and are not clipped by the View's Clip Area. /// /// /// Changing the size of an adornment (, , or ) will /// change the size of which will call to update the layout of the /// and its . /// /// public Padding? Padding { get; private set; } /// /// Gets the thickness describing the sum of the Adornments' thicknesses. /// /// /// /// The is offset from the by the thickness returned by this method. /// /// /// A thickness that describes the sum of the Adornments' thicknesses. public Thickness GetAdornmentsThickness () { Thickness result = Thickness.Empty; if (Margin is { }) { result += Margin.Thickness; } if (Border is { }) { result += Border.Thickness; } if (Padding is { }) { result += Padding.Thickness; } return result; } /// Sets the Frame's of the Margin, Border, and Padding. internal void SetAdornmentFrames () { if (this is Adornment) { // Adornments do not have Adornments return; } if (Margin is { }) { Margin!.Frame = Rectangle.Empty with { Size = Frame.Size }; } if (Border is { } && Margin is { }) { Border!.Frame = Margin!.Thickness.GetInside (Margin!.Frame); } if (Padding is { } && Border is { }) { Padding!.Frame = Border!.Thickness.GetInside (Border!.Frame); } } }