diff --git a/Terminal.Gui/Views/TreeView.cs b/Terminal.Gui/Views/TreeView.cs index 4f4503342..4fdf51ab1 100644 --- a/Terminal.Gui/Views/TreeView.cs +++ b/Terminal.Gui/Views/TreeView.cs @@ -609,6 +609,29 @@ namespace Terminal.Gui { } } + /// + /// + /// Returns the Y coordinate within the of the + /// tree at which would be displayed or null if + /// it is not currently exposed (e.g. its parent is collapsed). + /// + /// + /// Note that the returned value can be negative if the TreeView is scrolled + /// down and the object is off the top of the view. + /// + /// + /// + /// + public int? IndexOf(T toFind) + { + var idx = BuildLineMap ().IndexOf (o => o.Model.Equals (toFind)); + + if (idx == -1) + return null; + + return idx - ScrollOffsetVertical; + } + /// /// Moves the to the next item that begins with /// This method will loop back to the start of the tree if reaching the end without finding a match diff --git a/UICatalog/Scenarios/TreeViewFileSystem.cs b/UICatalog/Scenarios/TreeViewFileSystem.cs index de1d49f90..acb97161b 100644 --- a/UICatalog/Scenarios/TreeViewFileSystem.cs +++ b/UICatalog/Scenarios/TreeViewFileSystem.cs @@ -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 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 () diff --git a/UnitTests/TreeViewTests.cs b/UnitTests/TreeViewTests.cs index 41e0b12f4..7dc514b49 100644 --- a/UnitTests/TreeViewTests.cs +++ b/UnitTests/TreeViewTests.cs @@ -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};