- Home /
How to get the correct contextual menu mouse position on graph view when I have ContentDragger & ContentZoomer manipulators?
I've added the following manipulators to the GraphView:
this.AddManipulator(new ContentZoomer());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new ContentDragger());
this.AddManipulator(new RectangleSelector());
Then I've added a manipulator to add a Contextual Menu to add a node, like so:
this.AddManipulator(CreateContextualMenu("Title"));
private ContextualMenuManipulator CreateContextualMenu(string contextualMenuText)
{
return new ContextualMenuManipulator(menuEvent =>
menuEvent.menu.AppendAction(contextualMenuText, actionEvent =>
AddElement(CreateNode(actionEvent.eventInfo.mousePosition)), DropdownMenuAction.AlwaysEnabled));
}
The CreateNode method receives the mouse position and inserts the node at the correct place, until I drag the graph view (due to the content dragger) and try to create a new node.
I've inserted a log to see the position and it seems that the actionEvent.eventInfo.mousePosition (and others) only goes up to the current window size, and therefore instead of adding on the current position it creates in the closest to the window size (which in terms of graph position, it might be in a position that isn't showing after I drag).
The contextual menu is where I've clicked to add a node, and the node on the left is where it was added.
I've tried adding a MouseMove/Up/DownEvent to both the GraphView and GridBackground but it still does the same. I've also tried using Mouse.current.position.ReadValue() but the same happens.
Is there a way to fix this?
![alt text][2]
Answer by TheRealRan · Mar 26, 2021 at 02:02 PM
I was able to kind of solve it (isn't perfect but works better) by adding these lines:
Vector2 worldMousePosition = editorWindow.rootVisualElement.ChangeCoordinatesTo(editorWindow.rootVisualElement.parent, position - editorWindow.position.position);
Vector2 localMousePosition = contentViewContainer.WorldToLocal(worldMousePosition);
Taken from this tutorial: https://www.youtube.com/watch?v=F4cTWOxMjMY
Answer by quabug · Sep 18, 2021 at 11:12 AM
var position = viewTransform.matrix.inverse.MultiplyPoint(evt.localMousePosition)
Answer by MichaelDusk · Aug 10, 2021 at 03:54 PM
I found a solution that works perfect in my case (I use it as the position for newly created Nodes).
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
VisualElement contentViewContainer = ElementAt(1);
Vector3 screenMousePosition = evt.localMousePosition;
Vector2 worldMousePosition = screenMousePosition - contentViewContainer.transform.position;
worldMousePosition *= 1 / contentViewContainer.transform.scale.x;
// add context menu entries here...
}
Basically, ElementAt(1) is the "contentViewContainer" element, which is transformed (positioned and scaled) when you zoom / drag.
The evt parameter contains a localMousePosition that is in screenspace, with which you can calculate the "world position" .
Answer by Ziplaw · Oct 03, 2021 at 11:11 PM
This works like a charm, but I'll add that you should cache the localMousePosition of the event before modifying the event, otherwise in some versions of graphview it goes back to (0,0):
Vector2 localMousePos = evt.localMousePosition;
evt.menu.AppendAction(...) //And other possible manipulations...
Vector2 actualGraphPosition = viewTransform.matrix.inverse.MultiplyPoint(localMousePos );