2026-02-16

This commit is contained in:
2026-03-17 15:25:32 -06:00
parent d5dd373de0
commit 60100fbab2
560 changed files with 33397 additions and 20776 deletions
@@ -30,6 +30,9 @@ from ..utils import compat
from .utils import delete
from .utils import duplicate
# Module-level state for inspection delete
_inspect_delete_state = None
def _check_library_or_override(datablock):
"""Check if datablock is library-linked or override, return error message if so."""
@@ -488,115 +491,181 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
bl_label = "Delete Data-Block"
def execute(self, context):
atom = bpy.context.scene.atomic
atom = context.scene.atomic
inspection = atom.active_inspection
if inspection == 'COLLECTIONS':
key = atom.collections_field
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 = ""
elif inspection == 'IMAGES':
key = atom.images_field
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 = ""
elif inspection == 'LIGHTS':
key = atom.lights_field
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 = ""
elif inspection == 'MATERIALS':
key = atom.materials_field
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 = ""
elif inspection == 'NODE_GROUPS':
key = atom.node_groups_field
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 = ""
elif inspection == 'PARTICLES':
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 = ""
elif inspection == 'TEXTURES':
key = atom.textures_field
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 = ""
elif inspection == 'WORLDS':
key = atom.worlds_field
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 = ""
# Initialize progress tracking
atom.is_operation_running = True
atom.operation_progress = 0.0
atom.operation_status = f"Deleting {inspection.lower()}..."
atom.cancel_operation = False
# Store state in module-level variable for timer processing
global _inspect_delete_state
_inspect_delete_state = {
'inspection': inspection
}
# Start timer for processing (even though it's quick, keep UI responsive)
bpy.app.timers.register(_process_inspect_delete_step)
return {'FINISHED'}
def _process_inspect_delete_step():
"""Process inspection delete in steps to avoid blocking the UI"""
atom = bpy.context.scene.atomic
global _inspect_delete_state
if _inspect_delete_state is None:
return None
inspection = _inspect_delete_state['inspection']
# Check for cancellation
if atom.cancel_operation:
atom.is_operation_running = False
atom.operation_progress = 0.0
atom.operation_status = "Operation cancelled"
atom.cancel_operation = False
_inspect_delete_state = None
# Force UI update
for area in bpy.context.screen.areas:
area.tag_redraw()
return None
atom.operation_progress = 50.0
# Perform deletion
try:
if inspection == 'COLLECTIONS':
key = atom.collections_field
collections = bpy.data.collections
if key in collections.keys():
collection = collections[key]
error = _check_library_or_override(collection)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.collection(key)
atom.collections_field = ""
elif inspection == 'IMAGES':
key = atom.images_field
images = bpy.data.images
if key in images.keys():
image = images[key]
error = _check_library_or_override(image)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.image(key)
atom.images_field = ""
elif inspection == 'LIGHTS':
key = atom.lights_field
lights = bpy.data.lights
if key in lights.keys():
light = lights[key]
error = _check_library_or_override(light)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.light(key)
atom.lights_field = ""
elif inspection == 'MATERIALS':
key = atom.materials_field
materials = bpy.data.materials
if key in materials.keys():
material = materials[key]
error = _check_library_or_override(material)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.material(key)
atom.materials_field = ""
elif inspection == 'NODE_GROUPS':
key = atom.node_groups_field
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:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.node_group(key)
atom.node_groups_field = ""
elif inspection == 'PARTICLES':
key = atom.particles_field
particles = bpy.data.particles
if key in particles.keys():
particle = particles[key]
error = _check_library_or_override(particle)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.particle(key)
atom.particles_field = ""
elif inspection == 'TEXTURES':
key = atom.textures_field
textures = bpy.data.textures
if key in textures.keys():
texture = textures[key]
error = _check_library_or_override(texture)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.texture(key)
atom.textures_field = ""
elif inspection == 'WORLDS':
key = atom.worlds_field
worlds = bpy.data.worlds
if key in worlds.keys():
world = worlds[key]
error = _check_library_or_override(world)
if error:
atom.is_operation_running = False
atom.operation_status = ""
return None
delete.world(key)
atom.worlds_field = ""
except:
pass # Handle any errors gracefully
# Operation complete
atom.is_operation_running = False
atom.operation_progress = 100.0
atom.operation_status = ""
# Clear state
_inspect_delete_state = None
# Force UI update
for area in bpy.context.screen.areas:
area.tag_redraw()
return None # Stop timer
reg_list = [
ATOMIC_OT_inspection_rename,
ATOMIC_OT_inspection_replace,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -26,61 +26,131 @@ import bpy
from ...stats import unused
def collections():
def collections(cached_list=None):
# removes all unused collections from the project
for collection_key in unused.collections_deep():
bpy.data.collections.remove(bpy.data.collections[collection_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
collection_keys = cached_list
else:
collection_keys = unused.collections_deep()
for collection_key in collection_keys:
if collection_key in bpy.data.collections:
bpy.data.collections.remove(bpy.data.collections[collection_key])
def images():
def images(cached_list=None):
# removes all unused images from the project
for image_key in unused.images_deep():
bpy.data.images.remove(bpy.data.images[image_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
image_keys = cached_list
else:
image_keys = unused.images_deep()
for image_key in image_keys:
if image_key in bpy.data.images:
bpy.data.images.remove(bpy.data.images[image_key])
def lights():
def lights(cached_list=None):
# removes all unused lights from the project
for light_key in unused.lights_deep():
bpy.data.lights.remove(bpy.data.lights[light_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
light_keys = cached_list
else:
light_keys = unused.lights_deep()
for light_key in light_keys:
if light_key in bpy.data.lights:
bpy.data.lights.remove(bpy.data.lights[light_key])
def materials():
def materials(cached_list=None):
# removes all unused materials from the project
for light_key in unused.materials_deep():
bpy.data.materials.remove(bpy.data.materials[light_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
material_keys = cached_list
else:
material_keys = unused.materials_deep()
for material_key in material_keys:
if material_key in bpy.data.materials:
bpy.data.materials.remove(bpy.data.materials[material_key])
def node_groups():
def node_groups(cached_list=None):
# removes all unused node groups from the project
for node_group_key in unused.node_groups_deep():
bpy.data.node_groups.remove(bpy.data.node_groups[node_group_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
node_group_keys = cached_list
else:
node_group_keys = unused.node_groups_deep()
for node_group_key in node_group_keys:
if node_group_key in bpy.data.node_groups:
bpy.data.node_groups.remove(bpy.data.node_groups[node_group_key])
def particles():
def particles(cached_list=None):
# removes all unused particle systems from the project
for particle_key in unused.particles_deep():
bpy.data.particles.remove(bpy.data.particles[particle_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
particle_keys = cached_list
else:
particle_keys = unused.particles_deep()
for particle_key in particle_keys:
if particle_key in bpy.data.particles:
bpy.data.particles.remove(bpy.data.particles[particle_key])
def textures():
def textures(cached_list=None):
# removes all unused textures from the project
for texture_key in unused.textures_deep():
bpy.data.textures.remove(bpy.data.textures[texture_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
texture_keys = cached_list
else:
texture_keys = unused.textures_deep()
for texture_key in texture_keys:
if texture_key in bpy.data.textures:
bpy.data.textures.remove(bpy.data.textures[texture_key])
def worlds():
def worlds(cached_list=None):
# removes all unused worlds from the project
for world_key in unused.worlds():
bpy.data.worlds.remove(bpy.data.worlds[world_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
world_keys = cached_list
else:
world_keys = unused.worlds()
for world_key in world_keys:
if world_key in bpy.data.worlds:
bpy.data.worlds.remove(bpy.data.worlds[world_key])
def objects():
def objects(cached_list=None):
# removes all unused objects from the project
for object_key in unused.objects_deep():
bpy.data.objects.remove(bpy.data.objects[object_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
object_keys = cached_list
else:
object_keys = unused.objects_deep()
for object_key in object_keys:
if object_key in bpy.data.objects:
bpy.data.objects.remove(bpy.data.objects[object_key])
def armatures():
def armatures(cached_list=None):
# removes all unused armatures from the project
for armature_key in unused.armatures_deep():
bpy.data.armatures.remove(bpy.data.armatures[armature_key])
# If cached_list is provided, use it instead of recalculating
if cached_list is not None:
armature_keys = cached_list
else:
armature_keys = unused.armatures_deep()
for armature_key in armature_keys:
if armature_key in bpy.data.armatures:
bpy.data.armatures.remove(bpy.data.armatures[armature_key])