import bpy from bpy.props import BoolProperty, StringProperty from . import fn 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"} # Internal prop (use when launching from python) scene : StringProperty(name="Rener Scene", description="Scene to clear node from", default='', options={'SKIP_SAVE'}) node_scene : StringProperty(name="Compositing Scene", description="Scene containing nodes, using current scene when calling operator from UI to clean node", default='', options={'SKIP_SAVE'}) clear_unused_view_layers : BoolProperty(name="Clear unused view layers", description="Delete view layer that aren't used in the nodetree anymore", default=True) arrange_rl_nodes : BoolProperty(name="Arrange Render Node In Frames", description="Re-arrange Render Layer Nodes Y positions within each existing frames" , default=True) arrange_frames : BoolProperty(name="Arrange Frames", description="Re-arrange all frames Y positions" , default=True) reorder_inputs : 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 : BoolProperty(name="Clear Isolated Node In Groups", description="Clean content of 'NG_' nodegroup bpy deleting isolated nodes)", default=True) fo_clear_disconnected : 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): 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): if self.scene: scn = bpy.data.scenes.get(self.scene) if not scn: print(f'SKIP clean_compo_tree, No "{self.scene}" render scene found!') return {"CANCELLED"} else: scn = fn.get_render_scene(create=False) if self.node_scene: node_scene = bpy.data.scenes.get(self.node_scene) if not scn: print(f'SKIP clean_compo_tree, No "{self.node_scene}" compo scene found!') return {"CANCELLED"} else: node_scene = context.scene nodes = node_scene.node_tree.nodes for n in nodes: n.update() if self.clear_unused_view_layers: used_rlayer_names = [n.layer for n in nodes if n.type == 'R_LAYERS'] for rl in reversed(scn.view_layers): if rl.name in used_rlayer_names or rl.name == 'View Layer': continue scn.view_layers.remove(rl) if self.arrange_rl_nodes: fn.rearrange_rlayers_in_frames(node_scene.node_tree) if self.arrange_frames: fn.rearrange_frames(node_scene.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)