using System.ComponentModel; using System.Text.Json.Serialization; 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) { 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 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 and trigger 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. /// /// /// 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 a frame (, , or ) will /// change the size of the and trigger 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 . /// /// For more advanced customization of the view's border, manipulate see directly. /// public LineStyle BorderStyle { get => Border?.LineStyle ?? LineStyle.Single; set { var old = Border?.LineStyle ?? LineStyle.None; CancelEventArgs e = new (ref old, ref value); OnBorderStyleChanging (e); } } /// /// Called when the is changing. Invokes , which allows the event to be cancelled. /// /// /// Override to prevent the from changing. /// /// protected void OnBorderStyleChanging (CancelEventArgs e) { if (Border is null) { return; } BorderStyleChanging?.Invoke (this, e); if (e.Cancel) { return; } SetBorderStyle (e.NewValue); LayoutAdornments (); SetNeedsLayout (); return; } /// /// 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; } /// /// Fired when the is changing. Allows the event to be cancelled. /// public event EventHandler> BorderStyleChanging; /// /// 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 a frame (, , or ) will /// change the size of the and trigger 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 () { if (Margin is null) { return Thickness.Empty; } return Margin.Thickness + Border.Thickness + Padding.Thickness; } /// Lays out the Adornments of the View. /// /// Overriden by to do nothing, as does not have adornments. /// internal virtual void LayoutAdornments () { if (Margin is null) { return; // CreateAdornments () has not been called yet } if (Margin.Frame.Size != Frame.Size) { Margin.SetFrame (Rectangle.Empty with { Size = Frame.Size }); Margin.X = 0; Margin.Y = 0; Margin.Width = Frame.Size.Width; Margin.Height = Frame.Size.Height; } Margin.SetNeedsLayout (); Margin.SetNeedsDisplay (); if (IsInitialized) { Margin.LayoutSubviews (); } Rectangle border = Margin.Thickness.GetInside (Margin.Frame); if (border != Border.Frame) { Border.SetFrame (border); Border.X = border.Location.X; Border.Y = border.Location.Y; Border.Width = border.Size.Width; Border.Height = border.Size.Height; } Border.SetNeedsLayout (); Border.SetNeedsDisplay (); if (IsInitialized) { Border.LayoutSubviews (); } Rectangle padding = Border.Thickness.GetInside (Border.Frame); if (padding != Padding.Frame) { Padding.SetFrame (padding); Padding.X = padding.Location.X; Padding.Y = padding.Location.Y; Padding.Width = padding.Size.Width; Padding.Height = padding.Size.Height; } Padding.SetNeedsLayout (); Padding.SetNeedsDisplay (); if (IsInitialized) { Padding.LayoutSubviews (); } } }