Files
blender-portable-repo/scripts/addons/blender_log/operators/better_delete.py
T
2026-03-17 14:58:51 -06:00

171 lines
5.6 KiB
Python

# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
#
# SPDX-License-Identifier: GPL-3.0-or-later
import bpy
from typing import List
from ..hotkeys import addon_hotkey_register
from ..util import get_addon_prefs
class OBJECT_OT_blenlog_unlink_from_scene(bpy.types.Operator):
bl_idname = "object.blenlog_unlink_from_scene"
bl_label = "Unlink Selected From Scene"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
if context.area.type == 'OUTLINER':
return bool(get_objects_to_unlink(context) or get_collections_to_unlink(context))
elif context.area.type == 'VIEW_3D':
return bool(get_objects_to_unlink(context))
def execute(self, context):
unlink_collections_from_scene(get_collections_to_unlink(context), context.scene)
unlink_objects_from_scene(get_objects_to_unlink(context), context.scene)
return {'FINISHED'}
class OUTLINER_OT_blenlog_better_delete(bpy.types.Operator):
bl_idname = "outliner.blenlog_better_delete"
bl_label = "Delete Datablocks From File"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return context.area.type == 'OUTLINER' and context.selected_ids
def execute(self, context):
if context.scene in context.selected_ids:
self.report({'ERROR'}, "Cannot delete active Scene.")
return {'CANCELLED'}
if context.workspace in context.selected_ids:
self.report({'ERROR'}, "Cannot delete active Workspace.")
return {'CANCELLED'}
for id in context.selected_ids:
if id.id_type in {'SCREEN', 'WINDOWMANAGER'}:
self.report({'ERROR'}, f"Cannot delete type: {id.id_type}")
return {'CANCELLED'}
count = len(context.selected_ids)
plural = "s" if count>1 else ""
bpy.data.batch_remove(context.selected_ids)
self.report({'INFO'}, f"Deleted {count} datablock{plural}.")
return {'FINISHED'}
def get_objects_to_unlink(context) -> List[bpy.types.Object]:
if context.area.type == 'OUTLINER':
selected_objs = [id for id in context.selected_ids if type(id) == bpy.types.Object]
elif context.area.type == 'VIEW_3D':
selected_objs = context.selected_objects
scene_objs = set(context.scene.objects)
return [ob for ob in selected_objs if ob in scene_objs]
def unlink_objects_from_scene(objects, scene):
for obj in objects:
for coll in [scene.collection] + scene.collection.children_recursive:
if obj.name in coll.objects:
coll.objects.unlink(obj)
def get_collections_to_unlink(context) -> List[bpy.types.Collection]:
if context.area.type == 'OUTLINER':
return [id for id in context.selected_ids if type(id) == bpy.types.Collection]
elif context.area.type == 'VIEW_3D':
return []
def unlink_collections_from_scene(collections_to_unlink, scene):
for coll_to_unlink in collections_to_unlink:
for coll in scene.collection.children_recursive:
if coll_to_unlink.name in coll.children:
coll.children.unlink(coll_to_unlink)
class OBJECT_MT_delete_pie(bpy.types.Menu):
# bl_label is displayed at the center of the pie menu
bl_label = 'Unlink / Delete'
bl_idname = 'OBJECT_MT_delete_pie'
@classmethod
def poll(cls, context):
return context.area.type in {'VIEW_3D', 'OUTLINER'}
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
# <
pie.operator(OBJECT_OT_blenlog_unlink_from_scene.bl_idname, icon='TRASH', text="Unlink From Scene")
if context.area.type == 'VIEW_3D':
# > 3D View
op = pie.operator('object.delete', icon='X', text="Delete From File")
op.use_global = True
op.confirm = False
return
# >
pie.operator('outliner.blenlog_better_delete', icon='X', text="Delete From File")
# V
pie.operator('outliner.id_operation', text="Unlink From Collection", icon="OUTLINER_COLLECTION").type='UNLINK'
# ^
pie.operator('outliner.delete', text="Delete Hierarchy", icon="OUTLINER").hierarchy=True
registry = [
OBJECT_OT_blenlog_unlink_from_scene,
OUTLINER_OT_blenlog_better_delete,
OBJECT_MT_delete_pie
]
addon_hotkeys = []
def register_hotkeys():
addon_hotkeys.append(
addon_hotkey_register(
op_idname='wm.call_menu_pie',
keymap_name='Outliner',
key_id='X',
op_kwargs={'name': OBJECT_MT_delete_pie.bl_idname},
add_on_conflict=True,
warn_on_conflict=False,
error_on_conflict=False,
)
)
addon_hotkeys.append(
addon_hotkey_register(
op_idname='wm.call_menu_pie',
keymap_name='Object Mode',
key_id='X',
op_kwargs={'name': OBJECT_MT_delete_pie.bl_idname},
add_on_conflict=True,
warn_on_conflict=False,
error_on_conflict=False,
)
)
def delayed_hotkey_register():
"""We want to register hotkeys when Blender opens, but
only is the user preference is enabled.
And we can't access the user preference during registration, so
we gotta use a timer to do it with a delay.
"""
if get_addon_prefs().use_deletion_pie and addon_hotkeys == []:
register_hotkeys()
def unregister_hotkeys():
global addon_hotkeys
for keymap, kmi in addon_hotkeys:
keymap.keymap_items.remove(kmi)
addon_hotkeys = []
def register():
bpy.app.timers.register(delayed_hotkey_register)
def unregister():
unregister_hotkeys()