Added IndexOf method to TreeView to allow for keyboard context menus

This commit is contained in:
Thomas Nind
2022-05-10 16:05:09 +01:00
parent 5c39f6af48
commit e60d7f4363
3 changed files with 138 additions and 43 deletions

View File

@@ -609,6 +609,29 @@ namespace Terminal.Gui {
}
}
/// <summary>
/// <para>
/// Returns the Y coordinate within the <see cref="View.Bounds"/> of the
/// tree at which <paramref name="toFind"/> would be displayed or null if
/// it is not currently exposed (e.g. its parent is collapsed).
/// </para>
/// <para>
/// Note that the returned value can be negative if the TreeView is scrolled
/// down and the <paramref name="toFind"/> object is off the top of the view.
/// </para>
/// </summary>
/// <param name="toFind"></param>
/// <returns></returns>
public int? IndexOf(T toFind)
{
var idx = BuildLineMap ().IndexOf (o => o.Model.Equals (toFind));
if (idx == -1)
return null;
return idx - ScrollOffsetVertical;
}
/// <summary>
/// <para>Moves the <see cref="SelectedObject"/> to the next item that begins with <paramref name="character"/></para>
/// <para>This method will loop back to the start of the tree if reaching the end without finding a match</para>

View File

@@ -78,6 +78,7 @@ namespace UICatalog.Scenarios {
treeViewFiles.ObjectActivated += TreeViewFiles_ObjectActivated;
treeViewFiles.MouseClick += TreeViewFiles_MouseClick;
treeViewFiles.KeyPress += TreeViewFiles_KeyPress;
SetupFileTree ();
@@ -89,6 +90,29 @@ namespace UICatalog.Scenarios {
red = Application.Driver.MakeAttribute (Color.Red, Color.Blue);
}
private void TreeViewFiles_KeyPress (View.KeyEventEventArgs obj)
{
if(obj.KeyEvent.Key == (Key.R | Key.CtrlMask)) {
var selected = treeViewFiles.SelectedObject;
// nothing is selected
if (selected == null)
return;
var location = treeViewFiles.IndexOf (selected);
//selected object is offscreen or somehow not found
if (location == null || location < 0 || location > treeViewFiles.Frame.Height)
return;
ShowContextMenu (new Point (
5 + treeViewFiles.Frame.X,
location.Value + treeViewFiles.Frame.Y + 2),
selected);
}
}
private void TreeViewFiles_MouseClick (View.MouseEventArgs obj)
{
// if user right clicks
@@ -100,39 +124,44 @@ namespace UICatalog.Scenarios {
if (rightClicked == null)
return;
var menu = new ContextMenu ();
menu.Position = new Point(
ShowContextMenu (new Point (
obj.MouseEvent.X + treeViewFiles.Frame.X,
obj.MouseEvent.Y + treeViewFiles.Frame.Y +1);
menu.MenuItems = new MenuBarItem (new [] { new MenuItem ("Properties",null,()=> {
MessageBox.Query($"{rightClicked.Name}({rightClicked.GetType().Name})",Describe(rightClicked),"Ok");
}
) });
menu.Show ();
obj.MouseEvent.Y + treeViewFiles.Frame.Y + 2),
rightClicked);
}
}
private string Describe (FileSystemInfo f)
private void ShowContextMenu (Point screenPoint, FileSystemInfo forObject)
{
try {
var menu = new ContextMenu ();
menu.Position = screenPoint;
if (f is FileInfo fi) {
return "Size:" + fi.Length;
}
menu.MenuItems = new MenuBarItem (new [] { new MenuItem ("Properties", null, () => ShowPropertiesOf (forObject)) });
Application.MainLoop.Invoke(menu.Show);
}
if (f is DirectoryInfo d) {
return $@"Parent:{d.Parent}
Attributes:{d.Attributes}";
}
} catch (Exception) {
private void ShowPropertiesOf (FileSystemInfo fileSystemInfo)
{
if (fileSystemInfo is FileInfo f) {
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
sb.AppendLine ($"Path:{f.DirectoryName}");
sb.AppendLine ($"Size:{f.Length:N0} bytes");
sb.AppendLine ($"Modified:{ f.LastWriteTime}");
sb.AppendLine ($"Created:{ f.CreationTime}");
return "Could not get properties";
MessageBox.Query (f.Name, sb.ToString (), "Close");
}
return null;
if (fileSystemInfo is DirectoryInfo dir) {
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
sb.AppendLine ($"Path:{dir.Parent?.FullName}");
sb.AppendLine ($"Modified:{ dir.LastWriteTime}");
sb.AppendLine ($"Created:{ dir.CreationTime}");
MessageBox.Query (dir.Name, sb.ToString (), "Close");
}
}
private void SetupScrollBar ()
@@ -187,25 +216,7 @@ Attributes:{d.Attributes}";
private void TreeViewFiles_ObjectActivated (ObjectActivatedEventArgs<FileSystemInfo> obj)
{
if (obj.ActivatedObject is FileInfo f) {
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
sb.AppendLine ($"Path:{f.DirectoryName}");
sb.AppendLine ($"Size:{f.Length:N0} bytes");
sb.AppendLine ($"Modified:{ f.LastWriteTime}");
sb.AppendLine ($"Created:{ f.CreationTime}");
MessageBox.Query (f.Name, sb.ToString (), "Close");
}
if (obj.ActivatedObject is DirectoryInfo dir) {
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
sb.AppendLine ($"Path:{dir.Parent?.FullName}");
sb.AppendLine ($"Modified:{ dir.LastWriteTime}");
sb.AppendLine ($"Created:{ dir.CreationTime}");
MessageBox.Query (dir.Name, sb.ToString (), "Close");
}
ShowPropertiesOf (obj.ActivatedObject);
}
private void ShowLines ()

View File

@@ -768,7 +768,68 @@ namespace Terminal.Gui.Views {
Assert.Null (tv.HitTest (new Point (0, 3)));
Assert.Null (tv.HitTest (new Point (0, 4)));
}
[Fact, AutoInitShutdown]
[Fact, AutoInitShutdown]
public void TestTreeIndexOf ()
{
var tv = new TreeView { Width = 20, Height = 10 };
var n1 = new TreeNode ("normal");
var n1_1 = new TreeNode ("pink");
var n1_2 = new TreeNode ("normal");
n1.Children.Add (n1_1);
n1.Children.Add (n1_2);
var n2 = new TreeNode ("pink");
tv.AddObject (n1);
tv.AddObject (n2);
tv.Expand (n1);
tv.ColorScheme = new ColorScheme ();
tv.Redraw (tv.Bounds);
GraphViewTests.AssertDriverContentsAre (
@"├-normal
│ ├─pink
│ └─normal
└─pink
", output);
Assert.Equal (0, tv.IndexOf (n1));
Assert.Equal (1, tv.IndexOf (n1_1));
Assert.Equal (2, tv.IndexOf (n1_2));
Assert.Equal (3, tv.IndexOf (n2));
tv.Collapse (n1);
tv.Redraw (tv.Bounds);
GraphViewTests.AssertDriverContentsAre (
@"├+normal
└─pink
", output);
Assert.Equal (0, tv.IndexOf (n1));
Assert.Null (tv.IndexOf (n1_1));
Assert.Null (tv.IndexOf (n1_2));
Assert.Equal (1, tv.IndexOf (n2));
// scroll down 1
tv.ScrollOffsetVertical = 1;
tv.Redraw (tv.Bounds);
GraphViewTests.AssertDriverContentsAre (
@"└─pink
", output);
Assert.Equal (-1, tv.IndexOf (n1));
Assert.Null (tv.IndexOf (n1_1));
Assert.Null (tv.IndexOf (n1_2));
Assert.Equal (0, tv.IndexOf (n2));
}
[Fact, AutoInitShutdown]
public void TestTreeViewColor()
{
var tv = new TreeView{Width = 20,Height = 10};