Paste Code
Paste Blends
Paste Images
bl_info = {'name':'Keyframe QuickTools',
'author':'Joel Daniels',
'version':(0,1),
'category':'Animation',
'location':'3D View -> UI panel',
'description':'A handful of quick-reference tools for keyframe manipulation'}


import bpy


def get_keyframe(fcurves, frame):
'''Return first keyframe type found'''
for fcu in fcurves:
if fcu:
for kp in fcu.keyframe_points:
if kp.co.x == frame:
return kp

def type_name(keyframe):
'''Return a string for the type of keyframe'''
text = ""
if keyframe:
if keyframe.type == 'KEYFRAME':
return "Key Pose"
elif keyframe.type == 'EXTREME':
return "Primary Breakdown"
elif keyframe.type == 'BREAKDOWN':
return "Secondary Breakdown"
elif keyframe.type == 'JITTER':
return "Moving Hold"
else:
return "(None)"

#----------------------------------------------
class VIEW3D_OT_SetKeyTypeSBD(bpy.types.Operator):
bl_idname = "keyframes.settype_sbd"
bl_label = "S BD"
bl_description = "Set keyframe type to secondary breakdown"

def execute(self, context):
scene = context.scene
frame = scene.frame_current
object = context.object
fcurves = object.animation_data.action.fcurves

for fcu in fcurves:
if fcu:
for kp in fcu.keyframe_points:
if kp.co.x == frame:
kp.type = 'BREAKDOWN'
return {'FINISHED'}

#----------------------------------------------
class VIEW3D_OT_SetKeyTypeMH(bpy.types.Operator):
bl_idname = "keyframes.settype_mh"
bl_label = "MH"
bl_description = "Set keyframe type to moving hold"

def execute(self, context):
scene = context.scene
frame = scene.frame_current
object = context.object
fcurves = object.animation_data.action.fcurves

for fcu in fcurves:
if fcu:
for kp in fcu.keyframe_points:
if kp.co.x == frame:
kp.type = 'JITTER'
return {'FINISHED'}

#----------------------------------------------
class VIEW3D_OT_SetKeyTypeKP(bpy.types.Operator):
bl_idname = "keyframes.settype_key"
bl_label = "KEY"
bl_description = "Set keyframe type to key pose"

def execute(self, context):
scene = context.scene
frame = scene.frame_current
object = context.object
fcurves = object.animation_data.action.fcurves

for fcu in fcurves:
if fcu:
for kp in fcu.keyframe_points:
if kp.co.x == frame:
kp.type = 'KEYFRAME'
return {'FINISHED'}

#----------------------------------------------
class VIEW3D_OT_SetKeyTypePBD(bpy.types.Operator):
bl_idname = "keyframes.settype_pbd"
bl_label = "P BD"
bl_description = "Set keyframe type to primary breakdown"

def execute(self, context):
scene = context.scene
frame = scene.frame_current
object = context.object
fcurves = object.animation_data.action.fcurves

for fcu in fcurves:
if fcu:
for kp in fcu.keyframe_points:
if kp.co.x == frame:
kp.type = 'EXTREME'
return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_PushKeys(bpy.types.Operator):
bl_idname = "keyframes.push_keys"
bl_label = "Push Keys"
bl_description = "Push current and subsequent keys by a set number of frames"

def execute(self, context):
scene = context.scene
obj = context.object
fcurves = obj.animation_data.action.fcurves
current_frame = scene.frame_current

def push(fcurves):
for fcu in fcurves:
for kp in fcu.keyframe_points:
if scene.push_keys_mode == 'after':
if kp.co.x >= current_frame:
kp.co.x += scene.push_keys_int
kp.handle_left.x += scene.push_keys_int
kp.handle_right.x += scene.push_keys_int
elif scene.push_keys_mode == 'before':
if kp.co.x <= current_frame:
kp.co.x += scene.push_keys_int
kp.handle_left.x += scene.push_keys_int
kp.handle_right.x += scene.push_keys_int
elif scene.push_keys_mode == 'only_after':
if kp.co.x > current_frame:
kp.co.x += scene.push_keys_int
kp.handle_left.x += scene.push_keys_int
kp.handle_right.x += scene.push_keys_int
elif scene.push_keys_mode == 'only_before':
if kp.co.x < current_frame:
kp.co.x += scene.push_keys_int
kp.handle_left.x += scene.push_keys_int
kp.handle_right.x += scene.push_keys_int
#All
else:
kp.co.x += scene.push_keys_int
kp.handle_left.x += scene.push_keys_int
kp.handle_right.x += scene.push_keys_int

push(fcurves)

if obj.data.animation_data is not None and obj.data.animation_data.action is not None:
data_fcurves = obj.data.animation_data.action.fcurves
push(data_fcurves)

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_AutoClampedHandles(bpy.types.Operator):
bl_idname = "keyframes.to_autoclamped"
bl_label = "Auto-Clamped"
bl_description = "Set handle types to auto-clamped"

def execute(self, context):
scene = context.scene
fcurves = context.object.animation_data.action.fcurves
current_frame = scene.frame_current

for fcu in fcurves:
for kp in fcu.keyframe_points:
if scene.handle_mode == 'current':
if kp.co.x == current_frame:
kp.handle_right_type = 'AUTO_CLAMPED'
kp.handle_left_type = 'AUTO_CLAMPED'
else:
kp.handle_right_type = 'AUTO_CLAMPED'
kp.handle_left_type = 'AUTO_CLAMPED'

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_AlignedHandles(bpy.types.Operator):
bl_idname = "keyframes.to_aligned"
bl_label = "Aligned"
bl_description = "Set handle types to aligned"

def execute(self, context):
scene = context.scene
fcurves = context.object.animation_data.action.fcurves
current_frame = scene.frame_current

for fcu in fcurves:
for kp in fcu.keyframe_points:
if scene.handle_mode == 'current':
if kp.co.x == current_frame:
kp.handle_right_type = 'ALIGNED'
kp.handle_left_type = 'ALIGNED'
else:
kp.handle_right_type = 'ALIGNED'
kp.handle_left_type = 'ALIGNED'

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_VectorHandles(bpy.types.Operator):
bl_idname = "keyframes.to_vector"
bl_label = "Vector"
bl_description = "Set handle types to vector"

def execute(self, context):
scene = context.scene
fcurves = context.object.animation_data.action.fcurves
current_frame = scene.frame_current

for fcu in fcurves:
for kp in fcu.keyframe_points:
if scene.handle_mode == 'current':
if kp.co.x == current_frame:
kp.handle_right_type = 'VECTOR'
kp.handle_left_type = 'VECTOR'
else:
kp.handle_right_type = 'VECTOR'
kp.handle_left_type = 'VECTOR'

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_FreeHandles(bpy.types.Operator):
bl_idname = "keyframes.to_free"
bl_label = "Free"
bl_description = "Set handle types to free"

def execute(self, context):
scene = context.scene
fcurves = context.object.animation_data.action.fcurves
current_frame = scene.frame_current

for fcu in fcurves:
for kp in fcu.keyframe_points:
if scene.handle_mode == 'current':
if kp.co.x == current_frame:
kp.handle_right_type = 'FREE'
kp.handle_left_type = 'FREE'
else:
kp.handle_right_type = 'FREE'
kp.handle_left_type = 'FREE'

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_InterpType(bpy.types.Operator):
bl_idname = "keyframes.set_interp_type"
bl_label = "Set Interpolation"

def execute(self, context):
scene = context.scene
fcurves = context.object.animation_data.action.fcurves
current_frame = scene.frame_current

for fcu in fcurves:
for kp in fcu.keyframe_points:
#Spline
if scene.interp_type == 'spline':
if scene.interp_mode == 'current':
if kp.co.x == current_frame:
kp.interpolation = 'BEZIER'
else:
kp.interpolation = 'BEZIER'

#Linear
elif scene.interp_type == 'linear':
if scene.interp_mode == 'current':
if kp.co.x == current_frame:
kp.interpolation = 'LINEAR'
else:
kp.interpolation = 'LINEAR'

#Stepped
elif scene.interp_type == 'stepped':
if scene.interp_mode == 'current':
if kp.co.x == current_frame:
kp.interpolation = 'CONSTANT'
else:
kp.interpolation = 'CONSTANT'

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_ScaleKeys(bpy.types.Operator):
bl_idname = "keyframes.scale_keys"
bl_label = "Scale Keyframes"
bl_description = "Scale subsequent keyframes around current frame"

def execute(self, context):
scene = context.scene
current_frame = scene.frame_current
fcurves = context.object.animation_data.action.fcurves

for fcu in fcurves:
for i in reversed(range(1, fcu.keyframe_points.__len__())):
# for kp in fcu.keyframe_points:
# if kp.co.x > current_frame:
# kp.co.x *= scene.scale_amt
if fcu.keyframe_points[i].co.x > current_frame:
mult = scene.scale_amt * (fcu.keyframe_points[i].co.x - fcu.keyframe_points[i-1].co.x)
fcu.keyframe_points[i].co.x *= mult

return {'FINISHED'}

#-----------------------------------------------
class VIEW3D_OT_SetToStacked(bpy.types.Operator):
bl_idname = "keyframes.to_stacked"
bl_label = "Stack Keys"
bl_description = "Set all subsequent keyframes to stacked position - separated by only one frame each)"

def execute(self, context):
sce = bpy.context.scene
ob = bpy.context.object

if ob.animation_data is None or ob.animation_data.action is None:
raise ValueError
fcurves = ob.animation_data.action.fcurves

def stack(fcurves):
inverse_index = {}
for fcu in fcurves:
for point in fcu.keyframe_points:
f = round(point.co.x)
if f < sce.frame_current:
continue
try:
inverse_index[f].append(point)
except KeyError:
inverse_index[f] = [point]

i = sce.frame_current
for f, points in sorted(inverse_index.items()):
for point in points:
point.co.x = i
i += 1

stack(fcurves)

if ob.data.animation_data is not None and ob.data.animation_data.action is not None:
data_fcurves = ob.data.animation_data.action.fcurves
stack(data_fcurves)

return {'FINISHED'}

#----------------------------------------------
class VIEW3D_OT_NudgeKeys(bpy.types.Operator):
bl_idname = "keyframes.nudge_keys"
bl_label = "Nudge Keys"
bl_description = "Nudge keys one frame at a time"

forward = bpy.props.BoolProperty(default = True)

def execute(self, context):
scene = context.scene
current_frame = scene.frame_current
fcurves = context.object.animation_data.action.fcurves
obj = context.object

def nudge(fcurves):
if self.forward == True:
for fcu in fcurves:
for kp in fcu.keyframe_points:
if kp.co.x == current_frame:
kp.co.x += 1
kp.handle_left.x += 1
kp.handle_right.x += 1

else:
for fcu in fcurves:
for kp in fcu.keyframe_points:
if kp.co.x == current_frame:
kp.co.x -= 1
kp.handle_left.x -= 1
kp.handle_right.x -= 1


nudge(fcurves)
if obj.data.animation_data is not None and obj.data.animation_data.action is not None:
data_fcurves = obj.data.animation_data.action.fcurves
nudge(data_fcurves)

if self.forward:
scene.frame_current += 1
else:
scene.frame_current -= 1

return {'FINISHED'}

#-----------------------------------------------
#3D View UI panels
class VIEW3D_PT_KeyTypes(bpy.types.Panel):
bl_label = "Keyframe QuickTools"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"

@classmethod
def poll(cls, context):
return context.object is not None and context.object.animation_data is not None

def draw(self, context):
layout = self.layout
scene = context.scene
action = context.object.animation_data.action
fcurves = action.fcurves
current_frame = scene.frame_current
keyframes = get_keyframe(fcurves, current_frame)
type = type_name(keyframes)

layout.label("Current keyframe type:")
layout.label(type, icon = "SPACE2" if type != "(None)" else "ERROR")
# row = layout.row()
# row.enabled = False
# row.prop(keyframes, "type", text = "", toggle = True)

layout.label("Set keyframe type:")
row = layout.row(align = True)
row.operator("keyframes.settype_key")
row.operator("keyframes.settype_pbd")
row.operator("keyframes.settype_sbd")
row.operator("keyframes.settype_mh")

row = layout.row()
row.alignment = 'CENTER'
row.label("_______________________________________")

layout.label("Push keys:")
layout.operator("keyframes.push_keys", text = "Push Keys")
layout.prop(scene, "push_keys_mode")
layout.prop(scene, "push_keys_int")

layout.separator()

layout.label("Nudge keys:")
row = layout.row()
row.alignment = 'CENTER'
row.operator("keyframes.nudge_keys", text = "", icon = "TRIA_LEFT", emboss = False).forward = False
row.label("Nudge")
row.operator("keyframes.nudge_keys", text = "", icon = "TRIA_RIGHT", emboss = False).forward = True
#
# layout.label("Scale keys:")
# layout.operator("keyframes.scale_keys")
# layout.prop(scene, "scale_amt")

layout.separator()

layout.label("Set keys to stacked:")
layout.operator("keyframes.to_stacked")

row = layout.row()
row.alignment = 'CENTER'
row.label("_______________________________________")

layout.label("Keyframe handle types:")

row = layout.row()

row.operator("keyframes.to_autoclamped")
row.operator("keyframes.to_aligned")
row = layout.row()
row.operator("keyframes.to_vector")
row.operator("keyframes.to_free")
layout.label("Apply to:")
layout.prop(scene, "handle_mode")

row = layout.row()
row.alignment = 'CENTER'
row.label("_______________________________________")

layout.label("Keyframe interpolation:")
layout.operator("keyframes.set_interp_type")
row = layout.row()
row.prop(scene, "interp_type")
row.prop(scene, "interp_mode")

def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.push_keys_int = bpy.props.IntProperty(name = "Frames", description = "Push keyframes by this number of frames", default = 0)
bpy.types.Scene.push_keys_mode = bpy.props.EnumProperty(items = [
('only_after', "After Only", "Push only keys after current frame"),
('only_before', "Before Only", "Push only keys before current frame"),
('after', "Current and After", "Push current and subsequent keys"),
('before', "Current and Before", "Push current and previous keys"),
('all', "All Keys", "Push all keys")],
name = "",
description = "",
default = 'only_after')
bpy.types.Scene.handle_mode = bpy.props.EnumProperty(items = [
('current', "Current Frame", "Apply handles only to the current frame"),
('all', "All Frames", "Apply handles to all frames")],
name = "",
description = "",
default = 'all')

bpy.types.Scene.interp_mode = bpy.props.EnumProperty(items = [
('current', "Current Frame", "Apply handles only to the current frame"),
('all', "All Frames", "Apply handles to all frames")],
name = "",
description = "",
default = 'all')

bpy.types.Scene.interp_type = bpy.props.EnumProperty(items = [
('spline', "Spline", "Apply bezier interpolation"),
('linear', "Linear", "Apply linear interpolation"),
('stepped', "Stepped", "Apply stepped interpolation")],
name = "",
description = "",
default = 'spline')
bpy.types.Scene.scale_amt = bpy.props.FloatProperty(name = "Scale Amount", description = "Amount by which to scale keyframes around current frame", default = 1.0, min = 0.0)


def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()
  1. bl_info = {'name':'Keyframe QuickTools',
  2.             'author':'Joel Daniels',
  3.             'version':(0,1),
  4.             'category':'Animation',
  5.             'location':'3D View -> UI panel',
  6.             'description':'A handful of quick-reference tools for keyframe manipulation'}
  7.  
  8.  
  9. import bpy
  10.  
  11.  
  12. def get_keyframe(fcurves, frame):
  13.     '''Return first keyframe type found'''
  14.     for fcu in fcurves:
  15.         if fcu:
  16.             for kp in fcu.keyframe_points:
  17.                 if kp.co.x == frame:
  18.                     return kp
  19.  
  20. def type_name(keyframe):
  21.     '''Return a string for the type of keyframe'''
  22.     text = ""
  23.     if keyframe:
  24.         if keyframe.type == 'KEYFRAME':
  25.             return "Key Pose"
  26.         elif keyframe.type == 'EXTREME':
  27.             return "Primary Breakdown"    
  28.         elif keyframe.type == 'BREAKDOWN':
  29.             return "Secondary Breakdown"
  30.         elif keyframe.type == 'JITTER':
  31.             return "Moving Hold"
  32.     else:
  33.         return "(None)"
  34.        
  35. #----------------------------------------------
  36. class VIEW3D_OT_SetKeyTypeSBD(bpy.types.Operator):
  37.     bl_idname = "keyframes.settype_sbd"
  38.     bl_label = "S BD"
  39.     bl_description = "Set keyframe type to secondary breakdown"
  40.  
  41.     def execute(self, context):
  42.         scene = context.scene
  43.         frame = scene.frame_current
  44.         object = context.object
  45.         fcurves = object.animation_data.action.fcurves
  46.        
  47.         for fcu in fcurves:
  48.             if fcu:
  49.                 for kp in fcu.keyframe_points:
  50.                     if kp.co.x == frame:
  51.                         kp.type = 'BREAKDOWN'
  52.         return {'FINISHED'}
  53.  
  54. #----------------------------------------------
  55. class VIEW3D_OT_SetKeyTypeMH(bpy.types.Operator):
  56.     bl_idname = "keyframes.settype_mh"
  57.     bl_label = "MH"
  58.     bl_description = "Set keyframe type to moving hold"
  59.  
  60.     def execute(self, context):
  61.         scene = context.scene
  62.         frame = scene.frame_current
  63.         object = context.object
  64.         fcurves = object.animation_data.action.fcurves
  65.        
  66.         for fcu in fcurves:
  67.             if fcu:
  68.                 for kp in fcu.keyframe_points:
  69.                     if kp.co.x == frame:
  70.                         kp.type = 'JITTER'
  71.         return {'FINISHED'}
  72.  
  73. #----------------------------------------------
  74. class VIEW3D_OT_SetKeyTypeKP(bpy.types.Operator):
  75.     bl_idname = "keyframes.settype_key"
  76.     bl_label = "KEY"
  77.     bl_description = "Set keyframe type to key pose"
  78.  
  79.     def execute(self, context):
  80.         scene = context.scene
  81.         frame = scene.frame_current
  82.         object = context.object
  83.         fcurves = object.animation_data.action.fcurves
  84.        
  85.         for fcu in fcurves:
  86.             if fcu:
  87.                 for kp in fcu.keyframe_points:
  88.                     if kp.co.x == frame:
  89.                         kp.type = 'KEYFRAME'
  90.         return {'FINISHED'}
  91.    
  92. #----------------------------------------------
  93. class VIEW3D_OT_SetKeyTypePBD(bpy.types.Operator):
  94.     bl_idname = "keyframes.settype_pbd"
  95.     bl_label = "P BD"
  96.     bl_description = "Set keyframe type to primary breakdown"
  97.  
  98.     def execute(self, context):
  99.         scene = context.scene
  100.         frame = scene.frame_current
  101.         object = context.object
  102.         fcurves = object.animation_data.action.fcurves
  103.        
  104.         for fcu in fcurves:
  105.             if fcu:
  106.                 for kp in fcu.keyframe_points:
  107.                     if kp.co.x == frame:
  108.                         kp.type = 'EXTREME'
  109.         return {'FINISHED'}
  110.  
  111. #-----------------------------------------------
  112. class VIEW3D_OT_PushKeys(bpy.types.Operator):
  113.     bl_idname = "keyframes.push_keys"
  114.     bl_label = "Push Keys"
  115.     bl_description = "Push current and subsequent keys by a set number of frames"
  116.    
  117.     def execute(self, context):
  118.         scene = context.scene
  119.         obj = context.object
  120.         fcurves = obj.animation_data.action.fcurves
  121.         current_frame = scene.frame_current
  122.  
  123.         def push(fcurves):
  124.             for fcu in fcurves:
  125.                 for kp in fcu.keyframe_points:
  126.                     if scene.push_keys_mode == 'after':
  127.                         if kp.co.x >= current_frame:
  128.                             kp.co.x += scene.push_keys_int
  129.                             kp.handle_left.x += scene.push_keys_int
  130.                             kp.handle_right.x += scene.push_keys_int
  131.                     elif scene.push_keys_mode == 'before':
  132.                         if kp.co.x <= current_frame:
  133.                             kp.co.x += scene.push_keys_int
  134.                             kp.handle_left.x += scene.push_keys_int
  135.                             kp.handle_right.x += scene.push_keys_int
  136.                     elif scene.push_keys_mode == 'only_after':
  137.                         if kp.co.x > current_frame:
  138.                             kp.co.x += scene.push_keys_int
  139.                             kp.handle_left.x += scene.push_keys_int
  140.                             kp.handle_right.x += scene.push_keys_int
  141.                     elif scene.push_keys_mode == 'only_before':
  142.                         if kp.co.x < current_frame:
  143.                             kp.co.x += scene.push_keys_int
  144.                             kp.handle_left.x += scene.push_keys_int
  145.                             kp.handle_right.x += scene.push_keys_int
  146.                     #All
  147.                     else:
  148.                         kp.co.x += scene.push_keys_int
  149.                         kp.handle_left.x += scene.push_keys_int
  150.                         kp.handle_right.x += scene.push_keys_int
  151.                        
  152.         push(fcurves)
  153.        
  154.         if obj.data.animation_data is not None and obj.data.animation_data.action is not None:
  155.             data_fcurves = obj.data.animation_data.action.fcurves
  156.             push(data_fcurves)
  157.                    
  158.         return {'FINISHED'}
  159.  
  160. #-----------------------------------------------
  161. class VIEW3D_OT_AutoClampedHandles(bpy.types.Operator):
  162.     bl_idname = "keyframes.to_autoclamped"
  163.     bl_label = "Auto-Clamped"
  164.     bl_description = "Set handle types to auto-clamped"
  165.    
  166.     def execute(self, context):
  167.         scene = context.scene
  168.         fcurves = context.object.animation_data.action.fcurves
  169.         current_frame = scene.frame_current
  170.        
  171.         for fcu in fcurves:
  172.             for kp in fcu.keyframe_points:
  173.                 if scene.handle_mode == 'current':
  174.                     if kp.co.x == current_frame:
  175.                         kp.handle_right_type = 'AUTO_CLAMPED'
  176.                         kp.handle_left_type = 'AUTO_CLAMPED'
  177.                 else:
  178.                     kp.handle_right_type = 'AUTO_CLAMPED'
  179.                     kp.handle_left_type = 'AUTO_CLAMPED'
  180.                    
  181.         return {'FINISHED'}
  182.  
  183. #-----------------------------------------------
  184. class VIEW3D_OT_AlignedHandles(bpy.types.Operator):
  185.     bl_idname = "keyframes.to_aligned"
  186.     bl_label = "Aligned"
  187.     bl_description = "Set handle types to aligned"
  188.    
  189.     def execute(self, context):
  190.         scene = context.scene
  191.         fcurves = context.object.animation_data.action.fcurves
  192.         current_frame = scene.frame_current
  193.        
  194.         for fcu in fcurves:
  195.             for kp in fcu.keyframe_points:
  196.                 if scene.handle_mode == 'current':
  197.                     if kp.co.x == current_frame:
  198.                         kp.handle_right_type = 'ALIGNED'
  199.                         kp.handle_left_type = 'ALIGNED'
  200.                 else:
  201.                     kp.handle_right_type = 'ALIGNED'
  202.                     kp.handle_left_type = 'ALIGNED'
  203.                    
  204.         return {'FINISHED'}
  205.    
  206. #-----------------------------------------------
  207. class VIEW3D_OT_VectorHandles(bpy.types.Operator):
  208.     bl_idname = "keyframes.to_vector"
  209.     bl_label = "Vector"
  210.     bl_description = "Set handle types to vector"
  211.    
  212.     def execute(self, context):
  213.         scene = context.scene
  214.         fcurves = context.object.animation_data.action.fcurves
  215.         current_frame = scene.frame_current
  216.        
  217.         for fcu in fcurves:
  218.             for kp in fcu.keyframe_points:
  219.                 if scene.handle_mode == 'current':
  220.                     if kp.co.x == current_frame:
  221.                         kp.handle_right_type = 'VECTOR'
  222.                         kp.handle_left_type = 'VECTOR'
  223.                 else:
  224.                     kp.handle_right_type = 'VECTOR'
  225.                     kp.handle_left_type = 'VECTOR'
  226.                    
  227.         return {'FINISHED'}
  228.  
  229. #-----------------------------------------------
  230. class VIEW3D_OT_FreeHandles(bpy.types.Operator):
  231.     bl_idname = "keyframes.to_free"
  232.     bl_label = "Free"
  233.     bl_description = "Set handle types to free"
  234.    
  235.     def execute(self, context):
  236.         scene = context.scene
  237.         fcurves = context.object.animation_data.action.fcurves
  238.         current_frame = scene.frame_current
  239.        
  240.         for fcu in fcurves:
  241.             for kp in fcu.keyframe_points:
  242.                 if scene.handle_mode == 'current':
  243.                     if kp.co.x == current_frame:
  244.                         kp.handle_right_type = 'FREE'
  245.                         kp.handle_left_type = 'FREE'
  246.                 else:
  247.                     kp.handle_right_type = 'FREE'
  248.                     kp.handle_left_type = 'FREE'
  249.                    
  250.         return {'FINISHED'}
  251.  
  252. #-----------------------------------------------
  253. class VIEW3D_OT_InterpType(bpy.types.Operator):
  254.     bl_idname = "keyframes.set_interp_type"
  255.     bl_label = "Set Interpolation"
  256.    
  257.     def execute(self, context):
  258.         scene = context.scene
  259.         fcurves = context.object.animation_data.action.fcurves
  260.         current_frame = scene.frame_current
  261.        
  262.         for fcu in fcurves:
  263.             for kp in fcu.keyframe_points:
  264.                 #Spline
  265.                 if scene.interp_type == 'spline':
  266.                     if scene.interp_mode == 'current':
  267.                         if kp.co.x == current_frame:
  268.                             kp.interpolation = 'BEZIER'
  269.                     else:
  270.                         kp.interpolation = 'BEZIER'
  271.                
  272.                 #Linear
  273.                 elif scene.interp_type == 'linear':
  274.                     if scene.interp_mode == 'current':
  275.                         if kp.co.x == current_frame:
  276.                             kp.interpolation = 'LINEAR'
  277.                     else:
  278.                         kp.interpolation = 'LINEAR'
  279.                
  280.                 #Stepped
  281.                 elif scene.interp_type == 'stepped':
  282.                     if scene.interp_mode == 'current':
  283.                         if kp.co.x == current_frame:
  284.                             kp.interpolation = 'CONSTANT'
  285.                     else:
  286.                         kp.interpolation = 'CONSTANT'
  287.                        
  288.         return {'FINISHED'}
  289.  
  290. #-----------------------------------------------
  291. class VIEW3D_OT_ScaleKeys(bpy.types.Operator):
  292.     bl_idname = "keyframes.scale_keys"
  293.     bl_label = "Scale Keyframes"
  294.     bl_description = "Scale subsequent keyframes around current frame"
  295.  
  296.     def execute(self, context):
  297.         scene = context.scene
  298.         current_frame = scene.frame_current
  299.         fcurves = context.object.animation_data.action.fcurves
  300.  
  301.         for fcu in fcurves:
  302.             for i in reversed(range(1, fcu.keyframe_points.__len__())):
  303. #            for kp in fcu.keyframe_points:
  304. #                if kp.co.x > current_frame:
  305. #                    kp.co.x *= scene.scale_amt
  306.                 if fcu.keyframe_points[i].co.x > current_frame:
  307.                     mult = scene.scale_amt * (fcu.keyframe_points[i].co.x - fcu.keyframe_points[i-1].co.x)
  308.                     fcu.keyframe_points[i].co.x *= mult
  309.  
  310.         return {'FINISHED'}
  311.  
  312. #-----------------------------------------------
  313. class VIEW3D_OT_SetToStacked(bpy.types.Operator):
  314.     bl_idname = "keyframes.to_stacked"
  315.     bl_label = "Stack Keys"
  316.     bl_description = "Set all subsequent keyframes to stacked position - separated by only one frame each)"
  317.  
  318.     def execute(self, context):
  319.         sce = bpy.context.scene
  320.         ob = bpy.context.object
  321.  
  322.         if ob.animation_data is None or ob.animation_data.action is None:
  323.             raise ValueError
  324.         fcurves = ob.animation_data.action.fcurves
  325.  
  326.         def stack(fcurves):
  327.             inverse_index = {}
  328.             for fcu in fcurves:
  329.                 for point in fcu.keyframe_points:
  330.                     f = round(point.co.x)
  331.                     if f < sce.frame_current:
  332.                         continue
  333.                     try:
  334.                         inverse_index[f].append(point)
  335.                     except KeyError:
  336.                         inverse_index[f] = [point]
  337.  
  338.             i = sce.frame_current
  339.             for f, points in sorted(inverse_index.items()):
  340.                 for point in points:
  341.                     point.co.x = i
  342.                 i += 1
  343.                
  344.         stack(fcurves)
  345.  
  346.         if ob.data.animation_data is not None and ob.data.animation_data.action is not None:
  347.             data_fcurves = ob.data.animation_data.action.fcurves
  348.             stack(data_fcurves)
  349.            
  350.         return {'FINISHED'}
  351.  
  352. #----------------------------------------------
  353. class VIEW3D_OT_NudgeKeys(bpy.types.Operator):
  354.     bl_idname = "keyframes.nudge_keys"
  355.     bl_label = "Nudge Keys"
  356.     bl_description = "Nudge keys one frame at a time"
  357.    
  358.     forward = bpy.props.BoolProperty(default = True)
  359.    
  360.     def execute(self, context):
  361.         scene = context.scene
  362.         current_frame = scene.frame_current
  363.         fcurves = context.object.animation_data.action.fcurves
  364.         obj = context.object
  365.        
  366.         def nudge(fcurves):
  367.             if self.forward == True:
  368.                 for fcu in fcurves:
  369.                     for kp in fcu.keyframe_points:
  370.                         if kp.co.x == current_frame:
  371.                             kp.co.x += 1
  372.                             kp.handle_left.x += 1
  373.                             kp.handle_right.x += 1
  374.                            
  375.             else:
  376.                 for fcu in fcurves:
  377.                     for kp in fcu.keyframe_points:
  378.                         if kp.co.x == current_frame:
  379.                             kp.co.x -= 1
  380.                             kp.handle_left.x -= 1
  381.                             kp.handle_right.x -= 1
  382.                      
  383.  
  384.         nudge(fcurves)
  385.         if obj.data.animation_data is not None and obj.data.animation_data.action is not None:
  386.             data_fcurves = obj.data.animation_data.action.fcurves
  387.             nudge(data_fcurves)
  388.            
  389.         if self.forward:
  390.             scene.frame_current += 1    
  391.         else:
  392.             scene.frame_current -= 1
  393.        
  394.         return {'FINISHED'}
  395.  
  396. #-----------------------------------------------
  397. #3D View UI panels
  398. class VIEW3D_PT_KeyTypes(bpy.types.Panel):
  399.     bl_label = "Keyframe QuickTools"
  400.     bl_space_type = "VIEW_3D"
  401.     bl_region_type = "UI"
  402.    
  403.     @classmethod
  404.     def poll(cls, context):
  405.         return context.object is not None and context.object.animation_data is not None
  406.    
  407.     def draw(self, context):
  408.         layout = self.layout
  409.         scene = context.scene
  410.         action = context.object.animation_data.action
  411.         fcurves = action.fcurves
  412.         current_frame = scene.frame_current
  413.         keyframes = get_keyframe(fcurves, current_frame)
  414.         type = type_name(keyframes)
  415.        
  416.         layout.label("Current keyframe type:")
  417.         layout.label(type, icon = "SPACE2" if type != "(None)" else "ERROR")
  418. #        row = layout.row()
  419. #        row.enabled = False
  420. #        row.prop(keyframes, "type", text = "", toggle = True)
  421.        
  422.         layout.label("Set keyframe type:")
  423.         row = layout.row(align = True)
  424.         row.operator("keyframes.settype_key")
  425.         row.operator("keyframes.settype_pbd")
  426.         row.operator("keyframes.settype_sbd")
  427.         row.operator("keyframes.settype_mh")
  428.        
  429.         row = layout.row()
  430.         row.alignment = 'CENTER'
  431.         row.label("_______________________________________")
  432.        
  433.         layout.label("Push keys:")
  434.         layout.operator("keyframes.push_keys", text = "Push Keys")
  435.         layout.prop(scene, "push_keys_mode")
  436.         layout.prop(scene, "push_keys_int")
  437.  
  438.         layout.separator()
  439.  
  440.         layout.label("Nudge keys:")
  441.         row = layout.row()
  442.         row.alignment = 'CENTER'
  443.         row.operator("keyframes.nudge_keys", text = "", icon = "TRIA_LEFT", emboss = False).forward = False
  444.         row.label("Nudge")
  445.         row.operator("keyframes.nudge_keys", text = "", icon = "TRIA_RIGHT", emboss = False).forward = True
  446. #        
  447. #        layout.label("Scale keys:")
  448. #        layout.operator("keyframes.scale_keys")
  449. #        layout.prop(scene, "scale_amt")
  450.        
  451.         layout.separator()
  452.        
  453.         layout.label("Set keys to stacked:")
  454.         layout.operator("keyframes.to_stacked")
  455.        
  456.         row = layout.row()
  457.         row.alignment = 'CENTER'
  458.         row.label("_______________________________________")
  459.        
  460.         layout.label("Keyframe handle types:")
  461.        
  462.         row = layout.row()
  463.  
  464.         row.operator("keyframes.to_autoclamped")
  465.         row.operator("keyframes.to_aligned")
  466.         row = layout.row()
  467.         row.operator("keyframes.to_vector")
  468.         row.operator("keyframes.to_free")
  469.         layout.label("Apply to:")
  470.         layout.prop(scene, "handle_mode")
  471.        
  472.         row = layout.row()
  473.         row.alignment = 'CENTER'
  474.         row.label("_______________________________________")
  475.        
  476.         layout.label("Keyframe interpolation:")
  477.         layout.operator("keyframes.set_interp_type")
  478.         row = layout.row()
  479.         row.prop(scene, "interp_type")
  480.         row.prop(scene, "interp_mode")
  481.  
  482. def register():
  483.     bpy.utils.register_module(__name__)
  484.     bpy.types.Scene.push_keys_int = bpy.props.IntProperty(name = "Frames", description = "Push keyframes by this number of frames", default = 0)
  485.     bpy.types.Scene.push_keys_mode = bpy.props.EnumProperty(items = [
  486.                                         ('only_after', "After Only", "Push only keys after current frame"),
  487.                                         ('only_before', "Before Only", "Push only keys before current frame"),
  488.                                         ('after', "Current and After", "Push current and subsequent keys"),
  489.                                         ('before', "Current and Before", "Push current and previous keys"),
  490.                                         ('all', "All Keys", "Push all keys")],
  491.                                         name = "",
  492.                                         description = "",
  493.                                         default = 'only_after')
  494.     bpy.types.Scene.handle_mode = bpy.props.EnumProperty(items = [
  495.                                         ('current', "Current Frame", "Apply handles only to the current frame"),
  496.                                         ('all', "All Frames", "Apply handles to all frames")],
  497.                                         name = "",
  498.                                         description = "",
  499.                                         default = 'all')
  500.    
  501.     bpy.types.Scene.interp_mode = bpy.props.EnumProperty(items = [
  502.                                         ('current', "Current Frame", "Apply handles only to the current frame"),
  503.                                         ('all', "All Frames", "Apply handles to all frames")],
  504.                                         name = "",
  505.                                         description = "",
  506.                                         default = 'all')
  507.    
  508.     bpy.types.Scene.interp_type = bpy.props.EnumProperty(items = [
  509.                                         ('spline', "Spline", "Apply bezier interpolation"),
  510.                                         ('linear', "Linear", "Apply linear interpolation"),
  511.                                         ('stepped', "Stepped", "Apply stepped interpolation")],
  512.                                         name = "",
  513.                                         description = "",
  514.                                         default = 'spline')
  515.     bpy.types.Scene.scale_amt = bpy.props.FloatProperty(name = "Scale Amount", description = "Amount by which to scale keyframes around current frame", default = 1.0, min = 0.0)
  516.                                        
  517.                                        
  518. def unregister():
  519.     bpy.utils.unregister_module(__name__)
  520.    
  521. if __name__ == "__main__":
  522.     register()
  523.  
go to heaven