import bpy from . import fn class UAC_PT_walk_cycle_anim_panel(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Walk" bl_label = "Walk Cycle Anim" def draw(self, context): layout = self.layout prefs = fn.get_addon_prefs() ob = context.object settings = context.scene.anim_cycle_settings tweak = settings.tweak # need to know root orientation forward) ## know direction to evaluate feet moves ## Define Constraint axis (depend on root orientation) # layout.prop(settings, "forward_axis") # plain prop col = layout.column() row = col.row() row.label(text='Forward Axis') row.prop(settings, "forward_axis", text='') row.operator('uac.open_addon_prefs', icon='PREFERENCES', text='') col.operator("uac.autoset_axis", text='Auto-Set Axis') # maybe check for fcruve cycle at the end of autoset axis ? (like a check) col.operator("uac.create_cycles_modifiers", text='Add Cycles Modifiers', icon='GRAPH') pb = None constrained = False if ob and ob.type == 'ARMATURE': pb = ob.pose.bones.get(prefs.tgt_bone) if pb: follow = pb.constraints.get('Follow Path') if follow and follow.target: constrained = True if not settings.path_to_follow and not constrained: layout.operator('anim.create_curve_path', text='Create Curve at Root Position', icon='CURVE_BEZCURVE') else: layout.operator('uac.edit_curve', text='Edit Curve', icon='OUTLINER_DATA_CURVE') # FORCE_CURVE elif ob and ob.type == 'CURVE': if context.mode in ('OBJECT', 'EDIT_CURVE') \ and settings.path_to_follow \ and ob == settings.path_to_follow: layout.operator('uac.object_from_curve', text='Back To Object', icon='LOOP_BACK') box = layout.box() expand_icon = 'TRIA_DOWN' if tweak else 'TRIA_RIGHT' box.prop(settings, 'tweak', text='Curve Options', icon=expand_icon) if tweak: #-# path and ground objects box.prop(settings, "tgt_bone", text='Bone') box.prop_search(settings, "path_to_follow", context.scene, "objects") box.prop_search(settings, "gnd", context.scene, "objects") row = box.row() row.operator('anim.snap_curve_to_ground', text='Snap curve to ground', icon='SNAP_ON') row.active = bool(settings.gnd) # Determine if already has a constraint (a bit too much condition in a panel...) if ob: if ob.type == 'ARMATURE': pb = ob.pose.bones.get(prefs.tgt_bone) if pb: follow = pb.constraints.get('Follow Path') if follow and follow.target: box.label(text=f'{pb.name} -> {follow.target.name}', icon='CON_FOLLOWPATH') constrained = True ## Put this in a setting popup or submenu # if context.mode == 'POSE': if not constrained: box.operator('anim.create_follow_path', text='Add follow path constraint', icon='CON_FOLLOWPATH') box = layout.box() col=box.column() col.label(text='Motion:') col.prop(settings, "start_frame", text='Start') # col.prop(settings, "foot_axis", text='Foot Axis') col.operator('anim.animate_path', text='Animate Forward Motion', icon='ANIM') row=col.row() row.operator('anim.adjust_animation_length', text='Adjust Forward Speed', icon='MOD_TIME') ## Bake cycle (on selected) box = layout.box() col=box.column() col.label(text='Action:') row=col.row() row.prop(settings, "linear", text='Linear') row.prop(settings, "expand_on_selected_bones") txt = 'Bake keys' if settings.linear else 'Bake keys and step path' col.operator('anim.bake_cycle_and_step', text=txt, icon='SHAPEKEY_DATA') # Pin feet col.operator('anim.pin_feets', text='Pin feets', icon='PINNED') ## show a dropdown allowing to go back to unpinned, unbaked version of the animation if ob and ob.type == 'ARMATURE': anim = ob.animation_data if anim and anim.action and not anim.use_tweak_mode: # skipped if in NLA tweak mode because anim.is_property_readonly('action') = True if 'baked' in anim.action.name or 'pinned' in anim.action.name: col=box.column() col.operator('uac.step_back_actions', text='Use Previous Actions', icon= 'ACTION') class UAC_PT_anim_tools_panel(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Walk" bl_label = "Tools" def draw(self, context): layout = self.layout layout.operator('anim.contact_to_ground', text='Ground selected feet', icon='SNAP_OFF') row = layout.row() row.operator('anim.world_space_copy', text='Copy Pose', icon='COPYDOWN') # row.operator('anim.world_space_paste', text='Paste', icon='PASTEDOWN') # row = layout.row(align=False) ## multi buttons # row.label(text='Paste and jump:') # row = layout.row(align=True) # row.operator('anim.world_space_paste_next', text='Prev key', icon='PREV_KEYFRAME').prev = True # Paste Prev key # row.operator('anim.world_space_paste_next', text='Next key', icon='NEXT_KEYFRAME').prev = False # Paste Next key # row = layout.row(align=True) # row.operator('anim.world_space_paste_next_frame', text='Prev frame', icon='FRAME_PREV').prev = True # Paste Prev frame # row.operator('anim.world_space_paste_next_frame', text='Next frame', icon='FRAME_NEXT').prev = False # Paste Next frame row = layout.row(align=True) row.operator('anim.world_space_paste_next_frame', text='', icon='FRAME_PREV').prev = True row.operator('anim.world_space_paste_next', text='', icon='PREV_KEYFRAME').prev = True row.operator('anim.world_space_paste', text='', icon='PASTEDOWN') row.operator('anim.world_space_paste_next', text='', icon='NEXT_KEYFRAME').prev = False row.operator('anim.world_space_paste_next_frame', text='', icon='FRAME_NEXT').prev = False row.scale_x = 2 class UAC_PT_nla_tools_panel(bpy.types.Panel): bl_space_type = "NLA_EDITOR" bl_region_type = "UI" bl_category = "Strip" bl_label = "Walk Tools" def draw(self, context): layout = self.layout # layout.label(text='Retime Tools') layout.operator('anim.nla_key_speed', text='Set Time Keys', icon='TIME') classes=( UAC_PT_walk_cycle_anim_panel, UAC_PT_anim_tools_panel, UAC_PT_nla_tools_panel, ) classes_override_category =( UAC_PT_walk_cycle_anim_panel, UAC_PT_anim_tools_panel, ) ## Addons Preferences Update Panel def update_panel(self, context): for cls in classes_override_category: # classes try: bpy.utils.unregister_class(cls) except: pass cls.bl_category = self.category # fn.get_addon_prefs().category bpy.utils.register_class(cls) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)