Fix: Node Wrangler: new reroutes offset when output hidden
[blender-addons.git] / amaranth / animation / motion_paths.py
bloba61c7e4ee123ddc2ada0a94339b27a5c290a3610
1 # SPDX-License-Identifier: GPL-2.0-or-later
2 """
3 Bone Motion Paths:
5 Match Frame Range + Clear All Paths
7 * Clear All Paths:
8 Silly operator to loop through all bones and clear their paths, useful
9 when having hidden bones (othrewise you have to go through each one of
10 them and clear manually)
12 *Match Current Frame Range:
13 Set the current frame range as motion path range.
15 Both requests by Hjalti from Project Pampa
16 Thanks to Bassam Kurdali for helping finding out the weirdness behind
17 Motion Paths bpy.
19 Developed during Caminandes Open Movie Project
20 """
22 import bpy
25 class AMTH_POSE_OT_paths_clear_all(bpy.types.Operator):
27 """Clear motion paths from all bones"""
28 bl_idname = "pose.paths_clear_all"
29 bl_label = "Clear All Motion Paths"
30 bl_options = {"UNDO"}
32 @classmethod
33 def poll(cls, context):
34 return context.mode == "POSE"
36 def execute(self, context):
37 # silly but works
38 for b in context.object.data.bones:
39 b.select = True
40 bpy.ops.pose.paths_clear()
41 b.select = False
42 return {"FINISHED"}
45 class AMTH_POSE_OT_paths_frame_match(bpy.types.Operator):
47 """Match Start/End frame of scene to motion path range"""
48 bl_idname = "pose.paths_frame_match"
49 bl_label = "Match Frame Range"
50 bl_options = {"UNDO"}
52 def execute(self, context):
53 avs = context.object.pose.animation_visualization
54 scene = context.scene
56 if avs.motion_path.type == "RANGE":
57 if scene.use_preview_range:
58 avs.motion_path.frame_start = scene.frame_preview_start
59 avs.motion_path.frame_end = scene.frame_preview_end
60 else:
61 avs.motion_path.frame_start = scene.frame_start
62 avs.motion_path.frame_end = scene.frame_end
64 else:
65 if scene.use_preview_range:
66 avs.motion_path.frame_before = scene.frame_preview_start
67 avs.motion_path.frame_after = scene.frame_preview_end
68 else:
69 avs.motion_path.frame_before = scene.frame_start
70 avs.motion_path.frame_after = scene.frame_end
72 return {"FINISHED"}
75 def pose_motion_paths_ui(self, context):
77 layout = self.layout
78 scene = context.scene
79 avs = context.object.pose.animation_visualization
80 if context.active_pose_bone:
81 mpath = context.active_pose_bone.motion_path
82 layout.separator()
83 layout.label(text="Motion Paths Extras:")
85 split = layout.split()
87 col = split.column(align=True)
89 if context.selected_pose_bones:
90 if mpath:
91 sub = col.row(align=True)
92 sub.operator(
93 "pose.paths_update", text="Update Path", icon="BONE_DATA")
94 sub.operator("pose.paths_clear", text="", icon="X")
95 else:
96 col.operator(
97 "pose.paths_calculate",
98 text="Calculate Path",
99 icon="BONE_DATA")
100 else:
101 col.label(text="Select Bones First", icon="ERROR")
103 col = split.column(align=True)
104 col.operator(
105 AMTH_POSE_OT_paths_frame_match.bl_idname,
106 text="Set Preview Frame Range" if scene.use_preview_range else "Set Frame Range",
107 icon="PREVIEW_RANGE" if scene.use_preview_range else "TIME")
109 col = layout.column()
110 row = col.row(align=True)
112 if avs.motion_path.type == "RANGE":
113 row.prop(avs.motion_path, "frame_start", text="Start")
114 row.prop(avs.motion_path, "frame_end", text="End")
115 else:
116 row.prop(avs.motion_path, "frame_before", text="Before")
117 row.prop(avs.motion_path, "frame_after", text="After")
119 layout.separator()
120 layout.operator(AMTH_POSE_OT_paths_clear_all.bl_idname, icon="X")
123 def register():
124 bpy.utils.register_class(AMTH_POSE_OT_paths_clear_all)
125 bpy.utils.register_class(AMTH_POSE_OT_paths_frame_match)
126 bpy.types.DATA_PT_display.append(pose_motion_paths_ui)
129 def unregister():
130 bpy.utils.unregister_class(AMTH_POSE_OT_paths_clear_all)
131 bpy.utils.unregister_class(AMTH_POSE_OT_paths_frame_match)
132 bpy.types.DATA_PT_display.remove(pose_motion_paths_ui)