# registry.py import bpy from typing import Any, Callable _bpy_class_registry: list[type] = [] _timer_registry: list[Callable[..., int | None]] = [] def setup_bpy_annotations(cls: type) -> type: if not hasattr(cls, "__annotations__"): cls.__annotations__ = {} for name, val in list(cls.__dict__.items()): val_type_name = type(val).__name__ if "PropertyDeferred" in val_type_name or val_type_name.startswith("_Property") or (isinstance(val, tuple) and len(val) > 0 and "Property" in type(val[0]).__name__): cls.__annotations__[name] = val try: delattr(cls, name) except (AttributeError, TypeError): pass return cls # BPY CLASSES def register_class(cls: type) -> type: setup_bpy_annotations(cls) if cls not in _bpy_class_registry: _bpy_class_registry.append(cls) return cls def get() -> list[type]: return list(_bpy_class_registry) def get_label_by_name(name: str) -> str: for cls in get(): if cls.__name__ == name: return getattr(cls, "bl_label", "No Label") return '' def get_class_by_name(name: str) -> type | None: for cls in get(): if cls.__name__ == name: return cls return None def blender_register_classes(): for cls in _bpy_class_registry: try: setup_bpy_annotations(cls) bpy.utils.register_class(cls) except Exception as e: print(f"Nodeslicer: Failed to register {cls}: {e}") def blender_unregister_classes(): for cls in reversed(_bpy_class_registry): try: bpy.utils.unregister_class(cls) except Exception: pass # TIMERS def register_timer(clb: Callable[..., Any]): _timer_registry.append(clb) return clb def get_timers() -> list[Callable[..., int | None]]: return list(_timer_registry) def blender_register_timers(): for timer in _timer_registry: bpy.app.timers.register(timer, persistent=True) def blender_unregister_timers(): for timer in _timer_registry: bpy.app.timers.unregister(timer) import os try: from bpy.utils.previews import ImagePreviewCollection except ImportError: ImagePreviewCollection = Any # type: ignore _icons_pcoll: ImagePreviewCollection | None = None def blender_register_icons(): global _icons_pcoll _icons_pcoll = bpy.utils.previews.new() my_icons_dir = os.path.join(os.path.dirname(__file__), "icons") for filename in os.listdir(my_icons_dir): _icons_pcoll.load(filename, os.path.join(my_icons_dir, filename), 'IMAGE') def blender_unregister_icons(): global _icons_pcoll if not _icons_pcoll: return bpy.utils.previews.remove(_icons_pcoll) del _icons_pcoll def get_icon(icon_id: str) -> int: global _icons_pcoll if not _icons_pcoll: return -1 return _icons_pcoll[icon_id].icon_id