Browse Source

Move panel splitting logic (SplitLeft/SplitRight) to main SplitContainer class

tznind 2 years ago
parent
commit
8497dd7829
2 changed files with 105 additions and 36 deletions
  1. 80 0
      Terminal.Gui/Views/SplitContainer.cs
  2. 25 36
      UICatalog/Scenarios/SplitContainerNesting.cs

+ 80 - 0
Terminal.Gui/Views/SplitContainer.cs

@@ -245,6 +245,81 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		/// <summary>
+		/// Converts <see cref="Panel1"/> from a regular <see cref="View"/>
+		/// container to a new nested <see cref="SplitContainer"/>.  If <see cref="Panel1"/>
+		/// is already a <see cref="SplitContainer"/> then returns false.
+		/// </summary>
+		/// <remarks>After successful splitting, the returned container's <see cref="Panel1"/> 
+		/// will contain the original content (if any) while <see cref="Panel2"/> will be empty and available
+		/// for adding to.</remarks>
+		/// <param name="result">The new <see cref="SplitContainer"/> now showing in 
+		/// <see cref="Panel1"/> or the existing one if it was already been converted before.</param>
+		/// <returns><see langword="true"/> if a <see cref="View"/> was converted to a new nested
+		/// <see cref="SplitContainer"/>.  <see langword="false"/> if it was already a nested
+		/// <see cref="SplitContainer"/></returns>
+		public bool TrySplitPanel1(out SplitContainer result)
+		{
+			return TrySplit (
+				() => this.Panel1,
+				(n) => this.Panel1 = n,
+				out result);
+		}
+
+		/// <summary>
+		/// Converts <see cref="Panel2"/> from a regular <see cref="View"/>
+		/// container to a new nested <see cref="SplitContainer"/>.  If <see cref="Panel2"/>
+		/// is already a <see cref="SplitContainer"/> then returns false.
+		/// </summary>
+		/// <remarks>After successful splitting, the returned container's <see cref="Panel1"/> 
+		/// will contain the original content (if any) while <see cref="Panel2"/> will be empty and available
+		/// for adding to.</remarks>
+		/// <param name="result">The new <see cref="SplitContainer"/> now showing in 
+		/// <see cref="Panel2"/> or the existing one if it was already been converted before.</param>
+		/// <returns><see langword="true"/> if a <see cref="View"/> was converted to a new nested
+		/// <see cref="SplitContainer"/>.  <see langword="false"/> if it was already a nested
+		/// <see cref="SplitContainer"/></returns>
+		public bool TrySplitPanel2 (out SplitContainer result)
+		{
+			return TrySplit (
+				() => this.Panel2,
+				(n) => this.Panel2 = n,
+				out result);
+		}
+		private bool TrySplit(
+			Func<View> getter,
+			Action<SplitContainer> newSplitContainerSetter,
+			out SplitContainer result)
+		{
+			// Get the current panel contents (Panel1 or Panel2)
+			var toMove = getter();
+
+			if (toMove is SplitContainer existing) {
+				result = existing;
+				return false;
+			}
+
+			var newContainer = new SplitContainer {
+				Width = Dim.Fill (),
+				Height = Dim.Fill (),
+			};
+
+			// Replace current child contents 
+			Remove (toMove);
+			Add (newContainer);
+
+			// Set Panel (1 or 2) to the new container
+			newSplitContainerSetter(newContainer);
+
+			// Set the original content into the first panel of the new container
+			newContainer.Add (toMove);
+			newContainer.Panel1 = toMove;
+
+			result = newContainer;
+			return true;
+		}
+
+		
 		private List<SplitContainerLineView> GetAllChildSplitContainerLineViewRecursively (View v)
 		private List<SplitContainerLineView> GetAllChildSplitContainerLineViewRecursively (View v)
 		{
 		{
 			var lines = new List<SplitContainerLineView>();
 			var lines = new List<SplitContainerLineView>();
@@ -372,6 +447,11 @@ namespace Terminal.Gui {
 
 
 			var availableSpace = Orientation == Orientation.Horizontal ? this.Bounds.Height : this.Bounds.Width;
 			var availableSpace = Orientation == Orientation.Horizontal ? this.Bounds.Height : this.Bounds.Width;
 
 
+			// we probably haven't finished layout even if IsInitialized is true :(
+			if(availableSpace <= 0) {
+				return pos;
+			}
+
 			var idealPosition = pos.Anchor (availableSpace);
 			var idealPosition = pos.Anchor (availableSpace);
 
 
 			// bad position because not enough space for Panel1
 			// bad position because not enough space for Panel1

+ 25 - 36
UICatalog/Scenarios/SplitContainerNesting.cs

@@ -97,7 +97,7 @@ namespace UICatalog.Scenarios {
 
 
 			var root = CreateSplitContainer (1,startHorizontal ?
 			var root = CreateSplitContainer (1,startHorizontal ?
 					Terminal.Gui.Graphs.Orientation.Horizontal :
 					Terminal.Gui.Graphs.Orientation.Horizontal :
-					Terminal.Gui.Graphs.Orientation.Vertical, false);
+					Terminal.Gui.Graphs.Orientation.Vertical);
 
 
 			root.Panel1.Add (CreateTextView (1));
 			root.Panel1.Add (CreateTextView (1));
 			root.Panel2.Add (CreateTextView (2));
 			root.Panel2.Add (CreateTextView (2));
@@ -142,11 +142,11 @@ namespace UICatalog.Scenarios {
 			}
 			}
 
 
 			if (!(to.Panel1 is SplitContainer)) {
 			if (!(to.Panel1 is SplitContainer)) {
-				SplitLeft (to);
+				Split(to,true);
 			}
 			}
 
 
 			if (!(to.Panel2 is SplitContainer)) {
 			if (!(to.Panel2 is SplitContainer)) {
-				SplitRight (to);				
+				Split(to,false);				
 			}
 			}
 
 
 			if (to.Panel1 is SplitContainer && to.Panel2 is SplitContainer) {
 			if (to.Panel1 is SplitContainer && to.Panel2 is SplitContainer) {
@@ -156,47 +156,42 @@ namespace UICatalog.Scenarios {
 			}
 			}
 
 
 		}
 		}
-		private void SplitLeft(SplitContainer to)
+		private void Split(SplitContainer to, bool left)
 		{
 		{
 			if (panelsCreated == panelsToCreate) {
 			if (panelsCreated == panelsToCreate) {
 				return;
 				return;
 			}
 			}
 
 
-			// we can split Panel1
-			var tv = (TextView)to.Panel1.Subviews.Single ();
-
-			panelsCreated++;
-
-			var newContainer = CreateSplitContainer (panelsCreated, to.Orientation, true);
+			SplitContainer newContainer;
 
 
-			to.Remove (to.Panel1);
-			to.Add (newContainer);
-			to.Panel1 = newContainer;
+			if (left) {
+				to.TrySplitPanel1 (out newContainer);
 
 
-			newContainer.Panel1.Add (tv);
-			newContainer.Panel2.Add (CreateTextView (panelsCreated));
-		}
-		private void SplitRight(SplitContainer to)
-		{
-			if (panelsCreated == panelsToCreate) {
-				return;
+			}
+			else {
+				to.TrySplitPanel2 (out newContainer);
 			}
 			}
 
 
-			// we can split Panel2
-			var tv = (TextView)to.Panel2.Subviews.Single ();
 			panelsCreated++;
 			panelsCreated++;
 
 
-			var newContainer = CreateSplitContainer (panelsCreated, to.Orientation, true);
+			// we can split Panel1
+			SetPanelTitles (newContainer, panelsCreated);
 
 
-			to.Remove (to.Panel2);
-			to.Add (newContainer);
-			to.Panel2 = newContainer;
+			// Flip orientation
+			newContainer.Orientation = newContainer.Orientation == Orientation.Vertical ?
+				Orientation.Horizontal :
+				Orientation.Vertical;
+			
+			newContainer.Panel2.Add (CreateTextView (panelsCreated));
+		}
 
 
-			newContainer.Panel2.Add (tv);
-			newContainer.Panel1.Add (CreateTextView (panelsCreated));
+		private void SetPanelTitles (SplitContainer container, int containerNumber)
+		{
+			container.Panel1Title = cbTitles.Checked ? $"Panel {containerNumber}" : string.Empty;
+			container.Panel2Title = cbTitles.Checked ? $"Panel {containerNumber + 1}" : string.Empty;
 		}
 		}
 
 
-		private SplitContainer CreateSplitContainer (int titleNumber, Orientation orientation, bool flip)
+		private SplitContainer CreateSplitContainer (int titleNumber, Orientation orientation)
 		{
 		{
 			var toReturn = new SplitContainer {
 			var toReturn = new SplitContainer {
 				Width = Dim.Fill (),
 				Width = Dim.Fill (),
@@ -205,13 +200,7 @@ namespace UICatalog.Scenarios {
 				Orientation = orientation
 				Orientation = orientation
 			};
 			};
 
 
-			if (flip) {
-				toReturn.Orientation = toReturn.Orientation == Orientation.Vertical ?
-					Orientation.Horizontal :
-					Orientation.Vertical;
-			}
-			toReturn.Panel1Title = cbTitles.Checked ? $"Panel {titleNumber}" : string.Empty;
-			toReturn.Panel2Title = cbTitles.Checked ? $"Panel {titleNumber+1}" : string.Empty;
+			SetPanelTitles (toReturn, titleNumber);
 
 
 			return toReturn;
 			return toReturn;
 		}
 		}