Skip to content

Commit

Permalink
Update PortViewModel.cs
Browse files Browse the repository at this point in the history
  • Loading branch information
ivaylo-matov committed Dec 3, 2024
1 parent ccbdfae commit 270f38a
Showing 1 changed file with 66 additions and 1 deletion.
67 changes: 66 additions & 1 deletion src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public partial class PortViewModel : ViewModelBase
private DelegateCommand keepListStructureCommand;
private bool showUseLevelMenu;
private const double autocompletePopupSpacing = 2.5;
private const double proxyPortContextMenuOffset = 20;
internal bool inputPortDisconnectedByConnectCommand = false;
protected static readonly SolidColorBrush PortBackgroundColorPreviewOff = new SolidColorBrush(Color.FromRgb(102, 102, 102));
protected static readonly SolidColorBrush PortBackgroundColorDefault = new SolidColorBrush(Color.FromRgb(60, 60, 60));
Expand Down Expand Up @@ -238,6 +239,33 @@ internal virtual PortViewModel CreateProxyPortViewModel(PortModel portModel)
return new PortViewModel(node, portModel);
}

private UIElement FindProxyPortUIElement(PortViewModel proxyPortViewModel)
{
var mainWindow = Application.Current.MainWindow;

return FindChild<UIElement>(mainWindow, e =>
e is FrameworkElement fe && fe.DataContext == proxyPortViewModel);
}

private T FindChild<T>(DependencyObject parent, Func<T, bool> predicate) where T : DependencyObject
{
if (parent == null) return null;

for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T t && predicate(t))
{
return t;
}

var foundChild = FindChild(child, predicate);
if (foundChild != null)
return foundChild;
}
return null;
}

/// <summary>
/// Sets up the node autocomplete window to be placed relative to the node.
/// </summary>
Expand All @@ -254,10 +282,47 @@ internal void SetupNodeAutocompleteWindowPlacement(Popup popup)
/// <param name="popup">Node context menu popup.</param>
internal void SetupPortContextMenuPlacement(Popup popup)
{
var zoom = node.WorkspaceViewModel.Zoom;

if (PortModel.IsProxyPort)
{
// Find the UI element associated with the proxy port
var proxyPortElement = FindProxyPortUIElement(this);
if (proxyPortElement != null)
{
popup.PlacementTarget = proxyPortElement;
ConfigurePopupPlacement(popup, zoom);
return;
}
}

node.OnRequestPortContextMenuPlacementTarget(popup);
popup.CustomPopupPlacementCallback = PlacePortContextMenu;
}

/// <summary>
/// Configures the custom placement of the proxyport context menu popup.
/// </summary>
private void ConfigurePopupPlacement(Popup popup, double zoom)
{
popup.CustomPopupPlacementCallback = (popupSize, targetSize, offset) =>
{
double x;
double y = (targetSize.Height - popupSize.Height) / 2;

if (this is InPortViewModel)
{
x = -popupSize.Width + proxyPortContextMenuOffset * zoom;
}
else
{
x = targetSize.Width - proxyPortContextMenuOffset * zoom;
}

return new[] { new CustomPopupPlacement(new Point(x, y), PopupPrimaryAxis.None) };
};
}

private CustomPopupPlacement[] PlaceAutocompletePopup(Size popupSize, Size targetSize, Point offset)
{
var zoom = node.WorkspaceViewModel.Zoom;
Expand Down Expand Up @@ -305,7 +370,7 @@ private CustomPopupPlacement[] PlacePortContextMenu(Size popupSize, Size targetS
x = scaledWidth + targetSize.Width;
}
// Important - while zooming in and out, Node elements are scaled, while popup is not
// Calculate absolute popup halfheight to deduct from the overal y pos
// Calculate absolute popup halfheight to deduct from the overall y pos
// Then add the header, port height and port index position
var popupHeightOffset = - popupSize.Height * 0.5;
var headerHeightOffset = 2 * NodeModel.HeaderHeight * zoom;
Expand Down

0 comments on commit 270f38a

Please sign in to comment.