From fa679938e7881ebf0a28c53015728da6e9a1fb61 Mon Sep 17 00:00:00 2001 From: Ivo Petrov Date: Wed, 4 Jun 2025 09:17:12 +0100 Subject: [PATCH 1/2] context menu location on collapsed groups with different dpi scales --- .../Controls/InPortContextMenu.xaml | 4 ++-- .../ViewModels/Core/PortViewModel.cs | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml b/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml index 25af62e9991..a1b674e3e47 100644 --- a/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml +++ b/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml @@ -139,13 +139,13 @@ diff --git a/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs index e8ba37500c3..63b5b3a2c95 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs @@ -375,6 +375,8 @@ internal void SetupPortContextMenuPlacement(Popup popup) /// private void ConfigurePopupPlacement(Popup popup, double zoom) { + var dpiScale = GetDpiScale(); + popup.CustomPopupPlacementCallback = (popupSize, targetSize, offset) => { double x; @@ -382,11 +384,11 @@ private void ConfigurePopupPlacement(Popup popup, double zoom) if (this is InPortViewModel) { - x = -popupSize.Width + proxyPortContextMenuOffset * zoom; + x = -popupSize.Width + proxyPortContextMenuOffset * zoom * dpiScale; } else { - x = targetSize.Width - proxyPortContextMenuOffset * zoom; + x = targetSize.Width - proxyPortContextMenuOffset * zoom * dpiScale; } return new[] { new CustomPopupPlacement(new Point(x, y), PopupPrimaryAxis.None) }; @@ -398,6 +400,7 @@ private CustomPopupPlacement[] PlacePortContextMenu(Size popupSize, Size targetS // The actual zoom here is confusing // What matters is the zoom factor measured from the scaled : unscaled node size var zoom = node.WorkspaceViewModel.Zoom; + var dpiScale = GetDpiScale(); double x; var scaledWidth = autocompletePopupSpacing * targetSize.Width / node.ActualWidth; @@ -421,13 +424,21 @@ private CustomPopupPlacement[] PlacePortContextMenu(Size popupSize, Size targetS var rowOffset = PortModel.Index * PortModel.Height * zoom; var customNodeOffset = NodeModel.CustomNodeTopBorderHeight * zoom; - var y = popupHeightOffset + headerHeightOffset + portHalfHeight + rowOffset + customNodeOffset; + // popupSize.Height is already DPI-scaled (in screen pixels), so we do NOT apply dpiScale to it + // All other layout values are in logical units and must be multiplied by dpiScale for correct placement + var y = popupHeightOffset + (headerHeightOffset + portHalfHeight + rowOffset + customNodeOffset) * dpiScale; var placement = new CustomPopupPlacement(new Point(x, y), PopupPrimaryAxis.None); return new[] { placement }; } + private static double GetDpiScale() + { + var source = PresentationSource.FromVisual(Application.Current.MainWindow); + return source?.CompositionTarget?.TransformToDevice.M22 ?? 1.0; + } + private void WorkspacePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { switch (e.PropertyName) From df68fd1e42bbd2953af01668763d7339f6c4bd00 Mon Sep 17 00:00:00 2001 From: Ivo Petrov Date: Fri, 6 Jun 2025 14:14:33 +0100 Subject: [PATCH 2/2] Update PortViewModel.cs --- src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs index 63b5b3a2c95..2ac40742f65 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs @@ -435,8 +435,18 @@ private CustomPopupPlacement[] PlacePortContextMenu(Size popupSize, Size targetS private static double GetDpiScale() { - var source = PresentationSource.FromVisual(Application.Current.MainWindow); - return source?.CompositionTarget?.TransformToDevice.M22 ?? 1.0; + double dpiScale = 1.0; + try + { + var source = PresentationSource.FromVisual(Application.Current.MainWindow); + dpiScale = source?.CompositionTarget?.TransformToDevice.M22 ?? 1.0; + } + catch + { + // fallback to default DPI scale of 1.0 if anything fails + } + + return dpiScale; } private void WorkspacePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)