def update(self): """trigger on links or nodes collections changes, on assigning tree to a group node also it is triggered when a tree, next in the path, was changed (even if this tree was not effected)""" # When group input or output nodes are connected some extra work should be done if 'init_tree' in self.id_data: # tree is building by a script - let it do this return self.check_last_socket( ) # Should not be too expensive to call it each update if self.name not in bpy.data.node_groups: # load new file event return if not hasattr(bpy.context.space_data, 'path'): # 3D panel also can call update method O_o return if not self.group_node_name: # initialization tree return group_node: SvGroupTreeNode = None # update tree can lead to calling update of previous tree too, so should find position tree in the path for i, path in zip(range(-1, -1000, -1), reversed(bpy.context.space_data.path)): if path.node_tree == self: group_node = bpy.context.space_data.path[ i - 1].node_tree.nodes[self.group_node_name] break if group_node is None: # the tree was assigned to a group node, it does not have sense to update return self.check_reroutes_sockets() self.update_sockets( ) # probably more precise trigger could be found for calling this method handle_event(ev.GroupTreeEvent(self, self.get_update_path()))
def execute(self, context): group_node = context.node sub_tree: SvGroupTree = context.node.node_tree context.space_data.path.append(sub_tree, node=group_node) sub_tree.group_node_name = group_node.name event = ev.GroupTreeEvent(sub_tree, sub_tree.get_update_path()) handle_event(event) # todo make protection from editing the same trees in more then one area # todo add the same logic to exit from tree operator return {'FINISHED'}
def sv_pre_load(scene): """ This method is called whenever new file is opening THe update order is next: 1. pre_load handler 2. update methods of trees in a file 3. post_load handler 4. evaluate trees from main tree handler """ clear_all_socket_cache() sv_clean(scene) handle_event(ev.FileEvent())
def update_nodes(self, nodes: list): """ This method expect to get list of its nodes which should be updated Execution won't be immediately, use cases - 1. Node property of was changed 2. ??? """ # the method can be called during tree reconstruction from JSON file # in this case we does not intend doing any updates if not self.group_node_name: # initialization tree return handle_event(ev.GroupPropertyEvent(self, self.get_update_path(), nodes))
def update_group_tree(self, context): """Apply filtered tree to `node_tree` attribute. By this attribute Blender is aware of linking between the node and nested tree.""" handle_event(ev.TreesGraphEvent()) self.node_tree: SvGroupTree = self.group_tree # also default values should be fixed if self.node_tree: self.node_tree.use_fake_user = True for node_sock, interface_sock in zip(self.inputs, self.node_tree.inputs): if hasattr(interface_sock, 'default_value') and hasattr( node_sock, 'default_property'): node_sock.default_property = interface_sock.default_value self.node_tree.update_sockets( ) # properties of input socket properties should be updated else: # in case if None is assigned to node_tree self.inputs.clear() self.outputs.clear()
def sv_free(self): handle_event(ev.TreesGraphEvent())
def sv_copy(self, original): handle_event(ev.TreesGraphEvent())
class SverchCustomTree(NodeTree, SvNodeTreeCommon): ''' Sverchok - architectural node programming of geometry in low level ''' bl_idname = 'SverchCustomTreeType' bl_label = 'Sverchok Nodes' bl_icon = 'RNA' def turn_off_ng(self, context): """ Turn on/off displaying objects in viewport generated by viewer nodes Viewer nodes should have `show_viewport` method which takes 'to_show' bool argument """ for node in self.nodes: try: node.show_viewport(self.sv_show) except AttributeError: pass def on_draft_mode_changed(self, context): """ This is triggered when Draft mode of the tree is toggled. """ draft_nodes = [] for node in self.nodes: if hasattr(node, 'does_support_draft_mode' ) and node.does_support_draft_mode(): draft_nodes.append(node) node.on_draft_mode_changed(self.sv_draft) # From the user perspective, some of node parameters # got new parameter values, so the setup should be recalculated; # but techically, node properties were not changed # (only other properties were shown in UI), so enabling/disabling # of draft mode does not automatically trigger tree update. # Here we trigger it manually. if draft_nodes: self.update_nodes(draft_nodes) sv_process: BoolProperty( name="Process", default=True, description='Update upon tree and node property changes', update=lambda s, c: handle_event(ev.TreeEvent(s)), options=set(), ) sv_animate: BoolProperty(name="Animate", default=True, description='Animate this layout', options=set()) sv_show: BoolProperty(name="Show", default=True, description='Show this layout', update=turn_off_ng, options=set()) sv_show_socket_menus: BoolProperty( name="Show socket menus", description= "Display socket dropdown menu buttons. NOTE: options that are enabled in those menus will be effective regardless of this checkbox!", default=False, options=set()) # draft mode replaces selected properties of certain nodes with smaller values to lighten cpu load. sv_draft: BoolProperty( name="Draft", description="Draft (simplified processing) mode", default=False, update=on_draft_mode_changed, options=set(), ) sv_scene_update: BoolProperty( name="Scene update", description="Update upon changes in the scene", options=set(), default=True) def update(self): """This method is called if collection of nodes or links of the tree was changed""" handle_event(ev.TreeEvent(self)) def force_update(self): """Update whole tree from scratch""" # ideally we would never like to use this method but we live in the real world handle_event(ev.ForceEvent(self)) def update_nodes(self, nodes, cancel=True): """This method expects to get list of its nodes which should be updated""" return handle_event(ev.PropertyEvent(self, nodes)) def scene_update(self): """This method should be called by scene changes handler it ignores events related with S sverchok trees in other cases it updates nodes which read data from Blender""" handle_event(ev.SceneEvent(self)) def process_ani(self, frame_changed: bool, animation_playing: bool): """ Process the Sverchok node tree if animation layers show true. For animation callback/handler """ handle_event(ev.AnimationEvent(self, frame_changed, animation_playing))
class SvNodeTreeCommon: """Common class for all Sverchok trees (regular trees and group ones)""" tree_id_memory: StringProperty( default="" ) # identifier of the tree, should be used via `tree_id` property sv_show_time_nodes: BoolProperty( name="Node times", default=False, options=set(), update=lambda s, c: handle_event(ev.TreeEvent(s))) show_time_mode: EnumProperty( items=[(n, n, '') for n in ["Per node", "Cumulative"]], options=set(), update=lambda s, c: handle_event(ev.TreeEvent(s)), description="Mode of showing node update timings", ) @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 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'] def update_ui(self, nodes_errors, update_time): """ The method get information about node statistic of last update from the handler to show in view space The method is usually called by main handler to reevaluate view of the nodes in the tree even if the tree is not in the Live update mode""" update_time = update_time if self.sv_show_time_nodes else cycle([None]) for node, error, update in zip(self.nodes, nodes_errors, update_time): if hasattr(node, 'update_ui'): node.update_ui(error, update)
def process_ani(self, frame_changed: bool, animation_playing: bool): """ Process the Sverchok node tree if animation layers show true. For animation callback/handler """ handle_event(ev.AnimationEvent(self, frame_changed, animation_playing))
def scene_update(self): """This method should be called by scene changes handler it ignores events related with S sverchok trees in other cases it updates nodes which read data from Blender""" handle_event(ev.SceneEvent(self))
def update_nodes(self, nodes, cancel=True): """This method expects to get list of its nodes which should be updated""" return handle_event(ev.PropertyEvent(self, nodes))
def force_update(self): """Update whole tree from scratch""" # ideally we would never like to use this method but we live in the real world handle_event(ev.ForceEvent(self))
def update(self): """This method is called if collection of nodes or links of the tree was changed""" handle_event(ev.TreeEvent(self))