Browse Source

made titles work; refactored; fixed bugs

Charlie Kindel 2 years ago
parent
commit
74524a280a
3 changed files with 229 additions and 254 deletions
  1. 175 178
      Terminal.Gui/Views/SplitContainer.cs
  2. 42 38
      UICatalog/Scenarios/SplitContainerExample.cs
  3. 12 38
      UICatalog/UICatalog.cs

+ 175 - 178
Terminal.Gui/Views/SplitContainer.cs

@@ -1,4 +1,8 @@
-using System;
+using NStack;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
 using Terminal.Gui.Graphs;
 
 namespace Terminal.Gui {
@@ -7,15 +11,12 @@ namespace Terminal.Gui {
 	/// A <see cref="View"/> consisting of a moveable bar that divides
 	/// the display area into 2 resizeable panels.
 	/// </summary>
-	public class SplitContainer : View {
+	public class SplitContainer : FrameView {
 
-		private LineView splitterLine;
-		private bool panel1Collapsed;
-		private bool panel2Collapsed;
+		private SplitContainerLineView splitterLine;
 		private Pos splitterDistance = Pos.Percent (50);
 		private Orientation orientation = Orientation.Vertical;
-		private Pos panel1MinSize = 0;
-		private Pos panel2MinSize = 0;
+		private SplitterPanel [] splitterPanels = { new SplitterPanel(), new SplitterPanel() };
 
 		/// <summary>
 		/// Creates a new instance of the SplitContainer class.
@@ -24,34 +25,29 @@ namespace Terminal.Gui {
 		{
 			splitterLine = new SplitContainerLineView (this);
 
-			this.Add (Panel1);
+			this.Add (splitterPanels [0]);
 			this.Add (splitterLine);
-			this.Add (Panel2);
+			this.Add (splitterPanels [1]);
 
-			Setup ();
+			LayoutStarted += (e) => Setup ();
 
 			CanFocus = false;
 		}
 
 		/// <summary>
-		/// The left or top panel of the <see cref="SplitContainer"/>
-		/// (depending on <see cref="Orientation"/>).  Add panel contents
-		/// to this <see cref="View"/> using <see cref="View.Add(View)"/>.
+		/// Gets the list of panels. Currently only supports 2 panels.
+		/// <remarks>
+		/// <para>
+		/// The first item in the list is either the leftmost or topmost panel;
+		/// the second item is either the rightmost or bottom panel 
+		/// (depending on <see cref="Orientation"/>)
+		/// </para>
+		/// <para>
+		/// Add panel contents to the <see cref="SplitterPanel"/>s using <see cref="View.Add(View)"/>.
+		/// </para>
+		/// </remarks>
 		/// </summary>
-		public View Panel1 { get; } = new View ();
-
-		/// <summary>
-		/// The minimum size <see cref="Panel1"/> can be when adjusting
-		/// <see cref="SplitterDistance"/>.
-		/// </summary>
-		public Pos Panel1MinSize {
-			get { return panel1MinSize; }
-			set {
-				panel1MinSize = value;
-				Setup ();
-			}
-		}
-
+		public List<SplitterPanel> Panels { get { return splitterPanels.ToList(); } }
 
 		/// <summary>
 		/// Invoked when the <see cref="SplitterDistance"/> is changed
@@ -66,59 +62,6 @@ namespace Terminal.Gui {
 			SplitterMoved?.Invoke (this, new SplitterEventArgs (this, splitterDistance));
 		}
 
-
-		/// <summary>
-		/// This determines if <see cref="Panel1"/> is collapsed.
-		/// </summary>
-		public bool Panel1Collapsed {
-			get { return panel1Collapsed; }
-			set {
-				panel1Collapsed = value;
-				if (value && panel2Collapsed) {
-					panel2Collapsed = false;
-				}
-
-				Setup ();
-			}
-
-		}
-
-		/// <summary>
-		/// The right or bottom panel of the <see cref="SplitContainer"/>
-		/// (depending on <see cref="Orientation"/>).  Add panel contents
-		/// to this <see cref="View"/> using <see cref="View.Add(View)"/>
-		/// </summary>
-		public View Panel2 { get; } = new View ();
-
-		/// <summary>
-		/// The minimum size <see cref="Panel2"/> can be when adjusting
-		/// <see cref="SplitterDistance"/>.
-		/// </summary>
-		public Pos Panel2MinSize {
-			get {
-				return panel2MinSize;
-			}
-
-			set {
-				panel2MinSize = value;
-				Setup ();
-			}
-		}
-
-		/// <summary>
-		/// This determines if <see cref="Panel2"/> is collapsed.
-		/// </summary>
-		public bool Panel2Collapsed {
-			get { return panel2Collapsed; }
-			set {
-				panel2Collapsed = value;
-				if (value && panel1Collapsed) {
-					panel1Collapsed = false;
-				}
-				Setup ();
-			}
-		}
-
 		/// <summary>
 		/// Orientation of the dividing line (Horizontal or Vertical).
 		/// </summary>
@@ -130,7 +73,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-
 		/// <summary>
 		/// <para>Distance Horizontally or Vertically to the splitter line when
 		/// neither panel is collapsed.
@@ -164,85 +106,103 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (ColorScheme.Normal);
 			Clear ();
 			base.Redraw (bounds);
+
+			// Draw Splitter over Border (to get Ts)
+			if (splitterLine.Visible) {
+				splitterLine.Redraw (bounds);
+			}
+
+			// Draw Titles over Border
+			var screen = ViewToScreen (bounds);
+			if (splitterPanels[0].Visible && splitterPanels[0].Title.Length > 0) {
+				Driver.SetAttribute (splitterPanels[0].HasFocus ? ColorScheme.HotNormal : ColorScheme.Normal);
+				Driver.DrawWindowTitle (new Rect (screen.X, screen.Y, splitterPanels[0].Frame.Width, 1), splitterPanels[0].Title, 0, 0, 0, 0);
+			}
+			if (splitterLine.Visible) {
+				screen = ViewToScreen (splitterLine.Frame);
+			} else {
+				screen.X--;
+				screen.Y--;
+			}
+			if (Orientation == Orientation.Horizontal) {
+				if (splitterPanels[1].Visible && splitterPanels[1].Title.Length > 0) {
+
+					Driver.SetAttribute (splitterPanels[1].HasFocus ? ColorScheme.HotNormal : ColorScheme.Normal);
+					Driver.DrawWindowTitle (new Rect (screen.X + 1, screen.Y + 1, splitterPanels[1].Bounds.Width, 1), splitterPanels[1].Title, 0, 0, 0, 0);
+				}
+			} else {
+				if (splitterPanels[1].Visible && splitterPanels[1].Title.Length > 0) {
+					Driver.SetAttribute (splitterPanels[1].HasFocus ? ColorScheme.HotNormal : ColorScheme.Normal);
+					Driver.DrawWindowTitle (new Rect (screen.X + 1, screen.Y + 1, splitterPanels[1].Bounds.Width, 1), splitterPanels[1].Title, 0, 0, 0, 0);
+				}
+			}
 		}
 
 		private void Setup ()
 		{
 			splitterLine.Orientation = Orientation;
+			splitterLine.Text = splitterPanels[1].Title;
+
+			if (!splitterPanels[0].Visible || !splitterPanels[1].Visible) {
+				View toFullSize = !splitterPanels[0].Visible ? splitterPanels[1] : splitterPanels[0];
 
-			if (panel1Collapsed || panel2Collapsed) {
-				SetupForCollapsedPanel ();
+				splitterLine.Visible = false;
+
+				toFullSize.X = 0;
+				toFullSize.Y = 0;
+				toFullSize.Width = Dim.Fill ();
+				toFullSize.Height = Dim.Fill ();
 			} else {
-				SetupForNormal ();
-			}
-		}
+				splitterLine.Visible = true;
 
-		private void SetupForNormal ()
-		{
-			// Ensure all our component views are here
-			// (e.g. if we are transitioning from a collapsed state)
+				splitterDistance = BoundByMinimumSizes (splitterDistance);
 
-			if (!this.Subviews.Contains (splitterLine)) {
-				this.Add (splitterLine);
-			}
-			if (!this.Subviews.Contains (Panel1)) {
-				this.Add (Panel1);
-			}
-			if (!this.Subviews.Contains (Panel2)) {
-				this.Add (Panel2);
-			}
+				splitterPanels[0].X = 0;
+				splitterPanels[0].Y = 0;
+
+				splitterPanels[1].Width = Dim.Fill ();
+				splitterPanels[1].Height = Dim.Fill ();
+
+				switch (Orientation) {
+				case Orientation.Horizontal:
+					splitterLine.X = -1;
+					splitterLine.Y = splitterDistance;
+					splitterLine.Width = Dim.Fill () + 1;
+					splitterLine.Height = 1;
+					splitterLine.LineRune = Driver.HLine;
 
-			splitterDistance = BoundByMinimumSizes (splitterDistance);
-
-			switch (Orientation) {
-			case Orientation.Horizontal:
-				splitterLine.X = 0;
-				splitterLine.Y = splitterDistance;
-				splitterLine.Width = Dim.Fill ();
-				splitterLine.Height = 1;
-				splitterLine.LineRune = Driver.HLine;
-
-				this.Panel1.X = 0;
-				this.Panel1.Y = 0;
-				this.Panel1.Width = Dim.Fill ();
-				this.Panel1.Height = new Dim.DimFunc (() =>
-					splitterDistance.Anchor (Bounds.Height));
-
-				this.Panel2.Y = Pos.Bottom (splitterLine);
-				this.Panel2.X = 0;
-				this.Panel2.Width = Dim.Fill ();
-				this.Panel2.Height = Dim.Fill ();
-				break;
-
-			case Orientation.Vertical:
-				splitterLine.X = splitterDistance;
-				splitterLine.Y = 0;
-				splitterLine.Width = 1;
-				splitterLine.Height = Dim.Fill ();
-				splitterLine.LineRune = Driver.VLine;
-
-				this.Panel1.X = 0;
-				this.Panel1.Y = 0;
-				this.Panel1.Height = Dim.Fill ();
-				this.Panel1.Width = new Dim.DimFunc (() =>
-					splitterDistance.Anchor (Bounds.Width));
-
-				this.Panel2.X = Pos.Right (splitterLine);
-				this.Panel2.Y = 0;
-				this.Panel2.Width = Dim.Fill ();
-				this.Panel2.Height = Dim.Fill ();
-				break;
-
-			default: throw new ArgumentOutOfRangeException (nameof (orientation));
-			};
-
-			this.LayoutSubviews ();
+					splitterPanels[0].Width = Dim.Fill ();
+					splitterPanels[0].Height = new Dim.DimFunc (() =>
+					splitterDistance.Anchor (Bounds.Height)) - 1;
+
+					splitterPanels[1].Y = Pos.Bottom (splitterLine);
+					splitterPanels[1].X = 0;
+					break;
+
+				case Orientation.Vertical:
+					splitterLine.X = splitterDistance;
+					splitterLine.Y = -1;
+					splitterLine.Width = 1;
+					splitterLine.Height = Dim.Fill () + 1;
+					splitterLine.LineRune = Driver.VLine;
+
+					splitterPanels[0].Height = Dim.Fill ();
+					splitterPanels[0].Width = new Dim.DimFunc (() =>
+					splitterDistance.Anchor (Bounds.Width)) - 1;
+
+					splitterPanels[1].X = Pos.Right (splitterLine);
+					splitterPanels[1].Y = 0;
+					break;
+
+				default: throw new ArgumentOutOfRangeException (nameof (orientation));
+				};
+			}
 		}
 
 		/// <summary>
 		/// Considers <paramref name="pos"/> as a candidate for <see cref="splitterDistance"/>
-		/// then either returns (if valid) or returns adjusted if invalid with respect to
-		/// <see cref="Panel1MinSize"/> or <see cref="Panel2MinSize"/>.
+		/// then either returns (if valid) or returns adjusted if invalid with respect to the 
+		/// <see cref="SplitterPanel.MinSize"/> of the panels.
 		/// </summary>
 		/// <param name="pos"></param>
 		/// <returns></returns>
@@ -258,48 +218,70 @@ namespace Terminal.Gui {
 			var availableSpace = Orientation == Orientation.Horizontal ? this.Bounds.Height : this.Bounds.Width;
 
 			var idealPosition = pos.Anchor (availableSpace);
-			var panel1MinSizeAbs = panel1MinSize.Anchor (availableSpace);
-			var panel2MinSizeAbs = panel2MinSize.Anchor (availableSpace);
 
-			// bad position because not enough space for panel1
-			if (idealPosition < panel1MinSizeAbs) {
+			// bad position because not enough space for splitterPanels[0]
+			if (idealPosition < splitterPanels [0].MinSize.Anchor (availableSpace)) {
 
 				// TODO: we should preserve Absolute/Percent status here not just force it to absolute
-				return (Pos)Math.Min (panel1MinSizeAbs, availableSpace);
+				return (Pos)Math.Min (splitterPanels [0].MinSize.Anchor (availableSpace), availableSpace);
 			}
 
-			// bad position because not enough space for panel2
-			if (availableSpace - idealPosition <= panel2MinSizeAbs) {
+			// bad position because not enough space for splitterPanels[1]
+			if (availableSpace - idealPosition <= splitterPanels [1].MinSize.Anchor (availableSpace)) {
 
 				// TODO: we should preserve Absolute/Percent status here not just force it to absolute
 
 				// +1 is to allow space for the splitter
-				return (Pos)Math.Max (availableSpace - (panel2MinSizeAbs + 1), 0);
+				return (Pos)Math.Max (availableSpace - (splitterPanels [1].MinSize.Anchor (availableSpace) + 1), 0);
 			}
 
 			// this splitter position is fine, there is enough space for everyone
 			return pos;
 		}
 
-		private void SetupForCollapsedPanel ()
-		{
-			View toRemove = panel1Collapsed ? Panel1 : Panel2;
-			View toFullSize = panel1Collapsed ? Panel2 : Panel1;
+		/// <summary>
+		/// A panel within a <see cref="SplitterPanel"/>. 
+		/// </summary>
+		public class SplitterPanel : View {
+			Pos minSize = 2;
 
-			if (this.Subviews.Contains (splitterLine)) {
-				this.Remove (splitterLine);
+			/// <summary>
+			/// Gets or sets the minimum size for the panel.
+			/// </summary>
+			public Pos MinSize { get => minSize;
+				set { 
+					minSize = value;
+					SuperView?.SetNeedsLayout ();
+				} 
 			}
-			if (this.Subviews.Contains (toRemove)) {
-				this.Remove (toRemove);
+
+			ustring title = ustring.Empty;
+			/// <summary>
+			/// The title to be displayed for this <see cref="SplitterPanel"/>. The title will be rendered 
+			/// on the top border aligned to the left of the panel.
+			/// </summary>
+			/// <value>The title.</value>
+			public ustring Title {
+				get => title;
+				set {
+					title = value;
+					SetNeedsDisplay ();
+				}
 			}
-			if (!this.Subviews.Contains (toFullSize)) {
-				this.Add (toFullSize);
+
+			/// <inheritdoc/>
+			public override void Redraw (Rect bounds)
+			{
+				Driver.SetAttribute (ColorScheme.Normal);
+				base.Redraw (bounds);
 			}
 
-			toFullSize.X = 0;
-			toFullSize.Y = 0;
-			toFullSize.Width = Dim.Fill ();
-			toFullSize.Height = Dim.Fill ();
+			/// <inheritdoc/>
+			public override void OnVisibleChanged ()
+			{
+				base.OnVisibleChanged ();
+				SuperView?.SetNeedsLayout ();
+			}
 		}
 
 		private class SplitContainerLineView : LineView {
@@ -309,7 +291,6 @@ namespace Terminal.Gui {
 			Pos dragOrignalPos;
 			Point? moveRuneRenderLocation;
 
-			// TODO: Make focusable and allow moving with keyboard
 			public SplitContainerLineView (SplitContainer parent)
 			{
 				CanFocus = true;
@@ -337,10 +318,19 @@ namespace Terminal.Gui {
 				AddKeyBinding (Key.CursorLeft, Command.Left);
 				AddKeyBinding (Key.CursorUp, Command.LineUp);
 				AddKeyBinding (Key.CursorDown, Command.LineDown);
-			}
 
+				LayoutStarted += (e) => {
+					moveRuneRenderLocation = null;
+					if (Orientation == Orientation.Horizontal) {
+						StartingAnchor = Driver.LeftTee;
+						EndingAnchor = Driver.RightTee;
+					} else {
+						StartingAnchor = Driver.TopTee;
+						EndingAnchor = Driver.BottomTee;
+					}
+				};
+			}
 
-			///<inheritdoc/>
 			public override bool ProcessKey (KeyEvent kb)
 			{
 				if (!CanFocus || !HasFocus) {
@@ -353,10 +343,13 @@ namespace Terminal.Gui {
 
 				return base.ProcessKey (kb);
 			}
+
 			public override void PositionCursor ()
 			{
 				base.PositionCursor ();
-				Move (this.Bounds.Width / 2, this.Bounds.Height / 2);
+				var location = moveRuneRenderLocation ??
+					new Point (Bounds.Width / 2, Bounds.Height / 2);
+				Move (location.X, location.Y);
 			}
 
 			public override bool OnEnter (View view)
@@ -366,21 +359,19 @@ namespace Terminal.Gui {
 
 				return base.OnEnter (view);
 			}
+
 			public override void Redraw (Rect bounds)
 			{
 				base.Redraw (bounds);
 
 				if (CanFocus && HasFocus) {
-
 					var location = moveRuneRenderLocation ??
 						new Point (Bounds.Width / 2, Bounds.Height / 2);
 
 					AddRune (location.X, location.Y, Driver.Diamond);
 				}
-
 			}
 
-			///<inheritdoc/>
 			public override bool MouseEvent (MouseEvent mouseEvent)
 			{
 				if (!CanFocus) {
@@ -397,6 +388,12 @@ namespace Terminal.Gui {
 						dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
 						dragOrignalPos = Orientation == Orientation.Horizontal ? Y : X;
 						Application.GrabMouse (this);
+
+						if (Orientation == Orientation.Horizontal) {
+
+						} else {
+							moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Bounds.Height - 2, mouseEvent.Y)));
+						}
 					}
 
 					return true;
@@ -414,7 +411,7 @@ namespace Terminal.Gui {
 					} else {
 						int dx = mouseEvent.X - dragPosition.Value.X;
 						parent.SplitterDistance = Offset (X, dx);
-						moveRuneRenderLocation = new Point (0, mouseEvent.Y);
+						moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Bounds.Height - 2, mouseEvent.Y)));
 					}
 
 					parent.SetNeedsDisplay ();
@@ -431,11 +428,12 @@ namespace Terminal.Gui {
 						dragOrignalPos,
 						Orientation == Orientation.Horizontal ? Y : X);
 					dragPosition = null;
-					moveRuneRenderLocation = null;
+					//moveRuneRenderLocation = null;
 				}
 
 				return false;
 			}
+
 			private bool MoveSplitter (int distanceX, int distanceY)
 			{
 				if (Orientation == Orientation.Vertical) {
@@ -461,7 +459,6 @@ namespace Terminal.Gui {
 				}
 			}
 
-
 			private Pos Offset (Pos pos, int delta)
 			{
 				var posAbsolute = pos.Anchor (Orientation == Orientation.Horizontal ?

+ 42 - 38
UICatalog/Scenarios/SplitContainerExample.cs

@@ -5,54 +5,51 @@ using Terminal.Gui.Graphs;
 namespace UICatalog.Scenarios {
 	[ScenarioMetadata (Name: "Split Container", Description: "Demonstrates the SplitContainer functionality")]
 	[ScenarioCategory ("Controls")]
+	[ScenarioCategory ("LineView")]
 	public class SplitContainerExample : Scenario {
 
 		private SplitContainer splitContainer;
-
-
 		private MenuItem miVertical;
 		private MenuItem miShowBoth;
 		private MenuItem miShowPanel1;
 		private MenuItem miShowPanel2;
+		private MenuItem miShowNeither;
 
 		/// <summary>
 		/// Setup the scenario.
 		/// </summary>
 		public override void Setup ()
 		{
-			// Scenario Window's.
+			// Scenario Windows.
 			Win.Title = this.GetName ();
 			Win.Y = 1;
 
-			Win.Add (new Label ("This is a SplitContainer with a minimum panel size of 2.  Drag the splitter to resize:"));
-			Win.Add (new LineView (Orientation.Horizontal) { Y = 1 });
+			Win.Add (new Label ("This is a SplitContainer with a minimum panel size of 4. Drag the splitter to resize:"));
 
 			splitContainer = new SplitContainer {
 				Y = 2,
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
+				X = 2,
+				Width = Dim.Fill () - 2,
+				Height = Dim.Fill () - 1,
 				SplitterDistance = Pos.Percent (50), // TODO: get this to work with drag resizing and percents
-				Panel1MinSize = 2,
-				Panel2MinSize = 2,
 			};
-
+			splitContainer.Panels [0].MinSize = 4;
+			splitContainer.Panels [1].MinSize = 4;
 
 			Label lbl1;
-			splitContainer.Panel1.Add (new Label ("Hello"));
-			splitContainer.Panel1.Add (lbl1 = new Label ("Type Something:"){Y=2});
-			splitContainer.Panel1.Add (new TextField (){Width = Dim.Fill(),Y=2,X=Pos.Right(lbl1)+1});
-			
-			Label lbl2;
-			splitContainer.Panel2.Add (new Label ("World"));
-			splitContainer.Panel2.Add (lbl2 = new Label ("Type Here Too:"){Y=2});
-			splitContainer.Panel2.Add (new TextField (){Width = Dim.Fill(),Y=2,X=Pos.Right(lbl2)+1});
-			splitContainer.Panel2.Add (new Label ("Here is a Text box:") { Y = 4 });
-			splitContainer.Panel2.Add (new TextView () { Y = 5, Width = Dim.Fill(), Height = Dim.Fill(), AllowsTab = false});
+			splitContainer.Panels [0].Title = "Hello";
+			splitContainer.Panels [0].Add (lbl1 = new Label ("Type Something:") { Y = 1 });
+			splitContainer.Panels [0].Add (new TextField () { Width = Dim.Fill (), Y = 1, X = Pos.Right (lbl1) + 1 });
 
+			Label lbl2;
+			splitContainer.Panels [1].Title = "World";
+			splitContainer.Panels [1].Add (lbl2 = new Label ("Type Here Too:") { Y = 1 });
+			splitContainer.Panels [1].Add (new TextField () { Width = Dim.Fill (), Y = 1, X = Pos.Right (lbl2) + 1 });
+			splitContainer.Panels [1].Add (new Label ("Here is a Text box:") { Y = 3 });
+			splitContainer.Panels [1].Add (new TextView () { Y = 4, Width = Dim.Fill (), Height = Dim.Fill (), AllowsTab = false });
 
 			Win.Add (splitContainer);
 
-
 			var menu = new MenuBar (new MenuBarItem [] {
 			new MenuBarItem ("_File", new MenuItem [] {
 				new MenuItem ("_Quit", "", () => Quit()),
@@ -65,46 +62,53 @@ namespace UICatalog.Scenarios {
 				},
 				new MenuBarItem ("_Show", new MenuItem [] {
 						miShowBoth = new MenuItem ("Both", "",()=>{
-							splitContainer.Panel1Collapsed = false;
-							splitContainer.Panel2Collapsed = false;
+							splitContainer.Panels [0].Visible = true;
+							splitContainer.Panels [1].Visible = true;
 							UpdateShowMenuCheckedStates();
 						}),
-						miShowPanel1 = new MenuItem ("Panel1", "", () => {
-
-							splitContainer.Panel2Collapsed = true;
+						miShowPanel1 = new MenuItem ("Panel 1", "", () => {
+							splitContainer.Panels [0].Visible = true;
+							splitContainer.Panels [1].Visible = false;
 							UpdateShowMenuCheckedStates();
 						}),
-						miShowPanel2 = new MenuItem ("Panel2", "", () => {
-							splitContainer.Panel1Collapsed = true;
+						miShowPanel2 = new MenuItem ("Panel 2", "", () => {
+							splitContainer.Panels [0].Visible = false;
+							splitContainer.Panels [1].Visible = true;
 							UpdateShowMenuCheckedStates();
-						}),							
+						}),
+						miShowNeither = new MenuItem ("Neither", "",()=>{
+							splitContainer.Panels [0].Visible = false;
+							splitContainer.Panels [1].Visible = false;
+							UpdateShowMenuCheckedStates();
+						}),
 					})
 				}),
-
-			}) ;
+			});
 
 			UpdateShowMenuCheckedStates ();
-			
+
 			Application.Top.Add (menu);
 		}
 
 		private void UpdateShowMenuCheckedStates ()
 		{
-			miShowBoth.Checked = (!splitContainer.Panel1Collapsed) && (!splitContainer.Panel2Collapsed);
+			miShowBoth.Checked = (splitContainer.Panels [0].Visible) && (splitContainer.Panels [1].Visible);
 			miShowBoth.CheckType = MenuItemCheckStyle.Checked;
 
-			miShowPanel1.Checked = splitContainer.Panel2Collapsed;
+			miShowPanel1.Checked = splitContainer.Panels [0].Visible && !splitContainer.Panels [1].Visible;
 			miShowPanel1.CheckType = MenuItemCheckStyle.Checked;
 
-			miShowPanel2.Checked = splitContainer.Panel1Collapsed;
+			miShowPanel2.Checked = !splitContainer.Panels [0].Visible && splitContainer.Panels [1].Visible;
 			miShowPanel2.CheckType = MenuItemCheckStyle.Checked;
+
+			miShowNeither.Checked = (!splitContainer.Panels [0].Visible) && (!splitContainer.Panels [1].Visible);
+			miShowNeither.CheckType = MenuItemCheckStyle.Checked;
 		}
 
-		public void ToggleOrientation()
+		public void ToggleOrientation ()
 		{
-
 			miVertical.Checked = !miVertical.Checked;
-			splitContainer.Orientation =  miVertical.Checked ? Orientation.Vertical : Orientation.Horizontal;
+			splitContainer.Orientation = miVertical.Checked ? Orientation.Vertical : Orientation.Horizontal;
 		}
 
 		private void Quit ()

+ 12 - 38
UICatalog/UICatalog.cs

@@ -151,8 +151,7 @@ namespace UICatalog {
 			public MenuItem miIsMouseDisabled;
 			public MenuItem miHeightAsBuffer;
 
-			public FrameView ContentPane;
-			public SplitContainer SplitContainer;
+			public SplitContainer ContentPane;
 			public ListView CategoryListView;
 			public ListView ScenarioListView;
 
@@ -208,23 +207,17 @@ namespace UICatalog {
 					DriverName,
 				};
 
-				ContentPane = new FrameView ("Categories") {
+				ContentPane = new SplitContainer () {
 					X = 0,
 					Y = 1, // for menu
 					Width = Dim.Fill (),
 					Height = Dim.Fill (1),
 					CanFocus = true,
-					Shortcut = Key.CtrlMask | Key.C
-				};
-				
-				ContentPane.ShortcutAction = () => ContentPane.SetFocus ();
-
-				SplitContainer = new SplitContainer {
-					Width = Dim.Fill (0),
-					Height = Dim.Fill (0),
+					Shortcut = Key.CtrlMask | Key.C,
 					SplitterDistance = 25
 				};
-
+				ContentPane.ShortcutAction = () => ContentPane.SetFocus ();
+					
 				CategoryListView = new ListView (_categories) {
 					X = 0,
 					Y = 0,
@@ -237,16 +230,9 @@ namespace UICatalog {
 					ScenarioListView.SetFocus ();
 				};
 				CategoryListView.SelectedItemChanged += CategoryListView_SelectedChanged;
-				ContentPane.Add (SplitContainer);
-
-				SplitContainer.Panel1.Add (CategoryListView);
-
-				SetTitlePaddingToAlignScenariosHeader ();
-
-				SplitContainer.SplitterMoved += (s, e) => {
-					SetTitlePaddingToAlignScenariosHeader ();
-				};
 
+				ContentPane.Panels [0].Title = "Categories";
+				ContentPane.Panels [0].Add (CategoryListView);
 
 				ScenarioListView = new ListView () {
 					X = 0,
@@ -258,11 +244,14 @@ namespace UICatalog {
 				};
 
 				ScenarioListView.OpenSelectedItem += ScenarioListView_OpenSelectedItem;
-				SplitContainer.Panel2.Add (ScenarioListView);
+
+				ContentPane.Panels [1].Title = "Scenarios";
+				ContentPane.Panels [1].Add (ScenarioListView);
 
 				KeyDown += KeyDownHandler;
 				Add (MenuBar);
 				Add (ContentPane);
+
 				Add (StatusBar);
 
 				Loaded += LoadedHandler;
@@ -271,22 +260,7 @@ namespace UICatalog {
 				CategoryListView.SelectedItem = _cachedCategoryIndex;
 				ScenarioListView.SelectedItem = _cachedScenarioIndex;
 			}
-
-			private void SetTitlePaddingToAlignScenariosHeader ()
-			{ 
-				// Pos.Anchor is internal so we have to use reflection to access it
-				var anchor = typeof (Pos).GetMethod ("Anchor", BindingFlags.Instance | BindingFlags.NonPublic);
-				var splitterWidth = (int)anchor.Invoke (
-					SplitContainer.SplitterDistance, new object [] { SplitContainer.Bounds.Width}
-					);
-
-				var newTitle = $"Categories ({ContentPane.ShortcutTag})";
-				newTitle = newTitle.PadRight (splitterWidth + 1, (char)Driver.HLine);
-				newTitle += "Scenarios";
-
-				ContentPane.Title = newTitle;				
-			}
-
+ 
 			void LoadedHandler ()
 			{
 				Application.HeightAsBuffer = _heightAsBuffer;