import bpy from . import fn ## direct use (Pop up menu version below) """ class GPEXP_OT_clean_compo_tree(bpy.types.Operator): bl_idname = "gp.clean_compo_tree" bl_label = "Clean Compo Tree" bl_description = "Reorder inputs/outputs and clear unused viewlayers" bl_options = {"REGISTER"} @classmethod def poll(cls, context): return True # mode : bpy.props.StringProperty(default='NORMAL', options={'SKIP_SAVE'}) def execute(self, context): render = bpy.data.scenes.get('Render') if not render: print('SKIP, no Render scene') return {"CANCELLED"} print('re-arranging frames') fn.rearrange_frames(render.node_tree) for n in render.node_tree.nodes: if n.name.startswith('NG_'): fn.reorder_inputs(n) fn.reorder_outputs(n) # get output node to reorder output out = None for s in n.outputs: if not s.is_linked: continue out = s.links[0].to_node if out.type == 'OUTPUT_FILE': break if out: fn.reorder_fileout(out, ng=n) ## clear disconnected fileout ??... # for fo in render.node_tree.nodes: # if fo.type != 'OUTPUT_FILE': # continue # fn.clear_disconnected(fo) return {"FINISHED"} """ class GPEXP_OT_clean_compo_tree(bpy.types.Operator): bl_idname = "gp.clean_compo_tree" bl_label = "Clean Compo Tree" bl_description = "Pop up menu with cleaning options" bl_options = {"REGISTER", "UNDO"} clear_unused_view_layers : bpy.props.BoolProperty(name="Clear unused view layers", description="Delete view layer that aren't used in the nodetree anymore", default=True) arrange_rl_nodes : bpy.props.BoolProperty(name="Arrange Render Node In Frames", description="Re-arrange Render Layer Nodes Y positions within each existing frames" , default=True) arrange_frames : bpy.props.BoolProperty(name="Arrange Frames", description="Re-arrange all frames Y positions" , default=True) reorder_inputs : bpy.props.BoolProperty(name="Reorder I/O Sockets", description="Reorder inputs/outputs of all 'NG_' nodegroup and their connected file output", default=True) clear_isolated_node_in_groups : bpy.props.BoolProperty(name="Clear Isolated Node In Groups", description="Clean content of 'NG_' nodegroup bpy deleting isolated nodes)", default=True) fo_clear_disconnected : bpy.props.BoolProperty(name="Remove Disconnected Export Inputs", description="Clear any disconnected intput of every 'file output' node", default=False) @classmethod def poll(cls, context): return True def invoke(self, context, event): # self.nodes = context.object return context.window_manager.invoke_props_dialog(self) def draw(self, context): layout = self.layout layout.prop(self, 'clear_unused_view_layers') layout.prop(self, 'arrange_rl_nodes') layout.prop(self, 'arrange_frames') layout.prop(self, 'reorder_inputs') layout.prop(self, 'clear_isolated_node_in_groups') layout.separator() layout.prop(self, 'fo_clear_disconnected') if self.fo_clear_disconnected: layout.label(text='Disconnected inputs are not exported', icon='INFO') # box = layout.box() # box.prop(self, 'arrange_frames') # box.prop(self, 'reorder_inputs') # box.prop(self, 'fo_clear_disconnected') def execute(self, context): # render = bpy.data.scenes.get('Render') # if not render: # print('SKIP, no Render scene') # return {"CANCELLED"} render = context.scene nodes = render.node_tree.nodes if self.clear_unused_view_layers: used_rlayer_names = [n.layer for n in nodes if n.type == 'R_LAYERS'] for rl in reversed(render.view_layers): if rl.name in used_rlayer_names or rl.name == 'View Layer': continue render.view_layers.remove(rl) if self.arrange_rl_nodes: fn.rearrange_rlayers_in_frames(render.node_tree) if self.arrange_frames: fn.rearrange_frames(render.node_tree) if self.reorder_inputs: for n in nodes: if n.type != 'GROUP' or not n.name.startswith('NG_'): continue fn.reorder_inputs(n) fn.reorder_outputs(n) # get output node to reorder output out = None for s in n.outputs: if not s.is_linked: continue out = s.links[0].to_node if out.type == 'OUTPUT_FILE': break if out: fn.reorder_fileout(out, ng=n) # Clear input that do not exists fn.clean_nodegroup_inputs(n, skip_existing_pass=True) fn.bridge_reconnect_nodegroup(n) if self.clear_isolated_node_in_groups: for n in nodes: if n.type != 'GROUP' or not n.name.startswith('NG_'): continue fn.clear_nodegroup_content_if_disconnected(n.node_tree) if self.fo_clear_disconnected: for fo in nodes: if fo.type != 'OUTPUT_FILE': continue fn.clear_disconnected(fo) return {"FINISHED"} classes=( GPEXP_OT_clean_compo_tree, ) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)