294 lines
8.0 KiB
Python
294 lines
8.0 KiB
Python
|
|
import sys
|
|
import bpy
|
|
from pathlib import Path
|
|
import os
|
|
from bone_widget.shape_utils import get_bone
|
|
|
|
|
|
class BW_context:
|
|
def __init__(self):
|
|
|
|
self.module_dir = Path(__file__).parent
|
|
self.module_name = self.module_dir.name
|
|
self.id_name = 'bonewidget'
|
|
|
|
self._rig = None
|
|
self._folder_items = []
|
|
self.shapes = {} # used to store vert co for the transform properties
|
|
|
|
@property
|
|
def addon(self):
|
|
from bpy import context
|
|
return context.preferences.addons[__package__]
|
|
|
|
@property
|
|
def prefs(self):
|
|
return self.addon.preferences
|
|
|
|
#def settings(self):
|
|
# return bpy.context.window_manager.
|
|
@property
|
|
def show_transforms(self):
|
|
ops = bpy.context.window_manager.operators
|
|
id_names = [self.get_op_id(o) for o in ('transform_widget','create_widget', 'match_transform')]
|
|
return (ops and ops[-1].bl_idname in id_names)
|
|
|
|
@property
|
|
def clean_widget_op(self):
|
|
ops = bpy.context.window_manager.operators
|
|
op_idname = self.get_op_id('clean_widget')
|
|
|
|
#transforms = self.prefs.transforms
|
|
if ops and ops[-1].bl_idname == op_idname:
|
|
return ops[-1]
|
|
|
|
# @property
|
|
# def show_prefs_op(self):
|
|
# ops = bpy.context.window_manager.operators
|
|
# id_names = [
|
|
# self.get_op_id('show_preferences'),
|
|
# self.get_op_id('add_folder'),
|
|
# self.get_op_id('remove_folder')
|
|
# ]
|
|
|
|
# #transforms = self.prefs.transforms
|
|
# if ops and ops[-1].bl_idname in id_names:
|
|
# return True
|
|
|
|
@property
|
|
def category(self):
|
|
if not self.prefs:
|
|
return 'Rig'
|
|
|
|
return self.prefs.category
|
|
|
|
@property
|
|
def rig(self):
|
|
bone = self.bone
|
|
if bone:
|
|
return bone.id_data
|
|
|
|
@property
|
|
def widget_col(self):
|
|
col_name = self.prefs.collection
|
|
|
|
col_name = col_name.format(ob=bpy.context.object)
|
|
|
|
col = bpy.data.collections.get(col_name)
|
|
if not col:
|
|
col = bpy.data.collections.new(col_name)
|
|
col.hide_viewport = True
|
|
|
|
if col not in self.get_scene_cols():
|
|
bpy.context.scene.collection.children.link(col)
|
|
|
|
return col
|
|
|
|
@property
|
|
def widget_layer_col(self):
|
|
return next((c for c in self.get_layer_cols() if c.collection == self.widget_col), None)
|
|
|
|
@property
|
|
def default_folder_path(self):
|
|
return self.prefs.default_folder.abspath
|
|
|
|
@property
|
|
def custom_folder_paths(self):
|
|
return [f.abspath for f in self.prefs.folders if f.path]
|
|
|
|
@property
|
|
def folder_paths(self):
|
|
return [self.default_folder_path] + self.custom_folder_paths
|
|
|
|
@property
|
|
def folders(self):
|
|
return list(self.prefs.folders) + [self.prefs.default_folder]
|
|
|
|
@property
|
|
def active_folder(self):
|
|
folder = self.abspath(self.prefs.folder_enum)
|
|
if folder == self.default_folder_path:
|
|
return self.prefs.default_folder
|
|
else:
|
|
return next((f for f in self.prefs.folders if f.abspath==folder), None)
|
|
|
|
@property
|
|
def active_widget(self):
|
|
folder = self.active_folder
|
|
if not folder:
|
|
return
|
|
|
|
index = folder.widget_index
|
|
return folder.active_widget
|
|
|
|
@property
|
|
def bone(self):
|
|
if not self.poll():
|
|
return
|
|
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
return bpy.context.active_pose_bone
|
|
else:
|
|
return get_bone(ob)
|
|
|
|
|
|
|
|
@property
|
|
def bones(self):
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
return list(ob.pose.bones)
|
|
else:
|
|
widgets = self.widgets
|
|
return [b for b in self.rig.pose.bones if b.custom_shape in widgets]
|
|
|
|
@property
|
|
def selected_bones(self):
|
|
if not self.poll():
|
|
return []
|
|
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
return bpy.context.selected_pose_bones
|
|
#bones = ob.pose.bones
|
|
#return [b for b in bones if b.bone.select]
|
|
elif self.rig:
|
|
widgets = self.selected_widgets
|
|
return [b for b in self.rig.pose.bones if b.custom_shape in widgets]
|
|
|
|
return []
|
|
|
|
@property
|
|
def widget(self):
|
|
if not self.poll():
|
|
return
|
|
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
if bpy.context.active_pose_bone:
|
|
return bpy.context.active_pose_bone.custom_shape
|
|
else:
|
|
return ob
|
|
|
|
@property
|
|
def widgets(self):
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
return [b.custom_shape for b in self.bones if b.custom_shape]
|
|
|
|
@property
|
|
def selected_widgets(self):
|
|
if not self.poll():
|
|
return []
|
|
|
|
ob = bpy.context.object
|
|
if ob.type == 'ARMATURE':
|
|
bones = self.selected_bones
|
|
return [b.custom_shape for b in bones if b.custom_shape]
|
|
else:
|
|
objects = bpy.context.selected_objects
|
|
return [o for o in objects if o.select_get() and o.type in ('MESH', 'CURVE')]
|
|
|
|
@property
|
|
def folder_items(self):
|
|
for folder in self.folder_paths:
|
|
if not any(self.abspath(f[0])==folder for f in self._folder_items):
|
|
id = 0
|
|
if self._folder_items:
|
|
id = max([i[-1] for i in self._folder_items])+1
|
|
|
|
self._folder_items.append((str(folder), bpy.path.display_name(folder.name), '', '', id))
|
|
|
|
for f in reversed(self._folder_items):
|
|
if self.abspath(f[0]) not in self.folder_paths:
|
|
self._folder_items.remove(f)
|
|
|
|
return self._folder_items
|
|
|
|
|
|
def get_flipped_bone(self, bone):
|
|
pass
|
|
|
|
#def get_bone(self, shape):
|
|
# armatures = [o for o in bpy.context.scene.objects if o.type == 'ARMATURE']
|
|
# return next((b for a in armatures for b in a.pose.bones if b.custom_shape == shape), None)
|
|
|
|
def get_scene_cols(self, col=None, children=None):
|
|
if children is None:
|
|
children = set()
|
|
if col is None:
|
|
col = bpy.context.scene.collection
|
|
|
|
for c in col.children:
|
|
children.add(c)
|
|
self.get_scene_cols(c, children)
|
|
|
|
return list(children)
|
|
|
|
def get_layer_cols(self, col=None, children=None):
|
|
if children is None:
|
|
children = set()
|
|
if col is None:
|
|
col = bpy.context.view_layer.layer_collection
|
|
|
|
for c in col.children:
|
|
children.add(c)
|
|
self.get_layer_cols(c, children)
|
|
|
|
return list(children)
|
|
|
|
def abspath(self, path):
|
|
if not path:
|
|
return
|
|
|
|
if path.startswith('//'):
|
|
path = './' + path[2:]
|
|
elif path.startswith('./') or not '/' in str(path):
|
|
path = self.module_dir/'widgets' / path
|
|
|
|
return Path(path).absolute().resolve()
|
|
|
|
def poll(self):
|
|
ob = bpy.context.object
|
|
if not ob:
|
|
return False
|
|
if ob.type == 'ARMATURE' and ob.mode == 'POSE':
|
|
return True
|
|
if ob.type in ('MESH', 'CURVE'):
|
|
return True
|
|
return False
|
|
|
|
def store_shapes(self):
|
|
self.shapes.clear()
|
|
for widget in self.selected_widgets:
|
|
coords = [0]*len(widget.data.vertices)*3
|
|
widget.data.vertices.foreach_get('co', coords)
|
|
self.shapes[widget] = coords
|
|
|
|
def reset_transforms(self):
|
|
transforms = self.prefs.transforms
|
|
|
|
transforms['size'] = 1
|
|
transforms['xz_scale'] = 1
|
|
transforms['slide'] = 0
|
|
transforms['loc'] = (0, 0, 0)
|
|
transforms['rot'] = (0, 0, 0)
|
|
transforms['scale'] = (1, 1, 1)
|
|
|
|
def init_transforms(self):
|
|
self.store_shapes()
|
|
self.reset_transforms()
|
|
|
|
def get_op_id(self, name):
|
|
return f'{self.id_name.upper()}_OT_{name}'
|
|
|
|
#def call(self, op):
|
|
# ops_data = getattr(bpy.ops, ctx.id_name)
|
|
# getattr(ops_data, op)()
|
|
|
|
|
|
|
|
|