bone_widget/properties.py

272 lines
8.3 KiB
Python
Raw Normal View History

2022-10-28 23:23:06 +02:00
import bpy
import shutil
from pathlib import Path
import os
import bpy.utils.previews
from bpy.types import PropertyGroup, AddonPreferences
from bpy.props import StringProperty, BoolProperty, CollectionProperty, \
FloatProperty, IntProperty, PointerProperty, EnumProperty, FloatVectorProperty
from bone_widget import ctx
from .ui import update_tab, draw_prefs
from .transform_utils import transform_mesh
from .shape_utils import symmetrize_bone_shape, get_flipped_bone
def undo_redo(self, context):
wm = context.window_manager
op_names = ('transform_widget','create_widget', 'match_transform', 'clean_widget')
2023-01-18 16:02:42 +01:00
op_ids = [ctx.get_op_id(o) for o in op_names]
2022-10-28 23:23:06 +02:00
if (ops and ops[-1].bl_idname in op_ids):
bpy.ops.wm.undo()
bpy.ops.wm.redo()
def transform_widgets(self, context):
#bones = []
shapes = ctx.shapes
for shape, coords in shapes.items():
#bones.append(ctx.get_bone(shape))
#print(shape)
transform_mesh(shape.data, self.loc, self.rot, self.scale,
self.xz_scale, self.size, self.slide, coords=coords)
2023-01-24 22:54:40 +01:00
if ctx.prefs.auto_symmetrize:
2022-10-28 23:23:06 +02:00
for bone in ctx.selected_bones:
flipped_bone = get_flipped_bone(bone)
if flipped_bone and flipped_bone.custom_shape in shapes:
continue
symmetrize_bone_shape(bone, prefix=ctx.prefs.prefix)
class BW_PG_transforms(PropertyGroup):
2023-01-18 16:02:42 +01:00
size: FloatProperty(name='Size', default=1.0, min=0, update=transform_widgets)
xz_scale: FloatProperty(name='XZ Scale', default=1.0, min=0, update=transform_widgets)
slide: FloatProperty(name='Slide', default=0.0, update=transform_widgets)
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
loc: FloatVectorProperty(name='Location', default=(0.0, 0.0, 0.0),
2022-10-28 23:23:06 +02:00
subtype='TRANSLATION', update=transform_widgets)
2023-01-18 16:02:42 +01:00
rot: FloatVectorProperty(name = 'Rotation', default=(0.0, 0.0, 0.0),
2022-10-28 23:23:06 +02:00
subtype='EULER', step=100, precision=0, update=transform_widgets)
2023-01-18 16:02:42 +01:00
scale: FloatVectorProperty(name='Scale', default=(1.0, 1.0, 1.0),
2022-10-28 23:23:06 +02:00
subtype='XYZ', update=transform_widgets)
def rename_widget(self, context):
ctx.active_folder.rename_widget(self, self.name)
class BW_PG_widget(PropertyGroup):
2023-01-18 16:02:42 +01:00
name: StringProperty(update=rename_widget)
source_bone: StringProperty()
#path: StringProperty(subtype='FILE_PATH')
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
def refresh(self, context):
bpy.ops.bonewidget.refresh_folders()
2022-10-28 23:23:06 +02:00
class BW_PG_folder(PropertyGroup):
2023-02-06 15:10:00 +01:00
#icons = bpy.utils.previews.new()
2023-01-18 16:02:42 +01:00
path: StringProperty(subtype='FILE_PATH', default='Default', update=refresh)
expand: BoolProperty()
widgets: CollectionProperty(type=BW_PG_widget)
widget_index: IntProperty()
2022-10-28 23:23:06 +02:00
2023-02-06 15:10:00 +01:00
@property
def icons(self):
prefs = ctx.prefs
return prefs.get_folder_previews(self.as_pointer())
2022-10-28 23:23:06 +02:00
@property
def abspath(self):
return ctx.abspath(self.path)
@property
def name(self):
return Path(self.path).name
def load_icon(self, widget):
2023-01-18 16:02:42 +01:00
icon_name = self.get_icon_name(widget)
icon = self.icons.get(icon_name)
2022-10-28 23:23:06 +02:00
if icon:
icon.reload()
2023-01-18 16:02:42 +01:00
else:
2022-10-28 23:23:06 +02:00
icon_path = self.get_icon_path(widget)
2023-01-18 16:02:42 +01:00
self.icons.load(icon_name, str(icon_path), 'IMAGE', True)
def get_icon_name(self, widget):
return f'{Path(self.path).stem}_{widget.name}'
2022-10-28 23:23:06 +02:00
def get_widget_icon(self, widget):
2023-01-18 16:02:42 +01:00
return self.icons.get(self.get_icon_name(widget))
2022-10-28 23:23:06 +02:00
def add_widget(self, name):
name = self.get_widget_display_name(name)
w = self.widgets.get(name)
if w:
self.load_icon(w)
2023-01-18 16:02:42 +01:00
self.active_widget = w
2022-10-28 23:23:06 +02:00
return
w = self.widgets.add()
w.name = name
self.active_widget = w
self.load_icon(w)
return w
def remove_widget(self, widget):
index = self.widgets[:].index(widget)
widget_path = self.get_widget_path(widget)
icon_path = self.get_icon_path(widget)
if widget_path.exists():
os.remove(widget_path)
if icon_path.exists():
os.remove(icon_path)
self.widgets.remove(index)
self.widget_index = min(len(self.widgets)-1, index)
@property
def active_widget(self):
if self.widgets and self.widget_index < len(self.widgets):
return self.widgets[self.widget_index]
@active_widget.setter
def active_widget(self, widget):
self.widget_index = list(self.widgets).index(widget)
def get_widget_clean_name(self, widget):
name = widget if isinstance(widget, str) else widget.name
name = name.split('-', 1)[-1]
return bpy.path.clean_name(name).lower()
def get_widget_display_name(self, widget):
name = widget if isinstance(widget, str) else widget.name
return name.replace('_', ' ').title()
def get_widget_path(self, widget):
name = self.get_widget_clean_name(widget)
return (self.abspath/name).with_suffix('.blend')
def get_icon_path(self, widget):
name = self.get_widget_clean_name(widget)
return (self.abspath/name).with_suffix('.png')
def rename_widget(self, widget, name):
if not widget.get('_name'):
widget['_name'] = name
return
src_blend = self.get_widget_path(widget['_name'])
dst_blend = self.get_widget_path(name)
src_icon = self.get_icon_path(widget['_name'])
dst_icon = self.get_icon_path(name)
widget['_name'] = name
if not src_blend:
return
if not src_blend.exists():
self.remove_widget(widget)
if src_blend != dst_blend:
os.rename(str(src_blend), str(dst_blend))
if src_icon != dst_icon:
os.rename(str(src_icon), str(dst_icon))
self.load_icon(widget)
def load_widgets(self):
self.widgets.clear()
for widget_blend in self.abspath.glob('*.blend'):
self.add_widget(widget_blend.stem)
#class BW_PG_settings(PropertyGroup):
# pass
class BW_PG_bone_color(PropertyGroup):
value: FloatVectorProperty(name='Color', subtype='COLOR', default=[0.0, 0.0, 0.0])
name: StringProperty(name='Name')
class BW_prefs(AddonPreferences):
bl_idname = __package__
2023-02-06 15:10:00 +01:00
previews = {}
2023-01-18 16:02:42 +01:00
default_folder: PointerProperty(type=BW_PG_folder)
folders: CollectionProperty(type=BW_PG_folder)
folder_index: IntProperty()
folder_enum: EnumProperty(name='Folders', items=lambda s,c: ctx.folder_items)
collection: StringProperty(name='Collection', default='Widgets', description='Name of the widget collection use {ob.name} to include the name of the rig')
2023-01-22 00:35:21 +01:00
use_custom_collection: BoolProperty(name='Custom Collection', default=False, description='Allow to pick a collection from the scene')
2023-01-18 16:02:42 +01:00
prefix: StringProperty(name='Prefix', default='WGT-', description='Prefix for the shape object and data name')
category: StringProperty(name='Tab', default='Rigging', update=lambda s,c: update_tab())
2022-10-28 23:23:06 +02:00
2023-01-24 22:54:40 +01:00
auto_symmetrize: BoolProperty(name='Symmetrize', default=True, update=undo_redo)
auto_separate: BoolProperty(default=True, name="Separate", update=undo_redo)
auto_match_transform: BoolProperty(default=True, name="Match Transform", update=undo_redo)
auto_rename: BoolProperty(default=True, name="Rename", update=undo_redo)
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
show_transforms: BoolProperty(default=False)
2023-01-22 00:35:21 +01:00
show_preferences: BoolProperty(default=False)
2023-01-18 16:02:42 +01:00
transforms: PointerProperty(type=BW_PG_transforms)
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
#grid_view: BoolProperty(name='Grid View', default=True)
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
#use_custom_colors: BoolProperty(name='Custom Colors', default=False, update=set_default_colors)
2022-10-28 23:23:06 +02:00
2023-02-06 15:10:00 +01:00
def get_folder_previews(self, adress):
if adress not in self.previews:
self.previews[adress] = bpy.utils.previews.new()
return self.previews[adress]
2022-10-28 23:23:06 +02:00
def draw(self, context):
draw_prefs(self.layout)
classes = (
BW_PG_bone_color,
BW_PG_widget,
BW_PG_transforms,
BW_PG_folder,
BW_prefs
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
2023-01-18 16:02:42 +01:00
2023-01-22 00:35:21 +01:00
bpy.types.Armature.widget_collection = PointerProperty(type=bpy.types.Collection)
2022-10-28 23:23:06 +02:00
#update_folder_items()
def unregister():
#bpy.utils.previews.remove(ctx.prefs.default_folder.icons)
#for f in ctx.folders:
# bpy.utils.previews.remove(f.icons)
2023-01-22 00:35:21 +01:00
del bpy.types.Armature.widget_collection
2022-10-28 23:23:06 +02:00
for cls in classes:
bpy.utils.unregister_class(cls)