From 15ea092ac4bebc8f1dd3acc6812f6052575d49fd Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 9 Mar 2026 19:34:38 +0500 Subject: [PATCH] typing --- src/bonsai/bonsai/bim/import_ifc.py | 3 +- src/bonsai/bonsai/bim/module/bcf/operator.py | 4 +- src/bonsai/bonsai/bim/module/cost/ui.py | 2 +- src/bonsai/bonsai/bim/module/diff/operator.py | 4 +- src/bonsai/bonsai/bim/module/geometry/ui.py | 6 +- src/bonsai/bonsai/bim/module/misc/operator.py | 7 +- src/bonsai/bonsai/bim/module/misc/prop.py | 6 ++ src/bonsai/bonsai/bim/module/misc/ui.py | 4 +- .../bim/module/model/sverchok_modifier.py | 18 ++--- src/bonsai/bonsai/bim/module/model/ui.py | 2 +- .../bonsai/bim/module/nest/decorator.py | 2 - src/bonsai/bonsai/bim/module/resource/prop.py | 2 +- .../bonsai/bim/module/search/operator.py | 14 ++-- .../bonsai/bim/module/spatial/operator.py | 4 +- src/bonsai/bonsai/bim/module/style/prop.py | 5 +- src/bonsai/bonsai/bim/operator.py | 4 +- src/bonsai/bonsai/bim/prop.py | 3 +- src/bonsai/bonsai/bim/ui.py | 2 +- src/bonsai/bonsai/tool/blender.py | 66 +++++++++++++------ src/bonsai/bonsai/tool/collector.py | 3 +- src/bonsai/bonsai/tool/misc.py | 11 +++- src/bonsai/bonsai/tool/model.py | 15 +++-- src/bonsai/bonsai/tool/nest.py | 3 +- 23 files changed, 124 insertions(+), 66 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 7e8f40560e..1d6ad25f1b 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -1020,7 +1020,8 @@ class IfcImporter: obj.hide_select = True obj.hide_viewport = True self.project["blender"].objects.link(obj) - self.project["blender"].BIMCollectionProperties.obj = obj + collection_props = tool.Blender.get_collection_props(self.project["blender"]) + collection_props.obj = obj props = tool.Blender.get_object_bim_props(obj) props.collection = self.collections[project.GlobalId] = self.project["blender"] diff --git a/src/bonsai/bonsai/bim/module/bcf/operator.py b/src/bonsai/bonsai/bim/module/bcf/operator.py index 6edf257f05..461321852d 100644 --- a/src/bonsai/bonsai/bim/module/bcf/operator.py +++ b/src/bonsai/bonsai/bim/module/bcf/operator.py @@ -1253,8 +1253,8 @@ class ActivateBcfViewpoint(bpy.types.Operator): else: obj.data.show_background_images = False - area = next(area for area in context.screen.areas if area.type == "VIEW_3D") - area.spaces[0].region_3d.view_perspective = "CAMERA" + assert (space := tool.Blender.get_view3d_space()) + space.region_3d.view_perspective = "CAMERA" if self.file: self.set_viewpoint_components(viewpoint, context) diff --git a/src/bonsai/bonsai/bim/module/cost/ui.py b/src/bonsai/bonsai/bim/module/cost/ui.py index 73a578171f..98701b4ef8 100644 --- a/src/bonsai/bonsai/bim/module/cost/ui.py +++ b/src/bonsai/bonsai/bim/module/cost/ui.py @@ -398,8 +398,8 @@ class BIM_PT_cost_item_types(Panel): op = row2.operator("bim.calculate_cost_item_resource_value", text="", icon="DISC") op.cost_item = cost_item.ifc_definition_id - rtprops = context.scene.BIMResourceTreeProperties rprops = tool.Resource.get_resource_props() + rtprops = rprops.tree if rtprops.resources and rprops.active_resource_index < len(rtprops.resources): if has_quantity_names: op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES") diff --git a/src/bonsai/bonsai/bim/module/diff/operator.py b/src/bonsai/bonsai/bim/module/diff/operator.py index 330deed410..020c0c40f2 100644 --- a/src/bonsai/bonsai/bim/module/diff/operator.py +++ b/src/bonsai/bonsai/bim/module/diff/operator.py @@ -98,8 +98,8 @@ class VisualiseDiff(bpy.types.Operator): obj.color = (0.0, 1.0, 0.0, 1.0) elif global_id in diff["changed"]: obj.color = (0.0, 0.0, 1.0, 1.0) - area = next(area for area in context.screen.areas if area.type == "VIEW_3D") - area.spaces[0].shading.color_type = "OBJECT" + assert (space := tool.Blender.get_view3d_space()) + space.shading.color_type = "OBJECT" return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/geometry/ui.py b/src/bonsai/bonsai/bim/module/geometry/ui.py index 2af216c7a1..e7912c7a77 100644 --- a/src/bonsai/bonsai/bim/module/geometry/ui.py +++ b/src/bonsai/bonsai/bim/module/geometry/ui.py @@ -515,6 +515,8 @@ class BIM_PT_derived_coordinates(Panel): return context.active_object is not None def draw(self, context): + assert context.active_object + props = tool.Model.get_model_props() if not DerivedCoordinatesData.is_loaded: DerivedCoordinatesData.load() @@ -529,10 +531,8 @@ class BIM_PT_derived_coordinates(Panel): row = self.layout.row(align=True) row.enabled = False - area_3d = next((area for area in context.screen.areas if area.type == "VIEW_3D"), None) - space_3d = next((space for space in area_3d.spaces if space.type == "VIEW_3D"), None) - if bpy.context.scene.BIMModelProperties.show_bounding_box: + if props.show_bounding_box: for axis, icon, idx in [("X", "STRIP_COLOR_01", 0), ("Y", "STRIP_COLOR_04", 1), ("Z", "STRIP_COLOR_05", 2)]: row.label(text="", icon=icon) row.prop(context.active_object, "dimensions", text=axis, index=idx) diff --git a/src/bonsai/bonsai/bim/module/misc/operator.py b/src/bonsai/bonsai/bim/module/misc/operator.py index 02cc56834b..1d756f7b1e 100644 --- a/src/bonsai/bonsai/bim/module/misc/operator.py +++ b/src/bonsai/bonsai/bim/module/misc/operator.py @@ -41,10 +41,11 @@ class SetOverrideColour(bpy.types.Operator): return context.selected_objects def execute(self, context): + props = tool.Misc.get_misc_props() for obj in context.selected_objects: - obj.color = context.scene.BIMMiscProperties.override_colour - area = next(area for area in context.screen.areas if area.type == "VIEW_3D") - area.spaces[0].shading.color_type = "OBJECT" + obj.color = props.override_colour + assert (space := tool.Blender.get_view3d_space()) + space.shading.color_type = "OBJECT" return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/misc/prop.py b/src/bonsai/bonsai/bim/module/misc/prop.py index f596f22fc6..093ff60046 100644 --- a/src/bonsai/bonsai/bim/module/misc/prop.py +++ b/src/bonsai/bonsai/bim/module/misc/prop.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +from typing import TYPE_CHECKING + from bpy.props import ( FloatVectorProperty, IntProperty, @@ -32,3 +34,7 @@ class BIMMiscProperties(PropertyGroup): override_colour: FloatVectorProperty( name="Override Colour", subtype="COLOR", default=(1, 0, 0, 1), min=0.0, max=1.0, size=4 ) + + if TYPE_CHECKING: + total_storeys: int + override_colour: tuple[float, float, float, float] diff --git a/src/bonsai/bonsai/bim/module/misc/ui.py b/src/bonsai/bonsai/bim/module/misc/ui.py index c009b720e4..af0be1dfbc 100644 --- a/src/bonsai/bonsai/bim/module/misc/ui.py +++ b/src/bonsai/bonsai/bim/module/misc/ui.py @@ -18,6 +18,8 @@ import bpy +import bonsai.tool as tool + class BIM_PT_misc_utilities(bpy.types.Panel): bl_idname = "BIM_PT_misc_utilities" @@ -30,7 +32,7 @@ class BIM_PT_misc_utilities(bpy.types.Panel): def draw(self, context): layout = self.layout - props = context.scene.BIMMiscProperties + props = tool.Misc.get_misc_props() row = layout.split(factor=0.2, align=True) row.prop(props, "override_colour", text="") row.operator("bim.set_override_colour") diff --git a/src/bonsai/bonsai/bim/module/model/sverchok_modifier.py b/src/bonsai/bonsai/bim/module/model/sverchok_modifier.py index 08f29890c4..2eda14283b 100644 --- a/src/bonsai/bonsai/bim/module/model/sverchok_modifier.py +++ b/src/bonsai/bonsai/bim/module/model/sverchok_modifier.py @@ -31,7 +31,7 @@ import bonsai.tool as tool def update_sverchok_modifier(context): obj = context.active_object - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) element = tool.Ifc.get_entity(obj) psets = ifcopenshell.util.element.get_psets(element) pset = psets.get("BBIM_Sverchok", None) @@ -72,7 +72,7 @@ class CreateNewSverchokGraph(bpy.types.Operator, tool.Ifc.Operator): import sverchok obj = context.active_object - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) node_group = bpy.data.node_groups.new("IfcNodeTree", type="SverchCustomTreeType") plane = node_group.nodes.new(type="SvPlaneNodeMk3") @@ -96,7 +96,7 @@ class DeleteSverchokGraph(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): obj = context.active_object element = tool.Ifc.get_entity(obj) - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) bpy.data.node_groups.remove(props.node_group) return {"FINISHED"} @@ -113,7 +113,8 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER"} def invoke(self, context, event): - if not context.active_object.BIMSverchokProperties.node_group: + props = tool.Model.get_sverchok_props(context.active_object) + if not props.node_group: return context.window_manager.invoke_props_dialog(self) return self._execute(context) @@ -124,7 +125,7 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): obj = context.active_object element = tool.Ifc.get_entity(obj) - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) node_group = props.node_group if node_group: @@ -196,7 +197,7 @@ class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ImportHelper): importer = sverchok.utils.sv_json_import.JSONImporter.init_from_path(self.filepath) obj = context.active_object - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) node_group = context.scene.io_panel_properties.import_tree if not node_group: @@ -234,7 +235,7 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ExportHelper): import sverchok obj = context.active_object - props = obj.BIMSverchokProperties + props = tool.Model.get_sverchok_props(obj) ng = props.node_group destination_path = self.filepath if not destination_path.lower().endswith(".json"): @@ -273,7 +274,8 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ExportHelper): return {"FINISHED"} def draw(self, context): - graph_name = context.active_object.BIMSverchokProperties.node_group.name + props = tool.Model.get_sverchok_props(context.active_object) + graph_name = props.node_group.name self.layout.label(text=f'Save node tree "{graph_name}" into json:') col = self.layout.column(heading="Options") # new syntax in >= 2.90 diff --git a/src/bonsai/bonsai/bim/module/model/ui.py b/src/bonsai/bonsai/bim/module/model/ui.py index 512eaf3fdf..eef71ed433 100644 --- a/src/bonsai/bonsai/bim/module/model/ui.py +++ b/src/bonsai/bonsai/bim/module/model/ui.py @@ -360,7 +360,7 @@ class BIM_PT_sverchok(bpy.types.Panel): self.layout.label(text="Requires Sverchok Add-on", icon="ERROR") return - props = context.active_object.BIMSverchokProperties + props = tool.Model.get_sverchok_props(context.active_object) self.layout.prop_search(props, "node_group", bpy.data, "node_groups") self.layout.operator("bim.create_new_sverchok_graph", icon="ADD") diff --git a/src/bonsai/bonsai/bim/module/nest/decorator.py b/src/bonsai/bonsai/bim/module/nest/decorator.py index 66608b0171..28c3835ba7 100644 --- a/src/bonsai/bonsai/bim/module/nest/decorator.py +++ b/src/bonsai/bonsai/bim/module/nest/decorator.py @@ -215,8 +215,6 @@ class NestDecorator: self.draw_batch("LINES", line_z, color, [(0, 1)]) else: self.draw_batch("POINTS", [location], color) - # if context.scene.BIMNestProperties.in_aggregate_mode: - # return components = ifcopenshell.util.element.get_components(tool.Ifc.get_entity(nest)) components_objs = [tool.Ifc.get_object(p) for p in components] components_objs.append(nest) diff --git a/src/bonsai/bonsai/bim/module/resource/prop.py b/src/bonsai/bonsai/bim/module/resource/prop.py index 9f2c5ba85c..f08bacbab5 100644 --- a/src/bonsai/bonsai/bim/module/resource/prop.py +++ b/src/bonsai/bonsai/bim/module/resource/prop.py @@ -188,7 +188,7 @@ class BIMResourceProperties(PropertyGroup): @property def productivity(self) -> "BIMResourceProductivity": assert bpy.context.scene - productivity = bpy.context.scene.BIMResourceProductivity + productivity = bpy.context.scene.BIMResourceProductivity # pyright: ignore[reportAttributeAccessIssue] assert isinstance(productivity, BIMResourceProductivity) return productivity diff --git a/src/bonsai/bonsai/bim/module/search/operator.py b/src/bonsai/bonsai/bim/module/search/operator.py index b7ba62acdb..6a16a24631 100644 --- a/src/bonsai/bonsai/bim/module/search/operator.py +++ b/src/bonsai/bonsai/bim/module/search/operator.py @@ -1053,8 +1053,8 @@ class ColourByProperty(Operator): colourscheme[str(values[index])]["total"] += 1 obj.color = (*tool.Search.get_quantitative_palette(palette, value, min_value, max_value), 1) - if areas := [a for a in context.screen.areas if a.type == "VIEW_3D"]: - areas[0].spaces[0].shading.color_type = "OBJECT" + assert (space := tool.Blender.get_view3d_space()) + space.shading.color_type = "OBJECT" props.colourscheme.clear() @@ -1078,16 +1078,18 @@ class ColourByProperty(Operator): return (1, value) def store_state(self, context): - if areas := [a for a in context.screen.areas if a.type == "VIEW_3D"]: - self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type} + if space := tool.Blender.get_view3d_space(): + self.transaction_data = {"color_type": space.shading.color_type} def rollback(self, data): if data: - data["area"].spaces[0].shading.color_type = data["color_type"] + assert (space := tool.Blender.get_view3d_space()) + space.shading.color_type = data["color_type"] def commit(self, data): if data: - data["area"].spaces[0].shading.color_type = "OBJECT" + assert (space := tool.Blender.get_view3d_space()) + space.shading.color_type = "OBJECT" class SelectByProperty(Operator): diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index 23c0c28335..f1eb4ec4ee 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -512,7 +512,7 @@ class SetContainerVisibility(bpy.types.Operator): containers -= set(tool.Ifc.get().by_type("IfcSpatialZone")) for container in containers: if obj := tool.Ifc.get_object(container): - if collection := obj.BIMObjectProperties.collection: + if collection := tool.Blender.get_object_bim_props(obj).collection: collection.hide_viewport = True should_hide = False else: @@ -523,7 +523,7 @@ class SetContainerVisibility(bpy.types.Operator): while queue: container = queue.pop() if obj := tool.Ifc.get_object(container): - if collection := obj.BIMObjectProperties.collection: + if collection := tool.Blender.get_object_bim_props(obj).collection: collection.hide_viewport = should_hide if self.should_include_children: queue.extend(ifcopenshell.util.element.get_parts(container)) diff --git a/src/bonsai/bonsai/bim/module/style/prop.py b/src/bonsai/bonsai/bim/module/style/prop.py index 5d14bbd248..bd62021d65 100644 --- a/src/bonsai/bonsai/bim/module/style/prop.py +++ b/src/bonsai/bonsai/bim/module/style/prop.py @@ -102,7 +102,10 @@ def update_shading_styles(self: "BIMStylesProperties", context: bpy.types.Contex def update_shader_graph(self: Union["Texture", "BIMStylesProperties"], context: bpy.types.Context) -> None: - props = self.id_data.BIMStylesProperties if isinstance(self, Texture) else self + if isinstance(self, Texture): + props = tool.Style.get_style_props() + else: + props = self if not props.update_graph: return diff --git a/src/bonsai/bonsai/bim/operator.py b/src/bonsai/bonsai/bim/operator.py index f332c91401..3216478132 100644 --- a/src/bonsai/bonsai/bim/operator.py +++ b/src/bonsai/bonsai/bim/operator.py @@ -70,7 +70,7 @@ class SetTab(bpy.types.Operator): if context.area.spaces.active.search_filter: return {"FINISHED"} tool.Blender.setup_tabs() - aprops = tool.Blender.get_area_props(context) + aprops = tool.Blender.get_active_area_props(context) aprops.tab = self.tab return {"FINISHED"} @@ -85,7 +85,7 @@ class SwitchTab(bpy.types.Operator): if context.area.spaces.active.search_filter: return {"FINISHED"} tool.Blender.setup_tabs() - aprops = tool.Blender.get_area_props(context) + aprops = tool.Blender.get_active_area_props(context) aprops.tab = aprops.alt_tab return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/prop.py b/src/bonsai/bonsai/bim/prop.py index 61b916965e..e5d495c62a 100644 --- a/src/bonsai/bonsai/bim/prop.py +++ b/src/bonsai/bonsai/bim/prop.py @@ -59,7 +59,8 @@ def update_is_visible(self: "BIMTabVisibility", context: bpy.types.Context) -> N def update_global_tab(self: "BIMTabProperties", context: bpy.types.Context) -> None: tool.Blender.setup_tabs() screen = context.id_data - aprops = screen.BIMAreaProperties[screen.areas[:].index(context.area)] + assert isinstance(screen, bpy.types.Screen) + aprops = tool.Blender.get_area_props(screen)[screen.areas[:].index(context.area)] aprops.tab = self.tab diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 1d0e8742dd..bee0594afc 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -1031,7 +1031,7 @@ class BIM_PT_tabs(Panel): def draw(self, context): if not UIData.is_loaded: UIData.load() - aprops = tool.Blender.get_area_props(context) + aprops = tool.Blender.get_active_area_props(context) addon_prefs = tool.Blender.get_addon_preferences() row = self.layout.row() diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 205e592a35..9650db8de5 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -74,7 +74,13 @@ if TYPE_CHECKING: BIMSolarProperties, RadianceExporterProperties, ) - from bonsai.bim.prop import BIMObjectProperties, BIMProperties + from bonsai.bim.prop import ( + BIMAreaProperties, + BIMCollectionProperties, + BIMObjectProperties, + BIMProperties, + BIMTabProperties, + ) T = TypeVar("T") @@ -138,17 +144,20 @@ class Blender(bonsai.core.tool.Blender): space.region_3d.view_perspective = "CAMERA" @classmethod - def get_area_props(cls, context: bpy.types.Context) -> bpy.types.PropertyGroup: + def get_active_area_props(cls, context: bpy.types.Context) -> BIMAreaProperties | BIMTabProperties: + FULLSCREEN_SUFFIX = "-nonnormal" # Ctrl-space temporary fullscreen + assert (screen := context.screen) try: - if context.screen.name.endswith("-nonnormal"): # Ctrl-space temporary fullscreen - screen = bpy.data.screens[context.screen.name.removesuffix("-nonnormal")] + if screen.name.endswith(FULLSCREEN_SUFFIX): + screen = bpy.data.screens[screen.name.removesuffix(FULLSCREEN_SUFFIX)] # The original area object has its type changed to "EMPTY" apparently index = [a.type for a in screen.areas].index("EMPTY") - return screen.BIMAreaProperties[index] - return context.screen.BIMAreaProperties[context.screen.areas[:].index(context.area)] + return cls.get_area_props(screen)[index] + assert (area := context.area) + return cls.get_area_props(screen)[screen.areas[:].index(area)] except IndexError: # Fallback in case areas aren't setup yet. - return context.screen.BIMTabProperties + return cls.get_tab_props(screen) @classmethod def set_active_object(cls, obj: bpy.types.Object) -> None: @@ -165,15 +174,16 @@ class Blender(bonsai.core.tool.Blender): def setup_tabs(cls) -> None: # https://blender.stackexchange.com/questions/140644/how-can-make-the-state-of-a-boolean-property-relative-to-the-3d-view-area for screen in bpy.data.screens: - if len(screen.BIMAreaProperties) == 20: + area_props = cls.get_area_props(screen) + if len(area_props) == 20: continue - screen.BIMAreaProperties.clear() + area_props.clear() for i in range(20): # 20 is an arbitrary value of split areas - screen.BIMAreaProperties.add() + area_props.add() @classmethod def should_show_panel(cls, context: bpy.types.Context, tab: str, panel: str) -> bool: - aprops = cls.get_area_props(context) + aprops = cls.get_active_area_props(context) if aprops.path_from_id() == "BIMAreaProperties" and context.area.spaces.active.search_filter: return True if (is_bookmark_tab := aprops.tab == "BOOKMARK") or aprops.tab == tab: @@ -185,6 +195,7 @@ class Blender(bonsai.core.tool.Blender): return True elif panel_visibility.is_visible: return True + return False @classmethod def is_default_scene(cls) -> bool: @@ -330,7 +341,8 @@ class Blender(bonsai.core.tool.Blender): @classmethod def get_view3d_area(cls) -> Union[bpy.types.Area, None]: - for window in bpy.context.window_manager.windows: + assert (wm := bpy.context.window_manager) + for window in wm.windows: for area in window.screen.areas: if area.type == "VIEW_3D": return area @@ -338,7 +350,9 @@ class Blender(bonsai.core.tool.Blender): @classmethod def get_view3d_space(cls) -> Union[bpy.types.SpaceView3D, None]: if area := cls.get_view3d_area(): - return area.spaces.active + space = area.spaces.active + assert isinstance(space, bpy.types.SpaceView3D) + return space @classmethod def get_blender_prop_default_value(cls, props: bpy.types.bpy_struct, prop_name: str) -> Any: @@ -1489,7 +1503,7 @@ class Blender(bonsai.core.tool.Blender): def override_scene_panel(cls, original_panel: bpy.types.Panel) -> None: @classmethod def poll_check_blender_tab(cls, context): - aprops = tool.Blender.get_area_props(context) + aprops = tool.Blender.get_active_area_props(context) if aprops.path_from_id() == "BIMAreaProperties" and context.area.spaces.active.search_filter: return True return aprops.tab == "BLENDER" @@ -1829,6 +1843,18 @@ class Blender(bonsai.core.tool.Blender): assert (scene := bpy.context.scene) return scene.BIMProperties # pyright: ignore[reportAttributeAccessIssue] + @classmethod + def get_area_props(cls, screen: bpy.types.Screen) -> bpy.types.bpy_prop_collection_idprop[BIMAreaProperties]: + return screen.BIMAreaProperties # pyright: ignore[reportAttributeAccessIssue] + + @classmethod + def get_tab_props(cls, screen: bpy.types.Screen) -> BIMTabProperties: + return screen.BIMTabProperties # pyright: ignore[reportAttributeAccessIssue] + + @classmethod + def get_collection_props(cls, collection: bpy.types.Collection) -> BIMCollectionProperties: + return collection.BIMCollectionProperties # pyright: ignore[reportAttributeAccessIssue] + @classmethod def get_object_bim_props(cls, obj: bpy.types.Object) -> BIMObjectProperties: return obj.BIMObjectProperties # pyright: ignore[reportAttributeAccessIssue] @@ -1882,19 +1908,21 @@ class Blender(bonsai.core.tool.Blender): @classmethod def clear_undo_history(cls) -> None: """Clears the Blender history, Bonsai history, and IfcOpenShell history""" - old_undo_steps = bpy.context.preferences.edit.undo_steps - bpy.context.preferences.edit.undo_steps = 2 + assert (preferences := bpy.context.preferences) + old_undo_steps = preferences.edit.undo_steps + preferences.edit.undo_steps = 2 for i in range(3): bpy.ops.ed.undo_push(message="Undo history cleared") - bpy.context.preferences.edit.undo_steps = old_undo_steps + preferences.edit.undo_steps = old_undo_steps tool.Ifc.clear_history() old_history_size = tool.Ifc.get().history_size tool.Ifc.get().set_history_size(0) tool.Ifc.get().set_history_size(old_history_size) @classmethod - def get_unit_scale(cls): - unit_length = bpy.context.scene.unit_settings.length_unit + def get_unit_scale(cls) -> float: + assert (scene := bpy.context.scene) + unit_length = scene.unit_settings.length_unit unit_scale = 1.0 if unit_length == "CENTIMETERS": unit_scale = 0.01 diff --git a/src/bonsai/bonsai/tool/collector.py b/src/bonsai/bonsai/tool/collector.py index b0aa358629..1e6653acd1 100644 --- a/src/bonsai/bonsai/tool/collector.py +++ b/src/bonsai/bonsai/tool/collector.py @@ -157,7 +157,8 @@ class Collector(bonsai.core.tool.Collector): return collection = bpy.data.collections.new(obj.name) props.collection = collection - collection.BIMCollectionProperties.obj = obj + collection_props = tool.Blender.get_collection_props(collection) + collection_props.obj = obj return collection @classmethod diff --git a/src/bonsai/bonsai/tool/misc.py b/src/bonsai/bonsai/tool/misc.py index 890e8aac9b..f73970a508 100644 --- a/src/bonsai/bonsai/tool/misc.py +++ b/src/bonsai/bonsai/tool/misc.py @@ -16,7 +16,9 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . -from typing import Union +from __future__ import annotations + +from typing import TYPE_CHECKING, Union import bmesh import bpy @@ -30,8 +32,15 @@ import bonsai.core.root import bonsai.core.tool import bonsai.tool as tool +if TYPE_CHECKING: + from bonsai.bim.module.misc.prop import BIMMiscProperties + class Misc(bonsai.core.tool.Misc): + @classmethod + def get_misc_props(cls) -> BIMMiscProperties: + return bpy.context.scene.BIMMiscProperties + @classmethod def get_object_storey(cls, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]: element = tool.Ifc.get_entity(obj) diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index 23c0071b1b..60f79cc26e 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -76,6 +76,7 @@ if TYPE_CHECKING: BIMRailingProperties, BIMRoofProperties, BIMStairProperties, + BIMSverchokProperties, BIMWindowProperties, ) @@ -87,23 +88,27 @@ class Model(bonsai.core.tool.Model): @classmethod def get_door_props(cls, obj: bpy.types.Object) -> BIMDoorProperties: - return obj.BIMDoorProperties + return obj.BIMDoorProperties # pyright: ignore[reportAttributeAccessIssue] @classmethod def get_window_props(cls, obj: bpy.types.Object) -> BIMWindowProperties: - return obj.BIMWindowProperties + return obj.BIMWindowProperties # pyright: ignore[reportAttributeAccessIssue] @classmethod def get_stair_props(cls, obj: bpy.types.Object) -> BIMStairProperties: - return obj.BIMStairProperties + return obj.BIMStairProperties # pyright: ignore[reportAttributeAccessIssue] @classmethod def get_roof_props(cls, obj: bpy.types.Object) -> BIMRoofProperties: - return obj.BIMRoofProperties + return obj.BIMRoofProperties # pyright: ignore[reportAttributeAccessIssue] @classmethod def get_railing_props(cls, obj: bpy.types.Object) -> BIMRailingProperties: - return obj.BIMRailingProperties + return obj.BIMRailingProperties # pyright: ignore[reportAttributeAccessIssue] + + @classmethod + def get_sverchok_props(cls, obj: bpy.types.Object) -> BIMSverchokProperties: + return obj.BIMSverchokProperties # pyright: ignore[reportAttributeAccessIssue] @classmethod def get_array_props(cls, obj: bpy.types.Object) -> BIMArrayProperties: diff --git a/src/bonsai/bonsai/tool/nest.py b/src/bonsai/bonsai/tool/nest.py index a386e402ec..8b4fde0e78 100644 --- a/src/bonsai/bonsai/tool/nest.py +++ b/src/bonsai/bonsai/tool/nest.py @@ -124,8 +124,7 @@ class Nest(bonsai.core.tool.Nest): @classmethod def disable_nest_mode(cls): - context = bpy.context - props = context.scene.BIMNestProperties + props = cls.get_nest_props() for obj_prop in props.not_editing_objects: obj = obj_prop.obj obj.original.display_type = obj_prop.previous_display_type