This commit takes the 'Slotted Actions' out of the experimental phase. As a result: - All newly created Actions will be slotted Actions. - Legacy Actions loaded from disk will be versioned to slotted Actions. - The new Python API for slots, layers, strips, and channel bags is available. - The legacy Python API for accessing F-Curves and Action Groups is still available, and will operate on the F-Curves/Groups for the first slot only. - Creating an Action by keying (via the UI, operators, or the `rna_struct.keyframe_insert` function) will try and share Actions between related data-blocks. See !126655 for more info about this. - Assigning an Action to a data-block will auto-assign a suitable Action Slot. The logic for this is described below. However, There are cases where this does _not_ automatically assign a slot, and thus the Action will effectively _not_ animate the data-block. Effort has been spent to make Action selection work both reliably for Blender users as well as keep the behaviour the same for Python scripts. Where these two goals did not converge, reliability and understandability for users was prioritised. Auto-selection of the Action Slot upon assigning the Action works as follows. The first rule to find a slot wins. 1. The data-block remembers the slot name that was last assigned. If the newly assigned Action has a slot with that name, it is chosen. 2. If the Action has a slot with the same name as the data-block, it is chosen. 3. If the Action has only one slot, and it has never been assigned to anything, it is chosen. 4. If the Action is assigned to an NLA strip or an Action constraint, and the Action has a single slot, and that slot has a suitable ID type, it is chosen. This last step is what I was referring to with "Where these two goals did not converge, reliability and understandability for users was prioritised." For regular Action assignments (like via the Action selectors in the Properties editor) this rule doesn't apply, even though with legacy Actions the final state ("it is animated by this Action") differs from the final state with slotted Actions ("it has no slot so is not animated"). This is done to support the following workflow: - Create an Action by animating Cube. - In order to animate Suzanne with that same Action, assign the Action to Suzanne. - Start keying Suzanne. This auto-creates and auto-assigns a new slot for Suzanne. If rule 4. above would apply in this case, the 2nd step would automatically select the Cube slot for Suzanne as well, which would immediately overwrite Suzanne's properties with the Cube animation. Technically, this commit: - removes the `WITH_ANIM_BAKLAVA` build flag, - removes the `use_animation_baklava` experimental flag in preferences, - updates the code to properly deal with the fact that empty Actions are now always considered slotted/layered Actions (instead of that relying on the user preference). Note that 'slotted Actions' and 'layered Actions' are the exact same thing, just focusing on different aspects (slot & layers) of the new data model. The "Baklava phase 1" assumptions are still asserted. This means that: - an Action can have zero or one layer, - that layer can have zero or one strip, - that strip must be of type 'keyframe' and be infinite with zero offset. The code to handle legacy Actions is NOT removed in this commit. It will be removed later. For now it's likely better to keep it around as reference to the old behaviour in order to aid in some inevitable bugfixing. Ref: #120406
1769 lines
57 KiB
Python
1769 lines
57 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
from bpy.types import Panel
|
|
from bpy.app.translations import contexts as i18n_contexts
|
|
|
|
|
|
class ObjectConstraintPanel:
|
|
bl_context = "constraint"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.object)
|
|
|
|
|
|
class BoneConstraintPanel:
|
|
bl_context = "bone_constraint"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.pose_bone)
|
|
|
|
|
|
class OBJECT_PT_constraints(ObjectConstraintPanel, Panel):
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_label = "Object Constraints"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
def draw(self, _context):
|
|
layout = self.layout
|
|
|
|
layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
|
|
|
|
layout.template_constraints(use_bone_constraints=False)
|
|
|
|
|
|
class BONE_PT_constraints(BoneConstraintPanel, Panel):
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_label = "Bone Constraints"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
def draw(self, _context):
|
|
layout = self.layout
|
|
|
|
layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
|
|
|
|
layout.template_constraints(use_bone_constraints=True)
|
|
|
|
|
|
# Parent class for constraint panels, with templates and drawing methods
|
|
# shared between the bone and object constraint panels
|
|
class ConstraintButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_label = ""
|
|
bl_options = {'INSTANCED', 'HEADER_LAYOUT_EXPAND'}
|
|
|
|
@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, separator=True):
|
|
if target or owner:
|
|
if separator:
|
|
layout.separator()
|
|
if target:
|
|
layout.prop(con, "target_space", text="Target")
|
|
if owner:
|
|
layout.prop(con, "owner_space", text="Owner")
|
|
|
|
if con.target_space == 'CUSTOM' or con.owner_space == 'CUSTOM':
|
|
col = layout.column()
|
|
col.prop(con, "space_object")
|
|
if con.space_object and con.space_object.type == 'ARMATURE':
|
|
col.prop_search(con, "space_subtarget", con.space_object.data, "bones", text="Bone")
|
|
elif con.space_object and con.space_object.type in {'MESH', 'LATTICE'}:
|
|
col.prop_search(con, "space_subtarget", con.space_object, "vertex_groups", text="Vertex Group")
|
|
|
|
@staticmethod
|
|
def target_template(layout, con, subtargets=True):
|
|
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':
|
|
col.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
|
|
|
|
if con.subtarget and hasattr(con, "head_tail"):
|
|
row = col.row(align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "head_tail")
|
|
# XXX icon, and only when bone has segments?
|
|
sub.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
|
|
row.prop_decorator(con, "head_tail")
|
|
elif con.target.type in {'MESH', 'LATTICE'}:
|
|
col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
|
|
|
|
def get_constraint(self, _context):
|
|
con = self.custom_data
|
|
self.layout.context_pointer_set("constraint", con)
|
|
return con
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
con = self.get_constraint(context)
|
|
|
|
layout.template_constraint_header(con)
|
|
|
|
# Drawing methods for specific constraints. (Shared by object and bone constraint panels)
|
|
|
|
def draw_childof(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(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")
|
|
|
|
self.draw_influence(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
|
|
|
|
self.target_template(layout, con)
|
|
|
|
layout.prop(con, "track_axis", expand=True)
|
|
layout.prop(con, "up_axis", text="Up", expand=True)
|
|
layout.prop(con, "use_target_z")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_follow_path(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 con.use_fixed_location:
|
|
layout.prop(con, "offset_factor", text="Offset Factor")
|
|
else:
|
|
layout.prop(con, "offset")
|
|
|
|
layout.prop(con, "forward_axis", expand=True)
|
|
layout.prop(con, "up_axis", expand=True)
|
|
|
|
col = layout.column()
|
|
col.prop(con, "use_fixed_location")
|
|
col.prop(con, "use_curve_radius")
|
|
col.prop(con, "use_curve_follow")
|
|
|
|
layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
|
|
|
|
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')
|
|
|
|
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')
|
|
|
|
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, "euler_order", text="Order")
|
|
layout.prop(con, "use_transform_limit")
|
|
layout.prop(con, "use_legacy_behavior")
|
|
self.space_template(layout, con, target=False, owner=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_loc_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")
|
|
|
|
layout.prop(con, "use_transform_limit")
|
|
self.space_template(layout, con, target=False, owner=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
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")
|
|
|
|
layout.prop(con, "use_transform_limit")
|
|
self.space_template(layout, con, target=False, owner=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
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", align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "use_x", text="X", toggle=True)
|
|
sub.prop(con, "use_y", text="Y", toggle=True)
|
|
sub.prop(con, "use_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
row = layout.row(heading="Invert", align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "invert_x", text="X", toggle=True)
|
|
sub.prop(con, "invert_y", text="Y", toggle=True)
|
|
sub.prop(con, "invert_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_locate_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(heading="Axis", align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "use_x", text="X", toggle=True)
|
|
sub.prop(con, "use_y", text="Y", toggle=True)
|
|
sub.prop(con, "use_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
row = layout.row(heading="Invert", align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "invert_x", text="X", toggle=True)
|
|
sub.prop(con, "invert_y", text="Y", toggle=True)
|
|
sub.prop(con, "invert_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
layout.prop(con, "use_offset")
|
|
|
|
self.space_template(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(heading="Axis", align=True)
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "use_x", text="X", toggle=True)
|
|
sub.prop(con, "use_y", text="Y", toggle=True)
|
|
sub.prop(con, "use_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
col = layout.column()
|
|
col.prop(con, "power")
|
|
col.prop(con, "use_make_uniform")
|
|
|
|
col.prop(con, "use_offset")
|
|
row = col.row()
|
|
row.active = con.use_offset
|
|
row.prop(con, "use_add")
|
|
|
|
self.space_template(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(heading="Free Axis")
|
|
row.prop(con, "free_axis", expand=True)
|
|
|
|
layout.prop(con, "volume")
|
|
|
|
self.space_template(layout, con, target=False, owner=True)
|
|
|
|
self.draw_influence(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
|
|
|
|
self.target_template(layout, con)
|
|
|
|
layout.prop(con, "remove_target_shear")
|
|
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_action(self, context):
|
|
layout = self.layout
|
|
con = self.get_constraint(context)
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = True
|
|
|
|
target_row = layout.row(align=True)
|
|
target_row.active = not con.use_eval_time
|
|
self.target_template(target_row, con)
|
|
|
|
row = layout.row(align=True, heading="Evaluation Time")
|
|
row.use_property_decorate = False
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "use_eval_time", text="")
|
|
subsub = sub.row(align=True)
|
|
subsub.active = con.use_eval_time
|
|
subsub.prop(con, "eval_time", text="")
|
|
row.prop_decorator(con, "eval_time")
|
|
|
|
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
|
|
|
self.draw_influence(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
|
|
|
|
self.target_template(layout, con)
|
|
|
|
layout.prop(con, "track_axis", expand=True)
|
|
layout.prop(con, "lock_axis", expand=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_dist_limit(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()
|
|
row.prop(con, "distance")
|
|
row.operator("constraint.limitdistance_reset", text="", icon='X')
|
|
|
|
layout.prop(con, "limit_mode", text="Clamp Region")
|
|
|
|
layout.prop(con, "use_transform_limit")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_stretch_to(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()
|
|
row.prop(con, "rest_length")
|
|
row.operator("constraint.stretchto_reset", text="", icon='X')
|
|
|
|
layout.separator()
|
|
|
|
col = layout.column()
|
|
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")
|
|
|
|
row = col.row()
|
|
row.active = con.use_bulge_min or con.use_bulge_max
|
|
row.prop(con, "bulge_smooth", text="Smooth")
|
|
|
|
layout.prop(con, "volume", expand=True)
|
|
layout.prop(con, "keep_axis", text="Rotation", expand=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_min_max(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, "offset")
|
|
layout.prop(con, "floor_location", expand=True, text="Min/Max")
|
|
layout.prop(con, "use_rotation")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_clamp_to(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, "main_axis", expand=True)
|
|
|
|
layout.prop(con, "use_cyclic")
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_transform(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, "use_motion_extrapolate", text="Extrapolate")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
self.draw_influence(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
|
|
|
|
self.target_template(layout, con, False)
|
|
|
|
layout.prop(con, "distance")
|
|
layout.prop(con, "shrinkwrap_type", text="Mode")
|
|
|
|
layout.separator()
|
|
|
|
if con.shrinkwrap_type == 'PROJECT':
|
|
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")
|
|
|
|
layout.separator()
|
|
|
|
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")
|
|
|
|
layout.separator()
|
|
|
|
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
|
|
|
|
self.target_template(layout, con)
|
|
|
|
layout.prop(con, "track_axis", expand=True)
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
def draw_spline_ik(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)
|
|
|
|
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
|
|
|
|
self.target_template(layout, con)
|
|
|
|
if con.target:
|
|
layout.prop(con, "offset", text="Pivot Offset")
|
|
else:
|
|
layout.prop(con, "use_relative_location")
|
|
if con.use_relative_location:
|
|
layout.prop(con, "offset", text="Pivot Point")
|
|
else:
|
|
layout.prop(con, "offset", text="Pivot Point")
|
|
|
|
col = layout.column()
|
|
col.prop(con, "rotation_range", text="Rotation Range")
|
|
|
|
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:
|
|
clip = con.clip
|
|
|
|
layout.prop(con, "use_active_clip")
|
|
layout.prop(con, "use_3d_position")
|
|
|
|
row = layout.row()
|
|
row.active = not con.use_3d_position
|
|
row.prop(con, "use_undistorted_position")
|
|
|
|
if not con.use_active_clip:
|
|
layout.prop(con, "clip")
|
|
|
|
layout.prop(con, "frame_method")
|
|
|
|
if clip:
|
|
tracking = clip.tracking
|
|
|
|
layout.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
|
|
|
|
tracking_object = tracking.objects.get(con.object, tracking.objects[0])
|
|
|
|
layout.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
|
|
|
|
layout.prop(con, "camera")
|
|
|
|
row = layout.row()
|
|
row.active = not con.use_3d_position
|
|
row.prop(con, "depth_object")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
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:
|
|
layout.prop(con, "clip")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
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")
|
|
|
|
if not con.use_active_clip:
|
|
layout.prop(con, "clip")
|
|
|
|
if clip:
|
|
layout.prop_search(con, "object", clip.tracking, "objects", icon='OBJECT_DATA')
|
|
|
|
layout.prop(con, "camera")
|
|
|
|
row = layout.row()
|
|
row.operator("constraint.objectsolver_set_inverse")
|
|
row.operator("constraint.objectsolver_clear_inverse")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
self.draw_influence(layout, con)
|
|
|
|
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")
|
|
|
|
cache_file = con.cache_file
|
|
|
|
if cache_file is not None:
|
|
layout.prop_search(con, "object_path", cache_file, "object_paths")
|
|
|
|
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 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:
|
|
layout.label(text="No target bones added", icon='ERROR')
|
|
|
|
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")
|
|
|
|
# This button gives itself too much padding, so put it in a column with the subtarget
|
|
col = layout.column()
|
|
col.prop(con, "pole_target")
|
|
|
|
if con.pole_target and con.pole_target.type == 'ARMATURE':
|
|
col.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
|
|
|
|
col = layout.column()
|
|
if con.pole_target:
|
|
col.prop(con, "pole_angle")
|
|
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)
|
|
|
|
# Use separate rows and columns here to avoid an alignment issue with the lock buttons
|
|
loc_col = layout.column()
|
|
loc_col.prop(con, "use_location")
|
|
|
|
row = loc_col.row()
|
|
row.active = con.use_location
|
|
row.prop(con, "weight", text="Weight", slider=True)
|
|
|
|
row = loc_col.row(heading="Lock", align=True)
|
|
row.use_property_decorate = False
|
|
row.active = con.use_location
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "lock_location_x", text="X", toggle=True)
|
|
sub.prop(con, "lock_location_y", text="Y", toggle=True)
|
|
sub.prop(con, "lock_location_z", text="Z", toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
rot_col = layout.column()
|
|
rot_col.prop(con, "use_rotation")
|
|
|
|
row = rot_col.row()
|
|
row.active = con.use_rotation
|
|
row.prop(con, "orient_weight", text="Weight", slider=True)
|
|
|
|
row = rot_col.row(heading="Lock", align=True)
|
|
row.use_property_decorate = False
|
|
row.active = con.use_rotation
|
|
sub = row.row(align=True)
|
|
sub.prop(con, "lock_rotation_x", text="X", toggle=True)
|
|
sub.prop(con, "lock_rotation_y", text="Y", toggle=True)
|
|
sub.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
|
|
col = layout.column()
|
|
col.prop(con, "pole_target")
|
|
|
|
if con.pole_target and con.pole_target.type == 'ARMATURE':
|
|
col.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
|
|
|
|
col = layout.column()
|
|
if con.pole_target:
|
|
col.prop(con, "pole_angle")
|
|
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 sub-panels.
|
|
class ConstraintButtonsSubPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_label = ""
|
|
|
|
def get_constraint(self, _context):
|
|
con = self.custom_data
|
|
self.layout.context_pointer_set("constraint", con)
|
|
return con
|
|
|
|
def draw_transform_from(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
|
|
|
|
from_axes = [con.map_to_x_from, con.map_to_y_from, con.map_to_z_from]
|
|
|
|
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.active = "X" in from_axes
|
|
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.active = "Y" in from_axes
|
|
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.active = "Z" in from_axes
|
|
col.prop(con, "from_min_z" + ext, text="Z Min")
|
|
col.prop(con, "from_max_z" + ext, text="Max")
|
|
|
|
def draw_transform_to(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, "map_to_x_from", expand=False, text="X Source Axis")
|
|
col.prop(con, "to_min_x" + ext, text="Min")
|
|
col.prop(con, "to_max_x" + ext, text="Max")
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(con, "map_to_y_from", expand=False, text="Y Source Axis")
|
|
col.prop(con, "to_min_y" + ext, text="Min")
|
|
col.prop(con, "to_max_y" + ext, text="Max")
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(con, "map_to_z_from", expand=False, text="Z Source Axis")
|
|
col.prop(con, "to_min_z" + ext, text="Min")
|
|
col.prop(con, "to_max_z" + ext, text="Max")
|
|
|
|
layout.prop(con, "mix_mode" + ext, text="Mix", text_ctxt=i18n_contexts.constraint)
|
|
|
|
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
|
|
|
|
split = header.split(factor=0.45, align=True)
|
|
split.prop(tgt, "target", text="")
|
|
|
|
row = split.row(align=True)
|
|
row.active = has_target
|
|
if has_target:
|
|
row.prop_search(tgt, "subtarget", tgt.target.data, "bones", text="")
|
|
else:
|
|
row.prop(tgt, "subtarget", text="", icon='BONE_DATA')
|
|
|
|
header.operator("constraint.remove_target", text="", icon='X').index = i
|
|
|
|
row = box.row()
|
|
row.active = has_target and tgt.subtarget != ""
|
|
row.prop(tgt, "weight", slider=True, text="Weight")
|
|
|
|
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
|
|
|
|
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
|
|
|
|
layout.prop(con, "use_curve_radius")
|
|
|
|
layout.prop(con, "y_scale_mode")
|
|
layout.prop(con, "xz_scale_mode")
|
|
|
|
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
|
|
|
|
col = layout.column()
|
|
col.active = not con.use_eval_time
|
|
col.prop(con, "transform_channel", text="Channel")
|
|
ConstraintButtonsPanel.space_template(col, con, target=True, owner=False, separator=False)
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(con, "min", text="Range Min")
|
|
sub.prop(con, "max", text="Max")
|
|
|
|
def draw_action_action(self, context):
|
|
layout = self.layout
|
|
con = self.get_constraint(context)
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = True
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(con, "action")
|
|
if con.action and con.action.is_action_layered:
|
|
col.context_pointer_set("animated_id", con.id_data)
|
|
col.template_search(
|
|
con, "action_slot",
|
|
con, "action_slots",
|
|
new="", # No use in making a new slot here.
|
|
unlink="anim.slot_unassign_from_constraint",
|
|
text="Slot",
|
|
)
|
|
|
|
layout.prop(con, "use_bone_object_action")
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(con, "frame_start", text="Frame Start")
|
|
col.prop(con, "frame_end", text="End")
|
|
|
|
def draw_transform_cache_velocity(self, context):
|
|
self.draw_transform_cache_subpanel(
|
|
context, self.layout.template_cache_file_velocity
|
|
)
|
|
|
|
def draw_transform_cache_procedural(self, context):
|
|
self.draw_transform_cache_subpanel(
|
|
context, self.layout.template_cache_file_procedural
|
|
)
|
|
|
|
def draw_transform_cache_time(self, context):
|
|
self.draw_transform_cache_subpanel(
|
|
context, self.layout.template_cache_file_time_settings
|
|
)
|
|
|
|
def draw_transform_cache_layers(self, context):
|
|
self.draw_transform_cache_subpanel(
|
|
context, self.layout.template_cache_file_layers
|
|
)
|
|
|
|
def draw_transform_cache_subpanel(self, context, template_func):
|
|
con = self.get_constraint(context)
|
|
if con.cache_file is None:
|
|
return
|
|
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = True
|
|
template_func(con, "cache_file")
|
|
|
|
# Child Of Constraint
|
|
|
|
|
|
class OBJECT_PT_bChildOfConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_childof(context)
|
|
|
|
|
|
class BONE_PT_bChildOfConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_childof(context)
|
|
|
|
# Track To Constraint
|
|
|
|
|
|
class OBJECT_PT_bTrackToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_trackto(context)
|
|
|
|
|
|
class BONE_PT_bTrackToConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_trackto(context)
|
|
|
|
# Follow Path Constraint
|
|
|
|
|
|
class OBJECT_PT_bFollowPathConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_follow_path(context)
|
|
|
|
|
|
class BONE_PT_bFollowPathConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_follow_path(context)
|
|
|
|
|
|
# Rotation Limit Constraint
|
|
|
|
class OBJECT_PT_bRotLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_rot_limit(context)
|
|
|
|
|
|
class BONE_PT_bRotLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_rot_limit(context)
|
|
|
|
|
|
# Location Limit Constraint
|
|
|
|
class OBJECT_PT_bLocLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_loc_limit(context)
|
|
|
|
|
|
class BONE_PT_bLocLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_loc_limit(context)
|
|
|
|
|
|
# Size Limit Constraint
|
|
|
|
class OBJECT_PT_bSizeLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_size_limit(context)
|
|
|
|
|
|
class BONE_PT_bSizeLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_size_limit(context)
|
|
|
|
|
|
# Rotate Like Constraint
|
|
|
|
class OBJECT_PT_bRotateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_rotate_like(context)
|
|
|
|
|
|
class BONE_PT_bRotateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_rotate_like(context)
|
|
|
|
|
|
# Locate Like Constraint
|
|
|
|
class OBJECT_PT_bLocateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_locate_like(context)
|
|
|
|
|
|
class BONE_PT_bLocateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_locate_like(context)
|
|
|
|
|
|
# Size Like Constraint
|
|
|
|
class OBJECT_PT_bSizeLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_size_like(context)
|
|
|
|
|
|
class BONE_PT_bSizeLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_size_like(context)
|
|
|
|
|
|
# Same Volume Constraint
|
|
|
|
class OBJECT_PT_bSameVolumeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_same_volume(context)
|
|
|
|
|
|
class BONE_PT_bSameVolumeConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_same_volume(context)
|
|
|
|
|
|
# Trans Like Constraint
|
|
|
|
class OBJECT_PT_bTransLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_trans_like(context)
|
|
|
|
|
|
class BONE_PT_bTransLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_trans_like(context)
|
|
|
|
|
|
# Action Constraint
|
|
|
|
class OBJECT_PT_bActionConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_action(context)
|
|
|
|
|
|
class BONE_PT_bActionConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_action(context)
|
|
|
|
|
|
class OBJECT_PT_bActionConstraint_target(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
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, Panel):
|
|
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, Panel):
|
|
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, Panel):
|
|
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, Panel):
|
|
def draw(self, context):
|
|
self.draw_lock_track(context)
|
|
|
|
|
|
class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_lock_track(context)
|
|
|
|
|
|
# Distance Limit Constraint
|
|
|
|
class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_dist_limit(context)
|
|
|
|
|
|
class BONE_PT_bDistLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_dist_limit(context)
|
|
|
|
|
|
# Stretch To Constraint
|
|
|
|
class OBJECT_PT_bStretchToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_stretch_to(context)
|
|
|
|
|
|
class BONE_PT_bStretchToConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_stretch_to(context)
|
|
|
|
|
|
# Min Max Constraint
|
|
|
|
class OBJECT_PT_bMinMaxConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_min_max(context)
|
|
|
|
|
|
class BONE_PT_bMinMaxConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_min_max(context)
|
|
|
|
|
|
# Clamp To Constraint
|
|
|
|
class OBJECT_PT_bClampToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_clamp_to(context)
|
|
|
|
|
|
class BONE_PT_bClampToConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_clamp_to(context)
|
|
|
|
|
|
# Transform Constraint
|
|
|
|
class OBJECT_PT_bTransformConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_transform(context)
|
|
|
|
|
|
class BONE_PT_bTransformConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_transform(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformConstraint_source(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformConstraint"
|
|
bl_label = "Map From"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_from(context)
|
|
|
|
|
|
class BONE_PT_bTransformConstraint_from(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformConstraint"
|
|
bl_label = "Map From"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_from(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformConstraint_destination(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformConstraint"
|
|
bl_label = "Map To"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_to(context)
|
|
|
|
|
|
class BONE_PT_bTransformConstraint_to(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformConstraint"
|
|
bl_label = "Map To"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_to(context)
|
|
|
|
|
|
# Shrink-wrap Constraint.
|
|
|
|
class OBJECT_PT_bShrinkwrapConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_shrinkwrap(context)
|
|
|
|
|
|
class BONE_PT_bShrinkwrapConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_shrinkwrap(context)
|
|
|
|
|
|
# Damp Track Constraint
|
|
|
|
class OBJECT_PT_bDampTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_damp_track(context)
|
|
|
|
|
|
class BONE_PT_bDampTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_damp_track(context)
|
|
|
|
|
|
# Spline IK Constraint
|
|
|
|
class BONE_PT_bSplineIKConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_spline_ik(context)
|
|
|
|
|
|
class BONE_PT_bSplineIKConstraint_fitting(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
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, Panel):
|
|
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, Panel):
|
|
def draw(self, context):
|
|
self.draw_pivot(context)
|
|
|
|
|
|
class BONE_PT_bPivotConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_pivot(context)
|
|
|
|
|
|
# Follow Track Constraint
|
|
|
|
class OBJECT_PT_bFollowTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_follow_track(context)
|
|
|
|
|
|
class BONE_PT_bFollowTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_follow_track(context)
|
|
|
|
|
|
# Camera Solver Constraint
|
|
|
|
class OBJECT_PT_bCameraSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_camera_solver(context)
|
|
|
|
|
|
class BONE_PT_bCameraSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_camera_solver(context)
|
|
|
|
|
|
# Object Solver Constraint
|
|
|
|
class OBJECT_PT_bObjectSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_object_solver(context)
|
|
|
|
|
|
class BONE_PT_bObjectSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_object_solver(context)
|
|
|
|
|
|
# Transform Cache Constraint
|
|
|
|
class OBJECT_PT_bTransformCacheConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_transform_cache(context)
|
|
|
|
|
|
class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_transform_cache(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformCacheConstraint_velocity(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
|
|
bl_label = "Velocity"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_velocity(context)
|
|
|
|
|
|
class BONE_PT_bTransformCacheConstraint_velocity(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformCacheConstraint"
|
|
bl_label = "Velocity"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_velocity(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformCacheConstraint_layers(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
|
|
bl_label = "Override Layers"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_layers(context)
|
|
|
|
|
|
class BONE_PT_bTransformCacheConstraint_layers(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformCacheConstraint"
|
|
bl_label = "Override Layers"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_layers(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformCacheConstraint_procedural(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
|
|
bl_label = "Render Procedural"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_procedural(context)
|
|
|
|
|
|
class BONE_PT_bTransformCacheConstraint_procedural(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformCacheConstraint"
|
|
bl_label = "Render Procedural"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_procedural(context)
|
|
|
|
|
|
class OBJECT_PT_bTransformCacheConstraint_time(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
|
|
bl_label = "Time"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_time(context)
|
|
|
|
|
|
class BONE_PT_bTransformCacheConstraint_time(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
bl_parent_id = "BONE_PT_bTransformCacheConstraint"
|
|
bl_label = "Time"
|
|
|
|
def draw(self, context):
|
|
self.draw_transform_cache_time(context)
|
|
|
|
|
|
# Python Constraint
|
|
|
|
class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_python_constraint(context)
|
|
|
|
|
|
class BONE_PT_bPythonConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_python_constraint(context)
|
|
|
|
|
|
# Armature Constraint
|
|
|
|
class OBJECT_PT_bArmatureConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_armature(context)
|
|
|
|
|
|
class BONE_PT_bArmatureConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
def draw(self, context):
|
|
self.draw_armature(context)
|
|
|
|
|
|
class OBJECT_PT_bArmatureConstraint_bones(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
|
|
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, Panel):
|
|
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, Panel):
|
|
def draw(self, context):
|
|
self.draw_kinematic(context)
|
|
|
|
|
|
class BONE_PT_bKinematicConstraint(BoneConstraintPanel, ConstraintButtonsPanel, Panel):
|
|
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_destination,
|
|
OBJECT_PT_bShrinkwrapConstraint,
|
|
OBJECT_PT_bDampTrackConstraint,
|
|
OBJECT_PT_bPivotConstraint,
|
|
OBJECT_PT_bFollowTrackConstraint,
|
|
OBJECT_PT_bCameraSolverConstraint,
|
|
OBJECT_PT_bObjectSolverConstraint,
|
|
OBJECT_PT_bTransformCacheConstraint,
|
|
OBJECT_PT_bTransformCacheConstraint_time,
|
|
OBJECT_PT_bTransformCacheConstraint_procedural,
|
|
OBJECT_PT_bTransformCacheConstraint_velocity,
|
|
OBJECT_PT_bTransformCacheConstraint_layers,
|
|
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_from,
|
|
BONE_PT_bTransformConstraint_to,
|
|
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_bTransformCacheConstraint_time,
|
|
BONE_PT_bTransformCacheConstraint_procedural,
|
|
BONE_PT_bTransformCacheConstraint_velocity,
|
|
BONE_PT_bTransformCacheConstraint_layers,
|
|
BONE_PT_bPythonConstraint,
|
|
BONE_PT_bArmatureConstraint,
|
|
BONE_PT_bArmatureConstraint_bones,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|