2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
import bpy
|
|
|
|
import os
|
|
|
|
from os.path import abspath, join
|
|
|
|
|
|
|
|
from bpy.types import (AddonPreferences, PointerProperty, PropertyGroup)
|
|
|
|
from bpy.props import (BoolProperty, StringProperty, CollectionProperty,
|
|
|
|
EnumProperty, IntProperty)
|
|
|
|
|
|
|
|
from asset_library.constants import (DATA_TYPES, DATA_TYPE_ITEMS,
|
2022-12-25 02:54:50 +01:00
|
|
|
ICONS, RESOURCES_DIR, ADAPTER_DIR, ADAPTERS)
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
from asset_library.common.file_utils import import_module_from_path, norm_str
|
|
|
|
from asset_library.common.bl_utils import get_addon_prefs
|
|
|
|
from asset_library.common.functions import get_catalog_path
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
import importlib
|
|
|
|
import inspect
|
|
|
|
|
|
|
|
|
|
|
|
def update_library_config(self, context):
|
|
|
|
print('update_library_config not yet implemented')
|
|
|
|
|
|
|
|
def update_library_path(self, context):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
self['bundle_directory'] = str(self.library_path)
|
|
|
|
|
|
|
|
if not self.custom_bundle_name:
|
|
|
|
self['custom_bundle_name'] = self.name
|
|
|
|
|
|
|
|
if not self.custom_bundle_directory:
|
|
|
|
custom_bundle_dir = Path(prefs.bundle_directory, self.library_name).resolve()
|
|
|
|
self['custom_bundle_directory'] = str(custom_bundle_dir)
|
|
|
|
|
|
|
|
#if self.custom_bundle_directory:
|
|
|
|
# self['custom_bundle_directory'] = abspath(bpy.path.abspath(self.custom_bundle_directory))
|
|
|
|
#else:
|
|
|
|
# bundle_directory = join(prefs.bundle_directory, norm_str(self.name))
|
|
|
|
# self['custom_bundle_directory'] = abspath(bundle_directory)
|
|
|
|
|
|
|
|
self.set_library_path()
|
|
|
|
|
|
|
|
def update_all_library_path(self, context):
|
|
|
|
#print('update_all_assetlib_paths')
|
|
|
|
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
#if self.custom_bundle_directory:
|
|
|
|
# self['custom_bundle_directory'] = abspath(bpy.path.abspath(self.custom_bundle_directory))
|
|
|
|
|
|
|
|
for lib in prefs.libraries:
|
|
|
|
update_library_path(lib, context)
|
|
|
|
#lib.set_library_path()
|
|
|
|
|
|
|
|
def get_adapter_items(self, context):
|
|
|
|
#prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
items = [('NONE', 'None', '', 0)]
|
|
|
|
items += [(norm_str(a.name, format=str.upper), a.name, "", i+1) for i, a in enumerate(ADAPTERS)]
|
|
|
|
return items
|
|
|
|
|
|
|
|
def get_library_items(self, context):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
items = [('NONE', 'None', '', 0)]
|
|
|
|
items += [(l.name, l.name, "", i+1) for i, l in enumerate(prefs.libraries) if l != self]
|
|
|
|
|
|
|
|
return items
|
|
|
|
|
|
|
|
def get_store_library_items(self, context):
|
2022-12-25 02:54:50 +01:00
|
|
|
#prefs = get_addon_prefs()
|
2022-12-24 15:30:32 +01:00
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
#libraries = [l for l in prefs.libraries if l.merge_library == self.name]
|
2022-12-24 15:30:32 +01:00
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
return [(l.name, l.name, "", i) for i, l in enumerate([self] + self.merge_libraries)]
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
class AssetLibraryAdapters(PropertyGroup):
|
|
|
|
parent = None
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
return (getattr(self, p) for p in self.bl_rna.properties.keys() if p not in ('rna_type', 'name'))
|
|
|
|
|
|
|
|
|
|
|
|
class ConformAssetLibrary(PropertyGroup):
|
|
|
|
adapters : bpy.props.PointerProperty(type=AssetLibraryAdapters)
|
|
|
|
adapter_name : EnumProperty(items=get_adapter_items)
|
|
|
|
directory : StringProperty(
|
|
|
|
name="Destination Directory",
|
|
|
|
subtype='DIR_PATH',
|
|
|
|
default=''
|
|
|
|
)
|
|
|
|
image_template : StringProperty()
|
|
|
|
video_template : StringProperty()
|
|
|
|
|
|
|
|
externalize_data: BoolProperty(default=False, name='Externalize Data')
|
|
|
|
blend_depth: IntProperty(default=1, name='Blend Depth')
|
|
|
|
|
|
|
|
@property
|
|
|
|
def adapter(self):
|
|
|
|
name = norm_str(self.adapter_name)
|
|
|
|
if not hasattr(self.adapters, name):
|
|
|
|
return
|
|
|
|
|
|
|
|
return getattr(self.adapters, name)
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
def to_dict(self):
|
|
|
|
data = {p: getattr(self, p) for p in self.bl_rna.properties.keys() if p !='rna_type'}
|
|
|
|
|
|
|
|
data['adapter'] = self.adapter.to_dict()
|
|
|
|
data['adapter']['name'] = data.pop('adapter_name')
|
|
|
|
|
|
|
|
del data['adapters']
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
class AssetLibrary(PropertyGroup):
|
|
|
|
name : StringProperty(name='Name', default='Action Library', update=update_library_path)
|
|
|
|
id : StringProperty()
|
|
|
|
auto_bundle : BoolProperty(name='Auto Bundle', default=True)
|
|
|
|
expand : BoolProperty(name='Expand', default=False)
|
|
|
|
use : BoolProperty(name='Use', default=True, update=update_library_path)
|
2022-12-25 02:54:50 +01:00
|
|
|
data_type : EnumProperty(name='Type', items=DATA_TYPE_ITEMS, default='COLLECTION')
|
|
|
|
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
bundle_directory : StringProperty(
|
|
|
|
name="Bundle Directory",
|
|
|
|
subtype='DIR_PATH',
|
|
|
|
default=''
|
|
|
|
)
|
|
|
|
|
|
|
|
use_custom_bundle_directory : BoolProperty(default=False, update=update_library_path)
|
|
|
|
custom_bundle_directory : StringProperty(
|
|
|
|
name="Bundle Directory",
|
|
|
|
subtype='DIR_PATH',
|
|
|
|
default='',
|
|
|
|
update=update_library_path
|
|
|
|
)
|
|
|
|
#use_merge : BoolProperty(default=False, update=update_library_path)
|
|
|
|
|
|
|
|
use_custom_bundle_name : BoolProperty(default=False, update=update_library_path)
|
|
|
|
custom_bundle_name : StringProperty(name='Merge Name', update=update_library_path)
|
|
|
|
#merge_library : EnumProperty(name='Merge Library', items=get_library_items, update=update_library_path)
|
|
|
|
#merge_name : StringProperty(name='Merge Name', update=update_library_path)
|
|
|
|
|
|
|
|
#Library when adding an asset to the library if merge with another
|
|
|
|
store_library: EnumProperty(items=get_store_library_items, name="Library")
|
|
|
|
|
|
|
|
template: StringProperty()
|
|
|
|
expand_extra : BoolProperty(name='Expand', default=False)
|
|
|
|
blend_depth : IntProperty(name='Blend Depth', default=0)
|
|
|
|
|
|
|
|
# source_directory : StringProperty(
|
|
|
|
# name="Path",
|
|
|
|
# subtype='DIR_PATH',
|
|
|
|
# default='',
|
|
|
|
# update=update_library_path
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
|
|
#adapter : EnumProperty(items=adapter_ITEMS)
|
|
|
|
adapters : bpy.props.PointerProperty(type=AssetLibraryAdapters)
|
|
|
|
adapter_name : EnumProperty(items=get_adapter_items)
|
|
|
|
|
|
|
|
conform: bpy.props.PointerProperty(type=ConformAssetLibrary)
|
|
|
|
|
|
|
|
# data_file_path : StringProperty(
|
|
|
|
# name="Path",
|
|
|
|
# subtype='FILE_PATH',
|
|
|
|
# default='',
|
|
|
|
# )
|
|
|
|
|
|
|
|
#expand_conform : BoolProperty(name='Expand Conform', default=False)
|
|
|
|
|
|
|
|
#def __init__(self):
|
|
|
|
# self.adapters.parent = self
|
|
|
|
|
|
|
|
@property
|
|
|
|
def merge_libraries(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return [l for l in prefs.libraries if l != self and (l.library_path == self.library_path)]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def data_types(self):
|
|
|
|
return f'{self.data_type.lower()}s'
|
|
|
|
|
|
|
|
@property
|
|
|
|
def adapter(self):
|
|
|
|
name = norm_str(self.adapter_name)
|
|
|
|
if not hasattr(self.adapters, name):
|
|
|
|
return
|
|
|
|
|
|
|
|
return getattr(self.adapters, name)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def library(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
asset_lib_ref = bpy.context.space_data.params.asset_library_ref
|
|
|
|
|
|
|
|
#TODO work also outside asset_library_area
|
|
|
|
if asset_lib_ref not in prefs.libraries:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return prefs.libraries[asset_lib_ref]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def library_path(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
library_name = self.library_name
|
|
|
|
#if not self.use_custom_bundle_name:
|
|
|
|
# library_name = norm_str(library_name)
|
|
|
|
|
|
|
|
if self.use_custom_bundle_directory:
|
|
|
|
return Path(self.custom_bundle_directory, library_name).resolve()
|
|
|
|
else:
|
|
|
|
library_name = norm_str(library_name)
|
|
|
|
return Path(prefs.bundle_directory, library_name).resolve()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def library_name(self):
|
|
|
|
if self.use_custom_bundle_name:
|
|
|
|
return self.custom_bundle_name
|
|
|
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def image_template(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return prefs.image_template
|
|
|
|
|
|
|
|
@property
|
|
|
|
def video_template(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return prefs.video_template
|
|
|
|
|
|
|
|
@property
|
|
|
|
def asset_description_template(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return prefs.asset_description_template
|
|
|
|
|
|
|
|
@property
|
|
|
|
def catalog_path(self):
|
|
|
|
return get_catalog_path(self.library_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def options(self):
|
|
|
|
return {k: getattr(self.adapter, k) for k, v in self.options.bl_rna.properties.keys() if p !='rna_type'}
|
|
|
|
|
|
|
|
def clear_library_path(self):
|
|
|
|
#print('Clear Library Path', self.name)
|
|
|
|
|
|
|
|
prefs = bpy.context.preferences
|
|
|
|
libs = prefs.filepaths.asset_libraries
|
|
|
|
|
|
|
|
#path = self.library_path.as_posix()
|
|
|
|
|
|
|
|
for l in reversed(libs):
|
|
|
|
#lib_path = Path(l.path).resolve().as_posix()
|
|
|
|
|
|
|
|
prev_name = self.get('asset_library') or self.library_name
|
|
|
|
|
|
|
|
#print(l.name, prev_name)
|
|
|
|
|
|
|
|
if (l.name == prev_name):
|
|
|
|
index = list(libs).index(l)
|
|
|
|
try:
|
|
|
|
bpy.ops.preferences.asset_library_remove(index=index)
|
|
|
|
return
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
#print('No library removed')
|
|
|
|
|
|
|
|
def set_dict(self, data, obj=None):
|
|
|
|
""""Recursive method to set all attribute from a dict to this instance"""
|
2022-12-25 02:54:50 +01:00
|
|
|
|
|
|
|
if obj is None:
|
|
|
|
obj = self
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
# Make shure the input dict is not modidied
|
|
|
|
data = data.copy()
|
|
|
|
|
|
|
|
#print(obj)
|
|
|
|
|
|
|
|
for key, value in data.items():
|
|
|
|
if isinstance(value, dict):
|
|
|
|
|
|
|
|
if 'name' in value:
|
|
|
|
setattr(obj, f'{key}_name', value.pop('name'))
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
print('Nested value', getattr(obj, key))
|
2022-12-24 15:30:32 +01:00
|
|
|
self.set_dict(value, obj=getattr(obj, key))
|
|
|
|
|
|
|
|
elif key in obj.bl_rna.properties.keys():
|
|
|
|
if key == 'id':
|
|
|
|
value = str(value)
|
|
|
|
|
|
|
|
elif key == 'custom_bundle_name':
|
|
|
|
if not 'use_custom_bundle_name' in data.values():
|
|
|
|
obj["use_custom_bundle_name"] = True
|
|
|
|
|
|
|
|
elif isinstance(value, str):
|
|
|
|
value = os.path.expandvars(value)
|
|
|
|
value = os.path.expanduser(value)
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
#print('set attr', key, value)
|
|
|
|
setattr(obj, key, value)
|
|
|
|
#obj[key] = value
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
else:
|
|
|
|
print(f'Prop {key} of {obj} not exist')
|
|
|
|
|
|
|
|
self['bundle_directory'] = str(self.library_path)
|
|
|
|
|
|
|
|
if not self.custom_bundle_name:
|
|
|
|
self['custom_bundle_name'] = self.name
|
|
|
|
|
|
|
|
# self.adapter_name = data['adapter']
|
|
|
|
# if not self.adapter:
|
|
|
|
# print(f"No adapter named {data['adapter']}")
|
|
|
|
# return
|
|
|
|
|
|
|
|
|
|
|
|
# for key, value in data.items():
|
|
|
|
# if key == 'options':
|
|
|
|
# for k, v in data['options'].items():
|
|
|
|
# setattr(self.adapter, k, v)
|
|
|
|
# elif key in self.bl_rna.properties.keys():
|
|
|
|
# if key == 'id':
|
|
|
|
# value = str(value)
|
|
|
|
|
|
|
|
# if key == 'custom_bundle_name':
|
|
|
|
# if not 'use_custom_bundle_name' in data.values():
|
|
|
|
# self["use_custom_bundle_name"] = True
|
|
|
|
|
|
|
|
# self[key] = value
|
|
|
|
|
|
|
|
def to_dict(self):
|
|
|
|
data = {p: getattr(self, p) for p in self.bl_rna.properties.keys() if p !='rna_type'}
|
2022-12-25 02:54:50 +01:00
|
|
|
data['adapter'] = self.adapter.to_dict()
|
|
|
|
#data['adapter'] = data.pop('adapter_name')
|
|
|
|
data['adapter']['name'] = data.pop('adapter_name')
|
2022-12-24 15:30:32 +01:00
|
|
|
del data['adapters']
|
2022-12-25 02:54:50 +01:00
|
|
|
|
|
|
|
data['conform'] = self.conform.to_dict()
|
|
|
|
|
2022-12-24 15:30:32 +01:00
|
|
|
return data
|
|
|
|
|
|
|
|
def set_library_path(self):
|
|
|
|
'''Update the Blender Preference Filepaths tab with the addon libraries'''
|
|
|
|
|
|
|
|
prefs = bpy.context.preferences
|
|
|
|
|
|
|
|
name = self.library_name
|
|
|
|
prev_name = self.get('asset_library') or name
|
|
|
|
|
|
|
|
lib = prefs.filepaths.asset_libraries.get(prev_name)
|
|
|
|
lib_path = self.library_path
|
|
|
|
|
|
|
|
#print('name', name)
|
|
|
|
#print('lib', lib)
|
|
|
|
#print('lib_path', lib_path)
|
|
|
|
#print('self.merge_library ', self.merge_library)
|
|
|
|
#print('prev_name', prev_name)
|
|
|
|
#print('\nset_library_path')
|
|
|
|
#print(f'{self.name=}, {prev_name=}, {lib_path=}, {self.use}')
|
|
|
|
|
|
|
|
if not lib_path:
|
|
|
|
self.clear_library_path()
|
|
|
|
return
|
|
|
|
|
|
|
|
if not self.use:
|
|
|
|
if all(not l.use for l in self.merge_libraries):
|
|
|
|
self.clear_library_path()
|
|
|
|
return
|
|
|
|
|
|
|
|
# Create the Asset Library Path
|
|
|
|
if not lib:
|
|
|
|
try:
|
|
|
|
bpy.ops.preferences.asset_library_add(directory=str(lib_path))
|
|
|
|
except AttributeError:
|
|
|
|
return
|
|
|
|
|
|
|
|
lib = prefs.filepaths.asset_libraries[-1]
|
|
|
|
|
|
|
|
lib.name = name
|
|
|
|
|
|
|
|
self['asset_library'] = name
|
|
|
|
lib.path = str(lib_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_user(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return self in prefs.user_libraries.values()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_env(self):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
return self in prefs.env_libraries.values()
|
|
|
|
|
|
|
|
|
|
|
|
def add_row(self, layout, data=None, prop=None, label='',
|
|
|
|
boolean=None, factor=0.39):
|
|
|
|
'''Act like the use_property_split but with much more control'''
|
|
|
|
|
|
|
|
enabled = True
|
|
|
|
split = layout.split(factor=factor, align=True)
|
|
|
|
|
|
|
|
row = split.row(align=False)
|
|
|
|
row.use_property_split = False
|
|
|
|
row.alignment= 'RIGHT'
|
|
|
|
row.label(text=str(label))
|
|
|
|
if boolean:
|
|
|
|
boolean_data = self
|
|
|
|
if isinstance(boolean, (list, tuple)):
|
|
|
|
boolean_data, boolean = boolean
|
|
|
|
|
|
|
|
row.prop(boolean_data, boolean, text='')
|
|
|
|
enabled = getattr(boolean_data, boolean)
|
|
|
|
|
|
|
|
row = split.row(align=True)
|
|
|
|
row.enabled = enabled
|
|
|
|
|
|
|
|
if isinstance(data, str):
|
|
|
|
row.label(text=data)
|
|
|
|
else:
|
|
|
|
row.prop(data or self, prop, text='')
|
|
|
|
|
|
|
|
return split
|
|
|
|
|
|
|
|
|
|
|
|
def draw_operators(self, layout):
|
|
|
|
row = layout.row(align=True)
|
|
|
|
row.alignment = 'RIGHT'
|
|
|
|
row.prop(self, 'adapter_name', text='')
|
|
|
|
row.prop(self, 'auto_bundle', text='', icon='UV_SYNC_SELECT')
|
|
|
|
|
|
|
|
row.operator("assetlib.diff", text='', icon='FILE_REFRESH').name = self.name
|
|
|
|
|
|
|
|
op = row.operator("assetlib.bundle", icon='MOD_BUILD', text='')
|
|
|
|
op.name = self.name
|
|
|
|
|
|
|
|
layout.separator(factor=3)
|
|
|
|
|
|
|
|
def draw_extra(self, layout):
|
|
|
|
#box = layout.box()
|
|
|
|
|
|
|
|
col = layout.column(align=False)
|
|
|
|
|
|
|
|
row = col.row(align=True)
|
|
|
|
row.use_property_split = False
|
|
|
|
#row.alignment = 'LEFT'
|
|
|
|
icon = "DISCLOSURE_TRI_DOWN" if self.expand_extra else "DISCLOSURE_TRI_RIGHT"
|
|
|
|
row.label(icon='BLANK1')
|
|
|
|
subrow = row.row(align=True)
|
|
|
|
subrow.alignment = 'LEFT'
|
|
|
|
subrow.prop(self, 'expand_extra', icon=icon, emboss=False, text="Conform Options")
|
|
|
|
#row.prop(self, 'expand_extra', text='', icon="OPTIONS", emboss=False)
|
|
|
|
#row.prop(self, 'expand_extra', emboss=False, text='Options')
|
|
|
|
#row.label(text='Conform Options')
|
|
|
|
subrow = row.row(align=True)
|
|
|
|
subrow.alignment = 'RIGHT'
|
|
|
|
subrow.prop(self.conform, "adapter_name", text='')
|
|
|
|
|
|
|
|
op = subrow.operator('assetlib.diff', text='', icon='FILE_REFRESH')#, icon='MOD_BUILD'
|
|
|
|
op.name = self.name
|
|
|
|
op.conform = True
|
|
|
|
|
|
|
|
op = subrow.operator('assetlib.bundle', text='', icon='MOD_BUILD')#, icon='MOD_BUILD'
|
|
|
|
op.name = self.name
|
|
|
|
op.directory = self.conform.directory
|
2022-12-25 02:54:50 +01:00
|
|
|
op.conform = True
|
|
|
|
|
2022-12-24 15:30:32 +01:00
|
|
|
subrow.label(icon='BLANK1')
|
|
|
|
#subrow.separator(factor=3)
|
|
|
|
|
|
|
|
if self.expand_extra and self.conform.adapter:
|
|
|
|
col.separator()
|
|
|
|
#row = layout.row(align=True)
|
|
|
|
#row.label(text='Conform Library')
|
|
|
|
col.prop(self.conform, "directory")
|
|
|
|
col.prop(self.conform, "blend_depth")
|
|
|
|
col.prop(self.conform, "externalize_data")
|
|
|
|
col.prop(self.conform, "image_template", text='Image Template')
|
|
|
|
col.prop(self.conform, "video_template", text='Video Template')
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
self.conform.adapter.draw_prefs(col)
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw(self, layout):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
box = layout.box()
|
|
|
|
|
|
|
|
row = box.row(align=True)
|
2022-12-25 02:54:50 +01:00
|
|
|
#row.use_property_split = False
|
|
|
|
|
|
|
|
#row.alignment = 'LEFT'
|
2022-12-24 15:30:32 +01:00
|
|
|
icon = "DISCLOSURE_TRI_DOWN" if self.expand else "DISCLOSURE_TRI_RIGHT"
|
|
|
|
row.prop(self, 'expand', icon=icon, emboss=False, text='')
|
|
|
|
|
|
|
|
if self.is_user:
|
|
|
|
row.prop(self, 'use', text='')
|
|
|
|
row.prop(self, 'data_type', icon_only=True, emboss=False)
|
|
|
|
row.prop(self, 'name', text='')
|
|
|
|
|
|
|
|
self.draw_operators(row)
|
|
|
|
|
|
|
|
index = prefs.user_libraries.index(self)
|
|
|
|
row.operator("assetlib.remove_user_library", icon="X", text='', emboss=False).index = index
|
|
|
|
|
|
|
|
else:
|
|
|
|
row.prop(self, 'use', text='')
|
|
|
|
row.label(icon=ICONS[self.data_type])
|
2022-12-25 02:54:50 +01:00
|
|
|
#row.label(text=self.name)
|
|
|
|
subrow = row.row(align=True)
|
|
|
|
subrow.alignment = 'LEFT'
|
|
|
|
subrow.prop(self, 'expand', emboss=False, text=self.name)
|
|
|
|
#row.separator_spacer()
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
self.draw_operators(row)
|
|
|
|
|
|
|
|
sub_row = row.row()
|
|
|
|
sub_row.enabled = False
|
|
|
|
sub_row.label(icon='FAKE_USER_ON')
|
|
|
|
|
|
|
|
if self.expand:
|
|
|
|
col = box.column(align=False)
|
|
|
|
col.use_property_split = True
|
|
|
|
#row = col.row(align=True)
|
|
|
|
|
|
|
|
row = self.add_row(col,
|
|
|
|
prop="custom_bundle_name",
|
|
|
|
boolean="use_custom_bundle_name",
|
|
|
|
label='Custom Bundle Name')
|
|
|
|
|
|
|
|
row.enabled = not self.use_custom_bundle_directory
|
|
|
|
|
|
|
|
prop = "bundle_directory"
|
|
|
|
if self.use_custom_bundle_directory:
|
|
|
|
prop = "custom_bundle_directory"
|
|
|
|
|
|
|
|
self.add_row(col, prop=prop,
|
|
|
|
boolean="use_custom_bundle_directory",
|
|
|
|
label='Custom Bundle Directory',
|
|
|
|
)
|
|
|
|
|
|
|
|
if self.adapter:
|
|
|
|
col.separator()
|
|
|
|
self.adapter.draw_prefs(col)
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
self.draw_extra(col)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Collections:
|
|
|
|
'''Util Class to merge multiple collections'''
|
|
|
|
|
|
|
|
collections = []
|
|
|
|
|
|
|
|
def __init__(self, *collection):
|
|
|
|
self.collections = collection
|
|
|
|
|
|
|
|
for col in collection:
|
|
|
|
#print('Merge methods')
|
|
|
|
for attr in dir(col):
|
|
|
|
if attr.startswith('_'):
|
|
|
|
continue
|
|
|
|
|
|
|
|
value = getattr(col, attr)
|
|
|
|
#if not callable(value):
|
|
|
|
# continue
|
|
|
|
|
|
|
|
setattr(self, attr, value)
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
if isinstance(item, str):
|
|
|
|
return item in self.to_dict()
|
|
|
|
else:
|
|
|
|
return item in self
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
return self.to_list().__iter__()
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
if isinstance(item, int):
|
|
|
|
return self.to_list()[item]
|
|
|
|
else:
|
|
|
|
return self.to_dict()[item]
|
|
|
|
|
|
|
|
def get(self, item, fallback=None):
|
|
|
|
return self.to_dict().get(item) or fallback
|
|
|
|
|
|
|
|
def to_dict(self):
|
|
|
|
return {k:v for c in self.collections for k, v in c.items()}
|
|
|
|
|
|
|
|
def to_list(self):
|
|
|
|
return [v for c in self.collections for v in c.values()]
|
|
|
|
|
|
|
|
def get_parent(self, item):
|
|
|
|
for c in self.collections:
|
|
|
|
if item in c.values():
|
|
|
|
return c
|
|
|
|
|
|
|
|
def index(self, item):
|
|
|
|
c = self.get_parent(item)
|
|
|
|
|
|
|
|
if not c:
|
|
|
|
return item in self
|
|
|
|
|
|
|
|
return list(c.values()).index(item)
|
|
|
|
|
|
|
|
|
|
|
|
#class AssetLibraryOptions(PropertyGroup):
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
|
|
class AssetLibraryPrefs(AddonPreferences):
|
|
|
|
bl_idname = __package__
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
adapters = []
|
|
|
|
|
2022-12-24 15:30:32 +01:00
|
|
|
#action : bpy.props.PointerProperty(type=AssetLibraryPath)
|
|
|
|
#asset : bpy.props.PointerProperty(type=AssetLibraryPath)
|
|
|
|
#adapters = {}
|
|
|
|
|
|
|
|
image_player: StringProperty(default='')
|
|
|
|
video_player: StringProperty(default='')
|
|
|
|
|
|
|
|
adapter_directory : StringProperty(
|
|
|
|
name="Adapter Directory",
|
|
|
|
subtype='DIR_PATH'
|
|
|
|
)
|
|
|
|
|
|
|
|
env_libraries : CollectionProperty(type=AssetLibrary)
|
|
|
|
user_libraries : CollectionProperty(type=AssetLibrary)
|
|
|
|
expand_settings: BoolProperty(default=False)
|
|
|
|
bundle_directory : StringProperty(
|
|
|
|
name="Path",
|
|
|
|
subtype='DIR_PATH',
|
|
|
|
default='',
|
|
|
|
update=update_all_library_path
|
|
|
|
)
|
|
|
|
|
|
|
|
use_single_path : BoolProperty(default=True)
|
|
|
|
asset_description_template : StringProperty(default='../{name}_asset_description.json')
|
|
|
|
image_template : StringProperty(default='../{name}_image.png')
|
|
|
|
video_template : StringProperty(default='../{name}_video.mov')
|
|
|
|
|
|
|
|
config_directory : StringProperty(
|
|
|
|
name="Config Path",
|
|
|
|
subtype='FILE_PATH',
|
|
|
|
default=str(RESOURCES_DIR/"asset_library_config.json"),
|
|
|
|
update=update_library_config
|
|
|
|
)
|
|
|
|
|
|
|
|
def load_adapters(self):
|
|
|
|
from asset_library.adapters.adapter import AssetLibraryAdapter
|
|
|
|
|
|
|
|
#global ADAPTERS
|
|
|
|
|
|
|
|
print('\n------Load Adapters')
|
|
|
|
|
|
|
|
ADAPTERS.clear()
|
|
|
|
|
|
|
|
adapter_files = list(ADAPTER_DIR.glob('*.py'))
|
|
|
|
if self.adapter_directory:
|
|
|
|
user_adapter_dir = Path(self.adapter_directory)
|
|
|
|
if user_adapter_dir.exists():
|
|
|
|
adapter_files += list(user_adapter_dir.glob('*.py'))
|
|
|
|
|
|
|
|
for adapter_file in adapter_files:
|
|
|
|
mod = import_module_from_path(adapter_file)
|
|
|
|
|
|
|
|
if adapter_file.stem.startswith('_'):
|
|
|
|
continue
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
#print(adapter_file)
|
2022-12-24 15:30:32 +01:00
|
|
|
for name, obj in inspect.getmembers(mod):
|
|
|
|
|
|
|
|
if not inspect.isclass(obj):
|
|
|
|
continue
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
#print(obj.__bases__)
|
2022-12-24 15:30:32 +01:00
|
|
|
if not AssetLibraryAdapter in obj.__mro__:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Non registering base adapter
|
|
|
|
if obj is AssetLibraryAdapter or obj.name in (a.name for a in ADAPTERS):
|
|
|
|
continue
|
|
|
|
|
|
|
|
try:
|
|
|
|
print(f'Register Plugin {name}')
|
|
|
|
bpy.utils.register_class(obj)
|
|
|
|
setattr(AssetLibraryAdapters, norm_str(obj.name), bpy.props.PointerProperty(type=obj))
|
|
|
|
ADAPTERS.append(obj)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(f'Could not register adapter {name}')
|
|
|
|
print(e)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def libraries(self):
|
|
|
|
return Collections(self.env_libraries, self.user_libraries)
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
layout = self.layout
|
|
|
|
#layout.use_property_split = True
|
|
|
|
|
|
|
|
main_col = layout.column(align=False)
|
|
|
|
|
|
|
|
box = main_col.box()
|
|
|
|
row = box.row(align=True)
|
|
|
|
icon = "DISCLOSURE_TRI_DOWN" if self.expand_settings else "DISCLOSURE_TRI_RIGHT"
|
|
|
|
row.prop(self, 'expand_settings', icon=icon, emboss=False, text='')
|
|
|
|
row.label(icon='PREFERENCES')
|
|
|
|
row.label(text='Settings')
|
|
|
|
#row.separator_spacer()
|
|
|
|
subrow = row.row()
|
|
|
|
subrow.alignment = 'RIGHT'
|
|
|
|
subrow.operator("assetlib.reload_addon", text='Reload Addon')
|
|
|
|
|
|
|
|
if prefs.expand_settings:
|
|
|
|
col = box.column(align=True)
|
|
|
|
col.use_property_split = True
|
|
|
|
|
|
|
|
#col.prop(self, 'use_single_path', text='Single Path')
|
|
|
|
col.prop(self, 'bundle_directory', text='Bundle Directory')
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
col.prop(self, 'adapter_directory')
|
|
|
|
col.prop(self, 'config_directory')
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
col.prop(self, 'asset_description_template', text='Asset Description Template', icon='COPY_ID')
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
col.prop(self, 'image_template', text='Image Template', icon='COPY_ID')
|
|
|
|
col.prop(self, 'image_player', text='Image Player') #icon='OUTLINER_OB_IMAGE'
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
col.prop(self, 'video_template', text='Video Template', icon='COPY_ID')
|
|
|
|
col.prop(self, 'video_player', text='Video Player') #icon='FILE_MOVIE'
|
|
|
|
|
|
|
|
col.separator()
|
|
|
|
|
|
|
|
col.operator("assetlib.add_user_library", text='Bundle All Libraries', icon='MOD_BUILD')
|
|
|
|
|
|
|
|
for lib in self.libraries:# list(self.env_libraries) + list(self.user_libraries):
|
|
|
|
|
|
|
|
lib.draw(main_col)
|
|
|
|
|
|
|
|
row = main_col.row()
|
|
|
|
row.alignment = 'RIGHT'
|
|
|
|
row.operator("assetlib.add_user_library", icon="ADD", text='', emboss=False)
|
|
|
|
|
|
|
|
|
2022-12-25 02:54:50 +01:00
|
|
|
classes = [
|
2022-12-24 15:30:32 +01:00
|
|
|
AssetLibraryAdapters,
|
|
|
|
ConformAssetLibrary,
|
|
|
|
AssetLibrary,
|
|
|
|
AssetLibraryPrefs,
|
2022-12-25 02:54:50 +01:00
|
|
|
]
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
def register():
|
|
|
|
for cls in classes:
|
|
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
|
|
prefs = get_addon_prefs()
|
|
|
|
|
|
|
|
# Read Env and override preferences
|
|
|
|
bundle_dir = os.getenv('ASSETLIB_BUNDLE_DIR')
|
|
|
|
if bundle_dir:
|
2022-12-25 02:54:50 +01:00
|
|
|
prefs['bundle_directory'] = os.path.expandvars(bundle_dir)
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
config_dir = os.getenv('ASSETLIB_CONFIG_DIR')
|
|
|
|
if config_dir:
|
2022-12-25 02:54:50 +01:00
|
|
|
prefs['config_directory'] = os.path.expandvars(config_dir)
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
adapter_dir = os.getenv('ASSETLIB_ADAPTER_DIR')
|
|
|
|
if adapter_dir:
|
2022-12-25 02:54:50 +01:00
|
|
|
prefs['adapter_directory'] = os.path.expandvars(adapter_dir)
|
2022-12-24 15:30:32 +01:00
|
|
|
|
|
|
|
prefs.load_adapters()
|
|
|
|
|
|
|
|
def unregister():
|
2022-12-25 02:54:50 +01:00
|
|
|
for cls in reversed(classes + ADAPTERS):
|
2022-12-24 15:30:32 +01:00
|
|
|
bpy.utils.unregister_class(cls)
|
|
|
|
|
|
|
|
ADAPTERS.clear()
|