Add CIVIL tab to Bonsai Properties sidebar for alignment tools

- Add new CIVIL tab (4th position) with CURVE_DATA icon
- Create BIM_PT_tab_horizontal_alignment panel container
- Move alignment UI from N-panel to Properties sidebar
- Remove old "Saikei Civil" N-panel tab

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
DesertSpringsCivil
2026-02-01 18:39:38 -07:00
parent a37de44a24
commit de2a7c9527
5 changed files with 76 additions and 47 deletions
+2
View File
@@ -182,6 +182,8 @@ classes = [
ui.BIM_PT_tab_materials, ui.BIM_PT_tab_materials,
ui.BIM_PT_tab_styles, ui.BIM_PT_tab_styles,
ui.BIM_PT_tab_profiles, ui.BIM_PT_tab_profiles,
# Civil infrastructure
ui.BIM_PT_tab_horizontal_alignment,
# Drawings and documents # Drawings and documents
ui.BIM_PT_tab_sheets, ui.BIM_PT_tab_sheets,
ui.BIM_PT_tab_drawings, ui.BIM_PT_tab_drawings,
@@ -60,8 +60,8 @@ classes = (
# Operators - Stationing # Operators - Stationing
operator.SAIKEI_OT_add_stationing_referent, operator.SAIKEI_OT_add_stationing_referent,
operator.SAIKEI_OT_name_segments, operator.SAIKEI_OT_name_segments,
# UI Panels # UI Panels (appear in Properties sidebar under CIVIL tab)
ui.SAIKEI_PT_horizontal_alignment, ui.SAIKEI_PT_alignment_status,
ui.SAIKEI_PT_alignment_creation, ui.SAIKEI_PT_alignment_creation,
ui.SAIKEI_PT_pi_editor, ui.SAIKEI_PT_pi_editor,
ui.SAIKEI_PT_alignment_stationing, ui.SAIKEI_PT_alignment_stationing,
+43 -37
View File
@@ -19,7 +19,8 @@
"""UI panels for the alignment module """UI panels for the alignment module
All panels appear in the VIEW_3D N-panel under the "Saikei Civil" tab. All panels appear in the Properties sidebar under the CIVIL tab,
nested under BIM_PT_tab_horizontal_alignment.
""" """
import bpy import bpy
@@ -118,39 +119,44 @@ class SAIKEI_UL_alignment_pis(UIList):
# ============================================================================= # =============================================================================
# Main Panel # Main Status Panel
# ============================================================================= # =============================================================================
class SAIKEI_PT_horizontal_alignment(Panel): class SAIKEI_PT_alignment_status(Panel):
"""Main Horizontal Alignment panel in the N-panel""" """Status panel showing IFC schema and alignment count"""
bl_label = "Horizontal Alignment" bl_label = "Status"
bl_idname = "SAIKEI_PT_horizontal_alignment" bl_idname = "SAIKEI_PT_alignment_status"
bl_space_type = "VIEW_3D" bl_space_type = "PROPERTIES"
bl_region_type = "UI" bl_region_type = "WINDOW"
bl_category = "Saikei Civil" bl_context = "scene"
bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = {"HIDE_HEADER"}
@classmethod
def poll(cls, context):
return tool.Blender.should_show_panel(context, "CIVIL", cls.bl_idname) and tool.Ifc.get()
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
props = context.scene.SaikeiAlignmentProperties props = context.scene.SaikeiAlignmentProperties
# Status box
box = layout.box()
ifc = tool.Ifc.get() ifc = tool.Ifc.get()
if ifc is None: if ifc is None:
box.label(text="No IFC file loaded", icon="ERROR") row = layout.row()
box.label(text="Open an IFC4X3 file via Bonsai") row.label(text="No IFC file loaded", icon="ERROR")
return return
if ifc.schema != "IFC4X3": if ifc.schema != "IFC4X3":
box.label(text=f"Schema: {ifc.schema}", icon="ERROR") row = layout.row()
box.label(text="Alignments require IFC4X3") row.label(text=f"Schema: {ifc.schema}", icon="ERROR")
row = layout.row()
row.label(text="Alignments require IFC4X3")
return return
# IFC file is loaded and correct schema # IFC file is loaded and correct schema
row = box.row() row = layout.row()
row.label(text="IFC4X3", icon="CHECKMARK") row.label(text="IFC4X3", icon="CHECKMARK")
# Count alignments # Count alignments
@@ -159,9 +165,9 @@ class SAIKEI_PT_horizontal_alignment(Panel):
# Active alignment selector # Active alignment selector
if alignments: if alignments:
box = layout.box() row = layout.row()
box.label(text="Active Alignment:", icon="CURVE_PATH") row.label(text="Active Alignment:", icon="CURVE_DATA")
row = box.row() row = layout.row()
row.prop(props, "active_alignment_name", text="") row.prop(props, "active_alignment_name", text="")
@@ -175,15 +181,15 @@ class SAIKEI_PT_alignment_creation(Panel):
bl_label = "Creation" bl_label = "Creation"
bl_idname = "SAIKEI_PT_alignment_creation" bl_idname = "SAIKEI_PT_alignment_creation"
bl_space_type = "VIEW_3D" bl_space_type = "PROPERTIES"
bl_region_type = "UI" bl_region_type = "WINDOW"
bl_category = "Saikei Civil" bl_context = "scene"
bl_parent_id = "SAIKEI_PT_horizontal_alignment" bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = {"DEFAULT_CLOSED"} bl_options = {"DEFAULT_CLOSED"}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return is_ifc4x3() return tool.Blender.should_show_panel(context, "CIVIL", cls.bl_idname) and is_ifc4x3()
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -198,7 +204,7 @@ class SAIKEI_PT_alignment_creation(Panel):
# Creation operators # Creation operators
col = layout.column(align=True) col = layout.column(align=True)
col.operator("saikei.create_alignment", icon="ADD") col.operator("saikei.create_alignment", icon="ADD")
col.operator("saikei.create_alignment_by_pi", icon="CURVE_PATH") col.operator("saikei.create_alignment_by_pi", icon="CURVE_DATA")
col.operator("saikei.import_alignment_csv", icon="IMPORT") col.operator("saikei.import_alignment_csv", icon="IMPORT")
@@ -212,15 +218,15 @@ class SAIKEI_PT_pi_editor(Panel):
bl_label = "PI Editor" bl_label = "PI Editor"
bl_idname = "SAIKEI_PT_pi_editor" bl_idname = "SAIKEI_PT_pi_editor"
bl_space_type = "VIEW_3D" bl_space_type = "PROPERTIES"
bl_region_type = "UI" bl_region_type = "WINDOW"
bl_category = "Saikei Civil" bl_context = "scene"
bl_parent_id = "SAIKEI_PT_horizontal_alignment" bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = set() # Open by default bl_options = set() # Open by default
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return is_ifc4x3() return tool.Blender.should_show_panel(context, "CIVIL", cls.bl_idname) and is_ifc4x3()
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -327,15 +333,15 @@ class SAIKEI_PT_alignment_stationing(Panel):
bl_label = "Stationing" bl_label = "Stationing"
bl_idname = "SAIKEI_PT_alignment_stationing" bl_idname = "SAIKEI_PT_alignment_stationing"
bl_space_type = "VIEW_3D" bl_space_type = "PROPERTIES"
bl_region_type = "UI" bl_region_type = "WINDOW"
bl_category = "Saikei Civil" bl_context = "scene"
bl_parent_id = "SAIKEI_PT_horizontal_alignment" bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = {"DEFAULT_CLOSED"} bl_options = {"DEFAULT_CLOSED"}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return is_ifc4x3() return tool.Blender.should_show_panel(context, "CIVIL", cls.bl_idname) and is_ifc4x3()
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -352,4 +358,4 @@ class SAIKEI_PT_alignment_stationing(Panel):
# Stationing operators # Stationing operators
col = layout.column(align=True) col = layout.column(align=True)
col.operator("saikei.add_stationing_referent", icon="EMPTY_AXIS") col.operator("saikei.add_stationing_referent", icon="EMPTY_AXIS")
col.operator("saikei.name_segments", icon="FONT_DATA") col.operator("saikei.name_segments", icon="FONT_DATA")
+9 -8
View File
@@ -496,15 +496,16 @@ def get_tab(
("PROJECT", "Project Overview", "", bonsai.bim.icons[icon_key].icon_id, 0), ("PROJECT", "Project Overview", "", bonsai.bim.icons[icon_key].icon_id, 0),
("OBJECT", "Object Information", "", "FILE_3D", 1), ("OBJECT", "Object Information", "", "FILE_3D", 1),
("GEOMETRY", "Geometry and Materials", "", "MATERIAL", 2), ("GEOMETRY", "Geometry and Materials", "", "MATERIAL", 2),
("DRAWINGS", "Drawings and Documents", "", "DOCUMENTS", 3), ("CIVIL", "Civil Infrastructure", "", "CURVE_DATA", 3),
("SERVICES", "Services and Systems", "", "NETWORK_DRIVE", 4), ("DRAWINGS", "Drawings and Documents", "", "DOCUMENTS", 4),
("STRUCTURE", "Structural Analysis", "", "EDITMODE_HLT", 5), ("SERVICES", "Services and Systems", "", "NETWORK_DRIVE", 5),
("SCHEDULING", "Costing and Scheduling", "", "NLA", 6), ("STRUCTURE", "Structural Analysis", "", "EDITMODE_HLT", 6),
("FM", "Facility Management", "", "PACKAGE", 7), ("SCHEDULING", "Costing and Scheduling", "", "NLA", 7),
("QUALITY", "Quality and Coordination", "", "COMMUNITY", 8), ("FM", "Facility Management", "", "PACKAGE", 8),
("BOOKMARK", "Bookmark", "", "SOLO_ON", 9), ("QUALITY", "Quality and Coordination", "", "COMMUNITY", 9),
("BOOKMARK", "Bookmark", "", "SOLO_ON", 10),
None, None,
("BLENDER", "Blender Properties", "", "BLENDER", 10), ("BLENDER", "Blender Properties", "", "BLENDER", 11),
] ]
return get_tab.enum_items return get_tab.enum_items
+20
View File
@@ -1675,6 +1675,25 @@ class BIM_PT_tab_profiles(Panel):
pass pass
# Civil Infrastructure tab panels
class BIM_PT_tab_horizontal_alignment(Panel):
bl_idname = "BIM_PT_tab_horizontal_alignment"
bl_label = "Horizontal Alignment"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_order = 1
bim_tab_name = "CIVIL"
@classmethod
def poll(cls, context):
if tool.Blender.should_show_panel(context, cls.bim_tab_name, cls.bl_idname) and tool.Ifc.get():
return True
def draw(self, context):
pass
class BIM_PT_tab_sheets(Panel): class BIM_PT_tab_sheets(Panel):
bl_idname = "BIM_PT_tab_sheets" bl_idname = "BIM_PT_tab_sheets"
bl_label = "Sheets" bl_label = "Sheets"
@@ -1861,6 +1880,7 @@ class UIData:
("PROJECT", bonsai.bim.icons[f"{color_mode}_ifc"].icon_id, True), ("PROJECT", bonsai.bim.icons[f"{color_mode}_ifc"].icon_id, True),
("OBJECT", "FILE_3D", is_ifc_project), ("OBJECT", "FILE_3D", is_ifc_project),
("GEOMETRY", "MATERIAL", is_ifc_project), ("GEOMETRY", "MATERIAL", is_ifc_project),
("CIVIL", "CURVE_DATA", is_ifc_project),
("DRAWINGS", "DOCUMENTS", is_ifc_project), ("DRAWINGS", "DOCUMENTS", is_ifc_project),
("SERVICES", "NETWORK_DRIVE", is_ifc_project), ("SERVICES", "NETWORK_DRIVE", is_ifc_project),
("STRUCTURE", "EDITMODE_HLT", is_ifc_project), ("STRUCTURE", "EDITMODE_HLT", is_ifc_project),