class SvNodeTreeCommon(object): ''' Common methods shared between Sverchok node trees (normal and monad trees) ''' # auto update toggle of the node tree sv_process: BoolProperty(name="Process", default=True, description='Process layout') has_changed: BoolProperty(default=False) # "True if changes of links in tree was detected" # for throttle method usage when links are created in the tree via Python skip_tree_update: BoolProperty(default=False) # usage only via throttle_update method tree_id_memory: StringProperty(default="") # identifier of the tree, should be used via `tree_id` property sv_links = SvLinks() # cached Python links nodes_dict = SvNodesDict() # cached Python nodes @property def tree_id(self): """Identifier of the tree""" if not self.tree_id_memory: self.tree_id_memory = str(hash(self) ^ hash(time.monotonic())) return self.tree_id_memory def get_groups(self): """ It gets monads of node tree, Update them (the sv_update method will check if anything changed inside the monad and will change the monad outputs in that case) Return the monads that have changed ( to inform the caller function that the nodes downstream have to be updated with the new data) """ affected_groups =[] for node in self.nodes: if 'SvGroupNode' in node.bl_idname: sub_tree = node.monad sub_tree.sv_update() if sub_tree.has_changed: affected_groups.append(node) sub_tree.has_changed = False return affected_groups def sv_update(self): """ the method checks if anything changed inside the normal tree or monad and update them if necessary """ self.sv_links.create_new_links(self) if self.sv_links.links_have_changed(self): self.has_changed = True build_update_list(self) process_from_nodes(self.sv_links.get_nodes(self)) self.sv_links.store_links_cache(self) else: process_from_nodes(self.get_groups()) def animation_update(self): """Find animatable nodes and update from them""" animated_nodes = [] for node in self.nodes: if hasattr(node, 'is_animatable'): if node.is_animatable: animated_nodes.append(node) process_from_nodes(animated_nodes) @contextmanager def throttle_update(self): """ usage with tree.throttle_update(): tree.nodes.new(...) tree.links.new(...) tree should be updated manually if needed """ previous_state = self.skip_tree_update self.skip_tree_update = True try: yield self finally: self.skip_tree_update = previous_state
class SvNodeTreeCommon(object): ''' Common methods shared between Sverchok node trees ''' sv_process: BoolProperty(name="Process", default=True, description='Process layout') has_changed: BoolProperty(default=False) limited_init: BoolProperty(default=False) skip_tree_update: BoolProperty(default=False) configuring_new_node: BoolProperty(name="indicate node initialization", default=False) tree_id_memory: StringProperty(default="") sv_links = SvLinks() nodes_dict = SvNodesDict() @property def tree_id(self): if not self.tree_id_memory: self.tree_id_memory = str(hash(self) ^ hash(time.monotonic())) return self.tree_id_memory def build_update_list(self): build_update_list(self) def adjust_reroutes(self): reroutes = [n for n in self.nodes if n.bl_idname == 'NodeReroute'] if not reroutes: return for n in reroutes: s = n.inputs[0] if s.links: self.freeze(True) other = get_other_socket(s) s_type = other.bl_idname if n.outputs[0].bl_idname != s_type: out_socket = n.outputs.new(s_type, "Output") in_sockets = [l.to_socket for l in n.outputs[0].links] n.outputs.remove(n.outputs[0]) for i_s in in_sockets: l = self.links.new(i_s, out_socket) self.unfreeze(True) def freeze(self, hard=False): if hard: self["don't update"] = 1 elif not self.is_frozen(): self["don't update"] = 0 def is_frozen(self): return "don't update" in self def unfreeze(self, hard=False): if self.is_frozen(): if hard or self["don't update"] == 0: del self["don't update"] def get_update_lists(self): return get_update_lists(self) @property def sv_trees(self): res = [] for ng in bpy.data.node_groups: if ng.bl_idname in {'SverchCustomTreeType', 'SverchGroupTreeType'}: res.append(ng) return res def update_sv_links(self): self.sv_links.create_new_links(self) def links_have_changed(self): return self.sv_links.links_have_changed(self) def store_links_cache(self): self.sv_links.store_links_cache(self) def get_nodes(self): return self.sv_links.get_nodes(self) def get_groups(self): affected_groups =[] for node in self.nodes: if 'SvGroupNode' in node.bl_idname: sub_tree = node.monad sub_tree.sv_update() if sub_tree.has_changed: affected_groups.append(node) sub_tree.has_changed = False return affected_groups def sv_update(self): self.update_sv_links() if self.links_have_changed(): self.has_changed = True build_update_list(self) process_from_nodes(self.get_nodes()) self.store_links_cache() else: process_from_nodes(self.get_groups()) def animation_update(self): animated_nodes = [] for node in self.nodes: if hasattr(node, 'is_animatable'): if node.is_animatable: animated_nodes.append(node) process_from_nodes(animated_nodes)
class SvNodeTreeCommon(object): ''' Common methods shared between Sverchok node trees ''' # auto update toggle of the node tree sv_process: BoolProperty(name="Process", default=True, description='Process layout') has_changed: BoolProperty( default=False) # "True if changes of links in tree was detected" # for throttle method usage when links are created in the tree via Python skip_tree_update: BoolProperty( default=False) # usage only via throttle_update method tree_id_memory: StringProperty( default="" ) # identifier of the tree, should be used via `tree_id` property sv_links = SvLinks() # cached Python links nodes_dict = SvNodesDict() # cached Python nodes @property def tree_id(self): """Identifier of the tree""" if not self.tree_id_memory: self.tree_id_memory = str(hash(self) ^ hash(time.monotonic())) return self.tree_id_memory def sv_update(self): """ the method checks if anything changed inside the tree and update it if necessary """ self.sv_links.create_new_links(self) if self.sv_links.links_have_changed(self): self.has_changed = True build_update_list(self) process_from_nodes(self.sv_links.get_nodes(self)) self.sv_links.store_links_cache(self) def animation_update(self): """Find animatable nodes and update from them""" animated_nodes = [] for node in self.nodes: if hasattr(node, 'is_animatable'): if node.is_animatable: animated_nodes.append(node) process_from_nodes(animated_nodes) @contextmanager def throttle_update(self): """ usage with tree.throttle_update(): tree.nodes.new(...) tree.links.new(...) tree should be updated manually if needed """ previous_state = self.skip_tree_update self.skip_tree_update = True try: yield self finally: self.skip_tree_update = previous_state def update_gl_scale_info(self, origin=None): """ the nodeview scale and dpi differs between users and must be queried to get correct nodeview x,y and dpi scale info. this is instead of calling `get_dpi_factor` on every redraw. """ debug(f"update_gl_scale_info called from {origin or self.name}") try: from sverchok.utils.context_managers import sv_preferences with sv_preferences() as prefs: prefs.set_nodeview_render_params(None) except Exception as err: debug('failed to get gl scale info', err) @contextmanager def init_tree(self): """It suppresses calling the update method of nodes, main usage of it is during generating tree with python (JSON import)""" is_already_initializing = 'init_tree' in self if is_already_initializing: yield self else: self['init_tree'] = '' try: yield self finally: del self['init_tree']
class SvNodeTreeCommon(object): ''' Common methods shared between Sverchok node trees (normal and monad trees) ''' # auto update toggle of the node tree sv_process: BoolProperty(name="Process", default=True, description='Process layout') has_changed: BoolProperty( default=False) # "True if changes of links in tree was detected" # for throttle method usage when links are created in the tree via Python skip_tree_update: BoolProperty(default=False) tree_id_memory: StringProperty( default="" ) # identifier of the tree, should be used via `tree_id` property sv_links = SvLinks() # cached Python links nodes_dict = SvNodesDict() # cached Python nodes @property def tree_id(self): """Identifier of the tree""" if not self.tree_id_memory: self.tree_id_memory = str(hash(self) ^ hash(time.monotonic())) return self.tree_id_memory def freeze(self, hard=False): """Temporary prevent tree from updating nodes""" if hard: self["DoNotUpdate"] = 1 elif not self.is_frozen(): self["DoNotUpdate"] = 0 def is_frozen(self): """Nodes of the tree won't be updated during changes events""" return "DoNotUpdate" in self def unfreeze(self, hard=False): """ Remove freeze mode from tree. If freeze mode was in hard mode `hard` argument should be True to unfreeze tree """ if self.is_frozen(): if hard or self["DoNotUpdate"] == 0: del self["DoNotUpdate"] def get_groups(self): """ It gets monads of node tree, Update them (the sv_update method will check if anything changed inside the monad and will change the monad outputs in that case) Return the monads that have changed ( to inform the caller function that the nodes downstream have to be updated with the new data) """ affected_groups = [] for node in self.nodes: if 'SvGroupNode' in node.bl_idname: sub_tree = node.monad sub_tree.sv_update() if sub_tree.has_changed: affected_groups.append(node) sub_tree.has_changed = False return affected_groups def sv_update(self): """ the method checks if anything changed inside the normal tree or monad and update them if necessary """ self.sv_links.create_new_links(self) if self.sv_links.links_have_changed(self): self.has_changed = True build_update_list(self) process_from_nodes(self.sv_links.get_nodes(self)) self.sv_links.store_links_cache(self) else: process_from_nodes(self.get_groups()) def animation_update(self): """Find animatable nodes and update from them""" animated_nodes = [] for node in self.nodes: if hasattr(node, 'is_animatable'): if node.is_animatable: animated_nodes.append(node) process_from_nodes(animated_nodes)