blender/scripts/startup/bl_ui/properties_physics_rigidbody.py
Pablo Vazquez 0e5263ff5b UI: Replace use of Info, Warning, and Error icons
Instead of reusing `ERROR` for both warnings and errors, and the Info
Editor icon for "info" label comments, use the new icons from !161002.

* Use `STATUS_WARNING` when the code refers to simple warnings, the
  feature might still work.
* Use `STATUS_ERROR` when the code refers to incompatibility, broken
  functionality, general errors.
* Use `STATUS_INFO` for every info label. Keep `INFO` for the editor.
* Sometimes `WARNING_LARGE` was used, that should only be used for
  dialogs. Use the regular warning instead, it looks almost the same.
* When extra contrast is needed, the filled version is used.

Mostly no big visual changes, other than warnings that were meant as
actual errors using the proper icon now.

See !161038 for details and screenshots.

Pull Request: https://projects.blender.org/blender/blender/pulls/161038
2026-07-05 14:27:56 +02:00

345 lines
10 KiB
Python

# SPDX-FileCopyrightText: 2013-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import (
Panel,
)
def rigid_body_warning(layout, text):
row = layout.row(align=True)
row.alignment = 'RIGHT'
row.label(text=text, icon='STATUS_ERROR')
class PHYSICS_PT_rigidbody_panel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "physics"
class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body"
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
parent = ob.parent
rbo = ob.rigid_body
if rbo is None:
rigid_body_warning(layout, "Object does not have a Rigid Body")
return
if parent is not None and parent.rigid_body is not None:
if parent.rigid_body.collision_shape == 'COMPOUND':
row = layout.row(align=True)
row.alignment = 'RIGHT'
row.label(text="This object is part of a compound shape", icon='STATUS_INFO')
else:
rigid_body_warning(layout, "Rigid Body cannot be child of a non compound Rigid Body")
return
if parent is None or parent.rigid_body is None:
layout.prop(rbo, "type", text="Type")
class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Settings"
bl_parent_id = "PHYSICS_PT_rigid_body"
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
rbo = ob.rigid_body
if rbo is None:
rigid_body_warning(layout, "Object does not have a Rigid Body")
return
col = layout.column()
if rbo.type == 'ACTIVE':
col.prop(rbo, "mass")
col.prop(rbo, "enabled", text="Dynamic")
col.prop(rbo, "kinematic", text="Animated")
class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Collisions"
bl_parent_id = "PHYSICS_PT_rigid_body"
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if (
(obj.parent is not None) and
(obj.parent.rigid_body is not None) and
(not obj.parent.rigid_body.collision_shape == 'COMPOUND')
):
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
ob = context.object
parent = ob.parent
rbo = ob.rigid_body
layout.use_property_split = True
layout.prop(rbo, "collision_shape", text="Shape")
if rbo.collision_shape == 'COMPOUND':
if (
(parent is not None) and
(parent.rigid_body is not None) and
(parent.rigid_body.collision_shape == 'COMPOUND')
):
rigid_body_warning(layout, "Sub compound shapes are not allowed")
else:
found = False
for child in ob.children:
if child.rigid_body is not None:
found = True
break
if not found:
rigid_body_warning(layout, "There are no child rigid bodies")
if rbo.collision_shape in {'MESH', 'CONVEX_HULL'}:
layout.prop(rbo, "mesh_source", text="Source")
if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM':
layout.prop(rbo, "use_deform", text="Deforming")
class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Surface Response"
bl_parent_id = "PHYSICS_PT_rigid_body_collisions"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
ob = context.object
rbo = ob.rigid_body
col = flow.column()
col.prop(rbo, "friction")
col = flow.column()
col.prop(rbo, "restitution", text="Bounciness")
class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Sensitivity"
bl_parent_id = "PHYSICS_PT_rigid_body_collisions"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if (
(obj.parent is not None) and
(obj.parent.rigid_body is not None) and
(not obj.parent.rigid_body.collision_shape == 'COMPOUND')
):
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
rbo = ob.rigid_body
if rbo.collision_shape in {'MESH', 'CONE'}:
col = layout.column()
col.prop(rbo, "collision_margin", text="Margin")
else:
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
col = flow.column()
col.prop(rbo, "use_margin")
col = flow.column()
col.active = rbo.use_margin
col.prop(rbo, "collision_margin", text="Margin")
class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Collections"
bl_parent_id = "PHYSICS_PT_rigid_body_collisions"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
ob = context.object
rbo = ob.rigid_body
layout.prop(rbo, "collision_collections", text="")
class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Dynamics"
bl_parent_id = "PHYSICS_PT_rigid_body"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (
obj and obj.rigid_body and obj.rigid_body.type == 'ACTIVE' and
(context.engine in cls.COMPAT_ENGINES)
)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
ob = context.object
rbo = ob.rigid_body
# col = layout.column(align=True)
# col.label(text="Activation:")
# XXX: settings such as activate on collision/etc.
col = flow.column()
col.prop(rbo, "linear_damping", text="Damping Translation")
col = flow.column()
col.prop(rbo, "angular_damping", text="Rotation")
class PHYSICS_PT_rigid_body_dynamics_deactivation(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Deactivation"
bl_parent_id = "PHYSICS_PT_rigid_body_dynamics"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_WORKBENCH',
}
@classmethod
def poll(cls, context):
obj = context.object
return (
obj and obj.rigid_body and
obj.rigid_body.type == 'ACTIVE' and
(context.engine in cls.COMPAT_ENGINES)
)
def draw_header(self, context):
ob = context.object
rbo = ob.rigid_body
self.layout.prop(rbo, "use_deactivation", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
ob = context.object
rbo = ob.rigid_body
layout.active = rbo.use_deactivation
col = flow.column()
col.prop(rbo, "use_start_deactivated")
col = flow.column()
col.prop(rbo, "deactivate_linear_velocity", text="Velocity Linear")
col.prop(rbo, "deactivate_angular_velocity", text="Angular")
# TODO: other parameters such as time?
classes = (
PHYSICS_PT_rigid_body,
PHYSICS_PT_rigid_body_settings,
PHYSICS_PT_rigid_body_collisions,
PHYSICS_PT_rigid_body_collisions_surface,
PHYSICS_PT_rigid_body_collisions_sensitivity,
PHYSICS_PT_rigid_body_collisions_collections,
PHYSICS_PT_rigid_body_dynamics,
PHYSICS_PT_rigid_body_dynamics_deactivation,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)