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 )