blender/scripts/startup/bl_ui/properties_view_layer.py
Ruben Messerschmidt e02e46e78f UI: Use multi-line labels for longer warnings and descriptions
This replaces `UILayout::label` calls with `UILayout::label_multiline`
when used with longer warnings and descriptions, allowing readability
in compact layouts.

See #161779

Pull Request: https://projects.blender.org/blender/blender/pulls/162111

---------

Co-authored-by: Ruben Messerschmidt <ruben.messerschmidt@outlook.com>
2026-08-07 18:14:54 +02:00

383 lines
12 KiB
Python

# SPDX-FileCopyrightText: 2012-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Menu, Panel, UIList, ViewLayer
from bpy.app.translations import contexts as i18n_contexts
from rna_prop_ui import PropertyPanel
class VIEWLAYER_UL_aov(UIList):
@staticmethod
def aov_icon(item):
"""
:param item: AOV item to pick an icon for.
:type item: :class:`bpy.types.AOV`
:return: Icon identifier for *item*'s AOV type.
:rtype: str
"""
if not item.is_valid:
return 'ERROR'
aov_type = item.type
if aov_type == 'VALUE':
return 'NODE_SOCKET_FLOAT'
elif aov_type == 'COLOR':
return 'NODE_SOCKET_RGBA'
else:
raise ValueError("Unrecognized AOV type: " + aov_type)
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname):
del icon
row = layout.row()
split = row.split(factor=0.65)
split.row().prop(item, "name", text="", icon=self.aov_icon(item), emboss=False)
split.row().prop(item, "type", text="", emboss=False)
class ViewLayerButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "view_layer"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
@classmethod
def poll(cls, context):
return (context.engine in cls.COMPAT_ENGINES)
class VIEWLAYER_PT_context_layer(ViewLayerButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
window = context.window
scene = context.scene
layout.template_search(
window, "view_layer",
scene, "view_layers",
new="scene.view_layer_add",
unlink="scene.view_layer_remove",
)
class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel):
bl_label = "View Layer"
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
scene = context.scene
rd = scene.render
layer = context.view_layer
col = layout.column()
col.prop(layer, "use", text="Use for Rendering")
col.prop(rd, "use_single_layer", text="Render Single Layer")
class VIEWLAYER_PT_layer_passes(ViewLayerButtonsPanel, Panel):
bl_label = "Passes"
COMPAT_ENGINES = {
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
def draw(self, context):
pass
class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel):
bl_label = "Data"
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
view_layer = context.view_layer
col = layout.column()
col.prop(view_layer, "use_pass_combined")
col.prop(view_layer, "use_pass_z")
col.prop(view_layer, "use_pass_mist")
col.prop(view_layer, "use_pass_normal")
col.prop(view_layer, "use_pass_position")
sub = col.column()
sub.active = not scene.render.use_motion_blur
sub.prop(view_layer, "use_pass_vector")
col.prop(view_layer, "use_pass_grease_pencil", text="Grease Pencil")
view_layer_eevee = view_layer.eevee
prefs = context.preferences
use_debug = prefs.view.show_developer_ui
if use_debug:
col = layout.column(heading="Denoising", align=True)
col.prop(view_layer_eevee, "denoising_store_passes", text="Denoising Data")
sub = col.column()
sub.active = view_layer_eevee.denoising_store_passes
sub.prop(
view_layer_eevee,
"denoising_pass_use_albedo_roughness_weighting",
text="Albedo Roughness Weighting")
else:
col.prop(view_layer_eevee, "denoising_store_passes", text="Denoising Data")
class VIEWLAYER_PT_workbench_layer_passes_data(ViewLayerButtonsPanel, Panel):
bl_label = "Data"
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'BLENDER_WORKBENCH'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
col = layout.column()
col.prop(view_layer, "use_pass_combined")
col.prop(view_layer, "use_pass_z")
col.prop(view_layer, "use_pass_grease_pencil", text="Grease Pencil")
class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
bl_label = "Light"
bl_translation_context = i18n_contexts.render_layer
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
view_layer_eevee = view_layer.eevee
col = layout.column(heading="Diffuse", align=True)
col.prop(view_layer, "use_pass_diffuse_direct", text="Light", text_ctxt=i18n_contexts.render_layer)
col.prop(view_layer, "use_pass_diffuse_color", text="Color")
col = layout.column(heading="Specular", align=True)
col.prop(view_layer, "use_pass_glossy_direct", text="Light", text_ctxt=i18n_contexts.render_layer)
col.prop(view_layer, "use_pass_glossy_color", text="Color")
col = layout.column(heading="Volume", heading_ctxt=i18n_contexts.id_id, align=True)
col.prop(view_layer_eevee, "use_pass_volume_direct", text="Light", text_ctxt=i18n_contexts.render_layer)
col = layout.column(heading="Other", align=True)
col.prop(view_layer, "use_pass_emit", text="Emission")
col.prop(view_layer, "use_pass_environment")
col.prop(view_layer, "use_pass_shadow")
col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
col.prop(view_layer_eevee, "use_pass_transparent", text="Transparent")
col = layout.column()
col.active = view_layer.use_pass_ambient_occlusion
col.prop(view_layer_eevee, "ambient_occlusion_distance", text="Occlusion Distance")
class ViewLayerAOVPanelHelper(ViewLayerButtonsPanel):
bl_label = "Shader AOV"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
row = layout.row()
col = row.column()
col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer, "aovs", view_layer, "active_aov_index", rows=3)
col = row.column()
sub = col.column(align=True)
sub.operator("scene.view_layer_add_aov", icon='ADD', text="")
sub.operator("scene.view_layer_remove_aov", icon='REMOVE', text="")
aov = view_layer.active_aov
if aov and not aov.is_valid:
layout.label_multiline(text="Conflicts with another render pass with the same name", icon='STATUS_ERROR')
class VIEWLAYER_PT_layer_passes_aov(ViewLayerAOVPanelHelper, Panel):
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
class ViewLayerCryptomattePanelHelper(ViewLayerButtonsPanel):
bl_label = "Cryptomatte"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
col = layout.column()
col.prop(view_layer, "use_pass_cryptomatte_object", text="Object")
col.prop(view_layer, "use_pass_cryptomatte_material", text="Material")
col.prop(view_layer, "use_pass_cryptomatte_asset", text="Asset")
col = layout.column()
col.active = any((
view_layer.use_pass_cryptomatte_object,
view_layer.use_pass_cryptomatte_material,
view_layer.use_pass_cryptomatte_asset,
))
col.prop(view_layer, "pass_cryptomatte_depth", text="Levels")
class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanelHelper, Panel):
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
class VIEWLAYER_MT_lightgroup_sync(Menu):
bl_label = "Lightgroup Sync"
def draw(self, _context):
layout = self.layout
layout.operator("scene.view_layer_add_used_lightgroups", icon='ADD')
layout.operator("scene.view_layer_remove_unused_lightgroups", icon='REMOVE')
class ViewLayerLightgroupsPanelHelper(ViewLayerButtonsPanel):
bl_label = "Light Groups"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
row = layout.row()
col = row.column()
col.template_list(
"UI_UL_list", "lightgroups", view_layer,
"lightgroups", view_layer, "active_lightgroup_index", rows=3,
)
col = row.column()
sub = col.column(align=True)
sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="")
sub.operator("scene.view_layer_remove_lightgroup", icon='REMOVE', text="")
sub.separator()
sub.menu("VIEWLAYER_MT_lightgroup_sync", icon='DOWNARROW_HLT', text="")
class VIEWLAYER_PT_layer_passes_lightgroups(ViewLayerLightgroupsPanelHelper, Panel):
bl_parent_id = "VIEWLAYER_PT_layer_passes"
COMPAT_ENGINES = {'CYCLES'}
class VIEWLAYER_PT_filter(ViewLayerButtonsPanel, Panel):
bl_label = "Filter"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
view_layer = context.view_layer
col = layout.column(heading="Include")
col.prop(view_layer, "use_sky", text="Environment")
col.prop(view_layer, "use_solid", text="Surfaces")
col.prop(view_layer, "use_strand", text="Curves")
col.prop(view_layer, "use_volumes", text="Volumes")
col.prop(view_layer, "use_grease_pencil", text="Grease Pencil")
col = layout.column(heading="Use")
sub = col.row()
sub.prop(view_layer, "use_motion_blur", text="Motion Blur")
sub.active = scene.render.use_motion_blur
class VIEWLAYER_PT_override(ViewLayerButtonsPanel, Panel):
bl_label = "Override"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_EEVEE',
'CYCLES',
}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
layout.prop(view_layer, "material_override")
layout.prop(view_layer, "world_override")
layout.prop(view_layer, "samples")
class VIEWLAYER_PT_layer_custom_props(PropertyPanel, Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "view_layer"
_context_path = "view_layer"
_property_type = ViewLayer
classes = (
VIEWLAYER_MT_lightgroup_sync,
VIEWLAYER_PT_context_layer,
VIEWLAYER_PT_layer,
VIEWLAYER_PT_layer_passes,
VIEWLAYER_PT_workbench_layer_passes_data,
VIEWLAYER_PT_eevee_layer_passes_data,
VIEWLAYER_PT_eevee_layer_passes_light,
VIEWLAYER_PT_layer_passes_cryptomatte,
VIEWLAYER_PT_layer_passes_aov,
VIEWLAYER_PT_layer_passes_lightgroups,
VIEWLAYER_PT_filter,
VIEWLAYER_PT_override,
VIEWLAYER_PT_layer_custom_props,
VIEWLAYER_UL_aov,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)