Merge pull request #146 from tig/tznind-splitcontainer

Fixes & enhancments to SplitContainer
This commit is contained in:
Thomas Nind
2023-01-01 09:57:09 +00:00
committed by GitHub
3 changed files with 233 additions and 258 deletions

View File

@@ -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 (panel1Collapsed || panel2Collapsed) {
SetupForCollapsedPanel ();
if (!splitterPanels[0].Visible || !splitterPanels[1].Visible) {
View toFullSize = !splitterPanels[0].Visible ? splitterPanels[1] : splitterPanels[0];
splitterLine.Visible = false;
toFullSize.X = 0;
toFullSize.Y = 0;
toFullSize.Width = Dim.Fill ();
toFullSize.Height = Dim.Fill ();
} else {
SetupForNormal ();
splitterLine.Visible = true;
splitterDistance = BoundByMinimumSizes (splitterDistance);
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;
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));
};
}
}
private void SetupForNormal ()
{
// Ensure all our component views are here
// (e.g. if we are transitioning from a collapsed state)
if (!this.Subviews.Contains (splitterLine)) {
this.Add (splitterLine);
}
if (!this.Subviews.Contains (Panel1)) {
this.Add (Panel1);
}
if (!this.Subviews.Contains (Panel2)) {
this.Add (Panel2);
}
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 ();
}
/// <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);
}
if (this.Subviews.Contains (toRemove)) {
this.Remove (toRemove);
}
if (!this.Subviews.Contains (toFullSize)) {
this.Add (toFullSize);
/// <summary>
/// Gets or sets the minimum size for the panel.
/// </summary>
public Pos MinSize { get => minSize;
set {
minSize = value;
SuperView?.SetNeedsLayout ();
}
}
toFullSize.X = 0;
toFullSize.Y = 0;
toFullSize.Width = Dim.Fill ();
toFullSize.Height = Dim.Fill ();
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 ();
}
}
/// <inheritdoc/>
public override void Redraw (Rect bounds)
{
Driver.SetAttribute (ColorScheme.Normal);
base.Redraw (bounds);
}
/// <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 ?

View File

@@ -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 ()

View File

@@ -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;