DearPyGui
DearPyGui copied to clipboard
dpg.configure_item() Ignores Translation in Transform Matrix on Draw Nodes
Version of Dear PyGui
Version: 1.11.1 Operating System: Debian Bookworm (also tested on Windows 11)
My Issue
For drawings on a draw node with a transform, dpg.configure_item does not work properly. In these cases, it seems to ignore the 4th column (translate values) of the 4x4 transform matrix.
Deleting and re-creating the drawing produces the expected behavior. When dpg.configure_item() is used, drawings are effected by the scale of the transform matrix, but are not property translated.
To Reproduce
Steps to reproduce the behavior: (see code)
- Create a draw node and apply a transformation and drawing
- Update that drawing using dpg.configure_item() to change its position
- notice how the new position is no longer effected by the transformation's translation, but is still effected by scale
Expected behavior
When dpg.configure_item() is used to change a drawing's position, it should remain fully effected by the draw node transform.
Deleting then re-drawing the item produces the expected behavior but is not a practical alternative.
Screenshots/Video
Standalone, minimal, complete and verifiable example
import dearpygui.dearpygui as dpg
from dearpygui._dearpygui import mvMat4
class application:
def __init__(self, ):
# init variables for origin/dragging
self.scale = 0
self.origin_pre = [200.0, 200.0]
self.dragfrom = [0.0, 0.0]
self.dragto = [0.0, 0.0]
self.__any_hovered__ = False
# init dpg
dpg.create_context()
dpg.create_viewport(title='issue with dpg.configure_item()',vsync=False)
dpg.setup_dearpygui()
# init a viewport and draw node
self.id_background = dpg.add_viewport_drawlist(front=False, tag="background")
dpg.add_draw_node(tag="draw_node", parent="background")
dpg.apply_transform("draw_node", self.transform)
# init left-click-drag to move drawings
self.dragging_mouse = False
with dpg.handler_registry():
dpg.add_mouse_click_handler(callback=self.mouse_click_handler)
dpg.add_mouse_move_handler(callback=self.mouse_move_handler)
dpg.add_mouse_release_handler(callback=self.mouse_release_handler)
dpg.add_mouse_wheel_handler(callback=self.mouse_wheel_handler)
# add basic drawings
dpg.draw_circle(center=[0, 0], radius=5, fill=[255, 0, 0], color=[0, 0, 0, 0], parent="draw_node") # origin
dpg.draw_text(pos=[0, 0], text='(0, 0)', color=[255, 0, 0], size=32, parent="draw_node")
dpg.draw_circle(center=[200, 0], radius=5, fill=[255, 0, 0], color=[0, 0, 0, 0], parent="draw_node") # origin
dpg.draw_text(pos=[200, 0], text='(200, 0)', color=[255, 0, 0], size=32, parent="draw_node")
self.id = dpg.draw_rectangle(pmin=[0, 0], pmax=[100, 100], fill=[0, 0, 255, 128], parent="draw_node")
dpg.draw_rectangle(pmin=[200, 0], pmax=[300, 100], fill=[0, 0, 0], parent="draw_node")
# add controls to update drawing
with dpg.window(label="move object",no_background=False):
dpg.add_text("left-click and drag the background to update the draw_node transform.")
dpg.add_text("scroll to zoom in and out.")
self.button0 = dpg.add_button(label="reset", callback=self.reset)
self.button1 = dpg.add_button(label="dpg.configure_item", callback=self.move_rectangle)
self.button2 = dpg.add_button(label="dpg.delete_item and dpg.draw_rectangle", callback=self.replace_rectangle)
with dpg.tooltip(self.button1, delay=0.10, hide_on_activity=True):
dpg.add_text('actual behavior: demo shows that dpg.configure_item does not\n'\
'properly update drawings on draw nodes w/ transformations.')
with dpg.tooltip(self.button2, delay=0.10, hide_on_activity=True):
dpg.add_text('expected behavior')
# main loop
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
@property
def any_hovered(self):
# https://github.com/hoffstadt/DearPyGui/issues/2281
return any([s["hovered"] for s in [dpg.get_item_state(w) for w in dpg.get_windows()] if ("hovered" in s.keys())])
def mouse_click_handler(self, sender, app_data, user_data):
if app_data == 0: # left click
if not self.__any_hovered__ and not self.dragging_mouse:
self.dragging_mouse = True
xy = dpg.get_mouse_pos(local=False)
# print('mouse_click_handler xy:', xy)
self.dragfrom = xy
self.dragto = xy
def mouse_move_handler(self, sender, app_data, user_data):
self.__any_hovered__ = self.any_hovered
# print("any_hovered?:", self.any_hovered)
if self.dragging_mouse:
xy = dpg.get_mouse_pos(local=False)
# print('mouse_move_handler xy:', xy)
self.dragto = xy
dpg.apply_transform("draw_node", self.transform)
def mouse_release_handler(self, sender, app_data, user_data):
if app_data == 0: # left click
if not self.__any_hovered__ and self.dragging_mouse:
self.dragging_mouse = False
self.origin_pre = self.origin
self.dragfrom = [0.0, 0.0]
self.dragto = [0.0, 0.0]
# print('mouse_release_handler')
def mouse_wheel_handler(self, sender, app_data, user_data):
if not self.__any_hovered__:
if app_data > 0:
self.scale += 1
elif app_data < 0:
self.scale -= 1
dpg.apply_transform("draw_node", self.transform)
@property
def origin(self):
return [o + t - f for o, f, t in zip(self.origin_pre, self.dragfrom, self.dragto)]
@property
def transform(self):
s = 2 ** (self.scale / 8)
x, y = self.origin
return mvMat4(
s, 0.0, 0.0, x,
0.0, -s, 0.0, y,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0)
def move_rectangle(self, sender, app_data, user_data):
dpg.configure_item(self.id, pmin=[200, 0], pmax=[300, 100], parent="draw_node") # TODO: NEEDS FIX
def replace_rectangle(self, sender, app_data, user_data):
dpg.delete_item(self.id)
self.id = dpg.draw_rectangle(pmin=[200, 0], pmax=[300, 100], fill=[0, 0, 255, 128], parent="draw_node")
def reset(self, sender, app_data, user_data):
dpg.delete_item(self.id)
self.id = dpg.draw_rectangle(pmin=[0, 0], pmax=[100, 100], fill=[0, 0, 255, 128], parent="draw_node")
if __name__ == "__main__":
app = application()