Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2076
-rw-r--r--source/blender/blenkernel/BKE_constraint.h3
-rw-r--r--source/blender/blenkernel/intern/constraint.c9
-rw-r--r--source/blender/blenloader/intern/versioning_290.c15
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c2
-rw-r--r--source/blender/editors/include/UI_interface.h4
-rw-r--r--source/blender/editors/interface/interface_panel.c14
-rw-r--r--source/blender/editors/interface/interface_templates.c297
-rw-r--r--source/blender/editors/object/object_constraint.c71
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h7
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c15
14 files changed, 1678 insertions, 847 deletions
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 3fc54ff6d12..04d43c28c27 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -20,894 +20,753 @@
from bpy.types import Panel
-class ConstraintButtonsPanel:
+class ObjectConstraintPanel(Panel):
+ bl_context = "constraint"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.object)
+
+
+class BoneConstraintPanel(Panel):
+ bl_context = "bone_constraint"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.pose_bone)
+
+
+class OBJECT_PT_constraints(ObjectConstraintPanel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
- bl_context = "constraint"
+ bl_label = "Object Constraints"
+ bl_options = {'HIDE_HEADER'}
- def draw_constraint(self, context, con):
+ def draw(self, context):
layout = self.layout
- box = layout.template_constraint(con)
+ layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
- if box:
- # match enum type to our functions, avoids a lookup table.
- getattr(self, con.type)(context, box, con)
+ layout.template_constraints(use_bone_constraints=False)
- if con.type in {'RIGID_BODY_JOINT', 'NULL'}:
- return
- if con.type in {'IK', 'SPLINE_IK'}:
- # constraint.disable_keep_transform doesn't work well
- # for these constraints.
- box.prop(con, "influence")
- else:
- row = box.row(align=True)
- row.prop(con, "influence")
- row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
+class BONE_PT_constraints(BoneConstraintPanel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = "Bone Constraints"
+ bl_options = {'HIDE_HEADER'}
- @staticmethod
- def space_template(layout, con, target=True, owner=True):
- if target or owner:
+ def draw(self, context):
+ layout = self.layout
- split = layout.split(factor=0.2)
+ layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
- split.label(text="Space:")
- row = split.row()
+ layout.template_constraints(use_bone_constraints=True)
- if target:
- row.prop(con, "target_space", text="")
- if target and owner:
- row.label(icon='ARROW_LEFTRIGHT')
+# Parent class for constraint panels, with templates and drawing methods
+# shared between the bone and object constraint panels
+class ConstraintButtonsPanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = ""
+ bl_options = {'INSTANCED', 'HEADER_LAYOUT_EXPAND', 'DRAW_BOX'}
+ @staticmethod
+ def draw_influence(layout, con):
+ layout.separator()
+ if con.type in {'IK', 'SPLINE_IK'}:
+ # constraint.disable_keep_transform doesn't work well
+ # for these constraints.
+ layout.prop(con, "influence")
+ else:
+ row = layout.row(align=True)
+ row.prop(con, "influence")
+ row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
+
+ @staticmethod
+ def space_template(layout, con, target=True, owner=True):
+ if target or owner:
+ layout.separator()
+ if target:
+ layout.prop(con, "target_space", text="Target")
if owner:
- row.prop(con, "owner_space", text="")
+ layout.prop(con, "owner_space", text="Owner")
@staticmethod
def target_template(layout, con, subtargets=True):
- layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
+ col = layout.column()
+ col.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
if con.target and subtargets:
if con.target.type == 'ARMATURE':
- layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
+ col.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
if hasattr(con, "head_tail"):
- row = layout.row(align=True)
- row.label(text="Head/Tail:")
+ row = col.row(align=True, heading="Head/Tail")
+ row.use_property_decorate = False
row.prop(con, "head_tail", text="")
# XXX icon, and only when bone has segments?
row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
elif con.target.type in {'MESH', 'LATTICE'}:
- layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
+ col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
- @staticmethod
- def ik_template(layout, con):
- # only used for iTaSC
- layout.prop(con, "pole_target")
+ def get_constraint(self, context):
+ con = None
+ if context.pose_bone:
+ con = context.pose_bone.constraints[self.list_panel_index]
+ else:
+ con = context.object.constraints[self.list_panel_index]
+ self.layout.context_pointer_set("constraint", con)
+ return con
- if con.pole_target and con.pole_target.type == 'ARMATURE':
- layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+ def draw_header(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
- if con.pole_target:
- row = layout.row()
- row.label()
- row.prop(con, "pole_angle")
+ layout.template_constraint_header(con)
- split = layout.split(factor=0.33)
- col = split.column()
- col.prop(con, "use_tail")
- col.prop(con, "use_stretch")
+ # Drawing methods for specific constraints. (Shared by object and bone constraint panels)
- col = split.column()
- col.prop(con, "chain_count")
+ def draw_childof(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def CHILD_OF(self, _context, layout, con):
self.target_template(layout, con)
- split = layout.split()
-
- col = split.column()
- col.label(text="Location:")
- col.prop(con, "use_location_x", text="X")
- col.prop(con, "use_location_y", text="Y")
- col.prop(con, "use_location_z", text="Z")
-
- col = split.column()
- col.label(text="Rotation:")
- col.prop(con, "use_rotation_x", text="X")
- col.prop(con, "use_rotation_y", text="Y")
- col.prop(con, "use_rotation_z", text="Z")
-
- col = split.column()
- col.label(text="Scale:")
- col.prop(con, "use_scale_x", text="X")
- col.prop(con, "use_scale_y", text="Y")
- col.prop(con, "use_scale_z", text="Z")
+ row = layout.row(heading="Location")
+ row.use_property_decorate = False
+ row.prop(con, "use_location_x", text="X", toggle=True)
+ row.prop(con, "use_location_y", text="Y", toggle=True)
+ row.prop(con, "use_location_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Rotation")
+ row.use_property_decorate = False
+ row.prop(con, "use_rotation_x", text="X", toggle=True)
+ row.prop(con, "use_rotation_y", text="Y", toggle=True)
+ row.prop(con, "use_rotation_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Scale")
+ row.use_property_decorate = False
+ row.prop(con, "use_scale_x", text="X", toggle=True)
+ row.prop(con, "use_scale_y", text="Y", toggle=True)
+ row.prop(con, "use_scale_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
row = layout.row()
row.operator("constraint.childof_set_inverse")
row.operator("constraint.childof_clear_inverse")
- def TRACK_TO(self, _context, layout, con):
- self.target_template(layout, con)
-
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
-
- row = layout.row()
- row.prop(con, "up_axis", text="Up")
- row.prop(con, "use_target_z")
-
- self.space_template(layout, con)
-
- def IK(self, context, layout, con):
- if context.object.pose.ik_solver == 'ITASC':
- layout.prop(con, "ik_type")
- getattr(self, 'IK_' + con.ik_type)(context, layout, con)
- else:
- # Standard IK constraint
- self.target_template(layout, con)
- layout.prop(con, "pole_target")
-
- if con.pole_target and con.pole_target.type == 'ARMATURE':
- layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
-
- if con.pole_target:
- row = layout.row()
- row.prop(con, "pole_angle")
- row.label()
-
- split = layout.split()
- col = split.column()
- col.prop(con, "iterations")
- col.prop(con, "chain_count")
-
- col = split.column()
- col.prop(con, "use_tail")
- col.prop(con, "use_stretch")
-
- layout.label(text="Weight:")
-
- split = layout.split()
- col = split.column()
- row = col.row(align=True)
- row.prop(con, "use_location", text="")
- sub = row.row(align=True)
- sub.active = con.use_location
- sub.prop(con, "weight", text="Position", slider=True)
-
- col = split.column()
- row = col.row(align=True)
- row.prop(con, "use_rotation", text="")
- sub = row.row(align=True)
- sub.active = con.use_rotation
- sub.prop(con, "orient_weight", text="Rotation", slider=True)
+ self.draw_influence(layout, con)
- def IK_COPY_POSE(self, _context, layout, con):
- self.target_template(layout, con)
- self.ik_template(layout, con)
+ def draw_trackto(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- row = layout.row()
- row.label(text="Axis Ref:")
- row.prop(con, "reference_axis", expand=True)
- split = layout.split(factor=0.33)
- split.row().prop(con, "use_location")
- row = split.row()
- row.prop(con, "weight", text="Weight", slider=True)
- row.active = con.use_location
- split = layout.split(factor=0.33)
- row = split.row()
- row.label(text="Lock:")
- row = split.row()
- row.prop(con, "lock_location_x", text="X")
- row.prop(con, "lock_location_y", text="Y")
- row.prop(con, "lock_location_z", text="Z")
- split.active = con.use_location
-
- split = layout.split(factor=0.33)
- split.row().prop(con, "use_rotation")
- row = split.row()
- row.prop(con, "orient_weight", text="Weight", slider=True)
- row.active = con.use_rotation
- split = layout.split(factor=0.33)
- row = split.row()
- row.label(text="Lock:")
- row = split.row()
- row.prop(con, "lock_rotation_x", text="X")
- row.prop(con, "lock_rotation_y", text="Y")
- row.prop(con, "lock_rotation_z", text="Z")
- split.active = con.use_rotation
-
- def IK_DISTANCE(self, _context, layout, con):
self.target_template(layout, con)
- self.ik_template(layout, con)
- layout.prop(con, "limit_mode")
+ layout.prop(con, "track_axis", expand=True)
+ layout.prop(con, "up_axis", text="Up", expand=True)
+ layout.prop(con, "use_target_z")
- row = layout.row()
- row.prop(con, "weight", text="Weight", slider=True)
- row.prop(con, "distance", text="Distance", slider=True)
+ self.space_template(layout, con)
- def FOLLOW_PATH(self, _context, layout, con):
- self.target_template(layout, con)
- layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
+ self.draw_influence(layout, con)
- split = layout.split()
+ def draw_follow_path(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- col = split.column()
- col.prop(con, "use_curve_follow")
- col.prop(con, "use_curve_radius")
+ self.target_template(layout, con)
- col = split.column()
- col.prop(con, "use_fixed_location")
if con.use_fixed_location:
- col.prop(con, "offset_factor", text="Offset")
+ layout.prop(con, "offset_factor", text="Offset Factor")
else:
- col.prop(con, "offset")
+ layout.prop(con, "offset")
- row = layout.row()
- row.label(text="Forward:")
- row.prop(con, "forward_axis", expand=True)
+ layout.prop(con, "forward_axis", expand=True)
+ layout.prop(con, "up_axis", expand=True)
- row = layout.row()
- row.prop(con, "up_axis", text="Up")
- row.label()
+ col = layout.column()
+ col.prop(con, "use_fixed_location")
+ col.prop(con, "use_curve_radius")
+ col.prop(con, "use_curve_follow")
- def LIMIT_ROTATION(self, _context, layout, con):
- split = layout.split()
+ layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
- col = split.column(align=True)
- col.prop(con, "use_limit_x")
- sub = col.column(align=True)
+ self.draw_influence(layout, con)
+
+ def draw_rot_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ # Decorators and property split are really buggy with these properties
+ row = layout.row(heading="Limit X", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_x", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_x
sub.prop(con, "min_x", text="Min")
sub.prop(con, "max_x", text="Max")
+ row.label(icon="BLANK1")
- col = split.column(align=True)
- col.prop(con, "use_limit_y")
- sub = col.column(align=True)
+ row = layout.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_y", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_y
sub.prop(con, "min_y", text="Min")
sub.prop(con, "max_y", text="Max")
+ row.label(icon="BLANK1")
- col = split.column(align=True)
- col.prop(con, "use_limit_z")
- sub = col.column(align=True)
+ row = layout.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_z", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_z
sub.prop(con, "min_z", text="Min")
sub.prop(con, "max_z", text="Max")
+ row.label(icon="BLANK1")
layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def LIMIT_LOCATION(self, _context, layout, con):
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_min_x")
- sub = col.column()
- sub.active = con.use_min_x
- sub.prop(con, "min_x", text="")
- col.prop(con, "use_max_x")
- sub = col.column()
- sub.active = con.use_max_x
- sub.prop(con, "max_x", text="")
-
- col = split.column()
- col.prop(con, "use_min_y")
- sub = col.column()
- sub.active = con.use_min_y
- sub.prop(con, "min_y", text="")
- col.prop(con, "use_max_y")
- sub = col.column()
- sub.active = con.use_max_y
- sub.prop(con, "max_y", text="")
-
- col = split.column()
- col.prop(con, "use_min_z")
- sub = col.column()
- sub.active = con.use_min_z
- sub.prop(con, "min_z", text="")
- col.prop(con, "use_max_z")
- sub = col.column()
- sub.active = con.use_max_z
- sub.prop(con, "max_z", text="")
+ self.draw_influence(layout, con)
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ def draw_loc_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def LIMIT_SCALE(self, _context, layout, con):
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_min_x")
- sub = col.column()
- sub.active = con.use_min_x
- sub.prop(con, "min_x", text="")
- col.prop(con, "use_max_x")
- sub = col.column()
- sub.active = con.use_max_x
- sub.prop(con, "max_x", text="")
-
- col = split.column()
- col.prop(con, "use_min_y")
- sub = col.column()
- sub.active = con.use_min_y
- sub.prop(con, "min_y", text="")
- col.prop(con, "use_max_y")
- sub = col.column()
- sub.active = con.use_max_y
- sub.prop(con, "max_y", text="")
-
- col = split.column()
- col.prop(con, "use_min_z")
- sub = col.column()
- sub.active = con.use_min_z
- sub.prop(con, "min_z", text="")
- col.prop(con, "use_max_z")
- sub = col.column()
- sub.active = con.use_max_z
- sub.prop(con, "max_z", text="")
+ col = layout.column()
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ row = col.row(heading="Minimum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_x
+ subsub.prop(con, "min_x", text="")
+ row.prop_decorator(con, "min_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_y
+ subsub.prop(con, "min_y", text="")
+ row.prop_decorator(con, "min_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_z
+ subsub.prop(con, "min_z", text="")
+ row.prop_decorator(con, "min_z")
+
+ col.separator()
+
+ row = col.row(heading="Maximum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_x
+ subsub.prop(con, "max_x", text="")
+ row.prop_decorator(con, "max_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_y
+ subsub.prop(con, "max_y", text="")
+ row.prop_decorator(con, "max_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_z
+ subsub.prop(con, "max_z", text="")
+ row.prop_decorator(con, "max_z")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
+ layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- def COPY_ROTATION(self, _context, layout, con):
- self.target_template(layout, con)
+ self.draw_influence(layout, con)
- layout.prop(con, "euler_order", text="Order")
+ def draw_size_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ col = layout.column()
+
+ row = col.row(heading="Minimum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_x
+ subsub.prop(con, "min_x", text="")
+ row.prop_decorator(con, "min_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_y
+ subsub.prop(con, "min_y", text="")
+ row.prop_decorator(con, "min_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_z
+ subsub.prop(con, "min_z", text="")
+ row.prop_decorator(con, "min_z")
+
+ col.separator()
+
+ row = col.row(heading="Maximum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_x
+ subsub.prop(con, "max_x", text="")
+ row.prop_decorator(con, "max_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_y
+ subsub.prop(con, "max_y", text="")
+ row.prop_decorator(con, "max_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_z
+ subsub.prop(con, "max_z", text="")
+ row.prop_decorator(con, "max_z")
- split = layout.split()
- col = split.column()
- col.prop(con, "use_x", text="X")
- sub = col.column()
- sub.active = con.use_x
- sub.prop(con, "invert_x", text="Invert")
+ layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- col = split.column()
- col.prop(con, "use_y", text="Y")
- sub = col.column()
- sub.active = con.use_y
- sub.prop(con, "invert_y", text="Invert")
+ self.draw_influence(layout, con)
- col = split.column()
- col.prop(con, "use_z", text="Z")
- sub = col.column()
- sub.active = con.use_z
- sub.prop(con, "invert_z", text="Invert")
+ def draw_rotate_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ self.target_template(layout, con)
+
+ layout.prop(con, "euler_order", text="Order")
+
+ row = layout.row(heading="Axis")
+ row.use_property_decorate = False
+ row.prop(con, "use_x", text="X", toggle=True)
+ row.prop(con, "use_y", text="Y", toggle=True)
+ row.prop(con, "use_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Invert")
+ row.use_property_decorate = False
+ row.prop(con, "invert_x", text="X", toggle=True)
+ row.prop(con, "invert_y", text="Y", toggle=True)
+ row.prop(con, "invert_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
layout.prop(con, "mix_mode", text="Mix")
self.space_template(layout, con)
- def COPY_LOCATION(self, _context, layout, con):
- self.target_template(layout, con)
+ self.draw_influence(layout, con)
- split = layout.split()
+ def draw_locate_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- col = split.column()
- col.prop(con, "use_x", text="X")
- sub = col.column()
- sub.active = con.use_x
- sub.prop(con, "invert_x", text="Invert")
+ self.target_template(layout, con)
- col = split.column()
- col.prop(con, "use_y", text="Y")
- sub = col.column()
- sub.active = con.use_y
- sub.prop(con, "invert_y", text="Invert")
+ row = layout.row(heading="Axis")
+ row.use_property_decorate = False
+ row.prop(con, "use_x", text="X", toggle=True)
+ row.prop(con, "use_y", text="Y", toggle=True)
+ row.prop(con, "use_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
- col = split.column()
- col.prop(con, "use_z", text="Z")
- sub = col.column()
- sub.active = con.use_z
- sub.prop(con, "invert_z", text="Invert")
+ row = layout.row(heading="Invert")
+ row.use_property_decorate = False
+ row.prop(con, "invert_x", text="X", toggle=True)
+ row.prop(con, "invert_y", text="Y", toggle=True)
+ row.prop(con, "invert_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
layout.prop(con, "use_offset")
self.space_template(layout, con)
- def COPY_SCALE(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_size_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
self.target_template(layout, con)
- row = layout.row(align=True)
- row.prop(con, "use_x", text="X")
- row.prop(con, "use_y", text="Y")
- row.prop(con, "use_z", text="Z")
+ row = layout.row(heading="Axis")
+ row.prop(con, "use_x", text="X", toggle=True)
+ row.prop(con, "use_y", text="Y", toggle=True)
+ row.prop(con, "use_z", text="Z", toggle=True)
- layout.prop(con, "power")
- layout.prop(con, "use_make_uniform")
+ col = layout.column()
+ col.prop(con, "power")
+ col.prop(con, "use_make_uniform")
- row = layout.row()
- row.prop(con, "use_offset")
- row = row.row()
+ col.prop(con, "use_offset")
+ row = col.row()
row.active = con.use_offset
row.prop(con, "use_add")
self.space_template(layout, con)
- def MAINTAIN_VOLUME(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_same_volume(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
layout.prop(con, "mode")
- row = layout.row()
- row.label(text="Free:")
+ row = layout.row(heading="Free Axis")
row.prop(con, "free_axis", expand=True)
layout.prop(con, "volume")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def COPY_TRANSFORMS(self, _context, layout, con):
- self.target_template(layout, con)
+ layout.prop(con, "owner_space")
- layout.prop(con, "mix_mode", text="Mix")
-
- self.space_template(layout, con)
+ self.draw_influence(layout, con)
- # def SCRIPT(self, context, layout, con):
+ def draw_trans_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def ACTION(self, _context, layout, con):
self.target_template(layout, con)
- split = layout.split()
-
- col = split.column()
- col.label(text="From Target:")
- col.prop(con, "transform_channel", text="")
- col.prop(con, "target_space", text="")
-
- col = split.column()
- col.label(text="To Action:")
- col.prop(con, "action", text="")
- col.prop(con, "use_bone_object_action")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Target Range:")
- col.prop(con, "min", text="Min")
- col.prop(con, "max", text="Max")
-
- col = split.column(align=True)
- col.label(text="Action Range:")
- col.prop(con, "frame_start", text="Start")
- col.prop(con, "frame_end", text="End")
-
layout.prop(con, "mix_mode", text="Mix")
- def LOCKED_TRACK(self, _context, layout, con):
- self.target_template(layout, con)
+ self.space_template(layout, con)
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
+ self.draw_influence(layout, con)
- row = layout.row()
- row.label(text="Lock:")
- row.prop(con, "lock_axis", expand=True)
+ def draw_action(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def LIMIT_DISTANCE(self, _context, layout, con):
self.target_template(layout, con)
- col = layout.column(align=True)
- col.prop(con, "distance")
- col.operator("constraint.limitdistance_reset")
-
- row = layout.row()
- row.label(text="Clamp Region:")
- row.prop(con, "limit_mode", text="")
+ layout.prop(con, "mix_mode", text="Mix")
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ self.draw_influence(layout, con)
- self.space_template(layout, con)
+ def draw_lock_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def STRETCH_TO(self, _context, layout, con):
self.target_template(layout, con)
- row = layout.row()
- row.prop(con, "rest_length", text="Rest Length")
- row.operator("constraint.stretchto_reset", text="Reset")
-
- layout.prop(con, "bulge", text="Volume Variation")
- split = layout.split()
- col = split.column(align=True)
- col.prop(con, "use_bulge_min", text="Volume Min")
- sub = col.column()
- sub.active = con.use_bulge_min
- sub.prop(con, "bulge_min", text="")
- col = split.column(align=True)
- col.prop(con, "use_bulge_max", text="Volume Max")
- sub = col.column()
- sub.active = con.use_bulge_max
- sub.prop(con, "bulge_max", text="")
- col = layout.column()
- col.active = con.use_bulge_min or con.use_bulge_max
- col.prop(con, "bulge_smooth", text="Smooth")
+ layout.prop(con, "track_axis", expand=True)
+ layout.prop(con, "lock_axis", expand=True)
- split = layout.split(factor=0.3)
- split.label(text="Volume:")
- row = split.row()
- row.prop(con, "volume", expand=True)
+ self.draw_influence(layout, con)
- split = layout.split(factor=0.3)
- split.label(text="Rotation:")
- row = split.row()
- row.prop(con, "keep_axis", expand=True)
+ def draw_dist_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def FLOOR(self, _context, layout, con):
self.target_template(layout, con)
- layout.prop(con, "use_rotation")
- layout.prop(con, "offset")
-
row = layout.row()
- row.label(text="Min/Max:")
- row.prop(con, "floor_location", expand=True)
+ row.prop(con, "distance")
+ row.operator("constraint.limitdistance_reset", text="", icon="X")
- self.space_template(layout, con)
-
- def RIGID_BODY_JOINT(self, _context, layout, con):
- self.target_template(layout, con, subtargets=False)
+ layout.prop(con, "limit_mode", text="Clamp Region")
- layout.prop(con, "pivot_type")
- layout.prop(con, "child")
+ layout.prop(con, "use_transform_limit")
- row = layout.row()
- row.prop(con, "use_linked_collision", text="Linked Collision")
- row.prop(con, "show_pivot", text="Display Pivot")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Pivot:")
- col.prop(con, "pivot_x", text="X")
- col.prop(con, "pivot_y", text="Y")
- col.prop(con, "pivot_z", text="Z")
-
- col = split.column(align=True)
- col.label(text="Axis:")
- col.prop(con, "axis_x", text="X")
- col.prop(con, "axis_y", text="Y")
- col.prop(con, "axis_z", text="Z")
-
- if con.pivot_type == 'CONE_TWIST':
- layout.label(text="Limits:")
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_angular_limit_x", text="Angle X")
- sub = col.column()
- sub.active = con.use_angular_limit_x
- sub.prop(con, "limit_angle_max_x", text="")
-
- col = split.column()
- col.prop(con, "use_angular_limit_y", text="Angle Y")
- sub = col.column()
- sub.active = con.use_angular_limit_y
- sub.prop(con, "limit_angle_max_y", text="")
-
- col = split.column()
- col.prop(con, "use_angular_limit_z", text="Angle Z")
- sub = col.column()
- sub.active = con.use_angular_limit_z
- sub.prop(con, "limit_angle_max_z", text="")
-
- elif con.pivot_type == 'GENERIC_6_DOF':
- layout.label(text="Limits:")
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(con, "use_limit_x", text="X")
- sub = col.column(align=True)
- sub.active = con.use_limit_x
- sub.prop(con, "limit_min_x", text="Min")
- sub.prop(con, "limit_max_x", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_limit_y", text="Y")
- sub = col.column(align=True)
- sub.active = con.use_limit_y
- sub.prop(con, "limit_min_y", text="Min")
- sub.prop(con, "limit_max_y", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_limit_z", text="Z")
- sub = col.column(align=True)
- sub.active = con.use_limit_z
- sub.prop(con, "limit_min_z", text="Min")
- sub.prop(con, "limit_max_z", text="Max")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_x", text="Angle X")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_x
- sub.prop(con, "limit_angle_min_x", text="Min")
- sub.prop(con, "limit_angle_max_x", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_y", text="Angle Y")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_y
- sub.prop(con, "limit_angle_min_y", text="Min")
- sub.prop(con, "limit_angle_max_y", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_z", text="Angle Z")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_z
- sub.prop(con, "limit_angle_min_z", text="Min")
- sub.prop(con, "limit_angle_max_z", text="Max")
-
- elif con.pivot_type == 'HINGE':
- layout.label(text="Limits:")
- split = layout.split()
+ self.space_template(layout, con)
- row = split.row(align=True)
- col = row.column()
- col.prop(con, "use_angular_limit_x", text="Angle X")
+ self.draw_influence(layout, con)
- col = row.column()
- col.active = con.use_angular_limit_x
- col.prop(con, "limit_angle_min_x", text="Min")
- col = row.column()
- col.active = con.use_angular_limit_x
- col.prop(con, "limit_angle_max_x", text="Max")
+ def draw_stretch_to(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def CLAMP_TO(self, _context, layout, con):
self.target_template(layout, con)
row = layout.row()
- row.label(text="Main Axis:")
- row.prop(con, "main_axis", expand=True)
-
- layout.prop(con, "use_cyclic")
+ row.prop(con, "rest_length")
+ row.operator("constraint.stretchto_reset", text="", icon="X")
- def TRANSFORM(self, _context, layout, con):
- self.target_template(layout, con)
-
- layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
+ layout.separator()
col = layout.column()
- col.row().label(text="Source:")
- col.row().prop(con, "map_from", expand=True)
+ col.prop(con, "bulge", text="Volume Variation")
+
+ row = col.row(heading="Volume Min", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_bulge_min", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_bulge_min
+ subsub.prop(con, "bulge_min", text="")
+ row.prop_decorator(con, "bulge_min")
+
+ row = col.row(heading="Max", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_bulge_max", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_bulge_max
+ subsub.prop(con, "bulge_max", text="")
+ row.prop_decorator(con, "bulge_max")
- if con.map_from == 'ROTATION':
- layout.prop(con, "from_rotation_mode", text="Mode")
-
- split = layout.split()
- ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
-
- sub = split.column(align=True)
- sub.label(text="X:")
- sub.prop(con, "from_min_x" + ext, text="Min")
- sub.prop(con, "from_max_x" + ext, text="Max")
+ row = col.row()
+ row.active = con.use_bulge_min or con.use_bulge_max
+ row.prop(con, "bulge_smooth", text="Smooth")
- sub = split.column(align=True)
- sub.label(text="Y:")
- sub.prop(con, "from_min_y" + ext, text="Min")
- sub.prop(con, "from_max_y" + ext, text="Max")
+ layout.prop(con, "volume", expand=True)
+ layout.prop(con, "keep_axis", text="Rotation", expand=True)
- sub = split.column(align=True)
- sub.label(text="Z:")
- sub.prop(con, "from_min_z" + ext, text="Min")
- sub.prop(con, "from_max_z" + ext, text="Max")
+ self.draw_influence(layout, con)
- col = layout.column()
- row = col.row()
- row.label(text="Source to Destination Mapping:")
+ def draw_min_max(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- # note: chr(187) is the ASCII arrow ( >> ). Blender Text Editor can't
- # open it. Thus we are using the hard-coded value instead.
- row = col.row()
- row.prop(con, "map_to_x_from", expand=False, text="")
- row.label(text=" %s X" % chr(187))
+ self.target_template(layout, con)
- row = col.row()
- row.prop(con, "map_to_y_from", expand=False, text="")
- row.label(text=" %s Y" % chr(187))
+ layout.prop(con, "offset")
+ layout.prop(con, "floor_location", expand=True, text="Min/Max")
+ layout.prop(con, "use_rotation")
- row = col.row()
- row.prop(con, "map_to_z_from", expand=False, text="")
- row.label(text=" %s Z" % chr(187))
+ self.space_template(layout, con)
- split = layout.split()
+ self.draw_influence(layout, con)
- col = split.column()
- col.label(text="Destination:")
- col.row().prop(con, "map_to", expand=True)
+ def draw_clamp_to(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if con.map_to == 'ROTATION':
- layout.prop(con, "to_euler_order", text="Order")
+ self.target_template(layout, con)
- split = layout.split()
- ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
+ layout.prop(con, "main_axis", expand=True)
- col = split.column()
- col.label(text="X:")
+ layout.prop(con, "use_cyclic")
- sub = col.column(align=True)
- sub.prop(con, "to_min_x" + ext, text="Min")
- sub.prop(con, "to_max_x" + ext, text="Max")
+ self.draw_influence(layout, con)
- col = split.column()
- col.label(text="Y:")
+ def draw_transform(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- sub = col.column(align=True)
- sub.prop(con, "to_min_y" + ext, text="Min")
- sub.prop(con, "to_max_y" + ext, text="Max")
+ self.target_template(layout, con)
- col = split.column()
- col.label(text="Z:")
+ layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
- sub = col.column(align=True)
- sub.prop(con, "to_min_z" + ext, text="Min")
- sub.prop(con, "to_max_z" + ext, text="Max")
+ self.space_template(layout, con)
- layout.prop(con, "mix_mode" + ext, text="Mix")
+ self.draw_influence(layout, con)
- self.space_template(layout, con)
+ def draw_shrinkwrap(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def SHRINKWRAP(self, _context, layout, con):
self.target_template(layout, con, False)
layout.prop(con, "distance")
- layout.prop(con, "shrinkwrap_type")
+ layout.prop(con, "shrinkwrap_type", text="Mode")
- if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
- layout.prop(con, "wrap_mode", text="Snap Mode")
+ layout.separator()
if con.shrinkwrap_type == 'PROJECT':
- row = layout.row(align=True)
- row.prop(con, "project_axis", expand=True)
- split = layout.split(factor=0.4)
- split.label(text="Axis Space:")
- rowsub = split.row()
- rowsub.prop(con, "project_axis_space", text="")
- split = layout.split(factor=0.4)
- split.label(text="Face Culling:")
- rowsub = split.row()
- rowsub.prop(con, "cull_face", expand=True)
- row = layout.row()
- row.prop(con, "use_project_opposite")
- rowsub = row.row()
- rowsub.active = con.use_project_opposite and con.cull_face != 'OFF'
- rowsub.prop(con, "use_invert_cull")
- layout.prop(con, "project_limit")
+ layout.prop(con, "project_axis", expand=True, text="Project Axis")
+ layout.prop(con, "project_axis_space", text="Space")
+ layout.prop(con, "project_limit", text="Distance")
+ layout.prop(con, "use_project_opposite")
- if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
- layout.prop(con, "use_track_normal")
+ layout.separator()
- row = layout.row(align=True)
- row.active = con.use_track_normal
- row.prop(con, "track_axis", expand=True)
+ col = layout.column()
+ row = col.row()
+ row.prop(con, "cull_face", expand=True)
+ row = col.row()
+ row.active = con.use_project_opposite and con.cull_face != 'OFF'
+ row.prop(con, "use_invert_cull")
- def DAMPED_TRACK(self, _context, layout, con):
- self.target_template(layout, con)
+ layout.separator()
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
+ if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
+ layout.prop(con, "wrap_mode", text="Snap Mode")
+ row = layout.row(heading="Align to Normal", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_track_normal", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_track_normal
+ subsub.prop(con, "track_axis", text="")
+ row.prop_decorator(con, "track_axis")
+
+ self.draw_influence(layout, con)
+
+ def draw_damp_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def SPLINE_IK(self, _context, layout, con):
self.target_template(layout, con)
- col = layout.column()
- col.label(text="Spline Fitting:")
- col.prop(con, "chain_count")
- col.prop(con, "use_even_divisions")
- col.prop(con, "use_chain_offset")
+ layout.prop(con, "track_axis", expand=True)
- col = layout.column()
- col.label(text="Chain Scaling:")
- col.prop(con, "use_curve_radius")
+ self.draw_influence(layout, con)
- layout.prop(con, "y_scale_mode")
- layout.prop(con, "xz_scale_mode")
+ def draw_spline_ik(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}:
- layout.prop(con, "use_original_scale")
+ self.target_template(layout, con)
- if con.xz_scale_mode == 'VOLUME_PRESERVE':
- layout.prop(con, "bulge", text="Volume Variation")
- split = layout.split()
- col = split.column(align=True)
- col.prop(con, "use_bulge_min", text="Volume Min")
- sub = col.column()
- sub.active = con.use_bulge_min
- sub.prop(con, "bulge_min", text="")
- col = split.column(align=True)
- col.prop(con, "use_bulge_max", text="Volume Max")
- sub = col.column()
- sub.active = con.use_bulge_max
- sub.prop(con, "bulge_max", text="")
- col = layout.column()
- col.active = con.use_bulge_min or con.use_bulge_max
- col.prop(con, "bulge_smooth", text="Smooth")
+ self.draw_influence(layout, con)
+
+ def draw_pivot(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def PIVOT(self, _context, layout, con):
self.target_template(layout, con)
if con.target:
- col = layout.column()
- col.prop(con, "offset", text="Pivot Offset")
+ layout.prop(con, "offset", text="Pivot Offset")
else:
- col = layout.column()
- col.prop(con, "use_relative_location")
+ layout.prop(con, "use_relative_location")
if con.use_relative_location:
- col.prop(con, "offset", text="Relative Pivot Point")
+ layout.prop(con, "offset", text="Pivot Point")
else:
- col.prop(con, "offset", text="Absolute Pivot Point")
+ layout.prop(con, "offset", text="Pivot Point")
col = layout.column()
- col.prop(con, "rotation_range", text="Pivot When")
+ col.prop(con, "rotation_range", text="Rotation Range")
- @staticmethod
- def _getConstraintClip(context, con):
- if not con.use_active_clip:
- return con.clip
+ self.draw_influence(layout, con)
+
+ def draw_follow_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ clip = None
+ if con.use_active_clip:
+ clip = context.scene.active_clip
else:
- return context.scene.active_clip
+ clip = con.clip
- def FOLLOW_TRACK(self, context, layout, con):
- clip = self._getConstraintClip(context, con)
+ layout.prop(con, "use_active_clip")
+ layout.prop(con, "use_3d_position")
row = layout.row()
- row.prop(con, "use_active_clip")
- row.prop(con, "use_3d_position")
-
- sub = row.column()
- sub.active = not con.use_3d_position
- sub.prop(con, "use_undistorted_position")
+ row.active = not con.use_3d_position
+ row.prop(con, "use_undistorted_position")
- col = layout.column()
if not con.use_active_clip:
- col.prop(con, "clip")
+ layout.prop(con, "clip")
- row = col.row()
- row.prop(con, "frame_method", expand=True)
+ layout.prop(con, "frame_method")
if clip:
tracking = clip.tracking
- col.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
+ layout.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
tracking_object = tracking.objects.get(con.object, tracking.objects[0])
- col.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
+ layout.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
- col.prop(con, "camera")
+ layout.prop(con, "camera")
- row = col.row()
+ row = layout.row()
row.active = not con.use_3d_position
row.prop(con, "depth_object")
layout.operator("clip.constraint_to_fcurve")
- def CAMERA_SOLVER(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_camera_solver(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
layout.prop(con, "use_active_clip")
if not con.use_active_clip:
@@ -915,8 +774,19 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
- def OBJECT_SOLVER(self, context, layout, con):
- clip = self._getConstraintClip(context, con)
+ self.draw_influence(layout, con)
+
+ def draw_object_solver(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ clip = None
+ if con.use_active_clip:
+ clip = context.scene.active_clip
+ else:
+ clip = con.clip
layout.prop(con, "use_active_clip")
@@ -934,36 +804,236 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
- def TRANSFORM_CACHE(self, _context, layout, con):
- layout.label(text="Cache File Properties:")
- box = layout.box()
- box.template_cache_file(con, "cache_file")
+ self.draw_influence(layout, con)
- cache_file = con.cache_file
+ def draw_transform_cache(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ layout.template_cache_file(con, "cache_file")
- layout.label(text="Constraint Properties:")
- box = layout.box()
+ cache_file = con.cache_file
if cache_file is not None:
- box.prop_search(con, "object_path", cache_file, "object_paths")
+ layout.prop_search(con, "object_path", cache_file, "object_paths")
- def SCRIPT(self, _context, layout, _con):
+ self.draw_influence(layout, con)
+
+ def draw_python_constraint(self, context):
+ layout = self.layout
layout.label(text="Blender 2.6 doesn't support python constraints yet")
- def ARMATURE(self, context, layout, con):
- topcol = layout.column()
- topcol.use_property_split = True
- topcol.operator("constraint.add_target", text="Add Target Bone")
+ def draw_armature(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ col = layout.column()
+ col.prop(con, "use_deform_preserve_volume")
+ col.prop(con, "use_bone_envelopes")
+
+ if context.pose_bone:
+ col.prop(con, "use_current_location")
+
+ layout.operator("constraint.add_target", text="Add Target Bone")
+
+ layout.operator("constraint.normalize_target_weights")
+
+ self.draw_influence(layout, con)
if not con.targets:
- box = topcol.box()
- box.label(text="No target bones were added", icon='ERROR')
+ layout.label(text="No target bones added", icon='ERROR')
- for i, tgt in enumerate(con.targets):
- box = topcol.box()
+ def draw_kinematic(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ self.target_template(layout, con)
+
+ if context.object.pose.ik_solver == 'ITASC':
+ layout.prop(con, "ik_type")
+
+ layout.prop(con, "pole_target")
+
+ if con.pole_target and con.pole_target.type == 'ARMATURE':
+ layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+
+ if con.pole_target:
+ row = layout.row()
+ row.label()
+ row.prop(con, "pole_angle")
+
+ col = layout.column()
+ col.prop(con, "use_tail")
+ col.prop(con, "use_stretch")
+ col.prop(con, "chain_count")
+
+ if con.ik_type == 'COPY_POSE':
+ layout.prop(con, "reference_axis", expand=True)
+
+ col = layout.column()
+ col.prop(con, "use_location")
+
+ sub = col.column()
+ sub.active = con.use_location
+ sub.prop(con, "weight", text="Weight", slider=True)
+ row = sub.row(heading="Lock")
+ row.use_property_decorate = False
+ row.prop(con, "lock_location_x", text="X", toggle=True)
+ row.prop(con, "lock_location_y", text="Y", toggle=True)
+ row.prop(con, "lock_location_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ col = layout.column()
+ col.prop(con, "use_rotation")
+
+ sub = col.column()
+ sub.active = con.use_rotation
+ sub.prop(con, "orient_weight", text="Weight", slider=True)
+ row = sub.row(heading="Lock")
+ row.use_property_decorate = False
+ row.prop(con, "lock_rotation_x", text="X", toggle=True)
+ row.prop(con, "lock_rotation_y", text="Y", toggle=True)
+ row.prop(con, "lock_rotation_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ elif con.ik_type == 'DISTANCE':
+ layout.prop(con, "limit_mode")
+
+ col = layout.column()
+ col.prop(con, "weight", text="Weight", slider=True)
+ col.prop(con, "distance", text="Distance", slider=True)
+ else:
+ # Standard IK constraint
+ layout.prop(con, "pole_target")
+
+ if con.pole_target and con.pole_target.type == 'ARMATURE':
+ layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+
+ if con.pole_target:
+ row = layout.row()
+ row.prop(con, "pole_angle")
+ row.label()
+
+ col = layout.column()
+ col.prop(con, "iterations")
+ col.prop(con, "chain_count")
+ col.prop(con, "use_tail")
+ col.prop(con, "use_stretch")
+
+ col = layout.column()
+ row = col.row(align=True, heading="Weight Position")
+ row.prop(con, "use_location", text="")
+ sub = row.row(align=True)
+ sub.active = con.use_location
+ sub.prop(con, "weight", text="", slider=True)
+
+ row = col.row(align=True, heading="Rotation")
+ row.prop(con, "use_rotation", text="")
+ sub = row.row(align=True)
+ sub.active = con.use_rotation
+ sub.prop(con, "orient_weight", text="", slider=True)
+
+ self.draw_influence(layout, con)
+
+# Parent class for constraint subpanels
+class ConstraintButtonsSubPanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = ""
+ bl_options = {'DRAW_BOX'}
+
+ def get_constraint(self, context):
+ con = None
+ if context.pose_bone:
+ con = context.pose_bone.constraints[self.list_panel_index]
+ else:
+ con = context.active.constraints[self.list_panel_index]
+ self.layout.context_pointer_set("constraint", con)
+ return con
+
+ def draw_transform_source(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+
+ layout.prop(con, "map_from", expand=True)
+
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ if con.map_from == 'ROTATION':
+ layout.prop(con, "from_rotation_mode", text="Mode")
+
+ ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_x" + ext, text="X Min")
+ col.prop(con, "from_max_x" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_y" + ext, text="Y Min")
+ col.prop(con, "from_max_y" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_z" + ext, text="Z Min")
+ col.prop(con, "from_max_z" + ext, text="Max")
+
+ def draw_transform_mapping(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ layout.prop(con, "map_to_x_from", expand=False, text="Source Axis X")
+
+ layout.prop(con, "map_to_y_from", expand=False, text="Y")
+
+ layout.prop(con, "map_to_z_from", expand=False, text="Z")
+
+ def draw_transform_destination(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+
+ layout.prop(con, "map_to", expand=True)
+
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ if con.map_to == 'ROTATION':
+ layout.prop(con, "to_euler_order", text="Order")
+
+ ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_x" + ext, text="X Min")
+ col.prop(con, "to_max_x" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_y" + ext, text="Y Min")
+ col.prop(con, "to_max_y" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_z" + ext, text="Z Min")
+ col.prop(con, "to_max_z" + ext, text="Max")
+
+ layout.prop(con, "mix_mode" + ext, text="Mix")
+
+ def draw_armature_bones(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ for i, tgt in enumerate(con.targets):
has_target = tgt.target is not None
+ box = layout.box()
header = box.row()
header.use_property_split = False
@@ -977,61 +1047,615 @@ class ConstraintButtonsPanel:
else:
row.prop(tgt, "subtarget", text="", icon='BONE_DATA')
- header.operator("constraint.remove_target", text="", icon='REMOVE').index = i
+ header.operator("constraint.remove_target", text="", icon='X').index = i
- col = box.column()
- col.active = has_target and tgt.subtarget != ""
- col.prop(tgt, "weight", slider=True)
+ row = box.row()
+ row.active = has_target and tgt.subtarget != ""
+ row.prop(tgt, "weight", slider=True, text="Weight")
- topcol.operator("constraint.normalize_target_weights")
- topcol.prop(con, "use_deform_preserve_volume")
- topcol.prop(con, "use_bone_envelopes")
+ def draw_spline_ik_fitting(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if context.pose_bone:
- topcol.prop(con, "use_current_location")
+ col = layout.column()
+ col.prop(con, "chain_count")
+ col.prop(con, "use_even_divisions")
+ col.prop(con, "use_chain_offset")
+ def draw_spline_ik_chain_scaling(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
-class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
- bl_label = "Object Constraints"
- bl_context = "constraint"
- bl_options = {'HIDE_HEADER'}
+ layout.prop(con, "use_curve_radius")
- @classmethod
- def poll(cls, context):
- return (context.object)
+ layout.prop(con, "y_scale_mode")
+ layout.prop(con, "xz_scale_mode")
- def draw(self, context):
+ if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}:
+ layout.prop(con, "use_original_scale")
+
+ if con.xz_scale_mode == 'VOLUME_PRESERVE':
+ col = layout.column()
+ col.prop(con, "bulge", text="Volume Variation")
+
+ row = col.row(heading="Volume Min")
+ row.prop(con, "use_bulge_min", text="")
+ sub = row.row()
+ sub.active = con.use_bulge_min
+ sub.prop(con, "bulge_min", text="")
+
+ row = col.row(heading="Max")
+ row.prop(con, "use_bulge_max", text="")
+ sub = row.row()
+ sub.active = con.use_bulge_max
+ sub.prop(con, "bulge_max", text="")
+
+ row = layout.row()
+ row.active = con.use_bulge_min or con.use_bulge_max
+ row.prop(con, "bulge_smooth", text="Smooth")
+
+ def draw_action_target(self, context):
layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- obj = context.object
+ layout.prop(con, "transform_channel", text="Channel")
+ layout.prop(con, "target_space")
- layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
+ col = layout.column(align=True)
+ col.prop(con, "min", text="Range Min")
+ col.prop(con, "max", text="Max")
- for con in obj.constraints:
- self.draw_constraint(context, con)
+ def draw_action_action(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
-class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
- bl_label = "Bone Constraints"
- bl_context = "bone_constraint"
- bl_options = {'HIDE_HEADER'}
+ layout.prop(con, "action")
+ layout.prop(con, "use_bone_object_action")
- @classmethod
- def poll(cls, context):
- return (context.pose_bone)
+ col = layout.column(align=True)
+ col.prop(con, "frame_start", text="Frame Start")
+ col.prop(con, "frame_end", text="End")
+
+# Child Of Constraint
+
+class OBJECT_PT_bChildOfConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
def draw(self, context):
- layout = self.layout
+ self.draw_childof(context)
- layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
- for con in context.pose_bone.constraints:
- self.draw_constraint(context, con)
+class BONE_PT_bChildOfConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_childof(context)
+
+# Track To Constraint
+
+class OBJECT_PT_bTrackToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trackto(context)
+
+
+class BONE_PT_bTrackToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trackto(context)
+
+# Follow Path Constraint
+
+class OBJECT_PT_bFollowPathConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_path(context)
+
+
+class BONE_PT_bFollowPathConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_path(context)
+
+
+# Roation Limit Constraint
+
+class OBJECT_PT_bRotLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rot_limit(context)
+
+
+class BONE_PT_bRotLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rot_limit(context)
+
+
+# Location Limit Constraint
+
+class OBJECT_PT_bLocLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_loc_limit(context)
+
+
+class BONE_PT_bLocLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_loc_limit(context)
+
+
+# Size Limit Constraint
+
+class OBJECT_PT_bSizeLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_limit(context)
+
+
+class BONE_PT_bSizeLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_limit(context)
+
+
+# Rotate Like Constraint
+
+class OBJECT_PT_bRotateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rotate_like(context)
+
+
+class BONE_PT_bRotateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rotate_like(context)
+
+
+# Locate Like Constraint
+
+class OBJECT_PT_bLocateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_locate_like(context)
+
+
+class BONE_PT_bLocateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_locate_like(context)
+
+
+# Size Like Constraint
+
+class OBJECT_PT_bSizeLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_like(context)
+
+
+class BONE_PT_bSizeLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_like(context)
+
+
+# Same Volume Constraint
+
+class OBJECT_PT_bSameVolumeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_same_volume(context)
+
+
+class BONE_PT_bSameVolumeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_same_volume(context)
+
+
+# Trans Like Constraint
+
+class OBJECT_PT_bTransLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trans_like(context)
+
+
+class BONE_PT_bTransLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trans_like(context)
+
+
+# Action Constraint
+
+class OBJECT_PT_bActionConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_action(context)
+
+
+class BONE_PT_bActionConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_action(context)
+
+
+class OBJECT_PT_bActionConstraint_target(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bActionConstraint"
+ bl_label = "Target"
+
+ def draw(self, context):
+ self.draw_action_target(context)
+
+
+class BONE_PT_bActionConstraint_target(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bActionConstraint"
+ bl_label = "Target"
+
+ def draw(self, context):
+ self.draw_action_target(context)
+
+
+class OBJECT_PT_bActionConstraint_action(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bActionConstraint"
+ bl_label = "Action"
+
+ def draw(self, context):
+ self.draw_action_action(context)
+
+
+class BONE_PT_bActionConstraint_action(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bActionConstraint"
+ bl_label = "Action"
+
+ def draw(self, context):
+ self.draw_action_action(context)
+
+
+# Lock Track Constraint
+
+class OBJECT_PT_bLockTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_lock_track(context)
+
+
+class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_lock_track(context)
+
+
+# Disance Limit Constraint
+
+class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_dist_limit(context)
+
+
+class BONE_PT_bDistLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_dist_limit(context)
+
+
+# Stretch To Constraint
+
+class OBJECT_PT_bStretchToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_stretch_to(context)
+
+
+class BONE_PT_bStretchToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_stretch_to(context)
+
+
+# Min Max Constraint
+
+class OBJECT_PT_bMinMaxConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_min_max(context)
+
+
+class BONE_PT_bMinMaxConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_min_max(context)
+
+
+# Clamp To Constraint
+
+class OBJECT_PT_bClampToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_clamp_to(context)
+
+
+class BONE_PT_bClampToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_clamp_to(context)
+
+
+# Transform Constraint
+
+class OBJECT_PT_bTransformConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform(context)
+
+
+class BONE_PT_bTransformConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform(context)
+
+
+class OBJECT_PT_bTransformConstraint_source(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Source"
+
+ def draw(self, context):
+ self.draw_transform_source(context)
+
+
+class BONE_PT_bTransformConstraint_source(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Source"
+
+ def draw(self, context):
+ self.draw_transform_source(context)
+
+
+class OBJECT_PT_bTransformConstraint_mapping(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Mapping"
+
+ def draw(self, context):
+ self.draw_transform_mapping(context)
+
+
+class BONE_PT_bTransformConstraint_mapping(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Mapping"
+
+ def draw(self, context):
+ self.draw_transform_mapping(context)
+
+
+class OBJECT_PT_bTransformConstraint_destination(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Destination"
+
+ def draw(self, context):
+ self.draw_transform_destination(context)
+
+
+class BONE_PT_bTransformConstraint_destination(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Destination"
+
+ def draw(self, context):
+ self.draw_transform_destination(context)
+
+
+# Shrinkwrap Constraint
+
+class OBJECT_PT_bShrinkwrapConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_shrinkwrap(context)
+
+
+class BONE_PT_bShrinkwrapConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_shrinkwrap(context)
+
+
+# Damp Track Constraint
+
+class OBJECT_PT_bDampTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_damp_track(context)
+
+
+class BONE_PT_bDampTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_damp_track(context)
+
+
+# Spline IK Constraint
+
+class BONE_PT_bSplineIKConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_spline_ik(context)
+
+
+class BONE_PT_bSplineIKConstraint_fitting(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bSplineIKConstraint"
+ bl_label = "Fitting"
+
+ def draw(self, context):
+ self.draw_spline_ik_fitting(context)
+
+
+class BONE_PT_bSplineIKConstraint_chain_scaling(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bSplineIKConstraint"
+ bl_label = "Chain Scaling"
+
+ def draw(self, context):
+ self.draw_spline_ik_chain_scaling(context)
+
+
+# Pivot Constraint
+
+class OBJECT_PT_bPivotConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_pivot(context)
+
+
+class BONE_PT_bPivotConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_pivot(context)
+
+
+# Follow Track Constraint
+
+class OBJECT_PT_bFollowTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_track(context)
+
+
+class BONE_PT_bFollowTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_track(context)
+
+
+# Camera Solver Constraint
+
+class OBJECT_PT_bCameraSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_camera_solver(context)
+
+
+class BONE_PT_bCameraSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_camera_solver(context)
+
+
+# Object Solver Constraint
+
+class OBJECT_PT_bObjectSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_object_solver(context)
+
+
+class BONE_PT_bObjectSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_object_solver(context)
+
+
+# Transform Cache Constraint
+
+class OBJECT_PT_bTransformCacheConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform_cache(context)
+
+
+class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform_cache(context)
+
+
+# Python Constraint
+
+class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_python_constraint(context)
+
+class BONE_PT_bPythonConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_python_constraint(context)
+
+
+
+# Armature Constraint
+
+class OBJECT_PT_bArmatureConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_armature(context)
+
+
+class BONE_PT_bArmatureConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_armature(context)
+
+
+class OBJECT_PT_bArmatureConstraint_bones(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bArmatureConstraint"
+ bl_label = "Bones"
+
+ def draw(self, context):
+ self.draw_armature_bones(context)
+
+
+class BONE_PT_bArmatureConstraint_bones(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bArmatureConstraint"
+ bl_label = "Bones"
+
+ def draw(self, context):
+ self.draw_armature_bones(context)
+
+
+# Inverse Kinematic Constraint
+
+class OBJECT_PT_bKinematicConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_kinematic(context)
+
+
+class BONE_PT_bKinematicConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_kinematic(context)
+
classes = (
+ # Object Panels
OBJECT_PT_constraints,
BONE_PT_constraints,
+ OBJECT_PT_bChildOfConstraint,
+ OBJECT_PT_bTrackToConstraint,
+ OBJECT_PT_bKinematicConstraint,
+ OBJECT_PT_bFollowPathConstraint,
+ OBJECT_PT_bRotLimitConstraint,
+ OBJECT_PT_bLocLimitConstraint,
+ OBJECT_PT_bSizeLimitConstraint,
+ OBJECT_PT_bRotateLikeConstraint,
+ OBJECT_PT_bLocateLikeConstraint,
+ OBJECT_PT_bSizeLikeConstraint,
+ OBJECT_PT_bSameVolumeConstraint,
+ OBJECT_PT_bTransLikeConstraint,
+ OBJECT_PT_bActionConstraint,
+ OBJECT_PT_bActionConstraint_target,
+ OBJECT_PT_bActionConstraint_action,
+ OBJECT_PT_bLockTrackConstraint,
+ OBJECT_PT_bDistLimitConstraint,
+ OBJECT_PT_bStretchToConstraint,
+ OBJECT_PT_bMinMaxConstraint,
+ OBJECT_PT_bClampToConstraint,
+ OBJECT_PT_bTransformConstraint,
+ OBJECT_PT_bTransformConstraint_source,
+ OBJECT_PT_bTransformConstraint_mapping,
+ OBJECT_PT_bTransformConstraint_destination,
+ OBJECT_PT_bShrinkwrapConstraint,
+ OBJECT_PT_bDampTrackConstraint,
+ OBJECT_PT_bPivotConstraint,
+ OBJECT_PT_bFollowTrackConstraint,
+ OBJECT_PT_bCameraSolverConstraint,
+ OBJECT_PT_bObjectSolverConstraint,
+ OBJECT_PT_bTransformCacheConstraint,
+ OBJECT_PT_bPythonConstraint,
+ OBJECT_PT_bArmatureConstraint,
+ OBJECT_PT_bArmatureConstraint_bones,
+ # Bone panels
+ BONE_PT_bChildOfConstraint,
+ BONE_PT_bTrackToConstraint,
+ BONE_PT_bKinematicConstraint,
+ BONE_PT_bFollowPathConstraint,
+ BONE_PT_bRotLimitConstraint,
+ BONE_PT_bLocLimitConstraint,
+ BONE_PT_bSizeLimitConstraint,
+ BONE_PT_bRotateLikeConstraint,
+ BONE_PT_bLocateLikeConstraint,
+ BONE_PT_bSizeLikeConstraint,
+ BONE_PT_bSameVolumeConstraint,
+ BONE_PT_bTransLikeConstraint,
+ BONE_PT_bActionConstraint,
+ BONE_PT_bActionConstraint_target,
+ BONE_PT_bActionConstraint_action,
+ BONE_PT_bLockTrackConstraint,
+ BONE_PT_bDistLimitConstraint,
+ BONE_PT_bStretchToConstraint,
+ BONE_PT_bMinMaxConstraint,
+ BONE_PT_bClampToConstraint,
+ BONE_PT_bTransformConstraint,
+ BONE_PT_bTransformConstraint_source,
+ BONE_PT_bTransformConstraint_mapping,
+ BONE_PT_bTransformConstraint_destination,
+ BONE_PT_bShrinkwrapConstraint,
+ BONE_PT_bDampTrackConstraint,
+ BONE_PT_bSplineIKConstraint,
+ BONE_PT_bSplineIKConstraint_fitting,
+ BONE_PT_bSplineIKConstraint_chain_scaling,
+ BONE_PT_bPivotConstraint,
+ BONE_PT_bFollowTrackConstraint,
+ BONE_PT_bCameraSolverConstraint,
+ BONE_PT_bObjectSolverConstraint,
+ BONE_PT_bTransformCacheConstraint,
+ BONE_PT_bPythonConstraint,
+ BONE_PT_bArmatureConstraint,
+ BONE_PT_bArmatureConstraint_bones,
)
if __name__ == "__main__": # only for live edit.
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 8fe3bd77a26..020b0f8b913 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -136,6 +136,9 @@ typedef struct bConstraintTypeInfo {
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
+void BKE_constraint_panel_id(int type, char *r_name);
+void BKE_constraint_bone_panel_id(int type, char *r_name);
+
/* ---------------------------------------------------------------------------- */
/* Constraint function prototypes */
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 050e8d434ae..f215297c8a2 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -5412,9 +5412,16 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
/* Set up a generic constraint data-block. */
con->type = type;
- con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+ con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
con->enforce = 1.0f;
+ /* Only open the main panel when constraints are created, not the subpanels. */
+ con->ui_expand_flag = (1 << 0);
+ if (type == CONSTRAINT_TYPE_ACTION || CONSTRAINT_TYPE_SPLINEIK) {
+ /* Expand the two subpanels in the cases where the main panel barely has any properties. */
+ con->ui_expand_flag |= (1 << 1) | (1 << 2);
+ }
+
/* Determine a basic name, and info */
if (cti) {
/* initialize constraint data */
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 8d57ef25c4d..0dd1ecd0008 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -24,6 +24,7 @@
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_modifier_types.h"
@@ -287,5 +288,19 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
scene->eevee.motion_blur_max = 32;
}
}
+
+ /* Transition to saving expansion for all of a constraint's subpanels. */
+ if (!DNA_struct_elem_find(fd->filesdna, "bConstraint", "short", "ui_expand_flag")) {
+ for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
+ LISTBASE_FOREACH (bConstraint *, con, &object->constraints) {
+ if (con->flag & CONSTRAINT_EXPAND_DEPRECATED) {
+ con->ui_expand_flag = 1;
+ }
+ else {
+ con->ui_expand_flag = 0;
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 15bf26a5fa8..e591f54c750 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1318,7 +1318,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
+ if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag && (1 << 0))) {
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 59dcc9a8ace..d89e590122c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2004,6 +2004,8 @@ void uiTemplatePathBuilder(uiLayout *layout,
struct PointerRNA *root_ptr,
const char *text);
void uiTemplateModifiers(uiLayout *layout, struct bContext *C);
+void uiTemplateConstraints(uiLayout *layout, struct bContext *C, bool use_bone_constraints);
+
uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
void uiTemplateGpencilColorPreview(uiLayout *layout,
struct bContext *C,
@@ -2018,7 +2020,7 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct Pointe
void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C);
-uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
+void uiTemplateConstraintHeader(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplatePreview(uiLayout *layout,
struct bContext *C,
struct ID *id,
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 4fff80d5def..924b886f167 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -387,9 +387,19 @@ bool UI_panel_list_matches_data(ARegion *region,
ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func)
{
- int data_len = BLI_listbase_count(data);
+ /* Check for NULL data. */
+ int data_len = 0;
+ Link *data_link = NULL;
+ if (data == NULL) {
+ data_len = 0;
+ data_link = NULL;
+ }
+ else {
+ data_len = BLI_listbase_count(data);
+ data_link = data->first;
+ }
+
int i = 0;
- Link *data_link = data->first;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->type != NULL && panel->type->flag & PNL_INSTANCED) {
/* The panels were reordered by drag and drop. */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 1ce1e2950d5..189441a1f10 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1823,6 +1823,20 @@ void uiTemplatePathBuilder(uiLayout *layout,
* Template for building the panel layout for the active object's modifiers.
* \{ */
+/**
+ * Get the active object or the property region's pinned object.
+ */
+static Object *get_context_object(const bContext *C)
+{
+ SpaceProperties *sbuts = CTX_wm_space_properties(C);
+ if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) {
+ return (Object *)sbuts->pinid;
+ }
+ else {
+ return CTX_data_active_object(C);
+ }
+}
+
static void modifier_panel_id(void *md_link, char *r_name)
{
ModifierData *md = (ModifierData *)md_link;
@@ -1834,14 +1848,7 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C)
ScrArea *sa = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- Object *ob;
- SpaceProperties *sbuts = CTX_wm_space_properties(C);
- if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) {
- ob = (Object *)sbuts->pinid;
- }
- else {
- ob = CTX_data_active_object(C);
- }
+ Object *ob = get_context_object(C);
ListBase *modifiers = &ob->modifiers;
bool panels_match = UI_panel_list_matches_data(region, modifiers, modifier_panel_id);
@@ -1874,6 +1881,162 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Constraints Template
+ *
+ * Template for building the panel layout for the active object or bone's constraints.
+ * \{ */
+
+/** For building the panel UI for constraints. */
+#define CONSTRAINT_TYPE_PANEL_PREFIX "OBJECT_PT_"
+#define CONSTRAINT_BONE_TYPE_PANEL_PREFIX "BONE_PT_"
+
+/**
+ * Check if the panel's ID starts with 'BONE', meaning it is a bone constraint.
+ */
+static bool constraint_panel_is_bone(Panel *panel)
+{
+ return (panel->panelname[0] == 'B') && (panel->panelname[1] == 'O') &&
+ (panel->panelname[2] == 'N') && (panel->panelname[3] == 'E');
+}
+
+/**
+ * Get the constraints for the active pose bone or the active / pinned object.
+ */
+static ListBase *get_constraints(const bContext *C, bool use_bone_constraints)
+{
+ ListBase *constraints = {NULL};
+ if (use_bone_constraints) {
+ bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
+ if (pose_bone != NULL) {
+ constraints = &pose_bone->constraints;
+ }
+ }
+ else {
+ Object *ob = get_context_object(C);
+ if (ob != NULL) {
+ constraints = &ob->constraints;
+ }
+ }
+ return constraints;
+}
+
+/**
+ * Move a constraint to the index it's moved to after a drag and drop.
+ */
+static void constraint_reorder(bContext *C, Panel *panel, int new_index)
+{
+ bool constraint_from_bone = constraint_panel_is_bone(panel);
+ ListBase *lb = get_constraints(C, constraint_from_bone);
+
+ bConstraint *con = BLI_findlink(lb, panel->runtime.list_index);
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("CONSTRAINT_OT_move_to_index", false);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_string_set(&props_ptr, "constraint", con->name);
+ RNA_int_set(&props_ptr, "index", new_index);
+ /* Set owner to #EDIT_CONSTRAINT_OWNER_OBJECT or #EDIT_CONSTRAINT_OWNER_BONE. */
+ RNA_enum_set(&props_ptr, "owner", constraint_from_bone ? 1 : 0);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+}
+
+/**
+ * Get the expand flag from the active constraint to use for the panel.
+ */
+static short get_constraint_expand_flag(const bContext *C, Panel *panel)
+{
+ bool constraint_from_bone = constraint_panel_is_bone(panel);
+ ListBase *lb = get_constraints(C, constraint_from_bone);
+
+ bConstraint *con = BLI_findlink(lb, panel->runtime.list_index);
+ return con->ui_expand_flag;
+}
+
+/**
+ * Save the expand flag for the panel and subpanels to the constraint.
+ */
+static void set_constraint_expand_flag(const bContext *C, Panel *panel, short expand_flag)
+{
+ bool constraint_from_bone = constraint_panel_is_bone(panel);
+ ListBase *lb = get_constraints(C, constraint_from_bone);
+
+ bConstraint *con = BLI_findlink(lb, panel->runtime.list_index);
+ con->ui_expand_flag = expand_flag;
+}
+
+/**
+ * Function with void * argument for #uiListPanelIDFromDataFunc.
+ *
+ * \note: Constraint panel types are assumed to be named with the struct name field
+ * concatenated to the defined prefix.
+ */
+static void object_constraint_panel_id(void *md_link, char *r_name)
+{
+ bConstraint *con = (bConstraint *)md_link;
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(con->type);
+
+ strcpy(r_name, CONSTRAINT_TYPE_PANEL_PREFIX);
+ strcat(r_name, cti->structName);
+}
+
+static void bone_constraint_panel_id(void *md_link, char *r_name)
+{
+ bConstraint *con = (bConstraint *)md_link;
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(con->type);
+
+ strcpy(r_name, CONSTRAINT_BONE_TYPE_PANEL_PREFIX);
+ strcat(r_name, cti->structName);
+}
+
+/**
+ * Check if the constraint panels don't match the data and rebuild the panels if so.
+ */
+void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_constraints)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+
+ ListBase *constraints = get_constraints(C, use_bone_constraints);
+
+ /* Switch between the bone panel ID function and the object panel ID function. */
+ uiListPanelIDFromDataFunc panel_id_func = use_bone_constraints ? bone_constraint_panel_id :
+ object_constraint_panel_id;
+
+ bool panels_match = UI_panel_list_matches_data(region, constraints, panel_id_func);
+
+ if (!panels_match) {
+ UI_panels_free_instanced(C, region);
+ bConstraint *con = (constraints == NULL) ? NULL : constraints->first;
+ for (int i = 0; con; i++, con = con->next) {
+ char panel_idname[MAX_NAME];
+ panel_id_func(con, panel_idname);
+
+ Panel *new_panel = UI_panel_add_instanced(sa, region, &region->panels, panel_idname, i);
+ if (new_panel) {
+ /* Set the list panel functionality function pointers since we don't do it with python. */
+ new_panel->type->set_list_data_expand_flag = set_constraint_expand_flag;
+ new_panel->type->get_list_data_expand_flag = get_constraint_expand_flag;
+ new_panel->type->reorder = constraint_reorder;
+
+ UI_panel_set_expand_from_list_data(C, new_panel);
+ }
+ }
+ }
+ else {
+ /* The expansion might have been changed elsewhere, so we still need to set it. */
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED))
+ UI_panel_set_expand_from_list_data(C, panel);
+ }
+ }
+}
+
+#undef CONSTRAINT_TYPE_PANEL_PREFIX
+#undef CONSTRAINT_BONE_TYPE_PANEL_PREFIX
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Grease Pencil Modifier Template
* \{ */
@@ -2441,7 +2604,7 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Constraint Template
+/** \name Constraint Header Template
* \{ */
static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
@@ -2449,30 +2612,15 @@ static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
ED_object_constraint_active_set(ob_v, con_v);
}
-/* draw panel showing settings for a constraint */
-static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
+static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
{
bPoseChannel *pchan = BKE_pose_channel_active(ob);
- const bConstraintTypeInfo *cti;
uiBlock *block;
- uiLayout *result = NULL, *col, *box, *row;
+ uiLayout *sub;
PointerRNA ptr;
- char typestr[32];
short proxy_protected, xco = 0, yco = 0;
// int rb_col; // UNUSED
- /* get constraint typeinfo */
- cti = BKE_constraint_typeinfo_get(con);
- if (cti == NULL) {
- /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
- BLI_strncpy(typestr,
- (con->type == CONSTRAINT_TYPE_NULL) ? IFACE_("Null") : IFACE_("Unknown"),
- sizeof(typestr));
- }
- else {
- BLI_strncpy(typestr, IFACE_(cti->name), sizeof(typestr));
- }
-
/* determine whether constraint is proxy protected or not */
if (BKE_constraints_proxylocked_owner(ob, pchan)) {
proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0;
@@ -2487,36 +2635,23 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
- col = uiLayoutColumn(layout, true);
- uiLayoutSetContextPointer(col, "constraint", &ptr);
-
- box = uiLayoutBox(col);
- row = uiLayoutRow(box, false);
- block = uiLayoutGetBlock(box);
-
- /* Draw constraint header */
+ uiLayoutSetContextPointer(layout, "constraint", &ptr);
- /* open/close */
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
+ /* Constraint type icon. */
+ sub = uiLayoutRow(layout, false);
+ uiLayoutSetEmboss(sub, false);
+ uiLayoutSetRedAlert(sub, (con->flag & CONSTRAINT_DISABLE));
+ uiItemL(sub, "", RNA_struct_ui_icon(ptr.type));
- /* constraint-type icon */
- uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
UI_block_emboss_set(block, UI_EMBOSS);
- if (con->flag & CONSTRAINT_DISABLE) {
- uiLayoutSetRedAlert(row, true);
- }
-
if (proxy_protected == 0) {
- uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiItemR(layout, &ptr, "name", 0, "", ICON_NONE);
}
else {
- uiItemL(row, con->name, ICON_NONE);
+ uiItemL(layout, con->name, ICON_NONE);
}
- uiLayoutSetRedAlert(row, false);
-
/* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
if (proxy_protected) {
UI_block_emboss_set(block, UI_EMBOSS_NONE);
@@ -2555,54 +2690,20 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
UI_block_emboss_set(block, UI_EMBOSS);
}
else {
- short prev_proxylock, show_upbut, show_downbut;
-
- /* Up/Down buttons:
- * Proxy-constraints are not allowed to occur after local (non-proxy) constraints
- * as that poses problems when restoring them, so disable the "up" button where
- * it may cause this situation.
- *
- * Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose.
- */
- if (BKE_constraints_proxylocked_owner(ob, pchan)) {
- if (con->prev) {
- prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
- }
- else {
- prev_proxylock = 0;
- }
- }
- else {
- prev_proxylock = 0;
- }
-
- show_upbut = ((prev_proxylock == 0) && (con->prev));
- show_downbut = (con->next) ? 1 : 0;
-
/* enabled */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiItemR(row, &ptr, "mute", 0, "", 0);
+ uiItemR(layout, &ptr, "mute", 0, "", 0);
UI_block_emboss_set(block, UI_EMBOSS);
- uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
-
- /* up/down */
- if (show_upbut || show_downbut) {
- UI_block_align_begin(block);
- if (show_upbut) {
- uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
- }
-
- if (show_downbut) {
- uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
- }
- UI_block_align_end(block);
- }
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
/* Close 'button' - emboss calls here disable drawing of 'button' behind X */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
+ uiItemO(layout, "", ICON_X, "CONSTRAINT_OT_delete");
UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */
+ uiItemS(layout);
}
/* Set but-locks for protected settings (magic numbers are used here!) */
@@ -2610,23 +2711,11 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
UI_block_lock_set(block, true, TIP_("Cannot edit Proxy-Protected Constraint"));
}
- /* Draw constraint data */
- if ((con->flag & CONSTRAINT_EXPAND) == 0) {
- (yco) -= 10.5f * UI_UNIT_Y;
- }
- else {
- box = uiLayoutBox(col);
- block = uiLayoutAbsoluteBlock(box);
- result = box;
- }
-
/* clear any locks set up for proxies/lib-linking */
UI_block_lock_clear(block);
-
- return result;
}
-uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
+void uiTemplateConstraintHeader(uiLayout *layout, PointerRNA *ptr)
{
Object *ob;
bConstraint *con;
@@ -2634,7 +2723,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
/* verify we have valid data */
if (!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
RNA_warning("Expected constraint on object");
- return NULL;
+ return;
}
ob = (Object *)ptr->owner_id;
@@ -2642,7 +2731,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
if (!ob || !(GS(ob->id.name) == ID_OB)) {
RNA_warning("Expected constraint on object");
- return NULL;
+ return;
}
UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
@@ -2651,11 +2740,11 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
- return NULL;
+ return;
}
}
- return draw_constraint(layout, ob, con);
+ draw_constraint_header(layout, ob, con);
}
/** \} */
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index a2d33ffe413..5746480e3f8 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1557,6 +1557,77 @@ void CONSTRAINT_OT_move_up(wmOperatorType *ot)
/** \} */
/* ------------------------------------------------------------------- */
+/** \name Move Constraint To Index Operator
+ * \{ */
+
+static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ bConstraint *con = edit_constraint_property_get(op, ob, 0);
+
+ int new_index = RNA_int_get(op->ptr, "index");
+ if (new_index < 0) {
+ new_index = 0;
+ }
+
+ if (con) {
+ ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
+ int current_index = BLI_findindex(conlist, con);
+ BLI_assert(current_index >= 0);
+
+ BLI_listbase_link_move(conlist, con, new_index - current_index);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static int constraint_move_to_index_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (edit_constraint_invoke_properties(C, op)) {
+ return constraint_move_to_index_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void CONSTRAINT_OT_move_to_index(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Move Constraint To Index";
+ ot->idname = "CONSTRAINT_OT_move_to_index";
+ ot->description =
+ "Change the constraint's position in the list so it evaluates after the set number of "
+ "others";
+
+ /* callbacks */
+ ot->exec = constraint_move_to_index_exec;
+ ot->invoke = constraint_move_to_index_invoke;
+ ot->poll = edit_constraint_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ edit_constraint_properties(ot);
+ RNA_def_int(ot->srna,
+ "index",
+ 0,
+ 0,
+ INT_MAX,
+ "Index",
+ "The index to move the constraint to",
+ 0,
+ INT_MAX);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
/** \name Clear Pose Constraints Operator
* \{ */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index c5a6e38fbcb..1cd91f7c1f3 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -217,6 +217,7 @@ void POSE_OT_ik_clear(struct wmOperatorType *ot);
void CONSTRAINT_OT_delete(struct wmOperatorType *ot);
void CONSTRAINT_OT_move_up(struct wmOperatorType *ot);
+void CONSTRAINT_OT_move_to_index(struct wmOperatorType *ot);
void CONSTRAINT_OT_move_down(struct wmOperatorType *ot);
void CONSTRAINT_OT_stretchto_reset(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 05f1ced8615..84bc10f8064 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -179,6 +179,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(CONSTRAINT_OT_delete);
WM_operatortype_append(CONSTRAINT_OT_move_up);
WM_operatortype_append(CONSTRAINT_OT_move_down);
+ WM_operatortype_append(CONSTRAINT_OT_move_to_index);
WM_operatortype_append(CONSTRAINT_OT_stretchto_reset);
WM_operatortype_append(CONSTRAINT_OT_limitdistance_reset);
WM_operatortype_append(CONSTRAINT_OT_childof_set_inverse);
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 65087a6d459..85d9a04a902 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -61,7 +61,8 @@ typedef struct bConstraint {
/** Constraint name, MAX_NAME. */
char name[64];
- char _pad[2];
+ /* Flag for panel and subpanel closed / open state in the UI. */
+ short ui_expand_flag;
/** Amount of influence exherted by constraint (0.0-1.0). */
float enforce;
@@ -689,8 +690,8 @@ typedef enum eBConstraint_Types {
/* flag 0x20 (1 << 5) was used to indicate that a constraint was evaluated
* using a 'local' hack for posebones only. */
typedef enum eBConstraint_Flags {
- /* expand for UI */
- CONSTRAINT_EXPAND = (1 << 0),
+ /* Expansion for old box constraint layouts. Just for versioning. */
+ CONSTRAINT_EXPAND_DEPRECATED = (1 << 0),
/* pre-check for illegal object name or bone name */
CONSTRAINT_DISABLE = (1 << 2),
/* to indicate which Ipo should be shown, maybe for 3d access later too */
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 5405cb4e24a..af300f6e088 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -2483,7 +2483,7 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM);
RNA_def_property_ui_text(
- prop, "For Transform", "Transforms are affected by this constraint as well");
+ prop, "Affect Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false);
@@ -2556,7 +2556,7 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM);
RNA_def_property_ui_text(
- prop, "For Transform", "Transforms are affected by this constraint as well");
+ prop, "Affect Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false);
@@ -2644,7 +2644,7 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", LIMIT_TRANSFORM);
RNA_def_property_ui_text(
- prop, "For Transform", "Transforms are affected by this constraint as well");
+ prop, "Affect Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false);
@@ -2684,7 +2684,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMITDIST_TRANSFORM);
RNA_def_property_ui_text(
- prop, "For Transform", "Transforms are affected by this constraint as well");
+ prop, "Affect Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false);
@@ -3380,7 +3380,7 @@ void RNA_def_constraint(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND);
+ RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0);
RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI");
RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index fd65b713d15..8bfee4cc26c 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -1213,6 +1213,15 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Generates the UI layout for the modifier stack");
+ func = RNA_def_function(srna, "template_constraints", "uiTemplateConstraints");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Generates the panels for the constraint stack");
+ RNA_def_boolean(func,
+ "use_bone_constraints",
+ true,
+ "",
+ "Add panels for bone constraints instead of object constraints");
+
func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers");
@@ -1251,12 +1260,10 @@ void RNA_api_ui_layout(StructRNA *srna)
"",
"Optionally limit the items which can be selected");
- func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
- RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
+ func = RNA_def_function(srna, "template_constraint_header", "uiTemplateConstraintHeader");
+ RNA_def_function_ui_description(func, "Generates the header for constraint panels");
parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
- RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "template_preview", "uiTemplatePreview");
RNA_def_function_ui_description(