mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 14:02:27 +00:00
Bonsai: add category-level select-all to the Drawings list (#8826)
Add an "Is Selected" checkbox to each target-view category header in BIM_UL_drawinglist that toggles selection for all drawings in the category. The toggle only affects drawings currently visible in the list (honoring the show_drawings_on_sheets_only filter), and the header checkbox reflects the aggregate selection state of its drawings. Also make category headers more obvious: wrap them in a box() for a distinct inset background and make the header name clickable to expand/contract the category (same as the disclosure triangle). Ref: #8825 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -108,6 +108,7 @@ classes = (
|
|||||||
operator.SelectAssignedProduct,
|
operator.SelectAssignedProduct,
|
||||||
operator.SelectSimilarTextLiteralValue,
|
operator.SelectSimilarTextLiteralValue,
|
||||||
operator.ToggleTargetView,
|
operator.ToggleTargetView,
|
||||||
|
operator.ToggleDrawingCategorySelection,
|
||||||
operator.OpenDocumentationWebUi,
|
operator.OpenDocumentationWebUi,
|
||||||
operator.FilterSelectedObjectsIfIntersectedByCamera,
|
operator.FilterSelectedObjectsIfIntersectedByCamera,
|
||||||
prop.Variable,
|
prop.Variable,
|
||||||
|
|||||||
@@ -3874,6 +3874,26 @@ class ToggleTargetView(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ToggleDrawingCategorySelection(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.toggle_drawing_category_selection"
|
||||||
|
bl_label = "Toggle Category Selection"
|
||||||
|
bl_description = "Select or deselect all drawings in this view category"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
target_view: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
target_view: str
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
drawings = tool.Drawing.get_visible_drawings_in_category(self.target_view)
|
||||||
|
# If everything visible in the category is already selected, deselect all; otherwise select all.
|
||||||
|
new_state = not all(d.is_selected for d in drawings)
|
||||||
|
for drawing in drawings:
|
||||||
|
drawing.is_selected = new_state
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ExpandSheet(bpy.types.Operator):
|
class ExpandSheet(bpy.types.Operator):
|
||||||
bl_idname = "bim.expand_sheet"
|
bl_idname = "bim.expand_sheet"
|
||||||
bl_label = "Expand Sheet"
|
bl_label = "Expand Sheet"
|
||||||
|
|||||||
@@ -874,8 +874,8 @@ class BIM_UL_drawinglist(bpy.types.UIList):
|
|||||||
layout.label(text="", translate=False)
|
layout.label(text="", translate=False)
|
||||||
return
|
return
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
if item.is_drawing:
|
if item.is_drawing:
|
||||||
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="BLANK1")
|
row.label(text="", icon="BLANK1")
|
||||||
selected_icon = "CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
|
selected_icon = "CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
|
||||||
row.prop(item, "is_selected", text="", icon=selected_icon, emboss=False)
|
row.prop(item, "is_selected", text="", icon=selected_icon, emboss=False)
|
||||||
@@ -896,6 +896,9 @@ class BIM_UL_drawinglist(bpy.types.UIList):
|
|||||||
item.ifc_definition_id
|
item.ifc_definition_id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Give category headers a distinct inset background so they stand out from drawing rows.
|
||||||
|
box = layout.box()
|
||||||
|
row = box.row(align=True)
|
||||||
if item.target_view == "PLAN_VIEW":
|
if item.target_view == "PLAN_VIEW":
|
||||||
icon = "UV_FACESEL"
|
icon = "UV_FACESEL"
|
||||||
elif item.target_view == "ELEVATION_VIEW":
|
elif item.target_view == "ELEVATION_VIEW":
|
||||||
@@ -916,7 +919,19 @@ class BIM_UL_drawinglist(bpy.types.UIList):
|
|||||||
op = row.operator("bim.toggle_target_view", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT")
|
op = row.operator("bim.toggle_target_view", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT")
|
||||||
op.target_view = item.target_view
|
op.target_view = item.target_view
|
||||||
op.option = "EXPAND"
|
op.option = "EXPAND"
|
||||||
row.prop(item, "name", text="", icon=icon, emboss=False)
|
group = tool.Drawing.get_visible_drawings_in_category(item.target_view)
|
||||||
|
all_selected = bool(group) and all(d.is_selected for d in group)
|
||||||
|
row.operator(
|
||||||
|
"bim.toggle_drawing_category_selection",
|
||||||
|
text="",
|
||||||
|
icon="CHECKBOX_HLT" if all_selected else "CHECKBOX_DEHLT",
|
||||||
|
emboss=False,
|
||||||
|
).target_view = item.target_view
|
||||||
|
row.separator(factor=0.5, type="SPACE")
|
||||||
|
# Clicking the header name toggles expand/contract, same as the disclosure triangle.
|
||||||
|
op = row.operator("bim.toggle_target_view", text=item.name, icon=icon, emboss=False)
|
||||||
|
op.target_view = item.target_view
|
||||||
|
op.option = "CONTRACT" if item.is_expanded else "EXPAND"
|
||||||
|
|
||||||
def filter_items(self, context, data: DocProperties, propname: str):
|
def filter_items(self, context, data: DocProperties, propname: str):
|
||||||
drawings = getattr(data, propname)
|
drawings = getattr(data, propname)
|
||||||
|
|||||||
@@ -2908,6 +2908,29 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
result.add(drawing.id())
|
result.add(drawing.id())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_visible_drawings_in_category(cls, target_view: str) -> list[DrawingProperties]:
|
||||||
|
"""Get the drawing items in a target view category that are currently visible in the drawing list.
|
||||||
|
|
||||||
|
Grouping is positional: individual drawing items don't carry their own ``target_view``, they belong to
|
||||||
|
the most recent header item above them. Only expanded categories contribute drawing items to the
|
||||||
|
collection, so a collapsed category yields an empty list. Respects the ``show_drawings_on_sheets_only``
|
||||||
|
filter so that select-all only affects visible drawings.
|
||||||
|
"""
|
||||||
|
props = cls.get_document_props()
|
||||||
|
drawings: list[DrawingProperties] = []
|
||||||
|
in_category = False
|
||||||
|
for item in props.drawings:
|
||||||
|
if not item.is_drawing:
|
||||||
|
# Header row: we're inside the requested category until the next header.
|
||||||
|
in_category = item.target_view == target_view
|
||||||
|
elif in_category:
|
||||||
|
drawings.append(item)
|
||||||
|
if props.show_drawings_on_sheets_only:
|
||||||
|
sheeted_ids = cls.get_sheeted_drawing_ids()
|
||||||
|
drawings = [d for d in drawings if d.ifc_definition_id in sheeted_ids]
|
||||||
|
return drawings
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_camera_matrix(cls, camera: bpy.types.Object) -> Matrix:
|
def get_camera_matrix(cls, camera: bpy.types.Object) -> Matrix:
|
||||||
matrix_world = camera.matrix_world.copy().normalized()
|
matrix_world = camera.matrix_world.copy().normalized()
|
||||||
|
|||||||
Reference in New Issue
Block a user