# ***** BEGIN GPL LICENSE BLOCK ***** # # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ***** END GPL LICENCE BLOCK ***** import bpy class GizmoSizeUp(bpy.types.Operator): """Share keyframes between all the selected objects and bones""" bl_idname = "view3d.gizmo_size_up" bl_label = "Gizmo_Size_Up" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): context.preferences.view.gizmo_size += context.scene.animtoolbox.gizmo_size return {'PASS_THROUGH'} class GizmoSizeDown(bpy.types.Operator): """Share keyframes between all the selected objects and bones""" bl_idname = "view3d.gizmo_size_down" bl_label = "Gizmo_Size_Down" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): context.preferences.view.gizmo_size -= context.scene.animtoolbox.gizmo_size return {'PASS_THROUGH'} ######################################################################################################################## def clear_isolate_pose_mode(scene): if not len(scene.animtoolbox.isolated): return for obj in scene.animtoolbox.isolated: if not obj.hidden: continue obj.hidden.hide_set(False) scene.animtoolbox.isolated.clear() scene.animtoolbox.active_obj = None def isolate_pose_mode(scene): context = bpy.context #return when going out of isolate pose or when active object is not in pose mode if not scene.animtoolbox.isolate_pose_mode or context.active_object.mode != 'POSE': clear_isolate_pose_mode(scene) return #handler continue only if the active object is None otherwise it collects all armature objects if scene.animtoolbox.active_obj is None: scene.animtoolbox.active_obj = context.active_object else: return isolated = scene.animtoolbox.isolated for obj in context.view_layer.objects: if obj.type != 'ARMATURE': continue if obj.hide_get(): continue rig = isolated.add() if obj.mode == 'POSE': rig.selected = obj else: rig.hidden = obj obj.hide_set(True) class IsolatePoseMode(bpy.types.Operator): """Isolates armatures during pose mode""" bl_idname = "anim.isolate_pose_mode" bl_label = "Isolate Pose Mode" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): # If the modal is already running, then don't run it the second time scene = context.scene if scene.animtoolbox.isolate_pose_mode: if isolate_pose_mode in bpy.app.handlers.depsgraph_update_pre: clear_isolate_pose_mode(scene) bpy.app.handlers.depsgraph_update_pre.remove(isolate_pose_mode) scene.animtoolbox.isolate_pose_mode = False return {'FINISHED'} scene.animtoolbox.isolate_pose_mode = True isolate_pose_mode(scene) if isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre: bpy.app.handlers.depsgraph_update_pre.append(isolate_pose_mode) return {'FINISHED'} class SwitchBoneCollectionsVisibility(bpy.types.Operator): """Turn all bone collections visible and then press again to switch back""" bl_idname = "anim.switch_collections_visibility" bl_label = "Bone Collections Visibility" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): return bpy.app.version >= (4, 0, 0) def execute(self, context): obj = context.object if obj.type != 'ARMATURE': return {'CANCELLED'} if not obj.animation_data: self.report({'INFO'}, 'No animation is available') return {'CANCELLED'} if not obj.animation_data.action: self.report({'INFO'}, 'No animation is available') return {'CANCELLED'} collections = obj.data.collections if not len(collections): self.report({'INFO'}, 'No collections are available') return {'CANCELLED'} #check if there are collections that are marked with tagged_col = ['atb' in col.keys() for col in collections] atb_ui = context.scene.animtoolbox if any(tagged_col) and atb_ui.col_vis: #collections are already marked so return to previous collection visibilty for col in collections: if 'atb' in col.keys(): col.is_visible = col['atb'] del col['atb'] atb_ui.col_vis = False else: #Mark visible collections and turn collections with animated bones on animated_bones = set() start = 'pose.bones["' end = '"]' #get all the animated bones from the fcurves for fcu in obj.animation_data.action.fcurves: start_index = fcu.data_path.find(start) end_index = fcu.data_path.find(end) #if it's not a posebone fcurve then skip if start_index == -1 or end_index == -1: continue animated_bones.add(fcu.data_path[start_index + len(start):end_index]) #check if the collecetion that is turned off has animated bones find_anim = [] for col in collections: for bone in col.bones: if bone.name in animated_bones and not col.is_visible: # print(bone.name, 'in ', col.name) find_anim.append(col) break if not find_anim: self.report({'INFO'}, 'No collections with animated bones and no visibility are found') return {'CANCELLED'} #Turn on collections without visiblity for col in collections: if col in find_anim: #tag visibility col['atb'] = col.is_visible col.is_visible = True atb_ui.col_vis = True return {'FINISHED'} classes = (GizmoSizeUp, GizmoSizeDown, IsolatePoseMode, SwitchBoneCollectionsVisibility) def register(): from bpy.utils import register_class for cls in classes: register_class(cls) def unregister(): from bpy.utils import unregister_class for cls in classes: unregister_class(cls)