Files
blender-portable-repo/extensions/blender_org/optiploy/preferences.py
T
2026-03-17 14:30:01 -06:00

941 lines
39 KiB
Python

import bpy
from . import base_package
import os
from glob import glob
from bpy.props import (StringProperty, CollectionProperty,
IntProperty, EnumProperty,
BoolProperty, PointerProperty)
from bpy.types import (UIList, PropertyGroup,
AddonPreferences, Operator)
from bpy_extras.io_utils import ImportHelper
from .panel import SPAWNER_OT_genericText
no_recursion = False
def only(item, *argv):
for arg in argv:
if arg != item:
return False
return True
def exists(self, context):
prefs = context.preferences.addons[base_package].preferences
for blend in prefs.blends:
blend.exists = os.path.exists(blend.filepath)
for folder in prefs.folders:
folder.exists = os.path.exists(folder.filepath)
def blends_CB(self, context):
prefs = context.preferences.addons[base_package].preferences
items = []
for n, blend in enumerate(prefs.blends):
items.append((str(n), blend.name, 'This is a .blend file!', 'BLENDER', n))
return items
def folders_CB(self, context):
prefs = context.preferences.addons[base_package].preferences
items = []
for n, folder in enumerate(prefs.folders):
icon = 'FILE_FOLDER' if not folder.category else 'ASSET_MANAGER'
items.append((str(n), folder.name, 'This is a folder!', icon, n))
return items
def folders_blend_CB(self, context):
prefs = context.preferences.addons[base_package].preferences
items = []
folder = context.scene.optiploy_props.selected_folder
for n, blend in enumerate(prefs.folders[int(folder)].blends):
items.append((str(n), blend.name, 'This is a .blend file!', 'BLENDER', n))
return items
def redraw(self, context: bpy.types.Context):
print(dir(context.area), dir(context.space_data), dir(context.window), dir(context.ui_list))
context.area.tag_redraw()
class objects(PropertyGroup):
name: StringProperty(default='')
class collections(PropertyGroup):
name: StringProperty(default='')
class blends(PropertyGroup):
objects: CollectionProperty(type=objects, name='Spawnables', description='List of spawnable items detected in this .blend file')
collections: CollectionProperty(type=collections, name='Spawnables', description='List of spawnable items detected in this .blend file')
filepath: StringProperty(name='Filepath', description='Path to a .blend file', options=set(), subtype='FILE_PATH', update=exists)
name: StringProperty(name='Name')#, update=sorter)
exists: BoolProperty(default=True)
override_behavior: BoolProperty(default=False, name='Override Behavior')
localize_collections: BoolProperty(name='Localize collections', description='Fully localize new collections. Will not include new objects from the source .blend file',default=True, options=set())
localize_objects: BoolProperty(default=False, name='Localize objects', options=set())
localize_meshes: BoolProperty(default=False, name='Localize mesh data', options=set())
localize_materials: BoolProperty(default=False, name='Localize materials', options=set())
localize_node_groups: BoolProperty(default=False, name='Localize node groups', options=set())
localize_images: BoolProperty(default=False, name='Localize images', options=set())
localize_armatures: BoolProperty(default=False, name='Localize armatures', options=set())
localize_actions: BoolProperty(default=True, name='Localize actions', options=set())
localize_lights: BoolProperty(default=False, name='Localize lights', options=set())
localize_cameras: BoolProperty(default=False, name='Localize cameras', options=set())
localize_curves: BoolProperty(default=False, name='Localize curves', options=set())
localize_text_curves: BoolProperty(default=False, name='Localize text curves', options=set())
localize_metaballs: BoolProperty(default=False, name='Localize metaballs', options=set())
localize_surface_curves:BoolProperty(default=False, name='Localize surface curves', options=set())
localize_volumes: BoolProperty(default=False, name='Localize volumes', options=set())
localize_grease_pencil: BoolProperty(default=False, name='Localize grease pencil', options=set())
importer: EnumProperty(items=(('FAST', 'Fast', 'Fast importer'), ('STABLE', 'Stable', 'Stable importer')), name='Importer', description='Which importer to use', default='FAST')
class folders(PropertyGroup):
blends: CollectionProperty(type=blends, name='.blend files', description='List of .blend files under this folder.')
blend_index: IntProperty(default=0)
filepath: StringProperty(name='Folder Path', description='Path to this directory', subtype='DIR_PATH', update=exists)
name: StringProperty(name='Name')#, options=set(), update=sorter)
exists: BoolProperty(default=False)
category: BoolProperty(default=False)
recursive: BoolProperty(name='Include subfolders', description='Should subfolders be scanned as well?', default=False)
selected_blend: EnumProperty(items=folders_blend_CB, name='Selected .blend', description='Selected .blend file under active folder')
override_behavior: BoolProperty(default=False, name='Override Behavior')
localize_collections: BoolProperty(name='Localize collections', description='Fully localize new collections. Will not include new objects from the source .blend file',default=True, options=set())
localize_objects: BoolProperty(default=False, name='Localize objects', options=set())
localize_meshes: BoolProperty(default=False, name='Localize mesh data', options=set())
localize_materials: BoolProperty(default=False, name='Localize materials', options=set())
localize_node_groups: BoolProperty(default=False, name='Localize node groups', options=set())
localize_images: BoolProperty(default=False, name='Localize images', options=set())
localize_armatures: BoolProperty(default=False, name='Localize armatures', options=set())
localize_actions: BoolProperty(default=True, name='Localize actions', options=set())
localize_lights: BoolProperty(default=False, name='Localize lights', options=set())
localize_cameras: BoolProperty(default=False, name='Localize cameras', options=set())
localize_curves: BoolProperty(default=False, name='Localize curves', options=set())
localize_text_curves: BoolProperty(default=False, name='Localize text curves', options=set())
localize_metaballs: BoolProperty(default=False, name='Localize metaballs', options=set())
localize_surface_curves:BoolProperty(default=False, name='Localize surface curves', options=set())
localize_volumes: BoolProperty(default=False, name='Localize volumes', options=set())
localize_grease_pencil: BoolProperty(default=False, name='Localize grease pencil', options=set())
importer: EnumProperty(items=(('FAST', 'Fast', 'Fast importer'), ('STABLE', 'Stable', 'Stable importer')), name='Importer', description='Which importer to use', default='FAST')
class BLENDS_SPAWNER_UL_List(UIList):
def draw_item(self, context,
layout, data,
item, icon,
active_data, active_propname,
index):
prefs = context.preferences.addons[base_package].preferences
row = layout.row()
row.alignment = 'EXPAND'
row.label(text='', icon='BLENDER' if item.exists else 'CANCEL')
if data.blends[data.blend_index] == item:
row.prop(item, 'name', text='', expand=True)
else:
row.label(text=item.name)
row = row.row()
row.alignment = 'RIGHT'
row.label(text=str(len(item.objects)), icon='OBJECT_DATA')
row.label(text=str(len(item.collections)), icon='OUTLINER_COLLECTION')
op = row.operator('spawner.scan')
op.blend = index
op.folder = -1
if data != prefs:
op.folder = prefs.folders.find(data.name)
class FOLDERS_SPAWNER_UL_List(UIList):
def draw_item(self, context,
layout, data,
item, icon,
active_data, active_propname,
index):
prefs = context.preferences.addons[base_package].preferences
folders = prefs.folders
row = layout.row()
if item.exists:
icon = 'FILE_FOLDER'
elif item.category:
icon = 'ASSET_MANAGER'
else:
icon = 'CANCEL'
row.label(text='', icon=icon)
if prefs.folders[prefs.folder_index] == item:
row.prop(item, 'name', text='')
else:
row.label(text=item.name)
row = row.row()
row.alignment='RIGHT'
row.label(text=str(len(item.blends)), icon='BLENDER')
op = row.operator('spawner.scan')
op.folder = index
op.blend = -1
class SPAWNER_GENERIC_UL_List(UIList):
def draw_item(self, context,
layout, data,
item, icon,
active_data, active_propname,
index):
layout.label(text=item.name)
class blendentriespref(AddonPreferences):
bl_idname = base_package
#def set_blend_show(self, value):
# self['blend_more_info'] = value
#def get_blend_show(self):
# return self['blend_more_info'] and not self['folder_more_info']
def update_blend_show(self, context):
self['folder_more_info'] = False
def update_folder_show(self, context):
self['blend_more_info'] = False
blends: CollectionProperty(type=blends)
blend_index: IntProperty(name='Blend Entry Index', min=0, options=set())
selected_blend: EnumProperty(items=blends_CB, options=set(), name='Selected .blend File', description='Selected .blend file')
blend_more_info: BoolProperty(default=False, name='Show More', description='Show more of the selected .blend file', options=set(), update=update_blend_show)#get=get_blend_show, set=set_blend_show)
folders: CollectionProperty(type=folders)
folder_index: IntProperty(name='Folder Entry Index', min=0, options=set())
selected_folder: EnumProperty(items=folders_CB, options=set(), name='Selected Folder', description='Selected Folder')
folder_more_info: BoolProperty(default=False, name='Show More', description='Show more of the selected .blend file', options=set(), update=update_folder_show)
#folder_blend_more_info: BoolProperty(default=False, name='Show More', description='Show more of the selected .blend file', options=set())
obj_index: IntProperty(default=0, options=set())#, update=redraw)
col_index: IntProperty(default=0, options=set())#, update=redraw)
null: IntProperty(min=0, max=0)
to_cursor: BoolProperty(default=True, name='Move Parents to Cursor', options=set())
localize_collections: BoolProperty(name='Localize collections', description='Fully localize new collections. Will not include new objects from the source .blend file',default=True, options=set())
localize_objects: BoolProperty(default=True, name='Localize objects', options=set())
localize_meshes: BoolProperty(default=False, name='Localize mesh data', options=set())
localize_materials: BoolProperty(default=False, name='Localize materials', options=set())
localize_node_groups: BoolProperty(default=False, name='Localize node groups', options=set())
localize_images: BoolProperty(default=False, name='Localize images', options=set())
localize_armatures: BoolProperty(default=False, name='Localize armatures', options=set())
localize_actions: BoolProperty(default=True, name='Localize actions', options=set())
localize_lights: BoolProperty(default=False, name='Localize lights', options=set())
localize_cameras: BoolProperty(default=False, name='Localize cameras', options=set())
localize_curves: BoolProperty(default=False, name='Localize curves', options=set())
localize_text_curves: BoolProperty(default=False, name='Localize text curves', options=set())
localize_metaballs: BoolProperty(default=False, name='Localize metaballs', options=set())
localize_surface_curves:BoolProperty(default=False, name='Localize surface curves', options=set())
localize_volumes: BoolProperty(default=False, name='Localize volumes', options=set())
localize_grease_pencil: BoolProperty(default=False, name='Localize grease pencil', options=set())
execute_scripts: BoolProperty(default=True, name='Execute Attached Scripts', options=set())
importer: EnumProperty(items=(('FAST', 'Fast', 'Fast importer'), ('STABLE', 'Stable', 'Stable importer')), name='Importer', description='Which importer to use', default='FAST')
def draw(self, context):
layout = self.layout
alpha_text = '''This can only be undone through reverting to saved preferences.
Hold SHIFT to reverse sort.'''
alpha_icons = 'SORTALPHA,EVENT_SHIFT'
alpha_size = '56,56'
op = layout.row().operator('spawner.textbox', text="Assets not showing?", icon='QUESTION')
op.text = 'In OptiPloy, collections or objects need to be marked as "Assets" if they are to be used. If the scanning isn\'t returning any results, ensure objects or collections are marked as assets.'
op.size = '58'
op.icons = 'ASSET_MANAGER'
op.width=350
layout.row().label(text='.blend entries', icon='BLENDER')
box = layout.box()
row = box.row()
row.template_list('BLENDS_SPAWNER_UL_List', 'Blends', self, 'blends', self, 'blend_index')
col = row.column()
op = col.operator('spawner.add_entry', text='', icon='ADD')
op.blend=True
op.folder = False
op = col.operator('spawner.remove_entry', text='', icon='REMOVE')
op.blend = True
op.folder = False
col.separator()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = False
op.object = False
op.collection = False
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=False
op.object=False
op.collection=False
if (len(self.blends) != 0) and (self.blend_index < len(self.blends)):
blend = self.blends[self.blend_index]
box.row().prop(blend, 'filepath')
row = box.row()
row.prop(self, 'blend_more_info', toggle=True)
if self.blend_more_info:
objBox = box.box()
objBox.row().label(text='Objects', icon='OBJECT_DATA')
row = objBox.row()
if len(blend.objects) > 0:
row.template_list('SPAWNER_GENERIC_UL_List', 'Objects', blend, 'objects', self, 'obj_index')
col = row.column()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = False
op.object = True
op.collection = False
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=False
op.object=True
op.collection=False
else:
row.label(text='No objects!')
colBox = box.box()
colBox.row().label(text='Collections', icon='OUTLINER_COLLECTION')
row = colBox.row()
if len(blend.collections) > 0:
row.template_list('SPAWNER_GENERIC_UL_List', 'Collections', blend, 'collections', self, 'col_index')
col = row.column()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = False
op.object = False
op.collection = True
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=False
op.object=False
op.collection=True
else:
row.label(text='No collections!')
row = layout.row()
#col = layout.column()
row = row.row()
row.alignment = 'EXPAND'
row.label(text='Folder entries', icon='FILE_FOLDER')
row = row.row()
row.alignment = 'RIGHT'
row.label(text='Hold Shift to add a "Category"')
row = row.row(align=True)
row.label(text='', icon='ASSET_MANAGER')
box = layout.box()
row = box.row()
row.template_list('FOLDERS_SPAWNER_UL_List', 'Folders', self, 'folders', self, 'folder_index')
col = row.column()
op = col.operator('spawner.add_entry', text='', icon='ADD')
op.blend=False
op.folder = True
op = col.operator('spawner.remove_entry', text='', icon='REMOVE')
op.blend = False
op.folder = True
col.separator()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = False
op.folder = True
op.object = False
op.collection = False
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=False
op.folder=True
op.object=False
op.collection=False
if (len(self.folders) != 0) and (self.folder_index < len(self.folders)):
folder = self.folders[self.folder_index]
col = box.column(align=False)
if folder.category:
box.row().label(text='This is a category, a way to organize separated .blend files.')
else:
col.row().prop(folder, 'recursive')
col.separator()
col.row().prop(folder, 'filepath')
row = box.row()
row.prop(self, 'folder_more_info', toggle=True)
if self.folder_more_info:# and len(folder.blends) > 0:
row = box.row()
box = row.box()
box.row().label(text='.blends', icon='BLENDER')
row = box.row()
row.template_list('BLENDS_SPAWNER_UL_List', '.blend files', folder, 'blends', folder, 'blend_index')
col = row.column()
op = col.operator('spawner.add_entry', text='', icon='ADD')
op.blend=True
op.folder = True
op = col.operator('spawner.remove_entry', text='', icon='REMOVE')
op.blend = True
op.folder = True
col.separator()#1, 'LINE')
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = True
op.object = False
op.collection = False
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=True
op.object=False
op.collection=False
if len(folder.blends) > 0:
blend = folder.blends[max(min(folder.blend_index, len(folder.blends)-1), 0)]
box.row().prop(blend, 'filepath')
objBox = box.box()
objBox.row().label(text='Objects', icon='OBJECT_DATA')
row = objBox.row()
if len(blend.objects) > 0:
row.template_list('SPAWNER_GENERIC_UL_List', 'Objects', blend, 'objects', self, 'obj_index')
col = row.column()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = True
op.object = True
op.collection = False
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=True
op.object=True
op.collection=False
else:
row.label(text='No objects!')
colBox = box.box()
colBox.row().label(text='Collections', icon='OUTLINER_COLLECTION')
row = colBox.row()
if len(blend.collections) > 0:
row.template_list('SPAWNER_GENERIC_UL_List', 'Collections', blend, 'collections', self, 'col_index')
col = row.column()
for offset, icon in [(-1, 'TRIA_UP'), (1, 'TRIA_DOWN')]:
op = col.operator('spawner.move', text='', icon=icon)
op.offset = offset
op.blend = True
op.folder = True
op.object = False
op.collection = True
col.separator()
op = col.operator('spawner.alpha_sort', text='', icon='SORTALPHA')
op.text = alpha_text
op.icons = alpha_icons
op.size = alpha_size
op.width=310
op.blend=True
op.folder=True
op.object=False
op.collection=True
else:
row.label(text='No collections!')
class SPAWNER_OT_Add_Entry(Operator):
bl_idname = 'spawner.add_entry'
bl_label = 'Add Blend Entry'
bl_description = 'Add a .blend file to spawn from'
#bl_options = {''}
filepath: StringProperty()
directory: StringProperty()
blend: BoolProperty(default=True, options={'HIDDEN'})
folder: BoolProperty(default=False, options={'HIDDEN'})
filter_glob: StringProperty(default='*.blend', options={'HIDDEN'})
execute_only: BoolProperty(default=False, options={'HIDDEN'})
category: BoolProperty(default=False, options={'HIDDEN'})
category_name: StringProperty(default='', options={'HIDDEN'})
folder_select: IntProperty(default=-1, options={'HIDDEN'})
folder_recursive: BoolProperty(name='Folder Recursive Scan', description='Add recursive scans for folders and its sub-folders', default=False)
_shift = None
def invoke(self, context, event):
if self.execute_only:
self.execute_only = False
return self.execute(context)
self._shift = event.shift
if self.folder and self._shift:
return self.execute(context)
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def execute(self, context):
prefs = context.preferences.addons[base_package].preferences
if self.blend and self.folder:
if not os.path.exists(self.filepath):
self.report({'ERROR'}, f'{self.filepath} does not exist!')
return {'CANCELLED'}
folder = prefs.folders[prefs.folder_index]
if self.folder_select > -1:
folder = prefs.folders[self.folder_select]
self.folder_select = -1
new_entry = folder.blends.add()
new_entry.filepath = self.filepath
name = os.path.basename(self.filepath).rsplit('.', maxsplit=1)[0]
new_entry.name = name
scan(self, context, new_entry)
elif self.blend:
if not os.path.exists(self.filepath):
self.report({'ERROR'}, f'{self.filepath} does not exist!')
return {'CANCELLED'}
new_entry = prefs.blends.add()
new_entry.filepath = self.filepath
new_entry.filepath = bpy.path.abspath(new_entry.filepath) # just in case
name = os.path.basename(self.filepath).rsplit('.', maxsplit=1)[0]
new_entry.name = name
scan(self, context, new_entry)
else:
if not os.path.exists(self.directory) and not self._shift:
self.report({'ERROR'}, f'{self.directory} does not exist!')
return {'CANCELLED'}
new_entry = prefs.folders.add()
if self._shift or self.category:
new_name = 'New Category'
if self.category:
new_name = self.category_name
self.category = False
new_entry.category = True
new_entry.name = new_name
else:
new_entry.filepath = self.directory
new_entry.recursive = self.folder_recursive
directory: str = self.directory
directory = directory.removesuffix('/')
directory = directory.removesuffix('\\')
name = os.path.basename(directory)
new_entry.name = name
scan(self, context, new_entry)
context.window_manager.progress_end()
return {'FINISHED'}
class SPAWNER_OT_Remove_Entry(Operator):
bl_idname = 'spawner.remove_entry'
bl_label = 'Remove Blend Entry'
bl_description = 'Add a .blend file to spawn from'
blend: BoolProperty(default=True)
folder: BoolProperty(default=False)
def execute(self, context):
prefs = context.preferences.addons[base_package].preferences
if self.blend and self.folder:
folder = prefs.folders[prefs.folder_index]
folder.blends.remove(folder.blend_index)
folder.blend_index -= 1
elif self.blend:
index = prefs.blend_index
prefs.blend_index -= 1
prefs.blends.remove(index)
else:
index = prefs.folder_index
prefs.folder_index -= 1
prefs.folders.remove(index)
return {'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_confirm(self, event)
def scan(op: bpy.types.Operator, context: bpy.types.Context, item, skip = False):
wm = context.window_manager
wm.progress_begin(0, 9999)
wm.progress_update(0)
failed = 0
itemType = item.bl_rna.identifier
if itemType == 'blends':
if (len(item.objects) + len(item.collections) != 0) and skip:
return
wm.progress_update(1)
if not os.path.exists(item.filepath):
op.report({'ERROR'}, f'{item.filepath} does not exist!')
return {'CANCELLED'}
print(f'Opening {item.filepath}...')
try:
with bpy.data.libraries.load(item.filepath, assets_only=True) as (From, To):
pass
except:
op.report({'ERROR'}, f'Could not open {item.filepath}! Is it corrupt?')
return {'CANCELLED'}
print(f'Opened!')
item.objects.clear()
item.collections.clear()
if len(From.objects) + len(From.collections) == 0:
op.report({'WARNING'}, f'{item.filepath} does not have any objects or collections marked as assets!')
return {'FINISHED'}
wm.progress_update(2)
print(f'Found {len(From.objects)} object(s)')
for obj in sorted(From.objects):
new = item.objects.add()
new.name = obj
wm.progress_update(3)
print(f'Found {len(From.collections)} collection(s)')
for col in sorted(From.collections):
new = item.collections.add()
new.name = col
del From, To
return {'FINISHED'}
if itemType == 'folders':
print(f'Recursive Scan: {item.recursive}')
globPath = '*.blend'
if item.recursive:
globPath = '**/' + globPath
blends = glob(globPath, root_dir=item.filepath, recursive=item.recursive)
print(f'Scan result count: {len(blends)}')
if not skip:
item.blends.clear()
wm.progress_update(1)
for n, blend in enumerate(blends):
if (item.get(blend) != None) and skip: continue
blend_path = os.path.join(item.filepath, blend)
if not os.path.exists(blend_path): continue
wm.progress_update(n*10)
print(f'Opening {blend_path}...')
try:
with bpy.data.libraries.load(blend_path, assets_only=True) as (From, To):
pass
except:
op.report({'ERROR'}, f'Could not open {blend_path}! Is it corrupt?')
failed += 1
if len(From.objects) + len(From.collections) == 0:
op.report({'WARNING'}, f'{blend_path} does not have any objects or collections marked as assets!')
failed += 1
continue
print(f'Opened!')
print(f'Found {len(From.objects)} object(s)')
print(f'Found {len(From.collections)} collections(s)')
newBlend = item.blends.add()
newBlend.name = os.path.splitext(blend)[0]
newBlend.filepath = blend_path
wm.progress_update(n*10+1)
for obj in sorted(From.objects):
new = newBlend.objects.add()
new.name = obj
wm.progress_update(n*10+2)
for col in sorted(From.collections):
new = newBlend.collections.add()
new.name = col
if failed:
op.report({'WARNING'}, f'{failed} error(s) occured. Read INFO to learn more')
return {'FINISHED'}
class SPAWNER_OT_SCAN(Operator):
bl_idname = 'spawner.scan'
bl_label = 'Scan'
bl_description = 'Combs through .blend files to look for spawnable objects or collections'
blend: IntProperty(name='.blend file', default=-1)
folder: IntProperty(name='Folder', default=-1)
def execute(self, context):
prefs = context.preferences.addons[base_package].preferences
blend = self.blend
folder = self.folder
if blend != -1 and folder == -1:
blend = prefs.blends[blend]
return_val = scan(self, context, blend, False)
context.window_manager.progress_end()
return return_val
if folder != -1 and blend == -1:
folder = prefs.folders[folder]
if folder.category:
for blend in folder.blends:
scan(self, context, blend)
return_val = {'FINISHED'}
else:
return_val = scan(self, context, folder)
context.window_manager.progress_end()
return return_val
if not -1 in {folder, blend}:
blend = prefs.folders[folder].blends[blend]
return_val = scan(self, context, blend)
context.window_manager.progress_end()
return return_val
return {'FINISHED'}
class SPAWNER_OT_ALPHA_SORT(SPAWNER_OT_genericText):
bl_idname = 'spawner.alpha_sort'
bl_label = 'Sort by Alphabet'
bl_description = 'Hold SHIFT to sort backwards'
blend: BoolProperty(default=False)
folder: BoolProperty(default=False)
object: BoolProperty(default=False)
collection: BoolProperty(default=False)
_shift = None
def invoke_extra(self, context, event):
self._shift = event.shift
#return self.execute(context)
def execute(self, context):
prefs = context.preferences.addons[base_package].preferences
B = self.blend
F = self.folder
O = self.object
C = self.collection
if B == True and only(False, F, O, C):
item = prefs.blends
if F == True and only(False, B, O, C):
item = prefs.folders
if only(True, B, F) and only(False, O, C):
folder = prefs.folders[prefs.folder_index]
item = folder.blends
if F == False:
blend = prefs.blends[prefs.blend_index]
else:
folder = prefs.folders[prefs.folder_index]
blend = folder.blends[folder.blend_index]
if O == True:
item = blend.objects
if C == True:
item = blend.collections
ln = enumerate(item)
rev = sorted(ln, key=lambda a: a[1].name.casefold())
if not self._shift:
rev = reversed(rev)
rev = list(map(lambda a: a[0], rev))
for i in rev:
item.move(i, 0)
for n, _ in enumerate(rev):
val = rev[n]
if val < i:
rev[n] += 1
return {'FINISHED'}
class SPAWNER_OT_MOVE(Operator):
bl_idname = 'spawner.move'
bl_label = 'Move'
bl_description = 'Hold SHIFT to move an item to the top or bottom'
offset: IntProperty(default=0)
blend: BoolProperty(default=False)
folder: BoolProperty(default=False)
object: BoolProperty(default=False)
collection: BoolProperty(default=False)
_shift = None
def invoke(self, context, event):
self._shift = event.shift
return self.execute(context)
def execute(self, context):
prefs = context.preferences.addons[base_package].preferences
B = self.blend
F = self.folder
O = self.object
C = self.collection
offset = self.offset
if B == True and only(False, F, O, C):
item = prefs.blends
index = prefs.blend_index
maxlen = len(item) - 1
if self._shift:
offset = 0 if (offset < 0) else maxlen
else:
offset = index + offset
offset = min(max(offset, 0), maxlen)
item.move(index, offset)
prefs.blend_index = offset
return {'FINISHED'}
if F == True and only(False, B, O, C):
item = prefs.folders
index = prefs.folder_index
maxlen = len(item) - 1
if self._shift:
offset = 0 if (offset < 0) else maxlen
else:
offset = index + offset
offset = min(max(offset, 0), maxlen)
item.move(index, offset)
prefs.folder_index = offset
return {'FINISHED'}
if only(True, B, F) and only(False, O, C):
folder = prefs.folders[prefs.folder_index]
item = folder.blends
index = folder.blend_index
maxlen = len(item) - 1
if self._shift:
offset = 0 if (offset < 0) else maxlen
else:
offset = index + offset
offset = min(max(offset, 0), maxlen)
item.move(index, offset)
folder.blend_index = offset
return {'FINISHED'}
if F == False:
blend = prefs.blends[prefs.blend_index]
else:
folder = prefs.folders[prefs.folder_index]
blend = folder.blends[folder.blend_index]
if O == True:
item = blend.objects
index = prefs.obj_index
maxlen = len(item) - 1
if self._shift:
offset = 0 if (offset < 0) else maxlen
else:
offset = index + offset
offset = min(max(offset, 0), maxlen)
item.move(index, offset)
prefs.obj_index = offset
return {'FINISHED'}
if C == True:
item = blend.collections
index = prefs.col_index
maxlen = len(item) - 1
if self._shift:
offset = 0 if (offset < 0) else maxlen
else:
offset = index + offset
offset = min(max(offset, 0), maxlen)
item.move(index, offset)
prefs.col_index = offset
return {'FINISHED'}
return {'FINISHED'}
class SPAWNER_OT_CONTEXT(Operator):
bl_idname = 'spawner.context'
bl_label = 'context'
def execute(self, context):
print(context.space_data, context.area.type, context.window, context.screen)
return {'FINISHED'}
class spawner_props(PropertyGroup):
selected_blend: EnumProperty(items=blends_CB, options=set(), name='Selected .blend File', description='Selected .blend file')
selected_folder: EnumProperty(items=folders_CB, options=set(), name='Selected Folder', description='Selected Folder')
view: EnumProperty(items = (
('BLENDS', 'Blend Files', 'Spawn from your list of .blend files', 'BLENDER', 0),
('FOLDERS', 'Folders', 'Spawn from your list of folders', 'FILE_FOLDER', 1),
('TOOLS', 'Tools', 'Choose from the assortment of tools', 'TOOL_SETTINGS', 2)
),
name='View', description='View', options=set()
)
classes = [
objects,
collections,
blends,
folders,
spawner_props,
BLENDS_SPAWNER_UL_List,
FOLDERS_SPAWNER_UL_List,
SPAWNER_GENERIC_UL_List,
blendentriespref,
SPAWNER_OT_Add_Entry,
SPAWNER_OT_Remove_Entry,
SPAWNER_OT_SCAN,
SPAWNER_OT_ALPHA_SORT,
SPAWNER_OT_MOVE,
#SPAWNER_OT_CONTEXT,
]
def register():
for i in classes:
bpy.utils.register_class(i)
bpy.types.Scene.optiploy_props = PointerProperty(type=spawner_props)
def unregister():
for i in reversed(classes):
bpy.utils.unregister_class(i)
del bpy.types.Scene.optiploy_props