From 37a62e3004c7b44fd69614f3c142f38c64153631 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 31 Jul 2025 12:08:48 +0500 Subject: [PATCH] Zones UI - add psets ui #6941 --- src/bonsai/bonsai/bim/module/pset/__init__.py | 3 ++ src/bonsai/bonsai/bim/module/pset/data.py | 16 ++++++++ src/bonsai/bonsai/bim/module/pset/prop.py | 11 ++++++ src/bonsai/bonsai/bim/module/pset/ui.py | 37 ++++++++++++++++++- src/bonsai/bonsai/bim/module/system/prop.py | 12 +++++- src/bonsai/bonsai/tool/blender.py | 4 ++ src/bonsai/bonsai/tool/ifc.py | 1 + src/bonsai/bonsai/tool/pset.py | 2 + 8 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/pset/__init__.py b/src/bonsai/bonsai/bim/module/pset/__init__.py index 45221737c5..7e0d72061b 100644 --- a/src/bonsai/bonsai/bim/module/pset/__init__.py +++ b/src/bonsai/bonsai/bim/module/pset/__init__.py @@ -55,6 +55,7 @@ classes = ( ui.BIM_PT_group_qtos, ui.BIM_PT_profile_psets, ui.BIM_PT_work_schedule_psets, + ui.BIM_PT_zone_psets, ui.BIM_PT_bulk_property_editor, ui.BIM_PT_rename_parameters, ui.BIM_PT_add_edit_custom_properties, @@ -71,6 +72,7 @@ def register(): bpy.types.Scene.GroupPsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.ProfilePsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.WorkSchedulePsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) + bpy.types.Scene.ZonePsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.GlobalPsetProperties = bpy.props.PointerProperty(type=prop.GlobalPsetProperties) @@ -83,4 +85,5 @@ def unregister(): del bpy.types.Scene.GroupPsetProperties del bpy.types.Scene.ProfilePsetProperties del bpy.types.Scene.WorkSchedulePsetProperties + del bpy.types.Scene.ZonePsetProperties del bpy.types.Scene.GlobalPsetProperties diff --git a/src/bonsai/bonsai/bim/module/pset/data.py b/src/bonsai/bonsai/bim/module/pset/data.py index 272d8e8709..e9c9c0a210 100644 --- a/src/bonsai/bonsai/bim/module/pset/data.py +++ b/src/bonsai/bonsai/bim/module/pset/data.py @@ -41,6 +41,7 @@ def refresh(): GroupPsetData.is_loaded = False ProfilePsetsData.is_loaded = False WorkSchedulePsetsData.is_loaded = False + ZonePsetsData.is_loaded = False AddEditCustomPropertiesData.is_loaded = False @@ -318,6 +319,21 @@ class WorkSchedulePsetsData(Data): cls.is_loaded = True +class ZonePsetsData(Data): + data = {} + is_loaded = False + + @classmethod + def load(cls): + props = tool.System.get_zone_props() + assert (active_zone := props.active_zone) + ifc_definition_id = active_zone.ifc_definition_id + cls.data = { + "psets": (cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), psets_only=True)), + } + cls.is_loaded = True + + class AddEditCustomPropertiesData: data = {} is_loaded = False diff --git a/src/bonsai/bonsai/bim/module/pset/prop.py b/src/bonsai/bonsai/bim/module/pset/prop.py index 697ca06b16..2a16c29a79 100644 --- a/src/bonsai/bonsai/bim/module/pset/prop.py +++ b/src/bonsai/bonsai/bim/module/pset/prop.py @@ -81,6 +81,8 @@ def get_pset_name(self: "PsetProperties", context: bpy.types.Context) -> tool.Bl results = get_profile_pset_names(self, context) elif prop_type == "WorkSchedulePsetProperties": results = get_work_schedule_pset_names(self, context) + elif prop_type == "ZonePsetProperties": + results = get_zone_pset_names(self, context) items: list[tool.Blender.BLENDER_ENUM_ITEM] items = [("BBIM_CUSTOM", "Custom Pset", "Create a property set without using a template.")] @@ -212,6 +214,15 @@ def get_work_schedule_pset_names(self: "PsetProperties", context: object) -> too return psetnames[ifc_class] +def get_zone_pset_names(self: "PsetProperties", context: object) -> tool.Blender.BLENDER_ENUM_ITEMS: + global psetnames + ifc_class = "IfcZone" + if ifc_class not in psetnames: + psets = bonsai.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True, schema=tool.Ifc.get_schema()) + psetnames[ifc_class] = blender_formatted_enum_from_psets(psets) + return psetnames[ifc_class] + + # TODO: unsafe? def get_qto_name(self: "PsetProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS: pset_type = repr(self) diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py index a46cb75bb2..1f5ad19dd8 100644 --- a/src/bonsai/bonsai/bim/module/pset/ui.py +++ b/src/bonsai/bonsai/bim/module/pset/ui.py @@ -33,9 +33,10 @@ from bonsai.bim.module.pset.data import ( GroupPsetData, ProfilePsetsData, WorkSchedulePsetsData, + ZonePsetsData, ) from bonsai.bim.module.material.data import ObjectMaterialData -from typing import Any, Optional, TYPE_CHECKING, assert_never +from typing import Any, Optional, TYPE_CHECKING, assert_never, Literal if TYPE_CHECKING: from bonsai.bim.module.pset.prop import IfcProperty, PsetProperties @@ -791,6 +792,40 @@ class BIM_PT_work_schedule_psets(Panel): draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "WorkSchedule") +class BIM_PT_zone_psets(Panel): + bl_label = "Zone Property Sets" + bl_idname = "BIM_PT_zone_psets" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_zones" + + obj_type: Literal["Zone"] = "Zone" + + @classmethod + def poll(cls, context): + props = tool.System.get_zone_props() + return bool(props.active_zone) + + def draw(self, context): + if not ZonePsetsData.is_loaded: + ZonePsetsData.load() + + assert self.layout + props = tool.Pset.get_pset_props("", self.obj_type) + row = self.layout.row(align=True) + prop_with_search(row, props, "pset_name", text="") + op = row.operator("bim.add_pset", icon="ADD", text="") + op.obj_type = self.obj_type + + if not props.active_pset_id and props.active_pset_name and props.active_pset_type == "PSET": + draw_psetqto_ui(context, 0, {}, props, self.layout, self.obj_type) + + for pset in ZonePsetsData.data["psets"]: + draw_psetqto_ui(context, pset["id"], pset, props, self.layout, self.obj_type) + + class BIM_PT_bulk_property_editor(Panel): bl_label = "Bulk Property Editor" bl_space_type = "PROPERTIES" diff --git a/src/bonsai/bonsai/bim/module/system/prop.py b/src/bonsai/bonsai/bim/module/system/prop.py index 3c1f60fb9c..6ae14e4132 100644 --- a/src/bonsai/bonsai/bim/module/system/prop.py +++ b/src/bonsai/bonsai/bim/module/system/prop.py @@ -115,12 +115,18 @@ class BIMSystemProperties(PropertyGroup): return tool.Blender.get_active_uilist_element(self.systems, self.active_system_index) +def update_active_zone_index(self: "BIMZoneProperties", context: object) -> None: + from bonsai.bim.module.pset.data import ZonePsetsData + + ZonePsetsData.is_loaded = False + + class BIMZoneProperties(PropertyGroup): attributes: CollectionProperty(name="Attributes", type=Attribute) is_loaded: BoolProperty(name="Is Loaded", default=False) is_editing: IntProperty(name="Is Editing", default=0) zones: CollectionProperty(name="Zones", type=Zone) - active_zone_index: IntProperty(name="Active Zone Index") + active_zone_index: IntProperty(name="Active Zone Index", update=update_active_zone_index) if TYPE_CHECKING: attributes: bpy.types.bpy_prop_collection_idprop[Attribute] @@ -128,3 +134,7 @@ class BIMZoneProperties(PropertyGroup): is_editing: int zones: bpy.types.bpy_prop_collection_idprop[Zone] active_zone_index: int + + @property + def active_zone(self) -> Zone | None: + return tool.Blender.get_active_uilist_element(self.zones, self.active_zone_index) diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index d903210da2..3a183d19de 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -262,6 +262,10 @@ class Blender(bonsai.core.tool.Blender): props = tool.Blender.get_group_props() assert (active_group := props.active_group) return active_group.ifc_definition_id + elif obj_type == "Zone": + props = tool.System.get_zone_props() + assert (active_zone := props.active_zone) + return active_zone.ifc_definition_id assert_never(obj_type) @classmethod diff --git a/src/bonsai/bonsai/tool/ifc.py b/src/bonsai/bonsai/tool/ifc.py index 760dd8ba49..7f4b14bc02 100644 --- a/src/bonsai/bonsai/tool/ifc.py +++ b/src/bonsai/bonsai/tool/ifc.py @@ -46,6 +46,7 @@ class Ifc(bonsai.core.tool.Ifc): "Profile", "WorkSchedule", "Group", + "Zone", ] @classmethod diff --git a/src/bonsai/bonsai/tool/pset.py b/src/bonsai/bonsai/tool/pset.py index f8e9857aa1..fb44e6f527 100644 --- a/src/bonsai/bonsai/tool/pset.py +++ b/src/bonsai/bonsai/tool/pset.py @@ -90,6 +90,8 @@ class Pset(bonsai.core.tool.Pset): return bpy.context.scene.WorkSchedulePsetProperties elif obj_type == "Group": return bpy.context.scene.GroupPsetProperties + elif obj_type == "Zone": + return bpy.context.scene.ZonePsetProperties assert_never(obj_type) @classmethod