PanelView.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 ?? child?.Frame.X,
  63. Y = child?.Y ?? child?.Frame.Y,
  64. Width = child?.Width ?? child?.Frame.Width,
  65. Height = child?.Height ?? child?.Frame.Height
  66. };
  67. if (child == null) {
  68. Visible = false;
  69. return;
  70. }
  71. if (child?.Border != null) {
  72. Border = child.Border;
  73. } else {
  74. if (Border == null) {
  75. Border = new Border ();
  76. }
  77. Child.Border = Border;
  78. }
  79. Border.Child = childContentView;
  80. if (!child.IsInitialized) {
  81. child.Initialized += Child_Initialized;
  82. }
  83. childContentView.Add (Child);
  84. }
  85. }
  86. /// <inheritdoc />
  87. public override Border Border {
  88. get => base.Border;
  89. set {
  90. if (base.Border?.Child != null && value.Child == null) {
  91. value.Child = base.Border.Child;
  92. }
  93. base.Border = value;
  94. if (value == null) {
  95. return;
  96. }
  97. Border.BorderChanged += Border_BorderChanged;
  98. if (Child != null && (Child?.Border == null || Child?.Border != value)) {
  99. if (Child?.Border == null) {
  100. Child.Border = new Border ();
  101. }
  102. Child.Border = Border;
  103. Child.Border.BorderChanged += Border_BorderChanged;
  104. }
  105. AdjustContainer ();
  106. }
  107. }
  108. private void Child_Initialized (object sender, EventArgs e)
  109. {
  110. savedPanel = new SavedPosDim () {
  111. X = X,
  112. Y = Y,
  113. Width = Width,
  114. Height = Height
  115. };
  116. AdjustContainer ();
  117. Child.Initialized -= Child_Initialized;
  118. }
  119. private void Border_BorderChanged (Border obj)
  120. {
  121. AdjustContainer ();
  122. }
  123. private void AdjustContainer ()
  124. {
  125. if (Child?.IsInitialized == true) {
  126. if (Child?.Border != null && Child.Border != Border) {
  127. Border = Child.Border;
  128. }
  129. var borderLength = Child.Border.DrawMarginFrame ? 1 : 0;
  130. var sumPadding = Child.Border.GetSumThickness ();
  131. var effect3DOffset = Child.Border.Effect3D ? Child.Border.Effect3DOffset : new Point ();
  132. if (!UsePanelFrame) {
  133. X = savedPanel.X;
  134. childContentView.X = borderLength + sumPadding.Left;
  135. Y = savedPanel.Y;
  136. childContentView.Y = borderLength + sumPadding.Top;
  137. if (savedChild.Width is Dim.DimFill) {
  138. var margin = -savedChild.Width.Anchor (0);
  139. Width = Dim.Fill (margin);
  140. childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right);
  141. } else {
  142. var savedLayout = LayoutStyle;
  143. LayoutStyle = LayoutStyle.Absolute;
  144. Width = savedChild.X.Anchor (0) + savedChild.Width + (2 * borderLength) + sumPadding.Right + sumPadding.Left;
  145. LayoutStyle = savedLayout;
  146. childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
  147. }
  148. if (savedChild.Height is Dim.DimFill) {
  149. var margin = -savedChild.Height.Anchor (0);
  150. Height = Dim.Fill (margin);
  151. childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom);
  152. } else {
  153. var savedLayout = LayoutStyle;
  154. LayoutStyle = LayoutStyle.Absolute;
  155. Height = savedChild.Y.Anchor (0) + savedChild.Height + (2 * borderLength) + sumPadding.Bottom + sumPadding.Top;
  156. LayoutStyle = savedLayout;
  157. childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
  158. }
  159. } else {
  160. X = savedPanel.X - (effect3DOffset.X < 0 ? effect3DOffset.X : 0);
  161. childContentView.X = borderLength + sumPadding.Left;
  162. Y = savedPanel.Y - (effect3DOffset.Y < 0 ? effect3DOffset.Y : 0);
  163. childContentView.Y = borderLength + sumPadding.Top;
  164. Width = savedPanel.Width;
  165. Height = savedPanel.Height;
  166. if (Width is Dim.DimFill) {
  167. var margin = -savedPanel.Width.Anchor (0) +
  168. (effect3DOffset.X > 0 ? effect3DOffset.X : 0);
  169. Width = Dim.Fill (margin);
  170. childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right +
  171. (effect3DOffset.X > 0 ? effect3DOffset.X : 0));
  172. } else {
  173. childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
  174. }
  175. if (Height is Dim.DimFill) {
  176. var margin = -savedPanel.Height.Anchor (0) +
  177. (effect3DOffset.Y > 0 ? effect3DOffset.Y : 0);
  178. Height = Dim.Fill (margin);
  179. childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom +
  180. (effect3DOffset.Y > 0 ? effect3DOffset.Y : 0));
  181. } else {
  182. childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
  183. }
  184. }
  185. Visible = Child.Visible;
  186. } else {
  187. Visible = false;
  188. }
  189. }
  190. /// <inheritdoc/>
  191. public override void Add (View view)
  192. {
  193. if (Child != null) {
  194. Child = null;
  195. }
  196. Child = view;
  197. }
  198. /// <inheritdoc/>
  199. public override void Remove (View view)
  200. {
  201. if (view == childContentView) {
  202. base.Remove (view);
  203. return;
  204. }
  205. childContentView.Remove (view);
  206. if (Child != null) {
  207. Child = null;
  208. }
  209. }
  210. /// <inheritdoc/>
  211. public override void RemoveAll ()
  212. {
  213. if (Child != null) {
  214. Child = null;
  215. }
  216. }
  217. /// <inheritdoc/>
  218. public override void Redraw (Rect bounds)
  219. {
  220. if (!NeedDisplay.IsEmpty) {
  221. Driver.SetAttribute (Child.GetNormalColor ());
  222. Child.Border.DrawContent (Border.Child);
  223. }
  224. var savedClip = childContentView.ClipToBounds ();
  225. childContentView.Redraw (childContentView.Bounds);
  226. Driver.Clip = savedClip;
  227. ClearLayoutNeeded ();
  228. ClearNeedsDisplay ();
  229. }
  230. }
  231. }