PanelView.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using System;
  2. namespace Terminal.Gui {
  3. /// <summary>
  4. /// A container for single <see cref="Child"/> that will allow to drawn <see cref="Border"/> in
  5. /// two ways. If <see cref="UsePanelFrame"/> the borders and the child will be accommodated in the available
  6. /// panel size, otherwise the panel will be resized based on the child and borders thickness sizes.
  7. /// </summary>
  8. public class PanelView : View {
  9. ChildContentView childContentView;
  10. private class ChildContentView : View { }
  11. private class SavedPosDim {
  12. public Pos X;
  13. public Pos Y;
  14. public Dim Width;
  15. public Dim Height;
  16. }
  17. private SavedPosDim savedPanel;
  18. private SavedPosDim savedChild;
  19. private View child;
  20. private bool usePanelFrame;
  21. /// <summary>
  22. /// Initializes a panel with a null child.
  23. /// </summary>
  24. public PanelView () : this (null) { }
  25. /// <summary>
  26. /// Initializes a panel with a valid child.
  27. /// </summary>
  28. /// <param name="child"></param>
  29. public PanelView (View child)
  30. {
  31. childContentView = new ChildContentView ();
  32. base.Add (childContentView);
  33. CanFocus = false;
  34. Child = child;
  35. if (child != null) {
  36. Visible = child.Visible;
  37. }
  38. }
  39. /// <summary>
  40. /// Gets or sets if the panel size will used, otherwise the child size.
  41. /// </summary>
  42. public bool UsePanelFrame {
  43. get => usePanelFrame;
  44. set {
  45. usePanelFrame = value;
  46. AdjustContainer ();
  47. }
  48. }
  49. /// <summary>
  50. /// The child that will use this panel.
  51. /// </summary>
  52. public View Child {
  53. get => child;
  54. set {
  55. if (child != null && value == null) {
  56. childContentView.Remove (child);
  57. child = value;
  58. return;
  59. }
  60. child = value;
  61. savedChild = new SavedPosDim () {
  62. X = child?.X,
  63. Y = child?.Y,
  64. Width = child?.Width,
  65. Height = child?.Height
  66. };
  67. if (child == null) {
  68. Visible = false;
  69. return;
  70. }
  71. child.X = 0;
  72. child.Y = 0;
  73. AdjustContainer ();
  74. if (child?.Border != null) {
  75. child.Border.BorderChanged += Border_BorderChanged;
  76. Border = child.Border;
  77. Border.Child = childContentView;
  78. } else {
  79. if (Border == null) {
  80. Border = new Border ();
  81. }
  82. Border.BorderChanged += Border_BorderChanged;
  83. Border.Child = childContentView;
  84. }
  85. if (!child.IsInitialized) {
  86. child.Initialized += Child_Initialized;
  87. }
  88. childContentView.Add (Child);
  89. }
  90. }
  91. private void Child_Initialized (object sender, EventArgs e)
  92. {
  93. savedPanel = new SavedPosDim () {
  94. X = X,
  95. Y = Y,
  96. Width = Width,
  97. Height = Height
  98. };
  99. AdjustContainer ();
  100. Child.Initialized -= Child_Initialized;
  101. }
  102. private void Border_BorderChanged (Border obj)
  103. {
  104. AdjustContainer ();
  105. }
  106. private void AdjustContainer ()
  107. {
  108. if (Child?.IsInitialized == true) {
  109. var borderLength = Child.Border != null
  110. ? Child.Border.DrawMarginFrame ? 1 : 0
  111. : 0;
  112. var sumPadding = Child.Border != null
  113. ? Child.Border.GetSumThickness ()
  114. : new Thickness ();
  115. if (!UsePanelFrame) {
  116. X = savedChild.X;
  117. childContentView.X = borderLength + sumPadding.Left;
  118. Y = savedChild.Y;
  119. childContentView.Y = borderLength + sumPadding.Top;
  120. if (savedChild.Width is Dim.DimFill) {
  121. var margin = -savedChild.Width.Anchor (0);
  122. Width = Dim.Fill (margin);
  123. childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right);
  124. } else {
  125. Width = savedChild.Width + (2 * borderLength) + sumPadding.Right + sumPadding.Left;
  126. childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
  127. }
  128. if (savedChild.Height is Dim.DimFill) {
  129. var margin = -savedChild.Height.Anchor (0);
  130. Height = Dim.Fill (margin);
  131. childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom);
  132. } else {
  133. Height = savedChild.Height + (2 * borderLength) + sumPadding.Bottom + sumPadding.Top;
  134. childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
  135. }
  136. } else {
  137. X = savedPanel.X;
  138. childContentView.X = borderLength + sumPadding.Left;
  139. Y = savedPanel.Y;
  140. childContentView.Y = borderLength + sumPadding.Top;
  141. Width = savedPanel.Width;
  142. Height = savedPanel.Height;
  143. if (Width is Dim.DimFill) {
  144. var margin = -savedPanel.Width.Anchor (0);
  145. childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right);
  146. } else {
  147. childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
  148. }
  149. if (Height is Dim.DimFill) {
  150. var margin = -savedPanel.Height.Anchor (0);
  151. childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom);
  152. } else {
  153. childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
  154. }
  155. }
  156. Visible = Child.Visible;
  157. } else {
  158. Visible = false;
  159. }
  160. }
  161. /// <inheritdoc/>
  162. public override void Add (View view)
  163. {
  164. if (Child != null) {
  165. Child = null;
  166. }
  167. Child = view;
  168. }
  169. /// <inheritdoc/>
  170. public override void Remove (View view)
  171. {
  172. if (view == childContentView) {
  173. base.Remove (view);
  174. return;
  175. }
  176. childContentView.Remove (view);
  177. if (Child != null) {
  178. Child = null;
  179. }
  180. }
  181. /// <inheritdoc/>
  182. public override void RemoveAll ()
  183. {
  184. if (Child != null) {
  185. Child = null;
  186. }
  187. }
  188. /// <inheritdoc/>
  189. public override void Redraw (Rect bounds)
  190. {
  191. if (!NeedDisplay.IsEmpty) {
  192. Driver.SetAttribute (Child.GetNormalColor ());
  193. Border.DrawContent ();
  194. }
  195. var savedClip = childContentView.ClipToBounds ();
  196. childContentView.Redraw (childContentView.Bounds);
  197. Driver.Clip = savedClip;
  198. ClearLayoutNeeded ();
  199. ClearNeedsDisplay ();
  200. }
  201. }
  202. }