api.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. from collections import namedtuple
  2. from pydrk import Api, HostApi, PropertyType, PropertySubType, Property
  3. import zmq
  4. api = Api()
  5. host = HostApi(api)
  6. print("Node status:", api.hello())
  7. def make_sub_socket():
  8. context = zmq.Context()
  9. socket = context.socket(zmq.SUB)
  10. socket.setsockopt(zmq.SUBSCRIBE, b'')
  11. socket.connect("tcp://localhost:9485")
  12. return socket
  13. def rename_node(node, name):
  14. node_id = lookup_node(node)
  15. api.rename_node(node_id, name)
  16. def remove_all_slots(node_path, sig):
  17. node_id = api.lookup_node_id(node_path)
  18. for slot_id, slot in api.get_slots(node_id, sig):
  19. print(f"{node_path}:{sig}(): Unregistering slot '{slot}':{slot_id}")
  20. api.unregister_slot(node_id, sig, slot_id)
  21. def register_slot(node_path, sig, tag):
  22. remove_all_slots(node_path, sig)
  23. node_id = api.lookup_node_id(node_path)
  24. api.register_slot(node_id, sig, "", tag)
  25. def get_property(node_id, prop):
  26. node_id = lookup_node(node_id)
  27. return api.get_property(node_id, prop)
  28. def set_property(node_id, prop, val):
  29. node_id = lookup_node(node_id)
  30. match val:
  31. case float():
  32. api.set_property_f32(node_id, prop, val)
  33. case int():
  34. api.set_property_u32(node_id, prop, val)
  35. def set_property_bool(node_id, prop, val):
  36. node_id = lookup_node(node_id)
  37. api.set_property_bool(node_id, prop, val)
  38. def set_property_f32(node_id, prop, val):
  39. node_id = lookup_node(node_id)
  40. api.set_property_f32(node_id, prop, float(val))
  41. def set_property_u32(node_id, prop, val):
  42. node_id = lookup_node(node_id)
  43. api.set_property_u32(node_id, prop, int(val))
  44. def add_property_bool(node_id, prop, val=None):
  45. api.add_property(node_id, prop, PropertyType.BOOL)
  46. if val is not None:
  47. api.set_property_bool(node_id, prop, val)
  48. def add_property_f32(node_id, prop, val=None):
  49. api.add_property(node_id, prop, PropertyType.FLOAT32)
  50. if val is not None:
  51. api.set_property_f32(node_id, prop, val)
  52. def add_property_u32(node_id, prop, val=None):
  53. api.add_property(node_id, prop, PropertyType.UINT32)
  54. if val is not None:
  55. api.set_property_u32(node_id, prop, val)
  56. def lookup_node(node_id):
  57. if isinstance(node_id, str):
  58. node_id = api.lookup_node_id(node_id)
  59. return node_id
  60. def link_node(child_id, parent_id):
  61. child_id = lookup_node(child_id)
  62. parent_id = lookup_node(parent_id)
  63. api.link_node(child_id, parent_id)
  64. def unlink_node(child_id, parent_id):
  65. child_id = lookup_node(child_id)
  66. parent_id = lookup_node(parent_id)
  67. api.unlink_node(child_id, parent_id)
  68. def unlink_from_parents(node_id):
  69. node_id = lookup_node(node_id)
  70. for (_, parent_id, _) in api.get_parents(node_id):
  71. api.unlink_node(node_id, parent_id)
  72. def remove_node_recursive(node_id):
  73. node_id = lookup_node(node_id)
  74. for (_, child_id, _) in api.get_children(node_id):
  75. # Unlink the child
  76. api.unlink_node(child_id, node_id)
  77. # Remove the node
  78. remove_node_recursive(child_id)
  79. # Garbage collection
  80. if not api.get_parents(node_id):
  81. api.remove_node(node_id)
  82. def garbage_collect():
  83. dangling = api.scan_dangling()
  84. for node_id in dangling:
  85. remove_node_recursive(node_id)
  86. print(f"Garbage collect: removed {len(dangling)} nodes")
  87. KeyMods = namedtuple("KeyMods", ["shift", "ctrl", "alt", "logo"])
  88. class EventLoop:
  89. def __init__(self):
  90. self.subsock = make_sub_socket()
  91. register_slot("/window", "resize", b"rs")
  92. register_slot("/window/input/mouse", "button_down", b"ck")
  93. register_slot("/window/input/mouse", "wheel", b"wh")
  94. register_slot("/window/input/mouse", "move", b"mm")
  95. register_slot("/window/input/keyboard", "key_down", b"kd")
  96. def run(self):
  97. while True:
  98. data = self.subsock.recv()
  99. match data:
  100. case b"rs":
  101. w = get_property("/window", "width")
  102. h = get_property("/window", "height")
  103. self.resize_event(w, h)
  104. case b"ck":
  105. x = get_property("/window/input/mouse", "click_x")
  106. y = get_property("/window/input/mouse", "click_y")
  107. self.mouse_click(x, y)
  108. case b"wh":
  109. y = get_property("/window/input/mouse", "wheel_y")
  110. self.mouse_wheel(y)
  111. case b"mm":
  112. pass
  113. case b"kd":
  114. shift = get_property("/window/input/keyboard", "shift")
  115. ctrl = get_property("/window/input/keyboard", "ctrl")
  116. alt = get_property("/window/input/keyboard", "alt")
  117. logo = get_property("/window/input/keyboard", "logo")
  118. keycode = get_property("/window/input/keyboard", "keycode")
  119. repeat = get_property("/window/input/keyboard", "repeat")
  120. keymods = KeyMods(shift, ctrl, alt, logo)
  121. # Sometimes these get stuck when exiting the window.
  122. # We don't need these anyway
  123. if keycode in ("LeftShift", "LeftSuper"):
  124. continue
  125. self.key_down(keycode, keymods, repeat)
  126. def resize_event(self, w, h):
  127. pass
  128. def mouse_click(self, x, y):
  129. pass
  130. def mouse_wheel(self, y):
  131. pass
  132. def key_down(self, keycode, keymods, repeat):
  133. pass