SplitContainer.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using System;
  2. using Terminal.Gui.Graphs;
  3. using static Terminal.Gui.Dim;
  4. namespace Terminal.Gui {
  5. public class SplitContainer : View {
  6. private LineView splitterLine = new LineView ();
  7. private bool panel1Collapsed;
  8. private bool panel2Collapsed;
  9. private Pos splitterDistance = Pos.Percent (50);
  10. private Orientation orientation = Orientation.Vertical;
  11. public SplitContainer ()
  12. {
  13. // Default to a border of 1 so that View looks nice
  14. Border = new Border ();
  15. this.Add (splitterLine);
  16. this.Add (Panel1);
  17. this.Add (Panel2);
  18. Setup ();
  19. CanFocus = false;
  20. // TODO: Actually respect collapsed statuses
  21. }
  22. private void Setup ()
  23. {
  24. // TODO: Enforce minimum sizes
  25. splitterLine.Orientation = Orientation;
  26. if(panel1Collapsed || panel2Collapsed) {
  27. SetupForCollapsedPanel ();
  28. }
  29. else {
  30. SetupForNormal ();
  31. }
  32. }
  33. private void SetupForNormal ()
  34. {
  35. // Ensure all our component views are here
  36. // (e.g. if we are transitioning from a collapsed state)
  37. if (!this.Subviews.Contains (splitterLine)) {
  38. this.Add (splitterLine);
  39. }
  40. if (!this.Subviews.Contains (Panel1)) {
  41. this.Add (Panel1);
  42. }
  43. if (!this.Subviews.Contains (Panel2)) {
  44. this.Add (Panel2);
  45. }
  46. switch (Orientation) {
  47. case Orientation.Horizontal:
  48. splitterLine.X = 0;
  49. splitterLine.Y = splitterDistance;
  50. splitterLine.Width = Dim.Fill ();
  51. splitterLine.Height = 1;
  52. splitterLine.LineRune = Driver.HLine;
  53. this.Panel1.X = 0;
  54. this.Panel1.Y = 0;
  55. this.Panel1.Width = Dim.Fill ();
  56. this.Panel1.Height = new DimFunc (() =>
  57. splitterDistance.Anchor (Bounds.Height) - 1);
  58. this.Panel2.Y = Pos.Bottom (splitterLine) + 1;
  59. this.Panel2.X = 0;
  60. this.Panel2.Width = Dim.Fill ();
  61. this.Panel2.Height = Dim.Fill ();
  62. break;
  63. case Orientation.Vertical:
  64. splitterLine.X = splitterDistance;
  65. splitterLine.Y = 0;
  66. splitterLine.Width = 1;
  67. splitterLine.Height = Dim.Fill ();
  68. splitterLine.LineRune = Driver.VLine;
  69. this.Panel1.X = 0;
  70. this.Panel1.Y = 0;
  71. this.Panel1.Height = Dim.Fill ();
  72. this.Panel1.Width = new DimFunc (() =>
  73. splitterDistance.Anchor (Bounds.Width) - 1);
  74. this.Panel2.X = Pos.Right (splitterLine) + 1;
  75. this.Panel2.Y = 0;
  76. this.Panel2.Width = Dim.Fill ();
  77. this.Panel2.Height = Dim.Fill ();
  78. break;
  79. default: throw new ArgumentOutOfRangeException (nameof (orientation));
  80. };
  81. }
  82. private void SetupForCollapsedPanel ()
  83. {
  84. View toRemove = panel1Collapsed ? Panel1 : Panel2;
  85. View toFullSize = panel1Collapsed ? Panel2 : Panel1;
  86. if (this.Subviews.Contains (splitterLine)) {
  87. this.Subviews.Remove (splitterLine);
  88. }
  89. if (this.Subviews.Contains(toRemove)) {
  90. this.Subviews.Remove (toRemove);
  91. }
  92. if(!this.Subviews.Contains(toFullSize)) {
  93. this.Add (toFullSize);
  94. }
  95. toFullSize.X = 0;
  96. toFullSize.Y = 0;
  97. toFullSize.Width = Dim.Fill ();
  98. toFullSize.Height = Dim.Fill ();
  99. }
  100. /// <summary>
  101. /// The left or top panel of the <see cref="SplitContainer"/>
  102. /// (depending on <see cref="Orientation"/>). Add panel contents
  103. /// to this <see cref="View"/> using <see cref="View.Add(View)"/>.
  104. /// </summary>
  105. public View Panel1 { get; } = new View ();
  106. /// <summary>
  107. /// TODO: not implemented yet
  108. /// </summary>
  109. public int Panel1MinSize { get; set; }
  110. /// <summary>
  111. /// This determines if <see cref="Panel1"/> is collapsed.
  112. /// </summary>
  113. public bool Panel1Collapsed {
  114. get { return panel1Collapsed; }
  115. set {
  116. panel1Collapsed = value;
  117. if (value && panel2Collapsed) {
  118. panel2Collapsed = false;
  119. }
  120. Setup ();
  121. }
  122. }
  123. /// <summary>
  124. /// The right or bottom panel of the <see cref="SplitContainer"/>
  125. /// (depending on <see cref="Orientation"/>). Add panel contents
  126. /// to this <see cref="View"/> using <see cref="View.Add(View)"/>
  127. /// </summary>
  128. public View Panel2 { get; } = new View ();
  129. /// <summary>
  130. /// TODO: not implemented yet
  131. /// </summary>
  132. public int Panel2MinSize { get; set; }
  133. /// <summary>
  134. /// This determines if <see cref="Panel2"/> is collapsed.
  135. /// </summary>
  136. public bool Panel2Collapsed {
  137. get { return panel2Collapsed; }
  138. set {
  139. panel2Collapsed = value;
  140. if (value && panel1Collapsed) {
  141. panel1Collapsed = false;
  142. }
  143. Setup ();
  144. }
  145. }
  146. public Orientation Orientation {
  147. get { return orientation; }
  148. set {
  149. orientation = value;
  150. Setup ();
  151. }
  152. }
  153. public Pos SplitterDistance {
  154. get { return splitterDistance; }
  155. set {
  156. splitterDistance = value;
  157. Setup ();
  158. }
  159. }
  160. }
  161. }