Files
blender-portable-repo/scripts/addons/Animtoolbox/Display.py
T
2026-03-17 14:30:01 -06:00

189 lines
7.0 KiB
Python

# ***** 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)