Bonsai: add toggle to show only drawings placed on sheets (#8824)

Adds a "Show Only Drawings on Sheets" toggle below the drawing list. When
enabled, the list is filtered to drawings referenced by at least one sheet
(target-view headers with no sheeted drawings are hidden too), and
bim.select_all_drawings only acts on the visible/filtered drawings.

A drawing is considered sheeted when its drawing document Location matches a
document reference Location on any SHEET-scoped IfcDocumentInformation.
Filtering is computed live so it reflects sheet edits without reloading.

Closes #8823

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 2d59ea1988)
This commit is contained in:
Ryan Schultz
2026-07-20 19:03:56 -05:00
committed by Dion Moult
parent 8c5dbc3671
commit 46a0c4b00a
4 changed files with 69 additions and 0 deletions
@@ -2293,7 +2293,11 @@ class SelectAllDrawings(bpy.types.Operator):
def execute(self, context):
props = tool.Drawing.get_document_props()
# When filtering to sheeted drawings only, act on the visible drawings only.
sheeted_ids = tool.Drawing.get_sheeted_drawing_ids() if props.show_drawings_on_sheets_only else None
for drawing in props.drawings:
if sheeted_ids is not None and drawing.is_drawing and drawing.ifc_definition_id not in sheeted_ids:
continue
if drawing.is_selected != self.select_all:
drawing.is_selected = self.select_all
return {"FINISHED"}
@@ -409,6 +409,12 @@ class DocProperties(PropertyGroup):
options=set(),
)
is_editing_drawings: BoolProperty(name="Is Editing Drawings", default=False)
show_drawings_on_sheets_only: BoolProperty(
name="Show Only Drawings on Sheets",
description="Only show drawings that are placed on a sheet",
default=False,
options=set(),
)
is_editing_schedules: BoolProperty(name="Is Editing Schedules", default=False)
is_editing_references: BoolProperty(name="Is Editing References", default=False)
target_view: EnumProperty(
@@ -439,6 +445,7 @@ class DocProperties(PropertyGroup):
should_use_annotation_cache: bool
should_draw_linked_projects: bool
is_editing_drawings: bool
show_drawings_on_sheets_only: bool
is_editing_schedules: bool
is_editing_references: bool
target_view: Literal["PLAN_VIEW", "ELEVATION_VIEW", "SECTION_VIEW", "REFLECTED_PLAN_VIEW", "MODEL_VIEW"]
@@ -341,6 +341,7 @@ class BIM_PT_drawings(Panel):
self.layout.template_list(
"BIM_UL_drawinglist", "", self.props, "drawings", self.props, "active_drawing_index"
)
self.layout.prop(self.props, "show_drawings_on_sheets_only")
class BIM_PT_schedules(Panel):
@@ -917,6 +918,42 @@ class BIM_UL_drawinglist(bpy.types.UIList):
op.option = "EXPAND"
row.prop(item, "name", text="", icon=icon, emboss=False)
def filter_items(self, context, data: DocProperties, propname: str):
drawings = getattr(data, propname)
helper_funcs = bpy.types.UI_UL_list
flt_flags = []
flt_neworder = []
if self.filter_name:
flt_flags = helper_funcs.filter_items_by_name(
self.filter_name,
self.bitflag_filter_item,
drawings,
"name",
reverse=self.use_filter_sort_reverse,
)
if not flt_flags:
flt_flags = [self.bitflag_filter_item] * len(drawings)
props = tool.Drawing.get_document_props()
if props.show_drawings_on_sheets_only:
ifc_file = tool.Ifc.get()
sheeted_ids = tool.Drawing.get_sheeted_drawing_ids()
# Target view headers are only shown if they contain a sheeted drawing.
sheeted_target_views = {
tool.Drawing.get_drawing_target_view(ifc_file.by_id(drawing_id)) for drawing_id in sheeted_ids
}
for i, item in enumerate(drawings):
if item.is_drawing:
is_visible = item.ifc_definition_id in sheeted_ids
else:
is_visible = item.target_view in sheeted_target_views
if not is_visible:
flt_flags[i] &= ~self.bitflag_filter_item
return flt_flags, flt_neworder
class BIM_UL_sheets(bpy.types.UIList):
def draw_item(
+21
View File
@@ -2889,6 +2889,27 @@ class Drawing(bonsai.core.tool.Drawing):
break
return sheet_references
@classmethod
def get_sheeted_drawing_ids(cls) -> set[int]:
"""Get the IFC ids of all drawings that are placed on at least one sheet."""
ifc_file = tool.Ifc.get()
sheet_locations: set[Union[str, None]] = set()
for sheet in ifc_file.by_type("IfcDocumentInformation"):
if sheet.Scope != "SHEET":
continue
for reference in cls.get_document_references(sheet):
sheet_locations.add(reference.Location)
if not sheet_locations:
return set()
result: set[int] = set()
for drawing in ifc_file.by_type("IfcAnnotation"):
if drawing.ObjectType != "DRAWING":
continue
drawing_document = cls.get_drawing_document(drawing)
if drawing_document and drawing_document.Location in sheet_locations:
result.add(drawing.id())
return result
@classmethod
def get_camera_matrix(cls, camera: bpy.types.Object) -> Matrix:
matrix_world = camera.matrix_world.copy().normalized()