From 5ac96cb5b9829dcc9d3ca53e6dfaf60825e2a211 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 3 Apr 2024 15:42:23 +0500 Subject: [PATCH] change .poll for overridden panels instead of creating new classes Needed to avoid errors disabling addons that have overridden panels --- src/blenderbim/blenderbim/bim/__init__.py | 20 +++++++---- src/blenderbim/blenderbim/bim/handler.py | 41 ++++++++--------------- src/blenderbim/blenderbim/tool/blender.py | 8 +++-- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index f8cc59abbb..a9606d8ed4 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -23,6 +23,7 @@ import bpy.utils.previews import blenderbim import importlib from . import handler, ui, prop, operator, helper +from typing import Callable, Union try: from blenderbim.translations import translations_dict @@ -187,7 +188,7 @@ addon_keymaps = [] icons = None is_registering = False last_commit_hash = "8888888" -overridden_scene_panels = dict() +original_scene_panels_polls: dict[bpy.types.Panel, Union[Callable, None]] = dict() def on_register(scene): @@ -295,10 +296,17 @@ def unregister(): km.keymap_items.remove(kmi) addon_keymaps.clear() - for panel in tuple(overridden_scene_panels.keys()): - original_panel, override_panel = overridden_scene_panels[panel] - bpy.utils.unregister_class(override_panel) - bpy.utils.register_class(original_panel) - del overridden_scene_panels[panel] + for panel, poll in tuple(original_scene_panels_polls.items()): + if poll is None: + del panel.poll + else: + panel.poll = poll + # panel might be already unregisterd during blender exit + # or if it's addon was disabled + if panel.is_registered: + # reregister to activate new poll + bpy.utils.unregister_class(panel) + bpy.utils.register_class(panel) + del original_scene_panels_polls[panel] bpy.app.translations.unregister("blenderbim") diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 5f8c81dba4..32782b9537 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -260,34 +260,25 @@ def poll_check_blender_tab(cls, context): return tool.Blender.is_tab(context, "BLENDER") -def get_override_scene_panel(panel_name): - original_panel = getattr(bpy.types, panel_name) - - override_panel = type(f"Override_{panel_name}", (original_panel,), {}) - override_panel.bl_idname = f"{panel_name}_override" - - # some blender panel depend on other and register_class will throw an error - # if we won't override their `bl_parent_id` - bl_parent_id = getattr(override_panel, "bl_parent_id", None) - if bl_parent_id is not None: - override_panel.bl_parent_id = f"{bl_parent_id}_override" +def override_scene_panel(original_panel: bpy.types.Panel) -> None: + polls = blenderbim.bim.original_scene_panels_polls # override poll method - poll = getattr(override_panel, "poll", None) - if poll is None: - override_panel.poll = poll_check_blender_tab + if not hasattr(original_panel, "poll"): + polls[original_panel] = None + original_panel.poll = poll_check_blender_tab else: + polls[original_panel] = original_panel.poll @classmethod def wrapped_poll(cls, context): - return super(override_panel, cls).poll(context) and poll_check_blender_tab.__func__(cls, context) + return polls[cls](context) and poll_check_blender_tab.__func__(cls, context) - override_panel.poll = wrapped_poll + original_panel.poll = wrapped_poll - return override_panel - - -OVERRIDE_SCENE_PANELS = tool.Blender.get_scene_panels_list() + # reregister to activate new poll + bpy.utils.unregister_class(original_panel) + bpy.utils.register_class(original_panel) @persistent @@ -328,12 +319,8 @@ def load_post(scene): # To improve usability for new users, we hijack the scene properties # tab. We override default scene properties panels with our own poll # to hide them unless the user has chosen to view Blender properties. - for panel in OVERRIDE_SCENE_PANELS: - if panel in blenderbim.bim.overridden_scene_panels: + for panel in tool.Blender.get_scene_panels_list(): + if panel in blenderbim.bim.original_scene_panels_polls: continue - override_panel = get_override_scene_panel(panel) - original_panel = getattr(bpy.types, panel) - bpy.utils.register_class(override_panel) - bpy.utils.unregister_class(original_panel) - blenderbim.bim.overridden_scene_panels[panel] = (original_panel, override_panel) + override_scene_panel(panel) tool.Blender.setup_tabs() diff --git a/src/blenderbim/blenderbim/tool/blender.py b/src/blenderbim/blenderbim/tool/blender.py index ba5bf6ff2a..51399db0a3 100644 --- a/src/blenderbim/blenderbim/tool/blender.py +++ b/src/blenderbim/blenderbim/tool/blender.py @@ -877,7 +877,7 @@ class Blender(blenderbim.core.tool.Blender): pass @classmethod - def get_scene_panels_list(cls) -> tuple[str, ...]: + def get_scene_panels_list(cls) -> tuple[bpy.types.Panel, ...]: # example default blender scene panels can be found in # https://projects.blender.org/blender/blender/src/branch/main/scripts/startup/bl_ui/properties_scene.py#L421 scene_panels: list[str] = [] @@ -887,6 +887,9 @@ class Blender(blenderbim.core.tool.Blender): # filter only panels if not hasattr(item, "bl_rna") or not isinstance(item.bl_rna, bpy.types.Panel): continue + # ignore bbim panels + if item.__module__.startswith("blenderbim"): + continue # filter scene panels if getattr(item, "bl_context", None) != "scene": continue @@ -896,7 +899,8 @@ class Blender(blenderbim.core.tool.Blender): panels_to_parents[item_name] = parent_panel scene_panels = cls.sort_panels_for_register(scene_panels, panels_to_parents) - return tuple(scene_panels) + final_panels = [getattr(bpy.types, p) for p in scene_panels] + return tuple(final_panels) @classmethod def sort_panels_for_register(cls, items: list[str], items_to_parents: dict[str, str]) -> list[str]: