import bpy from bpy.types import Panel from . import fn # region viewlayer layout def viewlayer_layout(layout, scn): for vl in scn.view_layers: row = layout.row() row.prop(vl, 'use', text=vl.name, icon='RESTRICT_RENDER_OFF' if vl.use else 'RESTRICT_RENDER_ON', emboss=False, toggle=0) class RT_PT_viewlayers_ui(Panel): bl_space_type = "NODE_EDITOR" bl_region_type = "UI" bl_label = "View Layers" def draw(self, context): layout = self.layout layout.label(text=f'{context.scene.name} :: View layers') col = layout.column(align=True) viewlayer_layout(col, context.scene) class RT_PT_viewlayers_multi_ui(Panel): bl_space_type = "NODE_EDITOR" bl_region_type = "UI" bl_label = "Multi View Layers" def draw(self, context): layout = self.layout layout.label(text=f'{len(bpy.data.scenes)} scenes view layers:') for s in bpy.data.scenes: col = layout.column() # col.label(text=f'{s.name}:') col.label(text=s.name) viewlayer_layout(col, s) layout.separator() # region main panel class RT_PT_render_toolbox_ui(Panel): bl_space_type = "NODE_EDITOR" bl_region_type = "UI" bl_category = "Render" # Wrangler bl_label = "Render Toolbox" def draw(self, context): layout = self.layout ## Scene infos recap scn = context.scene text = f'{scn.render.resolution_x}x{scn.render.resolution_y} @ {scn.render.fps} fps' cam = context.scene.camera if cam: text = f'{cam.name} : {text}' else: text = f'No Camera ! : {text}' box = layout.box() col = box.column() col.label(text=text, icon='SCENE_DATA') # VIEW_CAMERA # col.label(text=f"{scn.render.fps} fps") if scn.render.resolution_percentage != 100: col.label(text='Percentage not 100%', icon='INFO') col.prop(scn.render, 'resolution_percentage', text="Resolution Percentage") percent = scn.render.resolution_percentage col.label(text=f"{int(scn.render.resolution_x * percent / 100)}x{int(scn.render.resolution_y * percent / 100)}", icon='INFO') if cam and cam.data.shift_x != 0 or cam.data.shift_y != 0: col.label(text='Camera has Shift', icon='INFO') # col.prop(cam.data, 'shift_x', text="Shift X") # col.prop(cam.data, 'shift_y', text="Shift Y") ## viewlayer section layout.label(text='View layers:') ct = len([n for n in context.scene.node_tree.nodes if n.type == 'R_LAYERS' and n.select]) # col = layout.column(align=True) # row=col.row(align=True) col = layout.column(align=False) row = col.row(align=True) row.operator("wm.call_panel", text="View layers", icon='RENDERLAYERS').name = "RT_PT_viewlayers_ui" row.operator("wm.call_panel", text="All View layers", icon='SCENE_DATA').name = "RT_PT_viewlayers_multi_ui" # row=layout.row(align=True) row1 = col.row(align=True) row1.operator('rt.activate_only_selected_layers', text=f'Activate Only {ct} RenderLayer Nodes') row1.enabled = ct > 0 exclude_count = len([vl for vl in scn.view_layers if not vl.use and vl.name not in {'exclude',}]) # 'View Layer', if exclude_count: # layout.label(text=f'{exclude_count} Excluded View Layers !') layout.operator('rt.enable_all_viewlayers', text=f'Reactivate {exclude_count} Excluded View Layers') # col = layout.column() # col.label(text='Clean and updates:') # col.operator('rt.clean_compo_tree', icon='BRUSHES_ALL', text='Clean Nodes') # NODE_CORNER # region file output ui class RT_PT_file_output_ui(bpy.types.Panel): bl_space_type = "NODE_EDITOR" bl_region_type = "UI" bl_category = "Render" bl_label = "File Output Manager" # bl_parent_id = "RT_PT_render_toolbox_ui" def draw(self, context): layout = self.layout col = layout.column() col.operator("rt.create_output_layers", text='Create File Output', icon="NODE") col.operator("rt.outputs_search_and_replace", text='Search And Replace Outputs', icon="BORDERMOVE") col.separator() col.operator('rt.set_output_node_format', icon='OUTPUT', text='Copy Output Format To Selected') col.operator('rt.set_active_file_output_slot_to_composite', icon='OUTPUT', text='Active Slot To Composite') layout.label(text='All Outputs:') row=layout.row(align=True) row.operator('rt.mute_toggle_output_nodes', icon='NODE_INSERT_ON', text='Mute').mute = True row.operator('rt.mute_toggle_output_nodes', icon='NODE_INSERT_OFF', text='Unmute').mute = False scn = context.scene disabled_output = [n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.mute] if disabled_output: output_ct = len([n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE']) layout.label(text=f'{len(disabled_output)}/{output_ct} Output Muted', icon='INFO') col = layout.column() ## (re)number exports ct = len([n for n in context.scene.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.select]) txt = f'Renumber {ct} Selected Outputs' subcol = col.column() subcol.enabled = bool(ct) row = subcol.row(align=True) row.operator('rt.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED' op = row.operator('rt.number_outputs', icon='X', text='') op.mode = 'SELECTED' op.clear = True # region visibility ui # Base panel for drawing class RT_PT_visibility_check_ui_base(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "View" bl_label = "Visibility Checks" bl_options = {'DEFAULT_CLOSED'} def draw_header_preset(self, context): layout = self.layout layout.operator('rt.scene_checker', text="", icon='CHECKMARK') #, depress=True def draw(self, context): layout = self.layout col = layout.column(align=True) col .label(text="List Visibility Conflicts:") # , icon='HIDE_OFF' row = col.row(align=True) row.operator("rt.list_object_visibility_conflicts", text="Objects", icon="OBJECT_DATAMODE") row.operator("rt.list_viewport_render_visibility", text="Viewport Vs Render") # , icon="OBJECT_DATAMODE" col.operator("rt.list_modifier_visibility", text="Modifiers", icon="MODIFIER") col.operator("rt.list_collection_visibility_conflicts", text="Collections", icon="OUTLINER_COLLECTION") layout.separator() layout.operator("rt.list_object_affected_by_simplify", text="List Object Affected By Simplify", icon="MOD_SIMPLIFY") class RT_PT_visibility_check_ui_viewport(RT_PT_visibility_check_ui_base): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "View" class RT_PT_visibility_check_ui_node(RT_PT_visibility_check_ui_base): bl_space_type = 'NODE_EDITOR' # bl_parent_id = "RT_PT_render_toolbox_ui" bl_region_type = 'UI' bl_category = "Render" # Wrangler ? # region conformation ui class RT_PT_conformation_ui(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "View" bl_label = "Conformation" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout ## Show properties for outliner conformation layout.use_property_split = True layout.use_property_decorate = False # props = context.scene.render_toolbox_conform props = context.view_layer.render_toolbox_conform col = layout.column(align=True) col.prop(props, "hierarchy_type", text="Work On") # , expand=True # col.separator() col.prop(props, "target_name", text="Search") # (Optional) ## Show current target box = layout.box() tgt_row = box.row() if props.hierarchy_type == 'COLLECTION': ref_collection = fn.get_target_collection(props.target_name, context) if not ref_collection or ref_collection == context.scene.collection: layout.label(text="Select a collection or search by name", icon='INFO') if ref_collection == context.scene.collection: layout.label(text="Cannot use the scene collection", icon='ERROR') layout.label(text="An excluded collection collection cannot be active (use search)") return if not ref_collection: layout.label(text=f"Error: Collection '{ref_collection.name}' not found", icon='ERROR') return ref_vlc = fn.get_view_layer_collection(ref_collection) if not ref_vlc: layout.label(text=f"Error: Viewlayer Collection '{ref_collection.name}' not found", icon='ERROR') return # tgt_row = layout.row(align=True) # tgt_row.label(text="", icon='TRIA_RIGHT') tgt_row.label(text=ref_collection.name, icon='OUTLINER_COLLECTION') col = layout.column(align=False) col.operator("rt.store_visibility_states", text='Store Target Hierarchy State', icon="DISK_DRIVE") ## Show current collection state (behave badly when changed, should be tweaked before) # col = layout.column(align=True) row = tgt_row.row(align=True) row.prop(ref_vlc, "exclude", text="", emboss=False) row.prop(ref_collection, "hide_select", text="", emboss=False) row.prop(ref_vlc, "hide_viewport", text="", emboss=False) row.prop(ref_collection, "hide_viewport", text="", emboss=False) row.prop(ref_collection, "hide_render", text="", emboss=False) row.prop(ref_vlc, "holdout", text="", emboss=False) row.prop(ref_vlc, "indirect_only", text="", emboss=False) layout.prop(props, "affect_target", text="Target Items") layout.separator() col = layout.column(align=True) row = col.row(align=True) row.label(text="To Conform:") ## Same order, greyout unused options collec_row = row.row(align=True) collec_row.prop(props, "conform_exclude", text="", icon='CHECKBOX_DEHLT' if ref_vlc.exclude else 'CHECKBOX_HLT') # Exclude from View Layer collec_row.active = props.affect_target != 'OBJECT' ## Object and collections row.prop(props, "conform_selectability", text="", icon='RESTRICT_SELECT_ON' if ref_collection.hide_select else 'RESTRICT_SELECT_OFF') # Hide Select row.prop(props, "conform_viewlayer", text="", icon='HIDE_ON' if ref_vlc.hide_viewport else 'HIDE_OFF') # Hide in current viewlayer (eye) row.prop(props, "conform_viewport", text="", icon='RESTRICT_VIEW_ON' if ref_collection.hide_viewport else 'RESTRICT_VIEW_OFF') # Disable in Viewports row.prop(props, "conform_render", text="", icon='RESTRICT_RENDER_ON' if ref_collection.hide_render else 'RESTRICT_RENDER_OFF') # Disable in Renders ## Specific to collections collec_row = row.row(align=True) collec_row.prop(props, "conform_holdout", text="", icon='HOLDOUT_OFF') # Holdout collec_row.prop(props, "conform_use_indirect", text="", icon='INDIRECT_ONLY_OFF') # Indirect Only collec_row.active = props.affect_target != 'OBJECT' else: ref_obj = fn.get_target_object(props.target_name, context) if not ref_obj: layout.label(text="Make object active or search by name", icon='INFO') return # tgt_row = layout.row(align=True) # tgt_row.label(text="", icon='TRIA_RIGHT') tgt_row.label(text=ref_obj.name, icon='OBJECT_DATA') if not ref_obj.children_recursive: tgt_row.label(text="No Children", icon='ERROR') return layout.separator() ## Show current collection state (can behave badly when changed, should be tweaked before) # col = layout.column(align=True) row = tgt_row.row(align=True) # row.label(text="Reference Object State:") row.prop(ref_obj, "hide_select", text="", emboss=False) # row.prop(props, "active_object_viewlayer_hide", text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF', emboss=False) # hack row.label(text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF') # hack row.prop(ref_obj, "hide_viewport", text="", emboss=False) row.prop(ref_obj, "hide_render", text="", emboss=False) layout.separator() col = layout.column(align=True) row = col.row(align=True) row.label(text="To Conform:") row.prop(props, "conform_selectability", text="", icon='RESTRICT_SELECT_ON' if ref_obj.hide_select else 'RESTRICT_SELECT_OFF') # Hide Select row.prop(props, "conform_viewlayer", text="", icon='HIDE_ON' if ref_obj.hide_get() else 'HIDE_OFF') # Hide in current viewlayer (eye) row.prop(props, "conform_viewport", text="", icon='RESTRICT_VIEW_ON' if ref_obj.hide_viewport else 'RESTRICT_VIEW_OFF') # Disable in Viewports row.prop(props, "conform_render", text="", icon='RESTRICT_RENDER_ON' if ref_obj.hide_render else 'RESTRICT_RENDER_OFF') # Disable in Renders layout.operator("rt.conform_collection_hierarchy",text="Conform Hierarchy", icon="CHECKMARK") # region outliner state class RT_PT_outliner_state_ui(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "View" bl_label = "Outliner State" bl_options = {'DEFAULT_CLOSED'} bl_parent_id = "RT_PT_conformation_ui" def draw(self, context): layout = self.layout ## Outliner state ## Scene col = layout.column() col.operator("rt.store_visibility_states", text='Store Whole Viewlayer State', icon="DISK_DRIVE").collection_name = "ALL-SCENE-COLLECTION" stored_keys = context.scene.get('outliner_state', {}).keys() if stored_keys and 'ALL' in stored_keys: row = col.row(align=True) row.operator("rt.apply_visibility_states", text=f"Restore Viewlayer State", icon="OUTLINER").collection_name = "ALL-SCENE-COLLECTION" row.operator("rt.delete_visibility_states", text="", icon="TRASH").collection_name = 'ALL' col = layout.column() ## Specific collection if stored_keys: col.label(text="Collections State:") for key in stored_keys: if key == 'ALL': continue row = col.row(align=True) row.operator("rt.apply_visibility_states", text=f"Restore: {key}", icon="OUTLINER").collection_name = key row.operator("rt.delete_visibility_states", text="", icon="TRASH").collection_name = key ## Unused, only exposed in Create output panel # class RT_PT_output_template(Panel): # bl_space_type = "3D_VIEW" # bl_region_type = "UI" # bl_category = "Render" # Wrangler # bl_label = "File Output Templates" # bl_parent_id = "RT_PT_render_toolbox_ui" # # bl_options = {'DEFAULT_CLOSED'} # def draw(self, context): # layout = self.layout # settings = context.scene.render_toolbox # col = layout.column(align=True) # col.label(text='Single file:') # col.prop(settings, "default_base_path", text="Base Path") # col.prop(settings, "default_file_slot", text="File Slot") # col.separator() # col = layout.column(align=True) # col.label(text='Multilayers:') # col.prop(settings, "default_multilayer_base_path", text="Base Path") # col.prop(settings, "default_multilayer_name", text="Layer Name") # ## Handle separate tech passes names ? classes = ( RT_PT_viewlayers_ui, RT_PT_viewlayers_multi_ui, RT_PT_render_toolbox_ui, RT_PT_file_output_ui, RT_PT_visibility_check_ui_viewport, RT_PT_visibility_check_ui_node, RT_PT_conformation_ui, RT_PT_outliner_state_ui, # RT_PT_output_template, ) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)