527 lines
35 KiB
Python
527 lines
35 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 *****
|
|
|
|
bl_info = {
|
|
"name": "AnimToolBox",
|
|
"author": "Tal Hershkovich",
|
|
"version" : (0, 0, 7, 3),
|
|
"blender" : (3, 2, 0),
|
|
"location": "View3D - Properties - Animation Panel",
|
|
"description": "A set of animation tools",
|
|
"wiki_url": "",
|
|
"category": "Animation"}
|
|
|
|
if "bpy" in locals():
|
|
import importlib
|
|
if "Rigger_Toolbox" in locals():
|
|
importlib.reload(Rigger_Toolbox)
|
|
if "TempCtrls" in locals():
|
|
importlib.reload(TempCtrls)
|
|
if "Tools" in locals():
|
|
importlib.reload(Tools)
|
|
if "Display" in locals():
|
|
importlib.reload(Display)
|
|
if "emp" in locals():
|
|
importlib.reload(emp)
|
|
if "multikey" in locals():
|
|
importlib.reload(multikey)
|
|
if "Rigger_Toolbox" in locals():
|
|
importlib.reload(Rigger_Toolbox)
|
|
if "ui" in locals():
|
|
importlib.reload(ui)
|
|
if "addon_updater_ops" in locals():
|
|
importlib.reload(addon_updater_ops)
|
|
|
|
import bpy
|
|
from . import addon_updater_ops
|
|
from . import TempCtrls
|
|
from . import Rigger_Toolbox
|
|
from . import Tools
|
|
from . import Display
|
|
from . import emp
|
|
from . import ui
|
|
from . import multikey
|
|
from . import Rigger_Toolbox
|
|
from pathlib import Path
|
|
from bpy.utils import register_class
|
|
from bpy.utils import unregister_class
|
|
from bpy.app.handlers import persistent
|
|
import os
|
|
|
|
|
|
class TempCtrlsItems(bpy.types.PropertyGroup):
|
|
#located at context.scene.btc.ctrl_items
|
|
controlled: bpy.props.PointerProperty(name = "controlled object", description = "rigs and objects that are being controlled", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
controller: bpy.props.PointerProperty(name = "controller object", description = "rigs and objects that are controling", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
class TempCtrlsSceneSettings(bpy.types.PropertyGroup):
|
|
#located at context.scene.btc
|
|
root: bpy.props.BoolProperty(name = "Root Empty", description = "Add a root to the empties ", default = False, override = {'LIBRARY_OVERRIDABLE'}, update = TempCtrls.root_prop)
|
|
root_bone: bpy.props.StringProperty(name = "Root bone", description = "Root empty as a root bone ", override = {'LIBRARY_OVERRIDABLE'}, update = TempCtrls.root_update)
|
|
root_object: bpy.props.PointerProperty(name = "Root object", description = "Root empty as a root object ", update = TempCtrls.root_update, type = bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
ctrl_type: bpy.props.EnumProperty(name = 'Controllers', description="Select empties or a bone with a new rig to bake to", items = [('BONE', 'Bone','Bake to bones','BONE_DATA', 0), ('EMPTY', 'Empty', 'Bake to empties', 'EMPTY_ARROWS', 1)])
|
|
ctrl_items: bpy.props.CollectionProperty(type = TempCtrlsItems, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
|
|
|
bake_range_type: bpy.props.EnumProperty(name = 'Bake Range', description="Use either scene, actions length or custom frame range", default = 'KEYFRAMES', update= TempCtrls.update_range_type,
|
|
items = [('SCENE', 'Scene Range', 'Bake to the scene range'), ('KEYFRAMES', 'Keyframes Range', 'Bake all the keyframes in the layers'), ('CUSTOM', 'Custom', 'Enter a custom frame range')], override = {'LIBRARY_OVERRIDABLE'})
|
|
bake_range: bpy.props.IntVectorProperty(name='Frame Range', description='Bake to a custom frame range', size = 2, update= TempCtrls.update_bake_range)
|
|
bake_layers: bpy.props.BoolProperty(name = "Bake Layers", description = "Use keyframes from all the layers to include in the bake", default = False)
|
|
|
|
target: bpy.props.EnumProperty(name = 'Affect', description="Cleanup created constraints and empties", default = 1,
|
|
items = [('ALL', 'All Ctrl Rigs','Bake to all Ctrl Rigs', 0),
|
|
('SELECTED', 'Selected Chains','Bake to only selected chain controlls', 1),
|
|
('RELATIVE', 'Relative Ctrls Rig','Bake to the Relative Control rigs', 2)])
|
|
# ('CONSTRAINTS', 'Constraints', 'Clean all the bone constraints', 3),
|
|
# ('CONTROLLERS', 'Controllers', 'Remove all the baked empties', 4)])
|
|
|
|
selection: bpy.props.EnumProperty(name = 'Select', description="Select all controls, original bones or their relative", default = 'CONTROLLERS',
|
|
items = [('RELATIVE_CTRLS', 'Relative Ctrls','Select the Relative controller to your current selection', 0),
|
|
('RELATIVE_CONSTRAINED', 'Relative Constrained','Select the Relative original constrained bone to your current selection', 1),
|
|
('CONTROLLERS', 'All Ctrls', 'Select all the controller bones or empties', 2), ('CONSTRAINED', 'All Constrained', 'Select all the original constrained bones', 3)])
|
|
|
|
#smartbake setting
|
|
linksettings: bpy.props.BoolProperty(name = "Link Settings", description = "Link Settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
bakesettings: bpy.props.BoolProperty(name = "bake settings", description = "bake settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
cleansettings: bpy.props.BoolProperty(name = "clean settings", description = "clean settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
smartbake: bpy.props.BoolProperty(name = "Smart Bake", description = "Keep Original Frame count", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
inbetween_keyframes: bpy.props.IntProperty(name = "Inbetween Keyframes", description = "Add inbetween keyframes", default = 0, override = {'LIBRARY_OVERRIDABLE'})
|
|
from_origin: bpy.props.BoolProperty(name = "From Origin", description = "Use Keyframes from Original Bone", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
from_ctrl: bpy.props.BoolProperty(name = "From Controller", description = "Use Keyframes from Controller Bone", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
clean_ctrls: bpy.props.BoolProperty(name = "Remove Ctrls", description = "Remove Controls", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
clean_constraints: bpy.props.BoolProperty(name = "Remove Constraints", description = "Remove Constraints", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
rebake_to_org: bpy.props.BoolProperty(name = "ReBake connections to original bones", description = "ReBake ctrls from connected chains current anim to the original bones", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
link_to: bpy.props.EnumProperty(name = 'Link to Chain', description="Link to begining of an active chain or the tip of the chain", default = 1,
|
|
items = [('BASE', 'Base','Link to the base of the active chain', 0), ('TIP', 'Tip', 'Link to the tip of the chain', 1)])
|
|
# link_from: bpy.props.EnumProperty(name = 'Link to Chain', description="Link to begining of an active chain or the tip of the chain", default = 0,
|
|
# items = [('BASE', 'Base','Link to the base of the active chain', 0), ('TIP', 'Tip', 'Link to the tip of the chain', 1)])
|
|
|
|
shape_size: bpy.props.FloatProperty(name='Size', description="Multiple factor for the shape size of the temp controls", update = TempCtrls.tempctrl_shapesize, min = 0.001, default = 1.5, override = {'LIBRARY_OVERRIDABLE'})#
|
|
shape_type: bpy.props.EnumProperty(name = 'Shape Type', description="Display type for the controls", items = TempCtrls.ctrl_shape_items, update = TempCtrls.tempctrl_shape_type)
|
|
color_set: bpy.props.EnumProperty(name="Bone Color Set", description="Choose a bone color set", items = TempCtrls.get_bone_color_sets, update = TempCtrls.update_bone_color, default = 9)
|
|
|
|
add_ik_ctrl: bpy.props.BoolProperty(name = 'Add an Extra IK Ctrl Bone', description = "Adds an extra bone ctrl as the ik ctrl", default = False, update = TempCtrls.add_ik_prop)
|
|
pole_target: bpy.props.BoolProperty(name = 'Add Pole Target', description = "Adding Pole Target to the IK Chain", default = True, update = TempCtrls.pole_prop)
|
|
pole_offset: bpy.props.FloatProperty(name="Offset", description="Offset the bone in the axis direction", default=1.0, update = TempCtrls.pole_offset)
|
|
child: bpy.props.BoolProperty(name = 'Add extra child Ctrls', description = "Add an child control for an overlay control", default = False, update = TempCtrls.child_prop)
|
|
orientation: bpy.props.BoolProperty(name = 'Use World Space Orientation', description = "Orient the bones to world space instead of to the original bones", default = True)
|
|
|
|
# enabled: bpy.props.BoolProperty(name = 'Switch On / Off', description = "Enabling and Disabling Temp Ctrls influence", default = True)
|
|
|
|
class TempCtrlsBoneSettings(bpy.types.PropertyGroup):
|
|
#located at obj.pose.bones[##].btc
|
|
root: bpy.props.BoolProperty(name = "Root Bone", description = "Bone is marked as the root bone", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
child: bpy.props.BoolProperty(name = "Child Bone", description = "Bone is marked as a child bone inside the setup", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
org_id: bpy.props.IntProperty(name = "Originate ID", description = "ID number of the bone the ctrl originates from", override = {'LIBRARY_OVERRIDABLE'})
|
|
setup_id: bpy.props.IntProperty(name = "Setup ID", description = "ID number of the current chain setup", override = {'LIBRARY_OVERRIDABLE'})
|
|
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of", override = {'LIBRARY_OVERRIDABLE'},
|
|
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
|
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
|
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 2),
|
|
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 3),
|
|
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 4),
|
|
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 5),
|
|
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 6),
|
|
('ROOT', 'Root', 'Root Ctrl for all the setups', 7),
|
|
('EMPTY', 'Root', 'Root Ctrl for all the setups', 8),
|
|
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 9),
|
|
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 10)])
|
|
|
|
#using org mostly to decide if it needs a custom shape
|
|
org: bpy.props.EnumProperty(name = 'Org Type', description="Describes what if the function of the bone", override = {'LIBRARY_OVERRIDABLE'},
|
|
items = [('CTRL', 'Controller Bone','Controller Bone', 0),
|
|
('ORG', 'Original Bone','Original Bone', 1),
|
|
('MCH', 'Mechanical Bone','Mechanical Bone', 2),
|
|
('NONE', 'Nothing applied','Nothing applied', 3)])
|
|
|
|
shape: bpy.props.BoolProperty(name = "Apply shape", description = "Mark if the bone needs a shape", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
class TempCtrlsObjectSetups(bpy.types.PropertyGroup):
|
|
#located at obj.animtoolbox.ctrl_setups
|
|
#name: using string of the id
|
|
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of",
|
|
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
|
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
|
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 2),
|
|
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 3),
|
|
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 4),
|
|
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 5),
|
|
('ROOT', 'Root', 'Root Ctrl for all the setups', 6),
|
|
('EMPTY', 'Root', 'Root Ctrl for all the setups', 8),
|
|
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 9),
|
|
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 10),
|
|
])
|
|
|
|
class MultikeyProperties(bpy.types.PropertyGroup):
|
|
|
|
selectedbones: bpy.props.BoolProperty(name="Selected Bones", description="Affect only selected bones", default=True, options={'HIDDEN'})
|
|
handletype: bpy.props.BoolProperty(name="Keep handle types", description="Keep handle types", default=False, options={'HIDDEN'})
|
|
scale: bpy.props.FloatProperty(name="Scale Factor", description="Scale percentage of the average value", default=1.0, update = multikey.scale_value)
|
|
randomness: bpy.props.FloatProperty(name="Randomness", description="Random Threshold of keyframes", default=0.1, min=0.0, max = 1.0, update = multikey.random_value)
|
|
|
|
class AnimToolBoxObjectSettings(bpy.types.PropertyGroup):
|
|
|
|
controlled: bpy.props.PointerProperty(name = 'Controlled Rig', description="Adding the rig object that is being controlled by the current object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
controller: bpy.props.PointerProperty(name = 'Controller Rig', description="Adding the rig object that is used as the temp control object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
ctrl_setups: bpy.props.CollectionProperty(type = TempCtrlsObjectSetups, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
|
ctrls_enabled: bpy.props.BoolProperty(name = 'Temp Ctrls Switch', description = "Enabling and Disabling Temp Ctrls influence", default = True)
|
|
# influence: bpy.props.FloatProperty(name = "Influence Slider for the Temp Ctrls", description = "Switching the influence slider for the temp ctrls", default = 1, min = 0.0, max = 1.0)
|
|
|
|
#Used for Bake to Empties
|
|
# org_id: bpy.props.IntProperty(name = "Originate ID", description = "ID number of the bone the ctrl originates from", override = {'LIBRARY_OVERRIDABLE'})
|
|
setup_id: bpy.props.IntProperty(name = "Setup ID", description = "ID number of the current chain setup", override = {'LIBRARY_OVERRIDABLE'})
|
|
root: bpy.props.BoolProperty(name = "Root Empty", description = "Empty is marked as the root ctrl", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
child: bpy.props.BoolProperty(name = "Child Empty", description = "Empty is marked as a child bone inside the setup", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
keyframes_offset: bpy.props.FloatProperty(name = "Keyframes Offset", description = "Interactive slider to offset keyframes back and forth ", default = 0)
|
|
|
|
class IsolatedRigs(bpy.types.PropertyGroup):
|
|
|
|
hidden: bpy.props.PointerProperty(name = "Hidden Rigs", description = "List of Rigs that are hidden during pose mode isolation", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
selected: bpy.props.PointerProperty(name = "Selected Rigs", description = "List of Rigs that are hidden during pose mode isolation", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
class AnimToolBoxUILayout(bpy.types.PropertyGroup):
|
|
'''Layout properties for the UI'''
|
|
quick_menu: bpy.props.BoolProperty(name = "Use Quick Menu", description = "Opens header menu with only icon", default = False)
|
|
copy_paste_matrix: bpy.props.BoolProperty(name = "Copy Matrix Menu", description = "Opens the menu for copy paste matrices", default = True)
|
|
copy_paste_world: bpy.props.BoolProperty(name = "Copy Paste World Matrix", description = "Copy and Paste the World Matrix", default = False, update = Tools.copy_paste_world_update)
|
|
copy_paste_relative: bpy.props.BoolProperty(name = "Copy Paste Relative Matrix", description = "Copy and Paste the Matrix relative to the active bone", default = False, update = Tools.copy_paste_relative_update)
|
|
Inbetweens: bpy.props.BoolProperty(name = "Blendings/Inbetweens", description = "Opens the menu for Inbetweens", default = True)
|
|
gizmo_size: bpy.props.BoolProperty(name = "Gizmo size", description = "Change the Gizmo size using alt +/- hotkeys", default = False)
|
|
# temp_ctrls: bpy.props.BoolProperty(name = "Temp Ctrls", description = "Open Temp Ctrls", default = False)
|
|
temp_ctrls_switch: bpy.props.BoolProperty(name = "Temp Ctrls Switch", description = "Temp Ctrls Switch", default = True)
|
|
temp_ctrls_shapes: bpy.props.BoolProperty(name = "Temp Ctrls Shapes", description = "Temp Ctrls Shapes", default = True)
|
|
|
|
markers_retimer: bpy.props.BoolProperty(name = "Marker Retimer", description = "Flag when marker retimer turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
relative_cursor: bpy.props.BoolProperty(name = "Relative Cursor Mode", description = "Cursor moves relative to the selection", default = False)
|
|
|
|
is_dragging: bpy.props.BoolProperty(default = False)
|
|
#using Blending sliders in the window manager to avoid undo issues with modal operators
|
|
inbetween_worldmatrix: bpy.props.FloatProperty(name='Inbetween World Matrix', description="Adds an inbetween of the World Matrix to the Layer's neighbor keyframes", soft_min = -1, soft_max = 1, default=0.0, update = Tools.add_inbetween_worldmatrix, override = {'LIBRARY_OVERRIDABLE'})
|
|
blend_mirror: bpy.props.FloatProperty(name='Blend Mirror', description="Blend into the mirrored pose", soft_min = 0, soft_max = 1, default=0, step = 1, update = Tools.blend_to_mirror, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
multikey: bpy.props.PointerProperty(type = MultikeyProperties, options={'LIBRARY_EDITABLE'}, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
class AnimToolBoxGlobalSettings(bpy.types.PropertyGroup):
|
|
#context.scene.animtoolbox
|
|
marker_frame_range: bpy.props.BoolProperty(name = "Marker Frame Range", description = "Flag when marker frame range turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
bake_frame_range: bpy.props.BoolProperty(name = "Bake Frame Range", description = "Flag when marker bake range turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
# markers_retimer: bpy.props.BoolProperty(name = "Marker Retimer", description = "Flag when marker retimer turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
keyframes_offset: bpy.props.FloatProperty(name = "Keyframes Offset", description = "Interactive slider to offset keyframes back and forth ", soft_max = 2, soft_min = -2, default = 0, update = Tools.keyframes_offset_slider)
|
|
rotation_mode: bpy.props.EnumProperty(name = 'Rotation Mode', description="Describes what kind of setup the bone is part of", override = {'LIBRARY_OVERRIDABLE'},
|
|
items = [('QUATERNION', 'Quaternion','Quaternion Rotation Order - No Gimbal Lock', 0),
|
|
('XYZ', 'XYZ', 'XYZ Rotation Order', 1), ('XZY', 'XZY','XZY Rotation Order', 2),
|
|
('YXZ', 'YXZ','YXZ Rotation Order', 3), ('YZX', 'YZX', 'YZX Rotation Order', 4),
|
|
('ZXY', 'ZXY', 'ZXY Rotation Order', 5), ('ZYX', 'ZYX', 'ZYX Rotation Order', 6),
|
|
('AXIS_ANGLE', 'AXIS_ANGLE', 'Axis Angle Rotation Order', 7)])
|
|
|
|
isolate_pose_mode: bpy.props.BoolProperty(name = "Isolate rig in pose mode", description = "Isolates the rig during pose mode, rigs in object mode are hidden", default = False)
|
|
active_obj: bpy.props.PointerProperty(name = "Active Object", description = "Current Active Object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
|
isolated: bpy.props.CollectionProperty(type = IsolatedRigs, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
|
|
|
#Blendings
|
|
inbetweener : bpy.props.FloatProperty(name='Inbetween Keyframe', description="Adds an inbetween Keyframe between the Layer's neighbor keyframes", soft_min = -1, soft_max = 1, default=0.0, options = set(), update = Tools.add_inbetween_key, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
motion_path: bpy.props.BoolProperty(name = "Motion Path", description = "Flag when Motion Path is on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_settings: bpy.props.BoolProperty(name = "Motion Path Settings", description = "Open the settings Menu", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_keyframe_scale: bpy.props.FloatProperty(name = "Scale Selecgted Keyframes Bounding Box", description = "Change the scale of the bounding box around the selected keyframes ", default = 0.1, step = 0.1, precision = 3)
|
|
mp_color_before: bpy.props.FloatVectorProperty(name="Motion Path Before Color", subtype='COLOR', default=(1.0, 0.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame")
|
|
mp_color_after: bpy.props.FloatVectorProperty(name="Motion Path After Color", subtype='COLOR', default=(0.0, 1.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame")
|
|
mp_infront: bpy.props.BoolProperty(name = "Motion Path In Front", description = "Display motion path in front of all the objects", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_points: bpy.props.BoolProperty(name = "Motion Path Points", description = "Display motion path points", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_lines: bpy.props.BoolProperty(name = "Motion Path Lines", description = "Display motion path lines", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_handles: bpy.props.BoolProperty(name = "Motion Path Handles", description = "Display motion path handles on keyframe selection", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_display_frames: bpy.props.BoolProperty(name = "Frame Numbers", description = "Display frame numbers on all the keyframes", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
|
mp_handle_types: bpy.props.EnumProperty(name = 'Set Keyframe Handle Type', description="Set handle type for selected keyframes", default = 'AUTO', update = emp.update_handle_type_prop,
|
|
items = [('FREE', 'Free', 'Free', 'HANDLE_FREE', 0),
|
|
('ALIGNED','Aligned', 'Aligned', 'HANDLE_ALIGNED', 1),
|
|
('VECTOR', 'Vector', 'Vector', 'HANDLE_VECTOR', 2),
|
|
('AUTO','Automatic', 'Automatic', 'HANDLE_AUTO', 3),
|
|
('AUTO_CLAMPED','Auto Clamped', 'Auto Clamped', 'HANDLE_AUTOCLAMPED', 4)])
|
|
|
|
mp_interpolation: bpy.props.EnumProperty(name = 'Set Interpolation', description="Set Keyframe Interpolation", default = 'BEZIER', update = emp.update_interpolation_prop,
|
|
items = [('BEZIER', 'Bezier', 'Bezier', 'IPO_BEZIER', 0),
|
|
('LINEAR','Linear', 'Linear', 'IPO_LINEAR', 1),
|
|
('CONSTANT', 'Constant', 'Constant', 'IPO_CONSTANT', 2)])
|
|
|
|
mp_frame_range: bpy.props.EnumProperty(name = 'Frame Range', description="Type of Frame Range", default = 'SCENE', #update = emp.mp_frame_range_update,
|
|
items = [('KEYS_ALL', 'All_Keys','Use the Scene Frame Length for the Range', 0),
|
|
('SCENE', 'Scene','Use the Scene Frame Length for the Range', 1),
|
|
('MANUAL', 'Manual','Custom Frame range using numerical input or the markers frame ranger', 2),
|
|
('AROUND', 'Around Frames','Show only around the current frame', 3)])
|
|
mp_before: bpy.props.IntProperty(name = "Before", description = "Show the frames Before the current frame", min = 0, default = 10)
|
|
mp_after: bpy.props.IntProperty(name = "After", description = "Show the frames After the current frame", min = 0, default = 10)
|
|
selected_keyframes: bpy.props.StringProperty(name="Selected Keyframes", description="Serialized representation of selected keyframes")
|
|
|
|
gizmo_size: bpy.props.IntProperty(name = "Add to Gizmo Size", description = "Addition to Gizmo Size", max = 100, min = -100, default = 10)
|
|
|
|
#Copy/Pase Matrix
|
|
range_type: bpy.props.EnumProperty(name = 'Paste to Frames', description="Paste to current frame or a range of frames.", update = Tools.bake_range_type,
|
|
items = [('CURRENT', 'Current Frame','Paste Matrix to only current frame', 0),
|
|
('SELECTED', 'Selected Keyframe','Paste Matrix to only selected keyframes', 1),
|
|
('RANGE', 'Frame Range','Paste Matrix to a Frame Range', 2)])
|
|
bake_frame_start: bpy.props.IntProperty(name = "Bake Frame Start", description = "Define the start frame to paste the matrix", min = 0, update = Tools.bake_frame_start_limit)
|
|
bake_frame_end: bpy.props.IntProperty(name = "Bake Frame End", description = "Define the end frame to paste the matrix", min = 0, update = Tools.bake_frame_end_limit)
|
|
|
|
filter_location: bpy.props.BoolVectorProperty(name="Location", description="Filter Location properties", default=(False, False, False), size = 3, options={'HIDDEN'}, update = Tools.filter_name_update)
|
|
filter_rotation: bpy.props.BoolVectorProperty(name="Rotation", description="Filter Rotation properties", default=(False, False, False, False), size = 4, options={'HIDDEN'}, update = Tools.filter_name_update)
|
|
filter_scale: bpy.props.BoolVectorProperty(name="Scale", description="Filter Scale properties", default=(False, False, False), size = 3, options={'HIDDEN'}, update = Tools.filter_name_update)
|
|
#The name displayed on the filter button
|
|
filter_name: bpy.props.StringProperty(name="Filter Name", description="Change the name of the button while chaging the filter options", default= "", options={'HIDDEN'})
|
|
filter_custom_props: bpy.props.BoolProperty(name = "Filter Custom Properties", description = "Filter custom properties", default = False)
|
|
filter_keyframes: bpy.props.BoolProperty(name = "Filter Aelected Keyframes", description = "Filter selected keyframes for specific tools", default = False)
|
|
|
|
col_vis: bpy.props.BoolProperty(name = "Animated collections visibility", description = "Display if animated collections are turned on or off", default = False)
|
|
|
|
@addon_updater_ops.make_annotations
|
|
class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
|
# this must match the addon name, use '__package__'
|
|
# when defining this in a submodule of a python package.
|
|
bl_idname = __package__
|
|
|
|
category: bpy.props.StringProperty(
|
|
name="Tab Category",
|
|
description="Choose a name for the category of the panel",
|
|
default="Animation",
|
|
update=ui.update_panel
|
|
)
|
|
|
|
quick_menu: bpy.props.BoolProperty(name = "Use Quick Menu", description = "Opens header menu with only icon", default = False)
|
|
riggertoolbox: bpy.props.BoolProperty(name = "RiggerToolBox", description = "Include RiggerToolbox (experimental)", default = False, update = ui.add_riggertoolbox)
|
|
multikey: bpy.props.BoolProperty(name = "Multikey", description = "Include Multikey for adju\sting multiply keyframes", default = False, update = ui.add_multikey)
|
|
|
|
#Temp Ctrls properties
|
|
in_front: bpy.props.BoolProperty(name = "Always In Front", description = "Set Temp Ctrls to be always in front", default = True)
|
|
clear_setup : bpy.props.BoolProperty(name = "Clear Selection Before Creating New Temp Ctrls", description = "Clear old setup when adding Temp ctrls to an existing chain", default = False)
|
|
|
|
#Editable motion path
|
|
keyframes_range: bpy.props.IntProperty(name = "Keyframe Range", description = "The range of distance from the keyframes while hovering over them", min = 5, max = 100, default = 15)
|
|
|
|
# addon updater preferences from `__init__`, be sure to copy all of them
|
|
auto_check_update: bpy.props.BoolProperty(
|
|
name = "Auto-check for Update",
|
|
description = "If enabled, auto-check for updates using an interval",
|
|
default = True,
|
|
)
|
|
|
|
updater_interval_months: bpy.props.IntProperty(
|
|
name='Months',
|
|
description = "Number of months between checking for updates",
|
|
default=0,
|
|
min=0
|
|
)
|
|
updater_interval_days: bpy.props.IntProperty(
|
|
name='Days',
|
|
description = "Number of days between checking for updates",
|
|
default=7,
|
|
min=0,
|
|
|
|
)
|
|
updater_interval_hours: bpy.props.IntProperty(
|
|
name='Hours',
|
|
description = "Number of hours between checking for updates",
|
|
default=0,
|
|
min=0,
|
|
max=23
|
|
)
|
|
updater_interval_minutes: bpy.props.IntProperty(
|
|
name='Minutes',
|
|
description = "Number of minutes between checking for updates",
|
|
default=0,
|
|
min=0,
|
|
max=59
|
|
)
|
|
|
|
#Draw the UI in the preferences
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
addon_updater_ops.update_settings_ui(self, context)
|
|
|
|
row = layout.row()
|
|
col = row.column()
|
|
|
|
col.label(text="Tab Category:")
|
|
col.prop(self, "category", text="")
|
|
|
|
layout.separator()
|
|
col = layout.column()
|
|
col.prop(self, "quick_menu", text="Use Quick Icons Menu")
|
|
|
|
layout.separator()
|
|
box = layout.box()
|
|
row = box.row()
|
|
row.label(text = 'Temp Ctrls: ')
|
|
row = box.row()
|
|
row.prop(self, 'clear_setup')
|
|
row.prop(self, 'in_front')
|
|
|
|
layout.separator()
|
|
col = layout.column()
|
|
col.label(text = 'Include Extras: ')
|
|
row = layout.row()
|
|
row.prop(self, "multikey", text="Multikey - Edit Multiply keyframes")
|
|
row.prop(self, "riggertoolbox", text="RiggerToolBox (Experimental)")
|
|
|
|
@persistent
|
|
def loadanimtoolbox_pre(self, context):
|
|
scene = bpy.context.scene
|
|
dns = bpy.app.driver_namespace
|
|
if scene.animtoolbox.bake_frame_range:
|
|
scene.animtoolbox.bake_frame_range = False
|
|
|
|
if scene.animtoolbox.motion_path:
|
|
scene.animtoolbox.motion_path = False
|
|
if 'mp_dh' in dns:
|
|
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
|
bpy.app.driver_namespace.pop('mp_dh')
|
|
|
|
if 'markers_retimer_dh' in dns:
|
|
bpy.types.SpaceView3D.draw_handler_remove(dns['markers_retimer_dh'], 'WINDOW')
|
|
bpy.app.driver_namespace.pop('markers_retimer_dh')
|
|
|
|
#remove the motion path app handler if it's still inside
|
|
if emp.mp_value_update in bpy.app.handlers.depsgraph_update_post:
|
|
bpy.app.handlers.depsgraph_update_post.remove(emp.mp_value_update)
|
|
if emp.mp_frame_change in bpy.app.handlers.frame_change_post:
|
|
bpy.app.handlers.frame_change_post.remove(emp.mp_frame_change)
|
|
if emp.mp_undo_update in bpy.app.handlers.undo_pre:
|
|
bpy.app.handlers.undo_pre.remove(emp.mp_undo_update)
|
|
|
|
@persistent
|
|
def loadanimtoolbox_post(self, context):
|
|
scene = bpy.context.scene
|
|
dns = bpy.app.driver_namespace
|
|
if scene.animtoolbox.isolate_pose_mode:
|
|
if Display.isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre:
|
|
bpy.app.handlers.depsgraph_update_pre.append(Display.isolate_pose_mode)
|
|
|
|
if scene.animtoolbox.motion_path:
|
|
scene.animtoolbox.motion_path = False
|
|
if 'mp_dh' in dns:
|
|
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
|
bpy.app.driver_namespace.pop('mp_dh')
|
|
|
|
Tools.selection_order(self, context)
|
|
|
|
classes = (TempCtrlsItems, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties, IsolatedRigs,
|
|
AnimToolBoxObjectSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
|
|
|
|
addon_keymaps = []
|
|
|
|
def register():
|
|
# Note that preview collections returned by bpy.utils.previews
|
|
# are regular py objects - you can use them to store custom data.
|
|
|
|
addon_updater_ops.register(bl_info)
|
|
register_class(AnimToolBoxPreferences)
|
|
addon_updater_ops.make_annotations(AnimToolBoxPreferences) # to avoid blender 2.8 warnings
|
|
TempCtrls.register()
|
|
Tools.register()
|
|
Display.register()
|
|
emp.register()
|
|
|
|
ui.register_custom_icon()
|
|
|
|
for cls in classes:
|
|
# print(cls)
|
|
register_class(cls)
|
|
|
|
bpy.types.Scene.btc = bpy.props.PointerProperty(type = TempCtrlsSceneSettings, override = {'LIBRARY_OVERRIDABLE'})
|
|
bpy.types.PoseBone.btc = bpy.props.PointerProperty(type = TempCtrlsBoneSettings, override = {'LIBRARY_OVERRIDABLE'})
|
|
bpy.types.Object.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxObjectSettings, override = {'LIBRARY_OVERRIDABLE'})
|
|
bpy.types.Scene.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxGlobalSettings, override = {'LIBRARY_OVERRIDABLE'})
|
|
bpy.types.WindowManager.atb_ui = bpy.props.PointerProperty(type = AnimToolBoxUILayout, override = {'LIBRARY_OVERRIDABLE'})
|
|
|
|
ui.update_panel(None, bpy.context)
|
|
ui.add_multikey(None, bpy.context)
|
|
ui.add_riggertoolbox(None, bpy.context)
|
|
|
|
if loadanimtoolbox_pre not in bpy.app.handlers.load_pre:
|
|
bpy.app.handlers.load_pre.append(loadanimtoolbox_pre)
|
|
if loadanimtoolbox_post not in bpy.app.handlers.load_post:
|
|
bpy.app.handlers.load_post.append(loadanimtoolbox_post)
|
|
|
|
if Tools.selection_order not in bpy.app.handlers.depsgraph_update_post:
|
|
bpy.app.handlers.depsgraph_update_post.append(Tools.selection_order)
|
|
|
|
#Make sure TAB hotkey in the NLA goes into full stack mode
|
|
wm = bpy.context.window_manager
|
|
kc = wm.keyconfigs.addon
|
|
km = kc.keymaps.new(name= '3D View', space_type= 'VIEW_3D')
|
|
if 'view3d.gizmo_size_up' not in km.keymap_items:
|
|
kmi = km.keymap_items.new('view3d.gizmo_size_up', type= 'NUMPAD_PLUS', value= 'PRESS', alt = True, repeat = True)
|
|
addon_keymaps.append((km, kmi))
|
|
if 'view3d.gizmo_size_down' not in km.keymap_items:
|
|
kmi = km.keymap_items.new('view3d.gizmo_size_down', type= 'NUMPAD_MINUS', value= 'PRESS', alt = True, repeat = True)
|
|
addon_keymaps.append((km, kmi))
|
|
|
|
#Add Tools to the Toolbar
|
|
bpy.utils.register_tool(ui.KeyframeOffsetTool, separator=True)
|
|
|
|
#Add tools to the menu
|
|
bpy.types.VIEW3D_MT_editor_menus.append(ui.draw_menu)
|
|
|
|
def unregister():
|
|
for pcoll in ui.preview_collections.values():
|
|
bpy.utils.previews.remove(pcoll)
|
|
ui.preview_collections.clear()
|
|
|
|
#addon_updater_ops.unregister()
|
|
addon_updater_ops.unregister()
|
|
unregister_class(AnimToolBoxPreferences)
|
|
|
|
TempCtrls.unregister()
|
|
# Rigger_Toolbox.unregister()
|
|
Tools.unregister()
|
|
Display.unregister()
|
|
emp.unregister()
|
|
|
|
ui.add_multikey(None, bpy.context)
|
|
ui.add_riggertoolbox(None, bpy.context)
|
|
|
|
for cls in classes:
|
|
unregister_class(cls)
|
|
|
|
bpy.utils.unregister_tool(ui.KeyframeOffsetTool)
|
|
|
|
#Remove the header menu ui
|
|
bpy.types.VIEW3D_MT_editor_menus.remove(ui.draw_menu)
|
|
|
|
del bpy.types.Scene.btc
|
|
# del bpy.types.Bone.btc
|
|
del bpy.types.Object.animtoolbox
|
|
del bpy.types.Scene.animtoolbox
|
|
if hasattr(bpy.types.Object, 'keyframes_offset'):
|
|
del bpy.types.Object.keyframes_offset
|
|
if hasattr(bpy.types.PoseBone, 'keyframes_offset'):
|
|
del bpy.types.PoseBone.keyframes_offset
|
|
|
|
if loadanimtoolbox_pre in bpy.app.handlers.load_pre:
|
|
bpy.app.handlers.load_pre.remove(loadanimtoolbox_pre)
|
|
if loadanimtoolbox_post in bpy.app.handlers.load_post:
|
|
bpy.app.handlers.load_post.remove(loadanimtoolbox_post)
|
|
if Tools.selection_order in bpy.app.handlers.depsgraph_update_post:
|
|
bpy.app.handlers.depsgraph_update_post.remove(Tools.selection_order)
|
|
|
|
for km, kmi in addon_keymaps:
|
|
km.keymap_items.remove(kmi)
|
|
addon_keymaps.clear()
|
|
|
|
if __name__ == "__main__":
|
|
register() |