namespace Terminal.Gui.ViewBase; public partial class View { // TODO: Change NeedsDraw to use a Region instead of Rectangle // TODO: Make _needsDrawRect nullable instead of relying on Empty // TODO: If null, it means ? // TODO: If Empty, it means no need to redraw // TODO: If not Empty, it means the region that needs to be redrawn /// /// The viewport-relative region that needs to be redrawn. Marked internal for unit tests. /// internal Rectangle NeedsDrawRect { get; set; } = Rectangle.Empty; /// Gets or sets whether the view needs to be redrawn. /// /// /// Will be if the property is or if /// any part of the view's needs to be redrawn. /// /// /// Setting has no effect on . /// /// public bool NeedsDraw { get => Visible && (NeedsDrawRect != Rectangle.Empty || Margin?.NeedsDraw == true || Border?.NeedsDraw == true || Padding?.NeedsDraw == true); set { if (value) { SetNeedsDraw (); } else { ClearNeedsDraw (); } } } /// Gets whether any SubViews need to be redrawn. public bool SubViewNeedsDraw { get; private set; } /// Sets that the of this View needs to be redrawn. /// /// If the view has not been initialized ( is ), this method /// does nothing. /// public void SetNeedsDraw () { Rectangle viewport = Viewport; if (!Visible || (NeedsDrawRect != Rectangle.Empty && viewport.IsEmpty)) { // This handles the case where the view has not been initialized yet return; } SetNeedsDraw (viewport); } /// Expands the area of this view needing to be redrawn to include . /// /// /// The location of is relative to the View's . /// /// /// If the view has not been initialized ( is ), the area to be /// redrawn will be the . /// /// /// The relative region that needs to be redrawn. public void SetNeedsDraw (Rectangle viewPortRelativeRegion) { if (!Visible) { return; } if (NeedsDrawRect.IsEmpty) { NeedsDrawRect = viewPortRelativeRegion; } else { int x = Math.Min (Viewport.X, viewPortRelativeRegion.X); int y = Math.Min (Viewport.Y, viewPortRelativeRegion.Y); int w = Math.Max (Viewport.Width, viewPortRelativeRegion.Width); int h = Math.Max (Viewport.Height, viewPortRelativeRegion.Height); NeedsDrawRect = new (x, y, w, h); } // Do not set on Margin - it will be drawn in a separate pass. if (Border is { } && Border.Thickness != Thickness.Empty) { Border?.SetNeedsDraw (); } if (Padding is { } && Padding.Thickness != Thickness.Empty) { Padding?.SetNeedsDraw (); } SuperView?.SetSubViewNeedsDraw (); if (this is Adornment adornment) { adornment.Parent?.SetSubViewNeedsDraw (); } // There was multiple enumeration error here, so calling new snapshot collection - probably a stop gap foreach (View subview in InternalSubViews.Snapshot ()) { if (subview.Frame.IntersectsWith (viewPortRelativeRegion)) { Rectangle subviewRegion = Rectangle.Intersect (subview.Frame, viewPortRelativeRegion); subviewRegion.X -= subview.Frame.X; subviewRegion.Y -= subview.Frame.Y; subview.SetNeedsDraw (subviewRegion); } } } /// Sets to for this View and all Superviews. public void SetSubViewNeedsDraw () { if (!Visible) { return; } SubViewNeedsDraw = true; if (this is Adornment adornment) { adornment.Parent?.SetSubViewNeedsDraw (); } if (SuperView is { SubViewNeedsDraw: false }) { SuperView.SetSubViewNeedsDraw (); } } /// Clears and . protected void ClearNeedsDraw () { NeedsDrawRect = Rectangle.Empty; Margin?.ClearNeedsDraw (); Border?.ClearNeedsDraw (); Padding?.ClearNeedsDraw (); // There was multiple enumeration error here, so calling new snapshot collection - probably a stop gap foreach (View subview in InternalSubViews.Snapshot ()) { subview.ClearNeedsDraw (); } SubViewNeedsDraw = false; if (SuperView is { }) { SuperView.SubViewNeedsDraw = false; } // This ensures LineCanvas' get redrawn if (!SuperViewRendersLineCanvas) { LineCanvas.Clear (); } } }