import vpython as vp
[docs]class VObject:
"""
Parent class for visual objects (using vpython), streamlining the automatic
updating of visuals when attributes are changed, mouse interaction, and keeping track
of sets of visual objects which might be toggled on or off.
"""
[docs] def __init__(self, scene=None):
super().__setattr__("auto_refresh_attrs", {})
super().__setattr__("toggles", {})
self.scene = scene if scene else vp.scene
self.vchildren = []
self.toggles = {}
self.refreshments = []
self.refreshing = False
self.mousedown_callbacks = {}
self.mousemove_callbacks = []
self.mouseup_callbacks = []
self.scene.bind("mousedown", self.mousedown)
self.scene.bind("mousemove", self.mousemove)
self.scene.bind("mouseup", self.mouseup)
def __setattr__(self, name, value):
if name in self.auto_refresh_attrs:
super().__setattr__(name, value)
self.auto_refresh_attrs[name]()
elif name in self.toggles:
self.toggle(name, value)
super().__setattr__(name, value)
def toggle(self, name, value=None):
super().__setattr__(name, (True if not hasattr(self, name) or not getattr(self, name) else False) if value == None else value)
if getattr(self, name) and not self.toggles[name]["exists"]:
self.toggles["vchildren"] = self.toggles[name]["create"]()
self.vchildren.extend(self.toggles["vchildren"])
self.toggles[name]["exists"] = True
elif not getattr(self, name) and self.toggles[name]["exists"]:
self.destroy_vchildren(self.toggles["vchildren"])
self.toggles["vchildren"] = []
self.toggles[name]["exists"] = False
def add_toggle(self, name, create):
self.toggles[name] = {"exists": False, "create": create, "vchildren": []}
def refresh(self):
self.refreshing = True
[refreshment() for refreshment in self.refreshments]
self.refreshing = False
def mousedown(self):
pick = self.scene.mouse.pick
if pick in self.vchildren:
if pick in self.mousedown_callbacks:
self.mousedown_callbacks[pick]()
def mousemove(self):
[mousemove_callback() for mousemove_callback in self.mousemove_callbacks]
def mouseup(self):
[mouseup_callback() for mouseup_callback in self.mouseup_callbacks]
def destroy_vchildren(self, vchildren):
if type(vchildren) != list:
vchildren = [vchildren]
for vchild in vchildren:
self.vchildren.remove(vchild)
vchild.visible = False
del vchild
def destroy(self):
for vchild in self.vchildren:
vchild.visible = False
del vchild
self.scene.bind("mousedown", self.mousedown)
self.scene.bind("mousemove", self.mousemove)
self.scene.bind("mouseup", self.mouseup)