Files
test/scripts/startup/bl_ui/properties_data_light.py
Philipp Oeser 2fd36b0ab7 Fix #142103: Animation decorator not working on Light Temperature value
When having a checkbox and a value both in one row together with an
animation decorator it is questionable whether the decorator should act
on animating the checkbox or the corresponding value.

We had similar cases before (e.g. 7c04ef210e)

In this case as well, one would think it is more desirable to animate
the actual Temperature **value** (instead of the checkbox), so this is
what this PR does.

Pull Request: https://projects.blender.org/blender/blender/pulls/142192
2025-07-17 15:03:50 +02:00

316 lines
9.3 KiB
Python

# SPDX-FileCopyrightText: 2018-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.app.translations import contexts as i18n_contexts
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
from bl_ui.space_properties import PropertiesAnimationMixin
class DataButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
engine = context.engine
return context.light and (engine in cls.COMPAT_ENGINES)
class DATA_PT_context_light(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
def draw(self, context):
layout = self.layout
ob = context.object
light = context.light
space = context.space_data
if ob:
layout.template_ID(ob, "data")
elif light:
layout.template_ID(space, "pin_id")
class DATA_PT_preview(DataButtonsPanel, Panel):
bl_label = "Preview"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
}
def draw(self, context):
self.layout.template_preview(context.light)
class DATA_PT_light(DataButtonsPanel, Panel):
bl_label = "Light"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_WORKBENCH'}
def draw(self, context):
layout = self.layout
light = context.light
# Compact layout for node editor.
if self.bl_space_type == 'PROPERTIES':
layout.row().prop(light, "type", expand=True)
layout.use_property_split = True
else:
layout.use_property_split = True
layout.row().prop(light, "type")
class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
bl_label = "Light"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
light = context.light
# Compact layout for node editor.
if self.bl_space_type == 'PROPERTIES':
layout.row().prop(light, "type", expand=True)
layout.use_property_split = True
else:
layout.use_property_split = True
layout.row().prop(light, "type")
col = layout.column()
heading = col.column(align=True, heading="Temperature")
row = heading.column(align=True).row(align=True)
row.use_property_decorate = False
row.prop(light, "use_temperature", text="")
# Don't show color preview for now, it is grayed out so the color
# is not accurate. Would not a change in the UI code to allow
# non-editable colors to be displayed as is.
if False: # light.use_temperature:
sub = row.split(factor=0.7, align=True)
sub.active = light.use_temperature
sub.prop(light, "temperature", text="")
sub.prop(light, "temperature_color", text="")
else:
sub = row.row()
sub.active = light.use_temperature
sub.prop(light, "temperature", text="")
row.prop_decorator(light, "temperature")
if light.use_temperature:
col.prop(light, "color", text="Tint")
else:
col.prop(light, "color", text="Color")
layout.separator()
col = layout.column()
col.prop(light, "energy")
col.prop(light, "exposure")
col.prop(light, "normalize")
layout.separator()
col = layout.column()
if light.type in {'POINT', 'SPOT'}:
col.prop(light, "shadow_soft_size", text="Radius")
col.prop(light, "use_soft_falloff")
elif light.type == 'SUN':
col.prop(light, "angle")
elif light.type == 'AREA':
col.prop(light, "shape")
sub = col.column(align=True)
if light.shape in {'SQUARE', 'DISK'}:
sub.prop(light, "size")
elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
sub.prop(light, "size", text="Size X")
sub.prop(light, "size_y", text="Y")
class DATA_PT_EEVEE_light_distance(DataButtonsPanel, Panel):
bl_label = "Custom Distance"
bl_parent_id = "DATA_PT_EEVEE_light"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
light = context.light
engine = context.engine
return (light and light.type != 'SUN') and (engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
light = context.light
layout = self.layout
layout.prop(light, "use_custom_distance", text="")
def draw(self, context):
layout = self.layout
light = context.light
layout.active = light.use_custom_distance
layout.use_property_split = True
layout.prop(light, "cutoff_distance", text="Distance")
class DATA_PT_EEVEE_light_shadow(DataButtonsPanel, Panel):
bl_label = "Shadow"
bl_parent_id = "DATA_PT_EEVEE_light"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw_header(self, context):
light = context.light
self.layout.prop(light, "use_shadow", text="")
def draw(self, context):
layout = self.layout
light = context.light
layout.use_property_split = True
layout.active = context.scene.eevee.use_shadows and light.use_shadow
col = layout.column(align=False, heading="Jitter")
row = col.row(align=True)
sub = row.row(align=True)
sub.prop(light, "use_shadow_jitter", text="")
sub = sub.row(align=True)
sub.active = light.use_shadow_jitter
sub.prop(light, "shadow_jitter_overblur", text="Overblur")
col = layout.column()
col.prop(light, "shadow_filter_radius", text="Filter")
sub = col.column(align=True)
row = sub.row(align=True)
row.prop(light, "shadow_maximum_resolution", text="Resolution Limit")
if light.type != 'SUN':
row.prop(light, "use_absolute_resolution", text="", icon='DRIVER_DISTANCE')
class DATA_PT_EEVEE_light_influence(DataButtonsPanel, Panel):
bl_label = "Influence"
bl_parent_id = "DATA_PT_EEVEE_light"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
ob = context.object
light = context.light
layout.use_property_split = True
col = layout.column(align=True)
sub = col.column(align=True)
sub.active = ob is None or ob.visible_diffuse
sub.prop(light, "diffuse_factor", text="Diffuse")
sub = col.column(align=True)
sub.active = ob is None or ob.visible_glossy
sub.prop(light, "specular_factor", text="Glossy")
sub = col.column(align=True)
sub.active = ob is None or ob.visible_transmission
sub.prop(light, "transmission_factor", text="Transmission")
sub = col.column(align=True)
sub.active = ob is None or ob.visible_volume_scatter
sub.prop(light, "volume_factor", text="Volume Scatter", text_ctxt=i18n_contexts.id_id)
class DATA_PT_spot(DataButtonsPanel, Panel):
bl_label = "Beam Shape"
bl_parent_id = "DATA_PT_EEVEE_light"
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
light = context.light
engine = context.engine
return (light and light.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
light = context.light
col = layout.column()
col.prop(light, "spot_size", text="Size")
col.prop(light, "spot_blend", text="Blend", slider=True)
col.prop(light, "show_cone")
class DATA_PT_light_animation(DataButtonsPanel, PropertiesAnimationMixin, PropertyPanel, Panel):
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
# DataButtonsPanel.poll ensures this is not None.
light = context.light
col = layout.column(align=True)
col.label(text="Light")
self.draw_action_and_slot_selector(context, col, light)
if node_tree := light.node_tree:
col = layout.column(align=True)
col.label(text="Shader Node Tree")
self.draw_action_and_slot_selector(context, col, node_tree)
class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
_context_path = "object.data"
_property_type = bpy.types.Light
classes = (
DATA_PT_context_light,
DATA_PT_preview,
DATA_PT_light,
DATA_PT_EEVEE_light,
DATA_PT_spot,
DATA_PT_EEVEE_light_shadow,
DATA_PT_EEVEE_light_influence,
DATA_PT_EEVEE_light_distance,
DATA_PT_light_animation,
DATA_PT_custom_props_light,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)