import bpy from bpy.types import Panel from .prefs import get_addon_prefs # 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 layout.operator('gp.render_scene_switch', icon='SCENE_DATA', text='Switch Scene') 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: layout.label(text=f'{len(disabled_output)} 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("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.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) subcol.operator('gp.number_outputs', icon='LINENUMBERS_ON', text=txt).mode = 'SELECTED' # 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') 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='Sub Scenes:') layout.operator('gp.split_to_scene', icon='DUPLICATE', text='Split To Scene') row = layout.row(align=True) row.operator('gp.set_crop_from_selection', icon='CON_OBJECTSOLVER', text='Set Crop') row.operator('gp.export_crop_coord_to_json', icon='FILE', text='Export json') layout.operator('gp.render_all_scenes', icon='RENDER_ANIMATION', text='Render All Sub-Scene') 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 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" layout.label(text=f'viewlayer: {context.object.data.layers.active.viewlayer_render}') ## 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) # merge (only accessible if multiple layers selected) row = layout.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') row.enabled= ct > 1 ## all and objects layout.separator() layout.label(text='Whole objects:') if context.scene.name != 'Render': 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 Visible GP To Render').mode='ALL' layout.separator() layout.operator('gp.layers_state', icon='CHECKMARK', text='Check layers') layout.operator('gp.lower_layers_name', icon='SYNTAX_OFF', text='Rename Lowercase') # row = layout.row() layout.prop(bpy.context.preferences.edit, 'use_anim_channel_group_colors') layout.separator() row = layout.row() row.operator('gp.export_as_pdf', icon='RENDER_STILL', text='Render All to PDF Sequences') if bpy.app.version < (3,0,0): row.label(text='Not Blender 3.0.0') 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, context): for vl in context.scene.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') viewlayer_layout(layout, context) 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 != 'Render': 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_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)