From d43e59b7c746fe84c0f91ea5387252138120222d Mon Sep 17 00:00:00 2001 From: Pullusb Date: Mon, 7 Feb 2022 16:05:47 +0100 Subject: [PATCH] Select node from layers 0.9.7 - feat: `Select Nodes` added in Dopesheet. Select nodes associated with selected gp layers and report if there are errors --- CHANGELOG.md | 4 +++ OP_setup_layers.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++ __init__.py | 2 +- fn.py | 33 ++++++++++++++++++++++ ui.py | 1 + 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 857e28d..0a3dfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ Activate / deactivate layer opaticty according to prefix Activate / deactivate all masks using MA layers --> +0.9.7 + +- feat: `Select Nodes` added in Dopesheet. Select nodes associated with selected gp layers and report if there are errors + 0.9.6 - added: `Check layers` disable multiframe-edit in all gp data. Seemed to cause artifacts on some renders (tested on 2.93.5) diff --git a/OP_setup_layers.py b/OP_setup_layers.py index 815b754..b8bedc3 100644 --- a/OP_setup_layers.py +++ b/OP_setup_layers.py @@ -534,12 +534,82 @@ class GPEXP_OT_check_masks(bpy.types.Operator): return {"FINISHED"} +class GPEXP_OT_select_layer_in_comp(bpy.types.Operator): + bl_idname = "gp.select_layer_in_comp" + bl_label = "Select Layer In Compositor" + bl_description = "Select associated render_layer node in compositing" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return context.object and context.object.type == 'GPENCIL' + + def execute(self, context): + gp = context.object.data + act = gp.layers.active + pool = fn.build_layers_targets_from_dopesheet(context) + if not pool: + self.report({'ERROR'}, 'No layers found in current GP dopesheet') + return {"CANCELLED"} + + if not context.scene.node_tree: + self.report({'ERROR'}, 'No compo node-tree in active scene') + return {"CANCELLED"} + + nodes = context.scene.node_tree.nodes + rl_nodes = [n for n in nodes if n.type == 'R_LAYERS'] + if not rl_nodes: + self.report({'ERROR'}, 'No render layers nodes in active scene') + return {"CANCELLED"} + + used_vl = [n.layer for n in rl_nodes] + selected = [] + infos = [] + + for l in pool: + if not l.select: + continue + vl_name = l.viewlayer_render + if not vl_name: + mess = f'{l.info} has no viewlayers' + print(mess) + infos.append(mess) + continue + + if not context.scene.view_layers.get(vl_name): + mess = f'/!\ {l.info}: view layer "{vl_name}" does not exists ' + print(mess) + infos.append(mess) + continue + + if not vl_name in used_vl: + mess = f'{l.info}: view layer "{vl_name}" not used in scene renderlayer nodes' + print(mess) + infos.append(mess) + continue + + for n in rl_nodes: + if n.layer == vl_name: + print(f'{l.info} -> Select node {n.name}') + selected.append(n.name) + n.select = True + + if not infos and not selected: + self.report({'ERROR'}, 'Nothing selected') + return {"CANCELLED"} + + infos = infos + [f'-- Selected {len(selected)} nodes --'] + selected + fn.show_message_box(_message=infos, _title="Selected viewlayer in compo", _icon='INFO') + + return {"FINISHED"} + classes=( GPEXP_OT_auto_number_object, GPEXP_OT_lower_layers_name, GPEXP_OT_export_infos_for_compo, GPEXP_OT_layers_state, GPEXP_OT_check_masks, +GPEXP_OT_select_layer_in_comp, ) def register(): diff --git a/__init__.py b/__init__.py index 19086bb..cb87712 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "GP Render", "description": "Organise export of gp layers through compositor output", "author": "Samuel Bernou", - "version": (0, 9, 6), + "version": (0, 9, 7), "blender": (2, 93, 0), "location": "View3D", "warning": "", diff --git a/fn.py b/fn.py index c0aac8e..66236b5 100644 --- a/fn.py +++ b/fn.py @@ -835,6 +835,39 @@ def normalize_layer_name(layer, prefix='', desc='', suffix='', lower=True, dash_ print(f' - updated in {ob.name} modifier {m.name}') m.layer = new +# unused currently +def build_dope_gp_list(layer_list): + '''Take a list of GP layers return a dict with pairs {gp data : own layer list}''' + from collections import defaultdict + gps = defaultdict(list) + for l in layer_list: + gps[l.id_data].append(l) + return gps + +def build_layers_targets_from_dopesheet(context): + '''Return all selected layers on context GP dopesheet according to seelction and filters''' + ob = context.object + gpl = context.object.data.layers + act = gpl.active + dopeset = context.space_data.dopesheet + + + if dopeset.show_only_selected: + pool = [o for o in context.selected_objects if o.type == 'GPENCIL'] + else: + pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + if not dopeset.show_hidden: + pool = [o for o in pool if o.visible_get()] + + layer_pool = [l for o in pool for l in o.data.layers] + layer_pool = list(set(layer_pool)) # remove dupli-layers from same data source with + + # apply search filter + if dopeset.filter_text: + layer_pool = [l for l in layer_pool if (dopeset.filter_text.lower() in l.info.lower()) ^ dopeset.use_filter_invert] + + return layer_pool + """ # old show message gox without operator support def show_message_box(_message = "", _title = "Message Box", _icon = 'INFO'): '''get a str to display or a list of [str, str] diff --git a/ui.py b/ui.py index 4b142e1..458797a 100644 --- a/ui.py +++ b/ui.py @@ -187,6 +187,7 @@ class GPEXP_PT_gp_dopesheet_ui(Panel): ## 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: