Open julioasotodv opened 1 year ago
You could query the items left and top of the editor for their rect width and rect height. With that you could then calculate the relative mouse position.
@cloasdata thank you for the response, but I believe that this way I would still have no info on where the mouse is within the Editor coordinate system (which works independently of the usual one that is used in the rest of DearPyGui).
For me this works. The solution with the reference node does not work, as dpg dies when try to hide the node.
The solution with the reference node works for me by simply initializing it far away where it is unlikely to be found, since hiding causes a Segmentation Fault (#2151).
Then I can calculate the mouse position in node editor coordinate space using the mouse position from dpg.get_mouse_pos(local=False)
, the initial reference node position that you set, and dpg.get_item_state(ref_node)["rect_min"]
.
Clearly less than ideal but it works.
What do you mean with "the reference node"? Is there any other related issue that already presents a solution for this?
The reference node is just an empty node I add to the editor at the start of the program, which has a fixed location (e.g. [-5000, -5000]). This node serves as a reference point of the internal coordinate system of the node editor. This works because dpg.get_item_state(ref_node)["rect_min"]
contains the window-space position of the node, and you know the node editor-space coordinates of the node (i.e. [-5000, -5000] or whichever location you choose). Then you can simply calculate the offset between the window-space coordinates and the node editor-space coordinates of the node, which allows to convert between window-space and node editor-space positions.
The only problem I have with this is that it messes with the minimap of the node editor (i.e. it contains the far away reference node):
I'm guessing setting show=False
in the reference node would solve this, but unfortunately that crashes DPG (#2151).
I see, thanks @PhilippThoelke for the tip. Will try when I have some time!
Actually this works quite well now. I set the reference node's position to the origin (0, 0) and configure its theme to be completely hidden (i.e. transparent background and empty label). I also set draggable=False
to prevent users from moving the reference node. It shows up on the minimap as a tiny dot and doesn't really interfere with anything.
Another workaround, instead of making the reference node transparent (which does have side effects on the minimap), would be to do a dpg.hide_item
on that node - but first let it render for 1 frame. You can do it with set_frame_callback
or other ways you want (e.g. item_visible_handler on the node editor, or split_frame if you create the node editor on the fly at runtime rather than on app initialization).
I'm going to push a PR for #2151 but it will take some time for the fix to go through all stages and get into a release.
Thanks @v-ein! Hiding the node after one frame with set_frame_callback
works but unfortunately breaks the workaround for determining the mouse position. It seems like dpg.get_item_state("_ref")["rect_min"]
doesn't get updated for hidden nodes, therefore I can't determine the coordinate offset of the node editor.
Played with node editor a bit... until this enhancement is implemented, using a reference node appears to be the only workaround. Also, as soon as you get a real node in your node editor, you can delete the dummy reference node and use any other node as a reference - but in this case, remember to restore the dummy node if you delete all the real nodes from the editor. This way you can keep your minimap unaffected by the dummy node.
Here's an example that uses the first node in the editor as a reference, no matter what that node contains. It works even if the user moves the first node around.
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.create_viewport(title=f"Test - {dpg.get_dearpygui_version()}", width=500, height=400)
dpg.setup_dearpygui()
with dpg.window(pos=(0, 30), width=500, height=350):
dpg.add_button(label="Drag me!")
with dpg.drag_payload(parent=dpg.last_item()):
dpg.add_text("A new node")
node_editor = dpg.generate_uuid()
def on_drop():
pos = dpg.get_mouse_pos(local=False)
ref_node = dpg.get_item_children(node_editor, slot=1)[0]
ref_screen_pos = dpg.get_item_rect_min(ref_node)
ref_grid_pos = dpg.get_item_pos(ref_node)
NODE_PADDING = (8, 8)
pos[0] = pos[0] - (ref_screen_pos[0] - NODE_PADDING[0]) + ref_grid_pos[0]
pos[1] = pos[1] - (ref_screen_pos[1] - NODE_PADDING[1]) + ref_grid_pos[1]
with dpg.node(label="New", pos=pos, parent=node_editor):
with dpg.node_attribute(attribute_type=dpg.mvNode_Attr_Static):
dpg.add_text(f"I'm a new node")
dpg.add_text(f"at {pos}!")
with dpg.group(drop_callback=on_drop):
with dpg.node_editor(tag=node_editor,
minimap=True,
minimap_location=dpg.mvNodeMiniMap_Location_BottomRight):
with dpg.node(label="A real node", pos=[50, 30]):
with dpg.node_attribute(attribute_type=dpg.mvNode_Attr_Static):
pass
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
Recently, I have also been researching But I can't achieve your effect Do you want to open source your demo examples thanks @julioasotodv
Is your feature request related to a problem? Please describe.
I am trying to make a Drag and Drop node editor, where I have a sidebar from which I can select nodes to add to a Node Editor area:
I have implemented already the drag and drop functionality. However, dragged nodes appear in a wrong position (and not where the drop callback happens).
This is due to how the drop callback works: I just get the mouse position using
dpg.get_mouse_pos(local=False)
, and create a new Node in the Node Editor using that position.The issue here is that positioning within the Node Editor work differently (it has its own coordinate system, which allows for panning through the editor by clicking the mouse wheel).
You can see the issue here:
Describe the solution you'd like
A simple way to get the mouse position within the Node Editor would solve the issue (using the same positioning system that
dpg.get_item_pos(some_node_item)
).Describe alternatives you've considered
The only alternative I can think of is to always create new nodes in position
[0,0]
, but then drag and drop would not make sense.Additional context Nothing noteworthy
Thank you! I really like the library.