From 1fc56585dd3b157f71fc4625d006ceebed1ef73e Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 28 Jun 2024 17:30:51 +0500 Subject: [PATCH] Support loading BlenderBIM in Blender 4.2+ as an extension 1) Used a hack to bring `blenderbim` into the main namespace instead of `bl_ext.repository.blenderbim`. This is not an official way to do it but this works for testing stuff (official way is to create a stub wheel that would redirect all `blenderbim` requests to `bl_ext.repository.blenderbim`). 2) AddonPreferences now require blender package name as it's bl_idname (e.g. bl_ext.repository.blenderbim) 3) Addressing preferences now also works through the blender package name. Created method in tool/Blender.py to incapsulate those details. --- src/blenderbim/blenderbim/__init__.py | 15 ++++++++++++++- src/blenderbim/blenderbim/bim/handler.py | 7 ++++--- src/blenderbim/blenderbim/bim/import_ifc.py | 6 +++--- .../blenderbim/bim/module/boundary/decorator.py | 2 +- .../blenderbim/bim/module/clash/decorator.py | 4 ++-- .../blenderbim/bim/module/drawing/decoration.py | 12 ++++++------ .../blenderbim/bim/module/drawing/operator.py | 12 ++++++------ .../blenderbim/bim/module/model/decorator.py | 2 +- .../blenderbim/bim/module/model/opening.py | 2 +- .../blenderbim/bim/module/project/decorator.py | 4 ++-- src/blenderbim/blenderbim/bim/module/pset/ui.py | 2 +- .../blenderbim/bim/module/system/decorator.py | 2 +- src/blenderbim/blenderbim/bim/ui.py | 2 +- src/blenderbim/blenderbim/tool/blender.py | 12 ++++++++++++ src/blenderbim/blenderbim/tool/cost.py | 2 +- src/blenderbim/blenderbim/tool/drawing.py | 6 +++--- 16 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/blenderbim/blenderbim/__init__.py b/src/blenderbim/blenderbim/__init__.py index 5abc678937..814607426b 100644 --- a/src/blenderbim/blenderbim/__init__.py +++ b/src/blenderbim/blenderbim/__init__.py @@ -33,6 +33,8 @@ import traceback import webbrowser from collections import deque +# NOTE: bl_info is superseded by blender_manifest.toml +# if addon is installed as an extension (Blender 4.2+) bl_info = { "name": "BlenderBIM", "description": "Transforms Blender into a native Building Information Model authoring platform using IFC.", @@ -92,7 +94,6 @@ if IN_BLENDER: sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages")) try: - import blenderbim.bim import ifcopenshell.api def log_api(usecase_path, ifc_file, settings): @@ -107,9 +108,21 @@ if IN_BLENDER: ifcopenshell.api.add_pre_listener("*", "action_logger", log_api) def register(): + global BLENDER_PACKAGE_NAME, __name__, __package__ + BLENDER_PACKAGE_NAME = __name__ + if bpy.app.version >= (4, 2, 0): + sys.modules["blenderbim"] = sys.modules[__name__] + __name__ = "blenderbim" + # Only renaming __name__ is actually required to make imports work. + # We renaming __package__ just for consistency. + __package__ = "blenderbim" + import blenderbim.bim + blenderbim.bim.register() def unregister(): + import blenderbim.bim + blenderbim.bim.unregister() except: diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 709c216da3..3497b1a0cb 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -291,12 +291,13 @@ def load_post(scene): ifcopenshell.api.owner.settings.get_application = get_application AuthoringData.type_thumbnails = {} - if not bpy.context.preferences.addons["blenderbim"].preferences.should_setup_toolbar: + preferences = tool.Blender.get_addon_preferences() + if not preferences.should_setup_toolbar: tool.Blender.unregister_toolbar() - if bpy.context.preferences.addons["blenderbim"].preferences.should_setup_workspace: + if preferences.should_setup_workspace: if "BIM" in bpy.data.workspaces: - if bpy.context.preferences.addons["blenderbim"].preferences.activate_workspace: + if preferences.activate_workspace: bpy.context.window.workspace = bpy.data.workspaces["BIM"] else: bpy.ops.workspace.append_activate(idname="BIM", filepath=os.path.join(cwd, "data", "workspace.blend")) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index d8d43965b9..7d1c062fce 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -538,7 +538,7 @@ class IfcImporter: shape = tool.Loader.create_generic_shape(grid) grid_obj = self.create_product(grid, shape) grid_placement = self.get_element_matrix(grid) - if bpy.context.preferences.addons["blenderbim"].preferences.lock_grids_on_import: + if tool.Blender.get_addon_preferences().lock_grids_on_import: grid_obj.lock_location = (True, True, True) grid_obj.lock_rotation = (True, True, True) self.create_grid_axes(grid.UAxes, grid_obj, grid_placement) @@ -551,7 +551,7 @@ class IfcImporter: shape = tool.Loader.create_generic_shape(axis.AxisCurve) mesh = self.create_mesh(axis, shape) obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh) - if bpy.context.preferences.addons["blenderbim"].preferences.lock_grids_on_import: + if tool.Blender.get_addon_preferences().lock_grids_on_import: obj.lock_location = (True, True, True) obj.lock_rotation = (True, True, True) self.link_element(axis, obj) @@ -620,7 +620,7 @@ class IfcImporter: print("Done creating geometry") def create_spatial_elements(self) -> None: - if bpy.context.preferences.addons["blenderbim"].preferences.spatial_elements_unselectable: + if tool.Blender.get_addon_preferences().spatial_elements_unselectable: self.create_generic_elements(self.spatial_elements, unselectable=True) else: self.create_generic_elements(self.spatial_elements, unselectable=False) diff --git a/src/blenderbim/blenderbim/bim/module/boundary/decorator.py b/src/blenderbim/blenderbim/bim/module/boundary/decorator.py index d48b60fe18..ce70cc23c9 100644 --- a/src/blenderbim/blenderbim/bim/module/boundary/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/boundary/decorator.py @@ -49,7 +49,7 @@ class BoundaryDecorator: batch.draw(shader) def __call__(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/module/clash/decorator.py b/src/blenderbim/blenderbim/bim/module/clash/decorator.py index af7946ddc1..43c40a339a 100644 --- a/src/blenderbim/blenderbim/bim/module/clash/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/clash/decorator.py @@ -55,7 +55,7 @@ class ClashDecorator: batch.draw(shader) def draw_text(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special @@ -75,7 +75,7 @@ class ClashDecorator: blf.draw(font_id, text) # Set your text here def draw_geometry(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index e085198ed4..f5cd213081 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -335,7 +335,7 @@ class BaseDecorator: """`verts` should be in winspace with `(0,0,0)` in the screen left bottom corner, not in the center""" region = context.region if not color: - color = context.preferences.addons["blenderbim"].preferences.decorations_colour + color = tool.Blender.get_addon_preferences().decorations_colour self.line_shader.bind() # POLYLINE_UNIFORM_COLOR specific uniforms @@ -404,7 +404,7 @@ class BaseDecorator: font_id = self.font_id - color = context.preferences.addons["blenderbim"].preferences.decorations_colour + color = tool.Blender.get_addon_preferences().decorations_colour ang = -Vector((1, 0)).angle_signed(text_dir) cos = math.cos(ang) @@ -812,7 +812,7 @@ class AngleDecorator(BaseDecorator): arcs_color = None edges_color = UNSPECIAL_ELEMENT_COLOR if context.active_object == obj and obj.data.is_editmode: - arcs_color = context.preferences.addons["blenderbim"].preferences.decorator_color_special + arcs_color = tool.Blender.get_addon_preferences().decorator_color_special edges_color = None self.draw_lines( @@ -1093,7 +1093,7 @@ class HiddenDecorator(BaseDecorator): else: verts, idxs = self.get_mesh_geom(obj) winspace_verts = worldspace_to_winspace(verts, context) - color = [i for i in context.preferences.addons["blenderbim"].preferences.decorations_colour] + color = [i for i in tool.Blender.get_addon_preferences().decorations_colour] color[3] = 0.5 self.draw_lines(context, obj, winspace_verts, idxs, color) @@ -1409,7 +1409,7 @@ class GridDecorator(BaseDecorator): # stem with gaps for circles add_verts_sequence([v0 + gap, v1 - gap], start_i, **out_kwargs) - color = [i for i in context.preferences.addons["blenderbim"].preferences.decorations_colour] + color = [i for i in tool.Blender.get_addon_preferences().decorations_colour] color[3] = 0.5 self.draw_lines(context, obj, output_verts, output_edges, color) self.draw_labels(context, obj, verts) @@ -1591,7 +1591,7 @@ class CutDecorator: cls.installed = None def __call__(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected all_vertices = [] diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 1f89581665..aae82ea44a 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -279,7 +279,7 @@ class CreateDrawing(bpy.types.Operator): svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg) tool.Drawing.open_with_user_command( - context.preferences.addons["blenderbim"].preferences.svg_command, svg_path + tool.Blender.get_addon_preferences().svg_command, svg_path ) if self.print_all: @@ -1374,8 +1374,8 @@ class CreateSheets(bpy.types.Operator, Operator): ), ) - svg2pdf_command = context.preferences.addons["blenderbim"].preferences.svg2pdf_command - svg2dxf_command = context.preferences.addons["blenderbim"].preferences.svg2dxf_command + svg2pdf_command = tool.Blender.get_addon_preferences().svg2pdf_command + svg2dxf_command = tool.Blender.get_addon_preferences().svg2dxf_command if svg2pdf_command: # With great power comes great responsibility. Example: @@ -1393,9 +1393,9 @@ class CreateSheets(bpy.types.Operator, Operator): subprocess.run([replacements.get(c, c) for c in command]) if svg2pdf_command: - tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf) + tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, pdf) else: - tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg) + tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg) class SelectAllDrawings(bpy.types.Operator): @@ -1463,7 +1463,7 @@ class OpenDrawing(bpy.types.Operator): for drawing_uri in drawing_uris: tool.Drawing.open_with_user_command( - context.preferences.addons["blenderbim"].preferences.svg_command, drawing_uri + tool.Blender.get_addon_preferences().svg_command, drawing_uri ) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/decorator.py b/src/blenderbim/blenderbim/bim/module/model/decorator.py index 080966c22d..d5da1ed2e8 100644 --- a/src/blenderbim/blenderbim/bim/module/model/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/model/decorator.py @@ -78,7 +78,7 @@ class ProfileDecorator: self.draw_batch("TRIS", vertices_coords, faces_color, face_indices) def __call__(self, context, get_custom_bmesh=None, draw_faces=False, exit_edit_mode_callback=None): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 0bf85ac035..dfadde94cf 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -904,7 +904,7 @@ class DecorationsHandler: batch.draw(shader) def __call__(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/module/project/decorator.py b/src/blenderbim/blenderbim/bim/module/project/decorator.py index 43f64d5497..511a8ffde5 100644 --- a/src/blenderbim/blenderbim/bim/module/project/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/project/decorator.py @@ -64,7 +64,7 @@ class ProjectDecorator: batch.draw(shader) def __call__(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special @@ -128,7 +128,7 @@ class ClippingPlaneDecorator: batch.draw(shader) def __call__(self, context): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/module/pset/ui.py b/src/blenderbim/blenderbim/bim/module/pset/ui.py index b8297fc16e..8a6f6d9346 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset/ui.py @@ -138,7 +138,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type, allow_remov else: has_props_displayed = False for prop in pset["Properties"]: - if context.preferences.addons["blenderbim"].preferences.should_hide_empty_props and ( + if tool.Blender.get_addon_preferences().should_hide_empty_props and ( prop["NominalValue"] is None or prop["NominalValue"] == "" ): continue diff --git a/src/blenderbim/blenderbim/bim/module/system/decorator.py b/src/blenderbim/blenderbim/bim/module/system/decorator.py index 146fa71abc..0cc8d8ad6f 100644 --- a/src/blenderbim/blenderbim/bim/module/system/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/system/decorator.py @@ -89,7 +89,7 @@ class SystemDecorator: self.draw_batch("TRIS", vertices_coords, faces_color, face_indices) def __call__(self, context, get_custom_bmesh=None, draw_faces=False, exit_edit_mode_callback=None): - self.addon_prefs = context.preferences.addons["blenderbim"].preferences + self.addon_prefs = tool.Blender.get_addon_preferences() selected_elements_color = self.addon_prefs.decorator_color_selected unselected_elements_color = self.addon_prefs.decorator_color_unselected special_elements_color = self.addon_prefs.decorator_color_special diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index e276164b58..4aaed962c7 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -191,7 +191,7 @@ class BIM_UL_topics(bpy.types.UIList): class BIM_ADDON_preferences(bpy.types.AddonPreferences): - bl_idname = "blenderbim" + bl_idname = tool.Blender.get_blender_addon_package_name() svg2pdf_command: StringProperty(name="SVG to PDF Command", description='E.g. [["inkscape", "svg", "-o", pdf]]') svg2dxf_command: StringProperty( name="SVG to DXF Command", diff --git a/src/blenderbim/blenderbim/tool/blender.py b/src/blenderbim/blenderbim/tool/blender.py index 40fd25c494..f0968a965a 100644 --- a/src/blenderbim/blenderbim/tool/blender.py +++ b/src/blenderbim/blenderbim/tool/blender.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . +from __future__ import annotations import bpy import bmesh import json @@ -1132,3 +1133,14 @@ class Blender(blenderbim.core.tool.Blender): @classmethod def clear_recent_ifc_projects(cls) -> None: cls.write_recent_ifc_projects([]) + + @classmethod + def get_blender_addon_package_name(cls) -> str: + if bpy.app.version >= (4, 2, 0): + return blenderbim.BLENDER_PACKAGE_NAME + return "blenderbim" + + @classmethod + def get_addon_preferences(cls) -> blenderbim.bim.ui.BIM_ADDON_preferences: + blender_package_name = cls.get_blender_addon_package_name() + return bpy.context.preferences.addons[blender_package_name].preferences diff --git a/src/blenderbim/blenderbim/tool/cost.py b/src/blenderbim/blenderbim/tool/cost.py index 9fb849e5c2..6af214519a 100644 --- a/src/blenderbim/blenderbim/tool/cost.py +++ b/src/blenderbim/blenderbim/tool/cost.py @@ -96,7 +96,7 @@ class Cost(blenderbim.core.tool.Cost): @classmethod def play_sound(cls): - if bpy.context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound: + if tool.Blender.get_addon_preferences().should_play_chaching_sound: cls.play_chaching_sound() # lol @classmethod diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 96cf221c65..4778667431 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -889,15 +889,15 @@ class Drawing(blenderbim.core.tool.Drawing): @classmethod def open_spreadsheet(cls, uri): - cls.open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.spreadsheet_command, uri) + cls.open_with_user_command(tool.Blender.get_addon_preferences().spreadsheet_command, uri) @classmethod def open_svg(cls, uri): - cls.open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.svg_command, uri) + cls.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, uri) @classmethod def open_layout_svg(cls, uri): - cls.open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.layout_svg_command, uri) + cls.open_with_user_command(tool.Blender.get_addon_preferences().layout_svg_command, uri) @classmethod def run_root_assign_class(