2026-01-01

This commit is contained in:
2026-03-17 15:16:34 -06:00
parent ec4cf523fb
commit b80274187b
263 changed files with 95164 additions and 3848 deletions
@@ -30,9 +30,10 @@ intefaces in Blender.
import bpy
from bpy.utils import register_class
from bpy.utils import unregister_class
from ..utils import compat
from .. import config
from ..stats import unused
from ..stats import unused_parallel
from .utils import nuke
from .utils import clean
from ..ui.utils import ui_layouts
@@ -157,8 +158,10 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
unused_lights = []
unused_materials = []
unused_node_groups = []
unused_objects = []
unused_particles = []
unused_textures = []
unused_armatures = []
unused_worlds = []
def draw(self, context):
@@ -167,67 +170,74 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
col = layout.column()
col.label(text="Remove the following data-blocks?")
collections = sorted(unused.collections_deep())
# Use cached values from invoke() instead of recalculating
ui_layouts.box_list(
layout=layout,
title="Collections",
items=collections,
items=sorted(self.unused_collections),
icon="OUTLINER_OB_GROUP_INSTANCE"
)
images = sorted(unused.images_deep())
ui_layouts.box_list(
layout=layout,
title="Images",
items=images,
items=sorted(self.unused_images),
icon="IMAGE_DATA"
)
lights = sorted(unused.lights_deep())
ui_layouts.box_list(
layout=layout,
title="Lights",
items=lights,
items=sorted(self.unused_lights),
icon="OUTLINER_OB_LIGHT"
)
materials = sorted(unused.materials_deep())
ui_layouts.box_list(
layout=layout,
title="Materials",
items=materials,
items=sorted(self.unused_materials),
icon="MATERIAL"
)
node_groups = sorted(unused.node_groups_deep())
ui_layouts.box_list(
layout=layout,
title="Node Groups",
items=node_groups,
items=sorted(self.unused_node_groups),
icon="NODETREE"
)
particles = sorted(unused.particles_deep())
ui_layouts.box_list(
layout=layout,
title="Objects",
items=sorted(self.unused_objects),
icon="OBJECT_DATA"
)
ui_layouts.box_list(
layout=layout,
title="Particle Systems",
items=particles,
items=sorted(self.unused_particles),
icon="PARTICLES"
)
textures = sorted(unused.textures_deep())
ui_layouts.box_list(
layout=layout,
title="Textures",
items=textures,
items=sorted(self.unused_textures),
icon="TEXTURE"
)
worlds = sorted(unused.worlds())
ui_layouts.box_list(
layout=layout,
title="Armatures",
items=sorted(self.unused_armatures),
icon="ARMATURE_DATA"
)
ui_layouts.box_list(
layout=layout,
title="Worlds",
items=worlds,
items=sorted(self.unused_worlds),
icon="WORLD"
)
@@ -240,8 +250,10 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
clean.lights()
clean.materials()
clean.node_groups()
clean.objects()
clean.particles()
clean.textures()
clean.armatures()
clean.worlds()
return {'FINISHED'}
@@ -249,14 +261,19 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
def invoke(self, context, event):
wm = context.window_manager
self.unused_collections = unused.collections_deep()
self.unused_images = unused.images_deep()
self.unused_lights = unused.lights_deep()
self.unused_materials = unused.materials_deep()
self.unused_node_groups = unused.node_groups_deep()
self.unused_particles = unused.particles_deep()
self.unused_textures = unused.textures_deep()
self.unused_worlds = unused.worlds()
# Use parallel execution for better performance
all_unused = unused_parallel.get_all_unused_parallel()
self.unused_collections = all_unused['collections']
self.unused_images = all_unused['images']
self.unused_lights = all_unused['lights']
self.unused_materials = all_unused['materials']
self.unused_node_groups = all_unused['node_groups']
self.unused_objects = all_unused['objects']
self.unused_particles = all_unused['particles']
self.unused_textures = all_unused['textures']
self.unused_armatures = all_unused['armatures']
self.unused_worlds = all_unused['worlds']
return wm.invoke_props_dialog(self)
@@ -790,4 +807,4 @@ def register():
def unregister():
for item in reg_list:
unregister_class(item)
compat.safe_unregister_class(item)
@@ -26,11 +26,18 @@ operators.
import bpy
from bpy.utils import register_class
from bpy.utils import unregister_class
from ..utils import compat
from .utils import delete
from .utils import duplicate
def _check_library_or_override(datablock):
"""Check if datablock is library-linked or override, return error message if so."""
if compat.is_library_or_override(datablock):
return "Cannot modify library-linked or override datablocks"
return None
# Atomic Data Manager Inspection Rename Operator
class ATOMIC_OT_inspection_rename(bpy.types.Operator):
"""Give this data-block a new name"""
@@ -51,35 +58,75 @@ class ATOMIC_OT_inspection_rename(bpy.types.Operator):
name = atom.rename_field
if inspection == 'COLLECTIONS':
bpy.data.collections[atom.collections_field].name = name
collection = bpy.data.collections[atom.collections_field]
error = _check_library_or_override(collection)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
collection.name = name
atom.collections_field = name
if inspection == 'IMAGES':
bpy.data.images[atom.images_field].name = name
image = bpy.data.images[atom.images_field]
error = _check_library_or_override(image)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
image.name = name
atom.images_field = name
if inspection == 'LIGHTS':
bpy.data.lights[atom.lights_field].name = name
light = bpy.data.lights[atom.lights_field]
error = _check_library_or_override(light)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
light.name = name
atom.lights_field = name
if inspection == 'MATERIALS':
bpy.data.materials[atom.materials_field].name = name
material = bpy.data.materials[atom.materials_field]
error = _check_library_or_override(material)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
material.name = name
atom.materials_field = name
if inspection == 'NODE_GROUPS':
bpy.data.node_groups[atom.node_groups_field].name = name
node_group = bpy.data.node_groups[atom.node_groups_field]
error = _check_library_or_override(node_group)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
node_group.name = name
atom.node_groups_field = name
if inspection == 'PARTICLES':
bpy.data.particles[atom.particles_field].name = name
particle = bpy.data.particles[atom.particles_field]
error = _check_library_or_override(particle)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
particle.name = name
atom.particles_field = name
if inspection == 'TEXTURES':
bpy.data.textures[atom.textures_field].name = name
texture = bpy.data.textures[atom.textures_field]
error = _check_library_or_override(texture)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
texture.name = name
atom.textures_field = name
if inspection == 'WORLDS':
bpy.data.worlds[atom.worlds_field].name = name
world = bpy.data.worlds[atom.worlds_field]
error = _check_library_or_override(world)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
world.name = name
atom.worlds_field = name
atom.rename_field = ""
@@ -172,44 +219,72 @@ class ATOMIC_OT_inspection_replace(bpy.types.Operator):
if inspection == 'IMAGES' and \
atom.replace_field in bpy.data.images.keys():
bpy.data.images[atom.images_field].user_remap(
bpy.data.images[atom.replace_field])
image = bpy.data.images[atom.images_field]
error = _check_library_or_override(image)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
image.user_remap(bpy.data.images[atom.replace_field])
atom.images_field = atom.replace_field
if inspection == 'LIGHTS' and \
atom.replace_field in bpy.data.lights.keys():
bpy.data.lights[atom.lights_field].user_remap(
bpy.data.lights[atom.replace_field])
light = bpy.data.lights[atom.lights_field]
error = _check_library_or_override(light)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
light.user_remap(bpy.data.lights[atom.replace_field])
atom.lights_field = atom.replace_field
if inspection == 'MATERIALS' and \
atom.replace_field in bpy.data.materials.keys():
bpy.data.materials[atom.materials_field].user_remap(
bpy.data.materials[atom.replace_field])
material = bpy.data.materials[atom.materials_field]
error = _check_library_or_override(material)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
material.user_remap(bpy.data.materials[atom.replace_field])
atom.materials_field = atom.replace_field
if inspection == 'NODE_GROUPS' and \
atom.replace_field in bpy.data.node_groups.keys():
bpy.data.node_groups[atom.node_groups_field].user_remap(
bpy.data.node_groups[atom.replace_field])
node_group = bpy.data.node_groups[atom.node_groups_field]
error = _check_library_or_override(node_group)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
node_group.user_remap(bpy.data.node_groups[atom.replace_field])
atom.node_groups_field = atom.replace_field
if inspection == 'PARTICLES' and \
atom.replace_field in bpy.data.particles.keys():
bpy.data.particles[atom.particles_field].user_remap(
bpy.data.particles[atom.replace_field])
particle = bpy.data.particles[atom.particles_field]
error = _check_library_or_override(particle)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
particle.user_remap(bpy.data.particles[atom.replace_field])
atom.particles_field = atom.replace_field
if inspection == 'TEXTURES' and \
atom.replace_field in bpy.data.textures.keys():
bpy.data.textures[atom.textures_field].user_remap(
bpy.data.textures[atom.replace_field])
texture = bpy.data.textures[atom.textures_field]
error = _check_library_or_override(texture)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
texture.user_remap(bpy.data.textures[atom.replace_field])
atom.textures_field = atom.replace_field
if inspection == 'WORLDS' and \
atom.replace_field in bpy.data.worlds.keys():
bpy.data.worlds[atom.worlds_field].user_remap(
bpy.data.worlds[atom.replace_field])
world = bpy.data.worlds[atom.worlds_field]
error = _check_library_or_override(world)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
world.user_remap(bpy.data.worlds[atom.replace_field])
atom.worlds_field = atom.replace_field
atom.replace_field = ""
@@ -232,38 +307,59 @@ class ATOMIC_OT_inspection_toggle_fake_user(bpy.types.Operator):
if inspection == 'IMAGES':
image = bpy.data.images[atom.images_field]
bpy.data.images[atom.images_field].use_fake_user = \
not image.use_fake_user
error = _check_library_or_override(image)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
image.use_fake_user = not image.use_fake_user
if inspection == 'LIGHTS':
light = bpy.data.lights[atom.lights_field]
bpy.data.lights[atom.lights_field].use_fake_user = \
not light.use_fake_user
error = _check_library_or_override(light)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
light.use_fake_user = not light.use_fake_user
if inspection == 'MATERIALS':
material = bpy.data.materials[atom.materials_field]
bpy.data.materials[atom.materials_field].use_fake_user = \
not material.use_fake_user
error = _check_library_or_override(material)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
material.use_fake_user = not material.use_fake_user
if inspection == 'NODE_GROUPS':
node_group = bpy.data.node_groups[atom.node_groups_field]
bpy.data.node_groups[atom.node_groups_field].use_fake_user = \
not node_group.use_fake_user
error = _check_library_or_override(node_group)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
node_group.use_fake_user = not node_group.use_fake_user
if inspection == 'PARTICLES':
particle = bpy.data.particles[atom.particles_field]
bpy.data.particles[atom.particles_field].use_fake_user = \
not particle.use_fake_user
error = _check_library_or_override(particle)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
particle.use_fake_user = not particle.use_fake_user
if inspection == 'TEXTURES':
texture = bpy.data.textures[atom.textures_field]
bpy.data.textures[atom.textures_field].use_fake_user = \
not texture.use_fake_user
error = _check_library_or_override(texture)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
texture.use_fake_user = not texture.use_fake_user
if inspection == 'WORLDS':
world = bpy.data.worlds[atom.worlds_field]
bpy.data.worlds[atom.worlds_field].use_fake_user = \
not world.use_fake_user
error = _check_library_or_override(world)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
world.use_fake_user = not world.use_fake_user
return {'FINISHED'}
@@ -283,6 +379,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
collections = bpy.data.collections
if key in collections.keys():
collection = collections[key]
error = _check_library_or_override(collection)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.collection(key)
atom.collections_field = copy_key
@@ -291,6 +392,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
images = bpy.data.images
if key in images.keys():
image = images[key]
error = _check_library_or_override(image)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.image(key)
atom.images_field = copy_key
@@ -299,6 +405,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
lights = bpy.data.lights
if key in lights.keys():
light = lights[key]
error = _check_library_or_override(light)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.light(key)
atom.lights_field = copy_key
@@ -307,6 +418,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
materials = bpy.data.materials
if key in materials.keys():
material = materials[key]
error = _check_library_or_override(material)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.material(key)
atom.materials_field = copy_key
@@ -315,6 +431,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
node_groups = bpy.data.node_groups
if key in node_groups.keys():
node_group = node_groups[key]
error = _check_library_or_override(node_group)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.node_group(key)
atom.node_groups_field = copy_key
@@ -323,6 +444,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
particles = bpy.data.particles
if key in particles.keys():
particle = particles[key]
error = _check_library_or_override(particle)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.particle(key)
atom.particles_field = copy_key
@@ -331,6 +457,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
textures = bpy.data.textures
if key in textures.keys():
texture = textures[key]
error = _check_library_or_override(texture)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.texture(key)
atom.textures_field = copy_key
@@ -339,6 +470,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
worlds = bpy.data.worlds
if key in worlds.keys():
world = worlds[key]
error = _check_library_or_override(world)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
copy_key = duplicate.world(key)
atom.worlds_field = copy_key
@@ -360,6 +496,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
collections = bpy.data.collections
if key in collections.keys():
collection = collections[key]
error = _check_library_or_override(collection)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.collection(key)
atom.collections_field = ""
@@ -368,6 +509,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
images = bpy.data.images
if key in images.keys():
image = images[key]
error = _check_library_or_override(image)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.image(key)
atom.images_field = ""
@@ -376,6 +522,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
lights = bpy.data.lights
if key in lights.keys():
light = lights[key]
error = _check_library_or_override(light)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.light(key)
atom.lights_field = ""
@@ -384,6 +535,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
materials = bpy.data.materials
if key in materials.keys():
material = materials[key]
error = _check_library_or_override(material)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.material(key)
atom.materials_field = ""
@@ -392,6 +548,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
node_groups = bpy.data.node_groups
if key in node_groups.keys():
node_group = node_groups[key]
error = _check_library_or_override(node_group)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.node_group(key)
atom.node_groups_field = ""
@@ -399,6 +560,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
key = atom.particles_field
particles = bpy.data.particles
if key in particles.keys():
particle = particles[key]
error = _check_library_or_override(particle)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.particle(key)
atom.particles_field = ""
@@ -407,6 +573,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
textures = bpy.data.textures
if key in textures.keys():
texture = textures[key]
error = _check_library_or_override(texture)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.texture(key)
atom.textures_field = ""
@@ -415,6 +586,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
worlds = bpy.data.worlds
if key in worlds.keys():
world = worlds[key]
error = _check_library_or_override(world)
if error:
self.report({'ERROR'}, error)
return {'CANCELLED'}
delete.world(key)
atom.worlds_field = ""
@@ -437,4 +613,4 @@ def register():
def unregister():
for item in reg_list:
unregister_class(item)
compat.safe_unregister_class(item)
@@ -26,8 +26,9 @@ various selection operations.
import bpy
from bpy.utils import register_class
from bpy.utils import unregister_class
from ..utils import compat
from ..stats import unused
from ..stats import unused_parallel
from .utils import clean
from .utils import nuke
from ..ui.utils import ui_layouts
@@ -57,7 +58,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel collections property is toggled
if atom.collections:
collections = sorted(bpy.data.collections.keys())
from ..utils import compat
collections = sorted([c.name for c in bpy.data.collections
if not compat.is_library_or_override(c)])
ui_layouts.box_list(
layout=layout,
title="Collections",
@@ -67,7 +70,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel images property is toggled
if atom.images:
images = sorted(bpy.data.images.keys())
from ..utils import compat
images = sorted([i.name for i in bpy.data.images
if not compat.is_library_or_override(i)])
ui_layouts.box_list(
layout=layout,
title="Images",
@@ -77,7 +82,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel lights property is toggled
if atom.lights:
lights = sorted(bpy.data.lights.keys())
from ..utils import compat
lights = sorted([l.name for l in bpy.data.lights
if not compat.is_library_or_override(l)])
ui_layouts.box_list(
layout=layout,
title="Lights",
@@ -87,7 +94,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel materials property is toggled
if atom.materials:
materials = sorted(bpy.data.materials.keys())
from ..utils import compat
materials = sorted([m.name for m in bpy.data.materials
if not compat.is_library_or_override(m)])
ui_layouts.box_list(
layout=layout,
title="Materials",
@@ -97,7 +106,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel node groups property is toggled
if atom.node_groups:
node_groups = sorted(bpy.data.node_groups.keys())
from ..utils import compat
node_groups = sorted([ng.name for ng in bpy.data.node_groups
if not compat.is_library_or_override(ng)])
ui_layouts.box_list(
layout=layout,
title="Node Groups",
@@ -107,7 +118,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel particle systems property is toggled
if atom.particles:
particles = sorted(bpy.data.particles.keys())
from ..utils import compat
particles = sorted([p.name for p in bpy.data.particles
if not compat.is_library_or_override(p)])
ui_layouts.box_list(
layout=layout,
title="Particle Systems",
@@ -117,7 +130,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel textures property is toggled
if atom.textures:
textures = sorted(bpy.data.textures.keys())
from ..utils import compat
textures = sorted([t.name for t in bpy.data.textures
if not compat.is_library_or_override(t)])
ui_layouts.box_list(
layout=layout,
title="Textures",
@@ -127,7 +142,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
# display when the main panel worlds property is toggled
if atom.worlds:
worlds = sorted(bpy.data.worlds.keys())
from ..utils import compat
worlds = sorted([w.name for w in bpy.data.worlds
if not compat.is_library_or_override(w)])
ui_layouts.box_list(
layout=layout,
title="Worlds",
@@ -184,8 +201,10 @@ class ATOMIC_OT_clean(bpy.types.Operator):
unused_lights = []
unused_materials = []
unused_node_groups = []
unused_objects = []
unused_particles = []
unused_textures = []
unused_armatures = []
unused_worlds = []
def draw(self, context):
@@ -197,8 +216,9 @@ class ATOMIC_OT_clean(bpy.types.Operator):
# display if no main panel properties are toggled
if not (atom.collections or atom.images or atom.lights or
atom.materials or atom.node_groups or atom.particles
or atom.textures or atom.worlds):
atom.materials or atom.node_groups or atom.objects or
atom.particles or atom.textures or atom.armatures or
atom.worlds):
ui_layouts.box_list(
layout=layout,
@@ -249,6 +269,15 @@ class ATOMIC_OT_clean(bpy.types.Operator):
icon="NODETREE"
)
# display when the main panel objects property is toggled
if atom.objects:
ui_layouts.box_list(
layout=layout,
title="Objects",
items=self.unused_objects,
icon="OBJECT_DATA"
)
# display when the main panel particle systems property is toggled
if atom.particles:
ui_layouts.box_list(
@@ -260,14 +289,22 @@ class ATOMIC_OT_clean(bpy.types.Operator):
# display when the main panel textures property is toggled
if atom.textures:
textures = sorted(unused.textures_deep())
ui_layouts.box_list(
layout=layout,
title="Textures",
items=textures,
items=self.unused_textures,
icon="TEXTURE"
)
# display when the main panel armatures property is toggled
if atom.armatures:
ui_layouts.box_list(
layout=layout,
title="Armatures",
items=self.unused_armatures,
icon="ARMATURE_DATA"
)
# display when the main panel worlds property is toggled
if atom.worlds:
ui_layouts.box_list(
@@ -297,12 +334,18 @@ class ATOMIC_OT_clean(bpy.types.Operator):
if atom.node_groups:
clean.node_groups()
if atom.objects:
clean.objects()
if atom.particles:
clean.particles()
if atom.textures:
clean.textures()
if atom.armatures:
clean.armatures()
if atom.worlds:
clean.worlds()
@@ -314,29 +357,38 @@ class ATOMIC_OT_clean(bpy.types.Operator):
wm = context.window_manager
atom = bpy.context.scene.atomic
# Use parallel execution for better performance
all_unused = unused_parallel.get_all_unused_parallel()
if atom.collections:
self.unused_collections = unused.collections_deep()
self.unused_collections = all_unused['collections']
if atom.images:
self.unused_images = unused.images_deep()
self.unused_images = all_unused['images']
if atom.lights:
self.unused_lights = unused.lights_deep()
self.unused_lights = all_unused['lights']
if atom.materials:
self.unused_materials = unused.materials_deep()
self.unused_materials = all_unused['materials']
if atom.node_groups:
self.unused_node_groups = unused.node_groups_deep()
self.unused_node_groups = all_unused['node_groups']
if atom.objects:
self.unused_objects = all_unused['objects']
if atom.particles:
self.unused_particles = unused.particles_deep()
self.unused_particles = all_unused['particles']
if atom.textures:
self.unused_textures = unused.textures_deep()
self.unused_textures = all_unused['textures']
if atom.armatures:
self.unused_armatures = all_unused['armatures']
if atom.worlds:
self.unused_worlds = unused.worlds()
self.unused_worlds = all_unused['worlds']
return wm.invoke_props_dialog(self)
@@ -359,30 +411,20 @@ class ATOMIC_OT_smart_select(bpy.types.Operator):
bl_label = "Smart Select"
def execute(self, context):
bpy.context.scene.atomic.collections = \
any(unused.collections_deep())
bpy.context.scene.atomic.images = \
any(unused.images_deep())
bpy.context.scene.atomic.lights = \
any(unused.lights_deep())
bpy.context.scene.atomic.materials = \
any(unused.materials_deep())
bpy.context.scene.atomic.node_groups = \
any(unused.node_groups_deep())
bpy.context.scene.atomic.particles = \
any(unused.particles_deep())
bpy.context.scene.atomic.textures = \
any(unused.textures_deep())
bpy.context.scene.atomic.worlds = \
any(unused.worlds())
# Use parallel execution for better performance
unused_flags = unused_parallel.get_unused_for_smart_select()
atom = bpy.context.scene.atomic
atom.collections = unused_flags['collections']
atom.images = unused_flags['images']
atom.lights = unused_flags['lights']
atom.materials = unused_flags['materials']
atom.node_groups = unused_flags['node_groups']
atom.objects = unused_flags['objects']
atom.particles = unused_flags['particles']
atom.textures = unused_flags['textures']
atom.armatures = unused_flags['armatures']
atom.worlds = unused_flags['worlds']
return {'FINISHED'}
@@ -441,4 +483,4 @@ def register():
def unregister():
for item in reg_list:
unregister_class(item)
compat.safe_unregister_class(item)
@@ -31,7 +31,7 @@ attempting to reload missing project files.
import bpy
from bpy.utils import register_class
from bpy.utils import unregister_class
from ..utils import compat
from ..stats import missing
from ..ui.utils import ui_layouts
@@ -192,4 +192,4 @@ def register():
def unregister():
for item in reg_list:
unregister_class(item)
compat.safe_unregister_class(item)
@@ -28,7 +28,7 @@ support page in the web browser.
import bpy
import webbrowser
from bpy.utils import register_class
from bpy.utils import unregister_class
from ..utils import compat
# Atomic Data Manager Open Support Me Operator
@@ -52,4 +52,4 @@ def register():
def unregister():
for cls in reg_list:
unregister_class(cls)
compat.safe_unregister_class(cls)
@@ -72,3 +72,15 @@ def worlds():
# removes all unused worlds from the project
for world_key in unused.worlds():
bpy.data.worlds.remove(bpy.data.worlds[world_key])
def objects():
# removes all unused objects from the project
for object_key in unused.objects_deep():
bpy.data.objects.remove(bpy.data.objects[object_key])
def armatures():
# removes all unused armatures from the project
for armature_key in unused.armatures_deep():
bpy.data.armatures.remove(bpy.data.armatures[armature_key])
@@ -24,11 +24,18 @@ data categories.
"""
import bpy
from ...utils import compat
def nuke_data(data):
# removes all data-blocks from the indicated set of data
# Skip library-linked and override datablocks
keys_to_remove = []
for key in data.keys():
datablock = data[key]
if not compat.is_library_or_override(datablock):
keys_to_remove.append(key)
for key in keys_to_remove:
data.remove(data[key])