From f67662cc459139ea146a9f735368c64c09f1e797 Mon Sep 17 00:00:00 2001 From: Peter Kirmeier Date: Thu, 31 Aug 2023 21:09:58 +0200 Subject: [PATCH] Fix context menu (right click) position Was bound to mouse position before, is bound to item position now. --- Business/KeyboardInput.cs | 3 +- DataClasses/RowData.cs | 11 ++++- UserInterface/Menu.xaml.cs | 92 ++++++++++++++++++++------------------ 3 files changed, 60 insertions(+), 46 deletions(-) diff --git a/Business/KeyboardInput.cs b/Business/KeyboardInput.cs index e22f146..8c381a0 100644 --- a/Business/KeyboardInput.cs +++ b/Business/KeyboardInput.cs @@ -7,7 +7,6 @@ namespace SystemTrayMenu.Business using System; using System.Windows.Input; using SystemTrayMenu.DataClasses; - using SystemTrayMenu.DllImports; using SystemTrayMenu.UserInterface; using SystemTrayMenu.Utilities; using static SystemTrayMenu.Helpers.GlobalHotkeys; @@ -125,7 +124,7 @@ namespace SystemTrayMenu.Business case Key.Apps: if (modifiers == ModifierKeys.None) { - focussedMenu?.SelectedItem?.OpenShellContextMenu(NativeMethods.Screen.CursorPosition); + focussedMenu?.SelectedItem?.OpenShellContextMenu(); } break; diff --git a/DataClasses/RowData.cs b/DataClasses/RowData.cs index d110ec7..b9f4b54 100644 --- a/DataClasses/RowData.cs +++ b/DataClasses/RowData.cs @@ -269,8 +269,17 @@ namespace SystemTrayMenu.DataClasses } } - internal void OpenShellContextMenu(Point position) + internal void OpenShellContextMenu() { + Point position = default; + + if (Owner != null) + { + Point positionChild = Owner.GetRelativeDataGridViewChildPosition(this); + Point positionDgv = Owner.GetRelativeChildPositionTo(Owner.GetDataGridView()); + position = new Point(Owner.Left + positionDgv.X + positionChild.X, Owner.Top + positionDgv.Y + positionChild.Y); + } + if (IsPointingToFolder) { ShellContextMenu.OpenShellContextMenu(new DirectoryInfo(Path), position); diff --git a/UserInterface/Menu.xaml.cs b/UserInterface/Menu.xaml.cs index 66d3da5..d76c9f8 100644 --- a/UserInterface/Menu.xaml.cs +++ b/UserInterface/Menu.xaml.cs @@ -729,49 +729,10 @@ namespace SystemTrayMenu.UserInterface y = originLocation.Y; // Set position on same height as the selected row from predecessor - ListView dgv = menuPredecessor.GetDataGridView()!; RowData? trigger = RowDataParent; if (trigger != null) { - // When scrolled, we have to reduce the index number as we calculate based on visual tree - int startIndex = 0; - double offset = 0D; - if (VisualTreeHelper.GetChild(dgv, 0) is Decorator { Child: ScrollViewer scrollViewer }) - { - startIndex = (int)scrollViewer.VerticalOffset; - if (trigger.RowIndex < startIndex) - { - // calculate position above starting point - for (int i = trigger.RowIndex; i < startIndex; i++) - { - ListViewItem? item = dgv.FindVisualChildOfType(i); - if (item != null) - { - offset -= item.ActualHeight; - } - } - } - } - - if (startIndex < trigger.RowIndex) - { - // calculate position below starting point - // outer loop check for max RowIndex, independend of currently active filter - // inner loop check for filtered and shown items - for (int i = startIndex; i < trigger.RowIndex; i++) - { - ListViewItem? item = dgv.FindVisualChildOfType(i); - if (item != null) - { - if (((RowData)item.Content).RowIndex >= trigger.RowIndex) - { - break; - } - - offset += item.ActualHeight; - } - } - } + double offset = menuPredecessor.GetRelativeDataGridViewChildPosition(trigger).Y; if (offset < 0) { @@ -780,6 +741,7 @@ namespace SystemTrayMenu.UserInterface } else { + ListView dgv = menuPredecessor.GetDataGridView(); double offsetList = menuPredecessor.GetRelativeChildPositionTo(dgv).Y; offsetList += dgv.ActualHeight; if (offsetList < offset) @@ -832,6 +794,52 @@ namespace SystemTrayMenu.UserInterface } } + internal Point GetRelativeDataGridViewChildPosition(RowData rowData) + { + // When scrolled, we have to reduce the index number as we calculate based on visual tree + int rowIndex = rowData.RowIndex; + int startIndex = 0; + double offset = 0D; + if (VisualTreeHelper.GetChild(dgv, 0) is Decorator { Child: ScrollViewer scrollViewer }) + { + startIndex = (int)scrollViewer.VerticalOffset; + if (rowIndex < startIndex) + { + // calculate position above starting point + for (int i = rowIndex; i < startIndex; i++) + { + ListViewItem? item = dgv.FindVisualChildOfType(i); + if (item != null) + { + offset -= item.ActualHeight; + } + } + } + } + + if (startIndex < rowIndex) + { + // calculate position below starting point + // outer loop check for max RowIndex, independend of currently active filter + // inner loop check for filtered and shown items + for (int i = startIndex; i < rowIndex; i++) + { + ListViewItem? item = dgv.FindVisualChildOfType(i); + if (item != null) + { + if (((RowData)item.Content).RowIndex >= rowIndex) + { + break; + } + + offset += item.ActualHeight; + } + } + } + + return new(0D, offset); + } + private static bool Filter_Default(RowData itemData) { if (Settings.Default.ShowOnlyAsSearchResult && itemData.IsAdditionalItem) @@ -1147,9 +1155,7 @@ namespace SystemTrayMenu.UserInterface // Prevent any use of MouseEnter/MouseLeave while the menu is open. // TODO: Find root case and fix this properly. isShellContextMenuOpen = true; - var position = Mouse.GetPosition(this); - position.Offset(Left, Top); - itemData.OpenShellContextMenu(position); + itemData.OpenShellContextMenu(); isShellContextMenuOpen = false; } }