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_styles,
ui.BIM_PT_tab_profiles,
# Civil infrastructure
ui.BIM_PT_tab_horizontal_alignment,
# Drawings and documents
ui.BIM_PT_tab_sheets,
ui.BIM_PT_tab_drawings,
@@ -60,8 +60,8 @@ classes = (
# Operators - Stationing
operator.SAIKEI_OT_add_stationing_referent,
operator.SAIKEI_OT_name_segments,
# UI Panels
ui.SAIKEI_PT_horizontal_alignment,
# UI Panels (appear in Properties sidebar under CIVIL tab)
ui.SAIKEI_PT_alignment_status,
ui.SAIKEI_PT_alignment_creation,
ui.SAIKEI_PT_pi_editor,
ui.SAIKEI_PT_alignment_stationing,
+43 -37
View File
@@ -19,7 +19,8 @@
"""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
@@ -118,39 +119,44 @@ class SAIKEI_UL_alignment_pis(UIList):
# =============================================================================
# Main Panel
# Main Status Panel
# =============================================================================
class SAIKEI_PT_horizontal_alignment(Panel):
"""Main Horizontal Alignment panel in the N-panel"""
class SAIKEI_PT_alignment_status(Panel):
"""Status panel showing IFC schema and alignment count"""
bl_label = "Horizontal Alignment"
bl_idname = "SAIKEI_PT_horizontal_alignment"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Saikei Civil"
bl_label = "Status"
bl_idname = "SAIKEI_PT_alignment_status"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
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):
layout = self.layout
props = context.scene.SaikeiAlignmentProperties
# Status box
box = layout.box()
ifc = tool.Ifc.get()
if ifc is None:
box.label(text="No IFC file loaded", icon="ERROR")
box.label(text="Open an IFC4X3 file via Bonsai")
row = layout.row()
row.label(text="No IFC file loaded", icon="ERROR")
return
if ifc.schema != "IFC4X3":
box.label(text=f"Schema: {ifc.schema}", icon="ERROR")
box.label(text="Alignments require IFC4X3")
row = layout.row()
row.label(text=f"Schema: {ifc.schema}", icon="ERROR")
row = layout.row()
row.label(text="Alignments require IFC4X3")
return
# IFC file is loaded and correct schema
row = box.row()
row = layout.row()
row.label(text="IFC4X3", icon="CHECKMARK")
# Count alignments
@@ -159,9 +165,9 @@ class SAIKEI_PT_horizontal_alignment(Panel):
# Active alignment selector
if alignments:
box = layout.box()
box.label(text="Active Alignment:", icon="CURVE_PATH")
row = box.row()
row = layout.row()
row.label(text="Active Alignment:", icon="CURVE_DATA")
row = layout.row()
row.prop(props, "active_alignment_name", text="")
@@ -175,15 +181,15 @@ class SAIKEI_PT_alignment_creation(Panel):
bl_label = "Creation"
bl_idname = "SAIKEI_PT_alignment_creation"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Saikei Civil"
bl_parent_id = "SAIKEI_PT_horizontal_alignment"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = {"DEFAULT_CLOSED"}
@classmethod
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):
layout = self.layout
@@ -198,7 +204,7 @@ class SAIKEI_PT_alignment_creation(Panel):
# Creation operators
col = layout.column(align=True)
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")
@@ -212,15 +218,15 @@ class SAIKEI_PT_pi_editor(Panel):
bl_label = "PI Editor"
bl_idname = "SAIKEI_PT_pi_editor"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Saikei Civil"
bl_parent_id = "SAIKEI_PT_horizontal_alignment"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = set() # Open by default
@classmethod
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):
layout = self.layout
@@ -327,15 +333,15 @@ class SAIKEI_PT_alignment_stationing(Panel):
bl_label = "Stationing"
bl_idname = "SAIKEI_PT_alignment_stationing"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Saikei Civil"
bl_parent_id = "SAIKEI_PT_horizontal_alignment"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_horizontal_alignment"
bl_options = {"DEFAULT_CLOSED"}
@classmethod
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):
layout = self.layout
@@ -352,4 +358,4 @@ class SAIKEI_PT_alignment_stationing(Panel):
# Stationing operators
col = layout.column(align=True)
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),
("OBJECT", "Object Information", "", "FILE_3D", 1),
("GEOMETRY", "Geometry and Materials", "", "MATERIAL", 2),
("DRAWINGS", "Drawings and Documents", "", "DOCUMENTS", 3),
("SERVICES", "Services and Systems", "", "NETWORK_DRIVE", 4),
("STRUCTURE", "Structural Analysis", "", "EDITMODE_HLT", 5),
("SCHEDULING", "Costing and Scheduling", "", "NLA", 6),
("FM", "Facility Management", "", "PACKAGE", 7),
("QUALITY", "Quality and Coordination", "", "COMMUNITY", 8),
("BOOKMARK", "Bookmark", "", "SOLO_ON", 9),
("CIVIL", "Civil Infrastructure", "", "CURVE_DATA", 3),
("DRAWINGS", "Drawings and Documents", "", "DOCUMENTS", 4),
("SERVICES", "Services and Systems", "", "NETWORK_DRIVE", 5),
("STRUCTURE", "Structural Analysis", "", "EDITMODE_HLT", 6),
("SCHEDULING", "Costing and Scheduling", "", "NLA", 7),
("FM", "Facility Management", "", "PACKAGE", 8),
("QUALITY", "Quality and Coordination", "", "COMMUNITY", 9),
("BOOKMARK", "Bookmark", "", "SOLO_ON", 10),
None,
("BLENDER", "Blender Properties", "", "BLENDER", 10),
("BLENDER", "Blender Properties", "", "BLENDER", 11),
]
return get_tab.enum_items
+20
View File
@@ -1675,6 +1675,25 @@ class BIM_PT_tab_profiles(Panel):
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):
bl_idname = "BIM_PT_tab_sheets"
bl_label = "Sheets"
@@ -1861,6 +1880,7 @@ class UIData:
("PROJECT", bonsai.bim.icons[f"{color_mode}_ifc"].icon_id, True),
("OBJECT", "FILE_3D", is_ifc_project),
("GEOMETRY", "MATERIAL", is_ifc_project),
("CIVIL", "CURVE_DATA", is_ifc_project),
("DRAWINGS", "DOCUMENTS", is_ifc_project),
("SERVICES", "NETWORK_DRIVE", is_ifc_project),
("STRUCTURE", "EDITMODE_HLT", is_ifc_project),