diff --git a/entry.py b/entry.py index dbffc9f..5c80e0e 100644 --- a/entry.py +++ b/entry.py @@ -8,6 +8,8 @@ import template.__init__ +# TODO: Make this autoload everything. importlib.reload(template.__init__) - +importlib.reload(template.template_panel) + template.__init__.register() diff --git a/generate_addon.py b/generate_addon.py new file mode 100644 index 0000000..901b3c0 --- /dev/null +++ b/generate_addon.py @@ -0,0 +1 @@ +addon_name = "test_addon" \ No newline at end of file diff --git a/template/__init__.py b/template/__init__.py index f98e254..79f04be 100644 --- a/template/__init__.py +++ b/template/__init__.py @@ -1,15 +1,10 @@ -from . import auto_load +from . import template_panel -print("Loading template") +print("Running template/__init__.py") def register(): - print("Registering template") - auto_load.test() - + template_panel.register() def unregister(): - auto_load.unregister() - - - - + template_panel.unregister() + \ No newline at end of file diff --git a/template/auto_load.py b/template/auto_load.py deleted file mode 100644 index 9f9daf7..0000000 --- a/template/auto_load.py +++ /dev/null @@ -1,155 +0,0 @@ -import os -import bpy -import sys -import typing -import inspect -import pkgutil -import importlib -from pathlib import Path - -blender_version = bpy.app.version - -modules = None -ordered_classes = None - -def test(): - print("Hello from auto_load.py") - -def init(): - global modules, ordered_classes - modules = get_all_submodules(Path(__file__).parent) - ordered_classes = get_ordered_classes_to_register(modules) - - -def register(): - # Check if class is already registered before registering it - for cls in ordered_classes: - try: - bpy.utils.register_class(cls) - except: - print("Failed to register", cls) - - for module in modules: - if module.__name__ == __name__: - continue - if hasattr(module, "register"): - module.register() - -def unregister(): - if ordered_classes is None: - return - for cls in reversed(ordered_classes): - bpy.utils.unregister_class(cls) - - for module in modules: - if module.__name__ == __name__: - continue - if hasattr(module, "unregister"): - module.unregister() - -def get_all_submodules(directory): - return list(iter_submodules(directory, directory.name)) - -def iter_submodules(path, package_name): - for name in sorted(iter_submodule_names(path)): - module = importlib.import_module(name) - try: - importlib.reload(module) - except: - pass - yield module - -def iter_submodule_names(path, root=""): - for _, module_name, is_package in pkgutil.iter_modules([str(path)]): - if is_package: - sub_path = path / module_name - sub_root = root + module_name + "." - yield from iter_submodule_names(sub_path, sub_root) - else: - yield root + module_name - -def get_ordered_classes_to_register(modules): - return toposort(get_register_deps_dict(modules)) - -def get_register_deps_dict(modules): - my_classes = set(iter_my_classes(modules)) - my_classes_by_idname = {cls.bl_idname : cls for cls in my_classes if hasattr(cls, "bl_idname")} - - deps_dict = {} - for cls in my_classes: - deps_dict[cls] = set(iter_my_register_deps(cls, my_classes, my_classes_by_idname)) - return deps_dict - -def iter_my_register_deps(cls, my_classes, my_classes_by_idname): - yield from iter_my_deps_from_annotations(cls, my_classes) - yield from iter_my_deps_from_parent_id(cls, my_classes_by_idname) - -def iter_my_deps_from_annotations(cls, my_classes): - for value in typing.get_type_hints(cls, {}, {}).values(): - dependency = get_dependency_from_annotation(value) - if dependency is not None: - if dependency in my_classes: - yield dependency - -def get_dependency_from_annotation(value): - if blender_version >= (2, 93): - if isinstance(value, bpy.props._PropertyDeferred): - return value.keywords.get("type") - else: - if isinstance(value, tuple) and len(value) == 2: - if value[0] in (bpy.props.PointerProperty, bpy.props.CollectionProperty): - return value[1]["type"] - return None - -def iter_my_deps_from_parent_id(cls, my_classes_by_idname): - if bpy.types.Panel in cls.__bases__: - parent_idname = getattr(cls, "bl_parent_id", None) - if parent_idname is not None: - parent_cls = my_classes_by_idname.get(parent_idname) - if parent_cls is not None: - yield parent_cls - -def iter_my_classes(modules): - base_types = get_register_base_types() - for cls in get_classes_in_modules(modules): - if any(base in base_types for base in cls.__bases__): - if not getattr(cls, "is_registered", False): - yield cls - else: - bpy.utils.unregister_class(cls) - yield cls - -def get_classes_in_modules(modules): - classes = set() - for module in modules: - for cls in iter_classes_in_module(module): - classes.add(cls) - return classes - -def iter_classes_in_module(module): - for value in module.__dict__.values(): - if inspect.isclass(value): - yield value - -def get_register_base_types(): - return set(getattr(bpy.types, name) for name in [ - "Panel", "Operator", "PropertyGroup", - "AddonPreferences", "Header", "Menu", - "Node", "NodeSocket", "NodeTree", - "UIList", "RenderEngine", - "Gizmo", "GizmoGroup", - ]) - -def toposort(deps_dict): - sorted_list = [] - sorted_values = set() - while len(deps_dict) > 0: - unsorted = [] - for value, deps in deps_dict.items(): - if len(deps) == 0: - sorted_list.append(value) - sorted_values.add(value) - else: - unsorted.append(value) - deps_dict = {value : deps_dict[value] - sorted_values for value in unsorted} - return sorted_list \ No newline at end of file diff --git a/template/blender_manifest.toml b/template/blender_manifest.toml index 70e2f54..1e9936b 100644 --- a/template/blender_manifest.toml +++ b/template/blender_manifest.toml @@ -5,7 +5,7 @@ schema_version = "1.0.0" id = "template" version = "1.0.0" name = "Template" -tagline = "Template for a Blender Addon" +tagline = "Template Blender Addon" maintainer = "Simon Nordon " # Supported types: "add-on", "theme" type = "add-on" diff --git a/template/readme.md b/template/readme.md new file mode 100644 index 0000000..523aba9 --- /dev/null +++ b/template/readme.md @@ -0,0 +1 @@ +Compress-Archive -Path ".\template" -DestinationPath "template.zip" -Force \ No newline at end of file diff --git a/template/template_dev_panel.py b/template/template_dev_panel.py deleted file mode 100644 index bad361f..0000000 --- a/template/template_dev_panel.py +++ /dev/null @@ -1,33 +0,0 @@ -import bpy -import auto_load - -class TemplateDevPanel(bpy.types.Panel): - bl_idname = "DEV_PT_template_dev_panel" - bl_label = "Template Dev Panel" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "Template" - - def draw(self, context): - layout = self.layout - layout.label(text="Template Panel", icon="MODIFIER") - layout.operator("dev_panel.reload_addon") - layout.operator("dev_panel.uninstall_addon") - -class ReloadAddonOperator(bpy.types.Operator): - bl_idname = "dev_panel.reload_addon" - bl_label = "Reload Addon" - - def execute(self, context): - auto_load.unregister() - auto_load.init() - auto_load.register() - return {"FINISHED"} - -class UninstallAddonOperator(bpy.types.Operator): - bl_idname = "dev_panel.uninstall_addon" - bl_label = "Uninstall Addon" - - def execute(self, context): - auto_load.unregister() - return {"FINISHED"} diff --git a/template/template_panel.py b/template/template_panel.py new file mode 100644 index 0000000..c488f8c --- /dev/null +++ b/template/template_panel.py @@ -0,0 +1,40 @@ +import bpy + +class TemplatePanel(bpy.types.Panel): + bl_idname = "OBJECT_PT_template_panel" + bl_label = "Template Panel" + bl_description = "This is a template panel, for starting a new addon." + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Template" + bl_order = 0 + + @classmethod + def poll(cls, context): + return context.object is not None + + def draw_header(self, context): + layout = self.layout + layout.label(text="", icon="OBJECT_DATA") + + def draw(self, context): + layout = self.layout + layout.operator("template.test_operator") + +class TemplateTestOperator(bpy.types.Operator): + bl_idname = "template.test_operator" + bl_label = "Testing 1, 2, 3" + + def execute(self, context): + self.report({'INFO'}, 'Hello from template panel.') + return {"FINISHED"} + +def register(): + bpy.utils.register_class(TemplatePanel) + bpy.utils.register_class(TemplateTestOperator) + +def unregister(): + bpy.utils.unregister_class(TemplatePanel) + bpy.utils.unregister_class(TemplateTestOperator) + +