import bpy from bpy.types import Panel from pathlib import Path from .prefs import get_addon_prefs from .constant import RD_SCENE_NAME # from .preferences import get_addon_prefs # Node view panel class GPEXP_PT_gp_node_ui(Panel): bl_space_type = "NODE_EDITOR" bl_region_type = "UI" # bl_category = "View" bl_category = "GP render" bl_label = "Gpencil Render Manager" def draw(self, context): prefs = get_addon_prefs() advanced = prefs.advanced layout = self.layout row = layout.row(align=True) row.operator('gp.render_scene_switch', icon='SCENE_DATA', text='Switch Scene') ## Check if there is another scene reference current scene in it's comp renderlayers ## If so, expose a button to go in (expensive check ?) node_scn = next((s for s in bpy.data.scenes if s != context.scene and s.use_nodes and next((n for n in s.node_tree.nodes if n.type == 'R_LAYERS' and n.scene == context.scene), None) ),None) if node_scn: row.operator('gp.render_scene_switch', icon='NODETREE', text='Node Scene').scene = node_scn.name scn = context.scene ## Camera swapping row = layout.row() cam = scn.camera if cam: text = f'{cam.name} : {scn.render.resolution_x}x{scn.render.resolution_y}' # Cam: else: text = f'None' # Cam: # if cam and cam_name == 'draw_cam': # cam_name = f'{cam.parent.name} > {cam_name}' row.operator("gp.swap_render_cams", text=text, icon='OUTLINER_OB_CAMERA') # Live checks if scn.render.resolution_percentage != 100: layout.label(text='Res Percentage not 100%', icon='ERROR') layout.prop(scn.render, 'resolution_percentage') exclude_count = len([vl for vl in scn.view_layers if not vl.use and vl.name not in {'View Layer', 'exclude'}]) if exclude_count: # layout.label(text=f'{exclude_count} Excluded View Layers !') layout.operator('gp.enable_all_viewlayers', text=f'Reactivate {exclude_count} Excluded View Layers') if not scn.use_nodes or not scn.node_tree: return 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') layout.separator() 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) row=layout.row(align=True) row1 = row.row(align=True) row1.operator('gp.activate_only_selected_layers', text=f'Activate Only {ct} Layer Nodes') row1.enabled = ct > 0 row2=row.row(align=True) row2.operator("wm.call_panel", text="", icon='RENDERLAYERS').name = "GPEXP_PT_viewlayers_ui" row2.operator("wm.call_panel", text="", icon='SCENE_DATA').name = "GPEXP_PT_viewlayers_multi_ui" # row2.operator("gp.viewlayer_popup", text="", icon='RENDERLAYERS') # Ops invoke hack # row2.operator("wm.call_menu", text="", icon='RENDERLAYERS').name = "GPEXP_MT_viewlayers_popup" # Bad menu if advanced: col = layout.column(align=True) txt = f'Merge {ct} Layer Nodes' col.operator('gp.merge_selected_viewlayer_nodes', icon='NODETREE', text=txt).disconnect = True col.operator('gp.merge_selected_viewlayer_nodes', icon='NODETREE', text='Merge (keep connect)').disconnect = False col.enabled = ct > 1 layout.separator() col = layout.column() subcol = col.column() n = context.scene.node_tree.nodes.active if n: subcol.enabled = n and n.type == 'R_LAYERS' and not n.outputs[0].is_linked else: subcol.enabled = False subcol.operator('gp.reconnect_render_layer', icon='ANIM', text=f'Reconnect {ct} Layer Node') col.operator('gp.delete_render_layer', icon='TRACKING_CLEAR_FORWARDS', text=f'Delete {ct} Layer Node') layout.separator() layout.label(text='All Outputs:') row=layout.row() row.operator('gp.mute_toggle_output_nodes', icon='NODE_INSERT_ON', text='Mute').mute = True row.operator('gp.mute_toggle_output_nodes', icon='NODE_INSERT_OFF', text='Unmute').mute = False layout.separator() col=layout.column() col.label(text='Clean and updates:') col.separator() col.operator('gp.clean_compo_tree', icon='BRUSHES_ALL', text='Clean Nodes') # NODE_CORNER col.operator('gp.reset_render_settings', icon='SCENE', text='Reset All Scenes Render Settings') col.operator('gp.check_render_scene', icon='PRESET', text='Check For Problems') col.separator() ## (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('gp.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED' op = row.operator('gp.number_outputs', icon='X', text='') op.mode = 'SELECTED' op.clear = True ## Set / remove preview row=layout.row(align=True) row.operator('gp.merge_preview_ouput', icon='NODETREE', text='Set Preview') row.operator('gp.merge_preview_ouput', icon='X', text='').clear = True # subcol.operator('gp.normalize_outnames', icon='SYNTAX_OFF', text=f'Normalize Paths {ct} Selected Ouptut') # not ready # col.operator('gp.number_outputs', icon='LINENUMBERS_ON', text='Renumber all outputs').mode = 'ALL' if advanced: subcol.operator('gp.set_output_node_format', icon='OUTPUT', text='Copy Active Output Format') subcol.operator('gp.set_active_fileout_to_compout', icon='OUTPUT', text='Active Slot to Composite') col.operator('gp.connect_selected_to_file_out', icon='OUTPUT', text='Connect Selection To Ouput') layout.separator() col=layout.column() col.label(text='Delete Options:') if advanced: col.operator('gp.clear_render_tree', icon='X', text='Clear Framed Nodes') col.operator('gp.clear_render_tree', icon='X', text='Clear & Delete Render Scene').mode = "COMPLETE" layout.separator() layout.label(text='Scenes:') row = layout.row(align=True) row.operator('gp.split_to_scene', icon='DUPLICATE', text='Split Selection To Scene').mode = 'ALL' row.operator('gp.split_to_scene', text='Split Individually').mode = 'INDIVIDUAL' row = layout.row(align=True) row.operator('gp.set_crop_from_selection', icon='CON_OBJECTSOLVER', text='Autoset Crop') row.operator('gp.export_crop_coord_to_json', icon='FILE', text='Export json') layout.label(text='Render:') row = layout.row(align=True) row.operator('gp.render_selected_scenes', icon='RENDER_ANIMATION', text='Render Selected Scene') row.operator('gp.bg_render_script_selected_scenes', icon='TEXT', text='Gen Batch') # row.operator('gp.render_all_scenes', icon='RENDER_ANIMATION', text='Render All') if advanced: layout.separator() col = layout.column() col.label(text='Post-Render:') col.operator('gp.renumber_files_on_disk', icon='FILE', text='Renumber Files On Disk') layout.prop(context.scene.gp_render_settings, 'use_aa', text='Use Native AA Settings') layout.prop(prefs, 'advanced', text='Show Advanced Options') # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'ALL' # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'SELECTED' # layout.operator('gp.merge_layers', icon='X', text='Merge selected nodes') class GPEXP_PT_gp_dopesheet_ui(Panel): bl_space_type = 'DOPESHEET_EDITOR' bl_region_type = 'UI' bl_category = "GP Render" # bl_parent_id='DOPESHEET_PT_gpencil_mode' bl_label = "Gpencil Render Manager" @classmethod def poll(cls, context): return context.object and context.object.type == 'GPENCIL' def draw(self, context): layout = self.layout settings = context.scene.gp_render_settings icon = 'DISCLOSURE_TRI_DOWN' if settings.show_scene_setup else 'DISCLOSURE_TRI_RIGHT' col = layout.column() col.prop(settings, 'show_scene_setup', icon=icon, text='Scenes Setup', emboss=False ) if settings.show_scene_setup: col.prop(settings, 'render_scene', icon='SCENE_DATA', placeholder=RD_SCENE_NAME) nodetree_placeholder = settings.render_scene or RD_SCENE_NAME col.prop(settings, 'node_scene', icon='NODETREE', placeholder=nodetree_placeholder) op = layout.operator('gp_export.render_auto_build') op.node_scene = settings.node_scene if context.object: layout.label(text=f'Object: {context.object.name}') if context.object.data.users > 1: row = layout.row() row.label(text=f'Multiple users ({context.object.data.users})', icon='ERROR') row.operator("wm.call_menu", text="", icon='QUESTION').name = "GPEXP_MT_multi_user_doc" if context.object.data.layers.active: layout.label(text=f'viewlayer: {context.object.data.layers.active.viewlayer_render}') else: layout.label(text=f'No active layer found') layout.label(text=f'(Active dopesheet layer not in active obj)') ## On layers col = layout.column() col.operator('gp.select_layer_in_comp', icon='RESTRICT_SELECT_OFF', text='Select Nodes') if context.object and context.object.type == 'GPENCIL': txt = f'{len([l for l in context.object.data.layers if l.select])} Layer(s) To Render' else: txt = 'Layer To Render' op = col.operator('gp.add_layer_to_render', icon='RENDERLAYERS', text=txt) op.node_scene = settings.node_scene # merge (only accessible if multiple layers selected) row = col.row() ct = len([l for l in context.object.data.layers if l.select]) txt = f'Merge {ct} layers' # merge layers from dopesheet row.operator('gp.merge_viewlayers_to_active', text=txt, icon='SELECT_EXTEND').multi_object_merge = True ct = len([l for ob in context.selected_objects if ob.type == 'GPENCIL' for l in ob.data.layers if l.select]) txt = f'Multi: {ct} layers' row.operator('gp.merge_viewlayers_to_active', text=txt, icon='SELECT_EXTEND').multi_object_merge = True row.enabled= ct > 1 col.operator('gpexp.auto_merge_adjacent_prefix', icon='SELECT_EXTEND') row = col.row(align=True) row.operator('gp.remove_viewlayer_on_selected', text=f'Exclude {ct} layers', icon='X').remove_all_hidden = False row.operator('gp.remove_viewlayer_on_selected', text='', icon='HIDE_ON').remove_all_hidden = True ## all and objects layout.separator() col = layout.column() col.label(text='Whole Objects:') txt = f'{len([o for o in context.selected_objects if o.type == "GPENCIL" and o.select_get()])} Selected Object(s) To Render' op = col.operator('gp.add_object_to_render', icon='RENDERLAYERS', text=txt) op.mode='SELECTED' op.node_scene = settings.node_scene op = col.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='All Visible GP To Render') op.mode='ALL' op.node_scene = settings.node_scene layout.separator() col = layout.column() col.label(text='Fixes:') row = col.row(align=True) row.operator('gp.auto_number_object', icon='OBJECT_DATAMODE', text='Renumber Objects') row.operator('gp.auto_number_object', icon='X', text='').delete = True col.operator('gp.lower_layers_name', icon='SYNTAX_OFF', text='Rename Lowercase') col.operator('gp.export_infos_for_compo', icon='FILE', text='Export Layers Infos') # Not really need, called in Check layers invoke row = layout.row(align=True) row.operator('gp.layers_state', icon='CHECKMARK', text='Check layers') row.operator('gp.restore_layers_state', icon='DECORATE_OVERRIDE', text='') col.operator('gp.check_masks', icon='MOD_MASK', text='Has Masks') # row = layout.row() layout.prop(bpy.context.preferences.edit, 'use_anim_channel_group_colors') layout.separator() # row.operator('gp.export_as_pdf', icon='RENDER_STILL', text='Render All to PDF Sequences') layout.label(text='Render All To Vector:') col= layout.column() row = col.row(align=True) row.operator('gp.export_as_pdf', icon='RENDER_STILL', text='PDF Sequences').export_type = 'pdf_sequence' row.operator('gp.export_as_pdf', icon='RENDER_STILL', text='PDF File').export_type = 'pdf' col.operator('gp.export_as_pdf', icon='RENDER_STILL', text='SWF File').export_type = 'swf' if bpy.app.version < (3,0,0): col.label(text='Not Blender 3.0.0+ !') ## Append GP Render workspace (usefull for user with disabled 'load_UI') if not bpy.data.workspaces.get('GP Render'): layout.operator('gp.set_gp_render_workspace') class GPEXP_MT_multi_user_doc(bpy.types.Menu): bl_label = "Case of multiuser objects" def draw(self, context): layout = self.layout # call another menu #layout.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map" #**Behavior from context mode** col = layout.column() col.label(text='Multi user data will be rendered all together on last generated viewlayers.', icon='INFO') col.label(text='Make them single user if needed to render separately.') # col.label(text='Select objects > call search pop-up (F3) > "Make single user" > tick "object data" > ok') col.label(text='Procedure:') col.label(text='- select concerned objects') col.label(text='- call search pop-up (F3)') col.label(text='- search "Make single user"') col.label(text='- tick only "object data"') 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) # row.prop(vl, 'use', text=vl.name, icon='RESTRICT_RENDER_OFF', emboss=False) ## Can only toggle one with a menu # class GPEXP_MT_viewlayers_popup(bpy.types.Menu): # bl_label = "View Layers" # def draw(self, context): # layout = self.layout # viewlayer_layout(layout, context) class GPEXP_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 GPEXP_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}::') viewlayer_layout(col, s) layout.separator() class GPEXP_OT_viewlayer_popup_invoke(bpy.types.Operator): bl_idname = "gp.viewlayer_popup" bl_label = "Viewlayer Popup" bl_description = "Pop up menu for toggling viewlayers" bl_options = {"REGISTER",} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) def draw(self, context): layout = self.layout viewlayer_layout(layout, context) def execute(self, context): return {"FINISHED"} ## not registered for now (better to place render menu in GP dopesheet) def manager_ui(self, context): '''appended to DATA_PT_gpencil_layers''' layout = self.layout ## On layers if context.object and context.object.type == 'GPENCIL': txt = f'{len([l for l in context.object.data.layers if l.select])} Layer(s) To Render' else: txt = 'Layer To Render' layout.operator('gp.add_layer_to_render', icon='RENDERLAYERS', text=txt) ## On objects # txt = 'Selected Object To Render' # if context.scene.name != RD_SCENE_NAME: txt = f'{len([o for o in context.selected_objects if o.type == "GPENCIL" and o.select_get()])} Selected Object(s) To Render' layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text=txt).mode='SELECTED' layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='All GP at once').mode='ALL' # ## function to append in a menu # def palette_manager_menu(self, context): # """Palette menu to append in existing menu""" # # GPENCIL_MT_material_context_menu # layout = self.layout # # {'EDIT_GPENCIL', 'PAINT_GPENCIL','SCULPT_GPENCIL','WEIGHT_GPENCIL', 'VERTEX_GPENCIL'} # layout.separator() # prefs = get_addon_prefs() # layout.operator("", text='do stuff from material submenu', icon='MATERIAL') #-# REGISTER classes=( GPEXP_PT_viewlayers_ui, GPEXP_PT_viewlayers_multi_ui, GPEXP_OT_viewlayer_popup_invoke, GPEXP_MT_multi_user_doc, GPEXP_PT_gp_node_ui, GPEXP_PT_gp_dopesheet_ui, ) def register(): for cls in classes: bpy.utils.register_class(cls) # bpy.types.DATA_PT_gpencil_layers.prepend(manager_ui) def unregister(): # bpy.types.DATA_PT_gpencil_layers.remove(manager_ui) for cls in reversed(classes): bpy.utils.unregister_class(cls)