using System; namespace Terminal.Gui { /// /// A container for single that will allow to drawn in /// two ways. If the borders and the child will be accommodated in the available /// panel size, otherwise the panel will be resized based on the child and borders thickness sizes. /// public class PanelView : View { ChildContentView childContentView; private class ChildContentView : View { } private class SavedPosDim { public Pos X; public Pos Y; public Dim Width; public Dim Height; } private SavedPosDim savedPanel; private SavedPosDim savedChild; private View child; private bool usePanelFrame; /// /// Initializes a panel with a null child. /// public PanelView () : this (null) { } /// /// Initializes a panel with a valid child. /// /// public PanelView (View child) { childContentView = new ChildContentView (); base.Add (childContentView); CanFocus = false; Child = child; if (child != null) { Visible = child.Visible; } } /// /// Gets or sets if the panel size will used, otherwise the child size. /// public bool UsePanelFrame { get => usePanelFrame; set { usePanelFrame = value; AdjustContainer (); } } /// /// The child that will use this panel. /// public View Child { get => child; set { if (child != null && value == null) { childContentView.Remove (child); child = value; return; } child = value; savedChild = new SavedPosDim () { X = child?.X ?? child?.Frame.X, Y = child?.Y ?? child?.Frame.Y, Width = child?.Width ?? child?.Frame.Width, Height = child?.Height ?? child?.Frame.Height }; if (child == null) { Visible = false; return; } if (child?.Border != null) { Border = child.Border; } else { if (Border == null) { Border = new Border (); } Child.Border = Border; } Border.Child = childContentView; if (!child.IsInitialized) { child.Initialized += Child_Initialized; } childContentView.Add (Child); } } /// public override Border Border { get => base.Border; set { if (base.Border?.Child != null && value.Child == null) { value.Child = base.Border.Child; } base.Border = value; if (value == null) { return; } Border.BorderChanged += Border_BorderChanged; if (Child != null && (Child?.Border == null || Child?.Border != value)) { if (Child?.Border == null) { Child.Border = new Border (); } Child.Border = Border; Child.Border.BorderChanged += Border_BorderChanged; } AdjustContainer (); } } private void Child_Initialized (object sender, EventArgs e) { savedPanel = new SavedPosDim () { X = X, Y = Y, Width = Width, Height = Height }; AdjustContainer (); Child.Initialized -= Child_Initialized; } private void Border_BorderChanged (Border obj) { AdjustContainer (); } private void AdjustContainer () { if (Child?.IsInitialized == true) { if (Child?.Border != null && Child.Border != Border) { Border = Child.Border; } var borderLength = Child.Border.DrawMarginFrame ? 1 : 0; var sumPadding = Child.Border.GetSumThickness (); var effect3DOffset = Child.Border.Effect3D ? Child.Border.Effect3DOffset : new Point (); if (!UsePanelFrame) { X = savedPanel.X; childContentView.X = borderLength + sumPadding.Left; Y = savedPanel.Y; childContentView.Y = borderLength + sumPadding.Top; if (savedChild.Width is Dim.DimFill) { var margin = -savedChild.Width.Anchor (0); Width = Dim.Fill (margin); childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right); } else { var savedLayout = LayoutStyle; LayoutStyle = LayoutStyle.Absolute; Width = savedChild.X.Anchor (0) + savedChild.Width + (2 * borderLength) + sumPadding.Right + sumPadding.Left; LayoutStyle = savedLayout; childContentView.Width = Dim.Fill (borderLength + sumPadding.Right); } if (savedChild.Height is Dim.DimFill) { var margin = -savedChild.Height.Anchor (0); Height = Dim.Fill (margin); childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom); } else { var savedLayout = LayoutStyle; LayoutStyle = LayoutStyle.Absolute; Height = savedChild.Y.Anchor (0) + savedChild.Height + (2 * borderLength) + sumPadding.Bottom + sumPadding.Top; LayoutStyle = savedLayout; childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom); } } else { X = savedPanel.X - (effect3DOffset.X < 0 ? effect3DOffset.X : 0); childContentView.X = borderLength + sumPadding.Left; Y = savedPanel.Y - (effect3DOffset.Y < 0 ? effect3DOffset.Y : 0); childContentView.Y = borderLength + sumPadding.Top; Width = savedPanel.Width; Height = savedPanel.Height; if (Width is Dim.DimFill) { var margin = -savedPanel.Width.Anchor (0) + (effect3DOffset.X > 0 ? effect3DOffset.X : 0); Width = Dim.Fill (margin); childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right + (effect3DOffset.X > 0 ? effect3DOffset.X : 0)); } else { childContentView.Width = Dim.Fill (borderLength + sumPadding.Right); } if (Height is Dim.DimFill) { var margin = -savedPanel.Height.Anchor (0) + (effect3DOffset.Y > 0 ? effect3DOffset.Y : 0); Height = Dim.Fill (margin); childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom + (effect3DOffset.Y > 0 ? effect3DOffset.Y : 0)); } else { childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom); } } Visible = Child.Visible; } else { Visible = false; } } /// public override void Add (View view) { if (Child != null) { Child = null; } Child = view; } /// public override void Remove (View view) { if (view == childContentView) { base.Remove (view); return; } childContentView.Remove (view); if (Child != null) { Child = null; } } /// public override void RemoveAll () { if (Child != null) { Child = null; } } /// public override void Redraw (Rect bounds) { if (!NeedDisplay.IsEmpty) { Driver.SetAttribute (Child.GetNormalColor ()); Clear (); Child.Border.DrawContent (Border.Child); } var savedClip = childContentView.ClipToBounds (); childContentView.Redraw (childContentView.Bounds); Driver.Clip = savedClip; ClearLayoutNeeded (); ClearNeedsDisplay (); } } }