diff --git a/src/bonsai/bonsai/bim/data/icons/dm_3-point_arc.png b/src/bonsai/bonsai/bim/data/icons/dm_3-point_arc.png new file mode 100644 index 0000000000..2344f24851 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_3-point_arc.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_add.png b/src/bonsai/bonsai/bim/data/icons/dm_add.png index c6c89c7d15..7c1371fe4f 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_add.png and b/src/bonsai/bonsai/bim/data/icons/dm_add.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_add_bend.png b/src/bonsai/bonsai/bim/data/icons/dm_add_bend.png new file mode 100644 index 0000000000..0483124069 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_add_bend.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_add_transition.png b/src/bonsai/bonsai/bim/data/icons/dm_add_transition.png new file mode 100644 index 0000000000..6f020d1dfa Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_add_transition.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_add_void.png b/src/bonsai/bonsai/bim/data/icons/dm_add_void.png index 9add3ea24e..a1c0df84a3 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_add_void.png and b/src/bonsai/bonsai/bim/data/icons/dm_add_void.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_apply.png b/src/bonsai/bonsai/bim/data/icons/dm_apply.png new file mode 100644 index 0000000000..78f3c601c1 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_apply.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_apply_axis.png b/src/bonsai/bonsai/bim/data/icons/dm_apply_axis.png new file mode 100644 index 0000000000..f77dd35c26 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_apply_axis.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_apply_profile.png b/src/bonsai/bonsai/bim/data/icons/dm_apply_profile.png new file mode 100644 index 0000000000..2d3a40e104 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_apply_profile.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_butt.png b/src/bonsai/bonsai/bim/data/icons/dm_butt.png index 615187620f..8ba6e70730 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_butt.png and b/src/bonsai/bonsai/bim/data/icons/dm_butt.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_centerline.png b/src/bonsai/bonsai/bim/data/icons/dm_centerline.png index 9f52ff4985..60ce5f0ce2 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_centerline.png and b/src/bonsai/bonsai/bim/data/icons/dm_centerline.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_centreline.png b/src/bonsai/bonsai/bim/data/icons/dm_centreline.png index 9f52ff4985..60ce5f0ce2 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_centreline.png and b/src/bonsai/bonsai/bim/data/icons/dm_centreline.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_circle.png b/src/bonsai/bonsai/bim/data/icons/dm_circle.png new file mode 100644 index 0000000000..8c5444dde1 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_circle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_connect_mep_elements.png b/src/bonsai/bonsai/bim/data/icons/dm_connect_mep_elements.png new file mode 100644 index 0000000000..8239fd14a6 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_connect_mep_elements.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_draw.png b/src/bonsai/bonsai/bim/data/icons/dm_draw.png new file mode 100644 index 0000000000..84d60b656b Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_draw.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_edit_axis.png b/src/bonsai/bonsai/bim/data/icons/dm_edit_axis.png index e804527460..e8700e5dd7 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_edit_axis.png and b/src/bonsai/bonsai/bim/data/icons/dm_edit_axis.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_edit_profile.png b/src/bonsai/bonsai/bim/data/icons/dm_edit_profile.png index 458cae080c..81e28320b7 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_edit_profile.png and b/src/bonsai/bonsai/bim/data/icons/dm_edit_profile.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_edit_railing_path.png b/src/bonsai/bonsai/bim/data/icons/dm_edit_railing_path.png new file mode 100644 index 0000000000..8c909b4256 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_edit_railing_path.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_edit_roof_path.png b/src/bonsai/bonsai/bim/data/icons/dm_edit_roof_path.png new file mode 100644 index 0000000000..a9a6ee7fc0 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_edit_roof_path.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_exterior.png b/src/bonsai/bonsai/bim/data/icons/dm_exterior.png index 19533f7ce9..c436505b36 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_exterior.png and b/src/bonsai/bonsai/bim/data/icons/dm_exterior.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_fillet.png b/src/bonsai/bonsai/bim/data/icons/dm_fillet.png new file mode 100644 index 0000000000..234752ae9d Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_fillet.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_flip.png b/src/bonsai/bonsai/bim/data/icons/dm_flip.png index 4a108ee2fb..55cc601555 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_flip.png and b/src/bonsai/bonsai/bim/data/icons/dm_flip.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_interior.png b/src/bonsai/bonsai/bim/data/icons/dm_interior.png index 2771aecafb..1b7b9903d2 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_interior.png and b/src/bonsai/bonsai/bim/data/icons/dm_interior.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_join.png b/src/bonsai/bonsai/bim/data/icons/dm_join.png new file mode 100644 index 0000000000..235f85935d Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_join.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_merge.png b/src/bonsai/bonsai/bim/data/icons/dm_merge.png index 1d78bd36a0..e9ec7312a7 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_merge.png and b/src/bonsai/bonsai/bim/data/icons/dm_merge.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_mirror.png b/src/bonsai/bonsai/bim/data/icons/dm_mirror.png index fb894b5898..826c392b85 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_mirror.png and b/src/bonsai/bonsai/bim/data/icons/dm_mirror.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_mitre.png b/src/bonsai/bonsai/bim/data/icons/dm_mitre.png index 552906a992..3b220db2f6 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_mitre.png and b/src/bonsai/bonsai/bim/data/icons/dm_mitre.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_offset.png b/src/bonsai/bonsai/bim/data/icons/dm_offset.png new file mode 100644 index 0000000000..5b4ffb4d73 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_offset.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_perform_quantity_take-off.png b/src/bonsai/bonsai/bim/data/icons/dm_perform_quantity_take-off.png index 7b538234c7..7ac80919d9 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_perform_quantity_take-off.png and b/src/bonsai/bonsai/bim/data/icons/dm_perform_quantity_take-off.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_rectangle.png b/src/bonsai/bonsai/bim/data/icons/dm_rectangle.png new file mode 100644 index 0000000000..f4323dfea6 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_rectangle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_rotate_90.png b/src/bonsai/bonsai/bim/data/icons/dm_rotate_90.png index 32c2e2fbdf..122fa80764 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_rotate_90.png and b/src/bonsai/bonsai/bim/data/icons/dm_rotate_90.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_set_gable_roof_angle.png b/src/bonsai/bonsai/bim/data/icons/dm_set_gable_roof_angle.png new file mode 100644 index 0000000000..d3dbf2f3c6 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/dm_set_gable_roof_angle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_split.png b/src/bonsai/bonsai/bim/data/icons/dm_split.png index e33e105c70..03018a8681 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_split.png and b/src/bonsai/bonsai/bim/data/icons/dm_split.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/dm_unjoin_walls.png b/src/bonsai/bonsai/bim/data/icons/dm_unjoin_walls.png index cb6f0f3f1f..453415aaa3 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/dm_unjoin_walls.png and b/src/bonsai/bonsai/bim/data/icons/dm_unjoin_walls.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_3-point_arc.png b/src/bonsai/bonsai/bim/data/icons/lm_3-point_arc.png new file mode 100644 index 0000000000..970710b2d8 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_3-point_arc.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_add.png b/src/bonsai/bonsai/bim/data/icons/lm_add.png index 8031b0577c..0ecbed228f 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_add.png and b/src/bonsai/bonsai/bim/data/icons/lm_add.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_add_bend.png b/src/bonsai/bonsai/bim/data/icons/lm_add_bend.png new file mode 100644 index 0000000000..daf84e0739 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_add_bend.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_add_transition.png b/src/bonsai/bonsai/bim/data/icons/lm_add_transition.png new file mode 100644 index 0000000000..12b8b1fdaf Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_add_transition.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_add_void.png b/src/bonsai/bonsai/bim/data/icons/lm_add_void.png index 90fba89728..58d5d4483a 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_add_void.png and b/src/bonsai/bonsai/bim/data/icons/lm_add_void.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_apply.png b/src/bonsai/bonsai/bim/data/icons/lm_apply.png new file mode 100644 index 0000000000..8d3e1c0108 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_apply.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_apply_axis.png b/src/bonsai/bonsai/bim/data/icons/lm_apply_axis.png new file mode 100644 index 0000000000..8f9725463b Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_apply_axis.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_apply_profile.png b/src/bonsai/bonsai/bim/data/icons/lm_apply_profile.png new file mode 100644 index 0000000000..25d94dd6f3 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_apply_profile.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_butt.png b/src/bonsai/bonsai/bim/data/icons/lm_butt.png index 73f33be177..baae236e38 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_butt.png and b/src/bonsai/bonsai/bim/data/icons/lm_butt.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_centerline.png b/src/bonsai/bonsai/bim/data/icons/lm_centerline.png index c49427f1ee..668c821754 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_centerline.png and b/src/bonsai/bonsai/bim/data/icons/lm_centerline.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_centreline.png b/src/bonsai/bonsai/bim/data/icons/lm_centreline.png index 718f41601c..668c821754 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_centreline.png and b/src/bonsai/bonsai/bim/data/icons/lm_centreline.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_circle.png b/src/bonsai/bonsai/bim/data/icons/lm_circle.png new file mode 100644 index 0000000000..02e5dfdd2a Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_circle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_connect_mep_elements.png b/src/bonsai/bonsai/bim/data/icons/lm_connect_mep_elements.png new file mode 100644 index 0000000000..25e314d574 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_connect_mep_elements.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_draw.png b/src/bonsai/bonsai/bim/data/icons/lm_draw.png new file mode 100644 index 0000000000..4b8a6717c7 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_draw.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_edit_axis.png b/src/bonsai/bonsai/bim/data/icons/lm_edit_axis.png index 536f15cd89..181582bbd9 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_edit_axis.png and b/src/bonsai/bonsai/bim/data/icons/lm_edit_axis.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_edit_profile.png b/src/bonsai/bonsai/bim/data/icons/lm_edit_profile.png index 16af577eec..5ca6dbe99b 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_edit_profile.png and b/src/bonsai/bonsai/bim/data/icons/lm_edit_profile.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_edit_railing_path.png b/src/bonsai/bonsai/bim/data/icons/lm_edit_railing_path.png new file mode 100644 index 0000000000..a726419632 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_edit_railing_path.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_edit_roof_path.png b/src/bonsai/bonsai/bim/data/icons/lm_edit_roof_path.png new file mode 100644 index 0000000000..686a4e53ca Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_edit_roof_path.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_exterior.png b/src/bonsai/bonsai/bim/data/icons/lm_exterior.png index e0ef805a04..b10fdd3ef0 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_exterior.png and b/src/bonsai/bonsai/bim/data/icons/lm_exterior.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_fillet.png b/src/bonsai/bonsai/bim/data/icons/lm_fillet.png new file mode 100644 index 0000000000..c29862e216 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_fillet.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_flip.png b/src/bonsai/bonsai/bim/data/icons/lm_flip.png index cb5df2c97b..b9e45b3e60 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_flip.png and b/src/bonsai/bonsai/bim/data/icons/lm_flip.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_interior.png b/src/bonsai/bonsai/bim/data/icons/lm_interior.png index b9bf1c76a3..db119ca332 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_interior.png and b/src/bonsai/bonsai/bim/data/icons/lm_interior.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_join.png b/src/bonsai/bonsai/bim/data/icons/lm_join.png new file mode 100644 index 0000000000..ff116439df Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_join.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_merge.png b/src/bonsai/bonsai/bim/data/icons/lm_merge.png index 0f707f1db9..271766bc1f 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_merge.png and b/src/bonsai/bonsai/bim/data/icons/lm_merge.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_mirror.png b/src/bonsai/bonsai/bim/data/icons/lm_mirror.png index 0a81d97d3f..c04bbc38c7 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_mirror.png and b/src/bonsai/bonsai/bim/data/icons/lm_mirror.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_mitre.png b/src/bonsai/bonsai/bim/data/icons/lm_mitre.png index b58f8d3f85..abaffeaab7 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_mitre.png and b/src/bonsai/bonsai/bim/data/icons/lm_mitre.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_offset.png b/src/bonsai/bonsai/bim/data/icons/lm_offset.png new file mode 100644 index 0000000000..36df4a2349 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_offset.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_perform_quantity_take-off.png b/src/bonsai/bonsai/bim/data/icons/lm_perform_quantity_take-off.png index c9a3ae8ed3..8dd986cc9c 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_perform_quantity_take-off.png and b/src/bonsai/bonsai/bim/data/icons/lm_perform_quantity_take-off.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_rectangle.png b/src/bonsai/bonsai/bim/data/icons/lm_rectangle.png new file mode 100644 index 0000000000..c87d1abba7 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_rectangle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_rotate_90.png b/src/bonsai/bonsai/bim/data/icons/lm_rotate_90.png index 9c9dd1161e..eaf26b2b5f 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_rotate_90.png and b/src/bonsai/bonsai/bim/data/icons/lm_rotate_90.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_set_gable_roof_angle.png b/src/bonsai/bonsai/bim/data/icons/lm_set_gable_roof_angle.png new file mode 100644 index 0000000000..0411b642f3 Binary files /dev/null and b/src/bonsai/bonsai/bim/data/icons/lm_set_gable_roof_angle.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_split.png b/src/bonsai/bonsai/bim/data/icons/lm_split.png index d3709d08ee..0fb0f5110b 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_split.png and b/src/bonsai/bonsai/bim/data/icons/lm_split.png differ diff --git a/src/bonsai/bonsai/bim/data/icons/lm_unjoin_walls.png b/src/bonsai/bonsai/bim/data/icons/lm_unjoin_walls.png index a67f0daa54..d6173d4898 100644 Binary files a/src/bonsai/bonsai/bim/data/icons/lm_unjoin_walls.png and b/src/bonsai/bonsai/bim/data/icons/lm_unjoin_walls.png differ diff --git a/src/bonsai/bonsai/bim/module/cad/__init__.py b/src/bonsai/bonsai/bim/module/cad/__init__.py index 3f0ac8e336..cf4d5297a0 100644 --- a/src/bonsai/bonsai/bim/module/cad/__init__.py +++ b/src/bonsai/bonsai/bim/module/cad/__init__.py @@ -40,8 +40,12 @@ def register(): bpy.utils.register_tool(workspace.CadTool, after={"builtin.transform"}, separator=True, group=False) bpy.types.Scene.BIMCadProperties = bpy.props.PointerProperty(type=prop.BIMCadProperties) + workspace.load_custom_icons() + def unregister(): if not bpy.app.background: bpy.utils.unregister_tool(workspace.CadTool) del bpy.types.Scene.BIMCadProperties + + workspace.unload_custom_icons() \ No newline at end of file diff --git a/src/bonsai/bonsai/bim/module/cad/workspace.py b/src/bonsai/bonsai/bim/module/cad/workspace.py index 501fbdb11f..6b3723cf72 100644 --- a/src/bonsai/bonsai/bim/module/cad/workspace.py +++ b/src/bonsai/bonsai/bim/module/cad/workspace.py @@ -24,11 +24,48 @@ import ifcopenshell.util.unit from bpy.types import WorkSpaceTool from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData +def check_display_mode(): + global display_mode + try: + theme = bpy.context.preferences.themes['Default'] + text_color = theme.user_interface.wcol_menu_item.text + background_color = theme.user_interface.wcol_menu_item.outline + print(f"text_color = {text_color}") + print(f"background_color = {background_color}") + if sum(text_color) < 2.6: + display_mode = "lm" + else: + display_mode = "dm" + except: + display_mode = "dm" + + +def load_custom_icons(): + global custom_icon_previews + if display_mode is None: + check_display_mode() + + icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons") + custom_icon_previews = bpy.utils.previews.new() + + prefix = f"{display_mode}_" + + for entry in os.scandir(icons_dir): + if entry.name.endswith(".png") and entry.name.startswith(prefix): + name = os.path.splitext(entry.name)[0].replace(prefix, "", 1) + custom_icon_previews.load(name.upper(), entry.path, "IMAGE") + + +def unload_custom_icons(): + global custom_icon_previews + if custom_icon_previews: + bpy.utils.previews.remove(custom_icon_previews) + custom_icon_previews = None + class CadTool(WorkSpaceTool): bl_space_type = "VIEW_3D" bl_context_mode = "EDIT_MESH" - bl_idname = "bim.cad_tool" bl_label = "CAD Tool" bl_description = "Gives you CAD authoring related superpowers" @@ -47,93 +84,47 @@ class CadTool(WorkSpaceTool): ) def draw_settings(context, layout, workspace_tool): + ui_context = str(context.region.type) obj = context.active_object if not obj or not obj.data: return if hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.subshape_type == "PROFILE": - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_Q") element = tool.Ifc.get_entity(obj) if element: if element.is_a("IfcProfileDef"): - row.operator("bim.edit_arbitrary_profile", text="Save Profile") - row.operator("bim.align_view_to_profile", text="", icon="AXIS_FRONT") - row.operator("bim.disable_editing_arbitrary_profile", text="", icon="CANCEL") + add_header_apply_button(layout, "Edit Profile", "bim.edit_arbitrary_profile", "bim.disable_editing_arbitrary_profile", ui_context) elif element.is_a("IfcRelSpaceBoundary"): - row.operator("bim.edit_boundary_geometry", text="Save Profile") - row.operator("bim.disable_editing_boundary_geometry", text="", icon="CANCEL") + add_header_apply_button(layout, "Edit Boundary Geometry", "bim.edit_boundary_geometry", "bim.disable_editing_boundary_geometry", ui_context) else: - row.operator("bim.edit_extrusion_profile", text="Save Profile") - row.operator("bim.align_view_to_profile", text="", icon="AXIS_FRONT") - row.operator("bim.disable_editing_extrusion_profile", text="", icon="CANCEL") + add_header_apply_button(layout, "Edit Profile", "bim.edit_extrusion_profile", "bim.disable_editing_extrusion_profile", ui_context) - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_E") - row.operator("bim.cad_hotkey", text="Extend").hotkey = "S_E" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_T") - row.operator("bim.cad_hotkey", text="Mitre").hotkey = "S_T" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_F") - row.operator("bim.cad_hotkey", text="Fillet").hotkey = "S_F" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_O") - row.operator("bim.cad_hotkey", text="Offset").hotkey = "S_O" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_R") - row.operator("bim.add_rectangle", text="Rectangle") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_C") - row.operator("bim.add_ifccircle", text="Circle") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_V") - row.operator("bim.set_arc_index", text="3-Point Arc") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_X") - row.operator("bim.reset_vertex", text="Reset Vertex") + row = layout.row(align=True) + add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Fillet", "S_V", "Fillet", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Offset", "S_O", "Offset", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Rectangle", "S_R", "Rectangle", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Circle", "S_C", "Circle", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "3-Point Arc", "S_V", "3-Point Arc", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Reset Vertex", "S_X", "Reset Vertex", ui_context) elif hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.subshape_type == "AXIS": - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_Q") - row.operator("bim.edit_extrusion_axis", text="Save Axis") - row.operator("bim.disable_editing_extrusion_axis", text="", icon="CANCEL") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_E") - row.operator("bim.cad_hotkey", text="Extend").hotkey = "S_E" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_T") - row.operator("bim.cad_hotkey", text="Mitre").hotkey = "S_T" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_F") - row.operator("bim.cad_hotkey", text="Fillet").hotkey = "S_F" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_O") - row.operator("bim.cad_hotkey", text="Offset").hotkey = "S_O" + add_header_apply_button(layout, "Edit Axis", "bim.set_arc_index", "bim.set_arc_index", ui_context) + row = layout.row(align=True) + add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Fillet", "S_F", "Fillet", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Offset", "S_O", "Offset", ui_context) else: if ( @@ -141,54 +132,29 @@ class CadTool(WorkSpaceTool): and RailingData.data["pset_data"] and context.active_object.BIMRailingProperties.is_editing_path ): - row = layout.row(align=True) - row.label(text="", icon=f"EVENT_TAB") - row.operator("bim.finish_editing_railing_path") - row.operator("bim.cancel_editing_railing_path", icon="CANCEL", text="") + add_header_apply_button(layout, "Edit Railing Path", "bim.finish_editing_railing_path", "bim.cancel_editing_railing_path", ui_context) elif ( (RoofData.is_loaded or not RoofData.load()) and RoofData.data["pset_data"] and context.active_object.BIMRoofProperties.is_editing_path ): - row = layout.row(align=True) - row.label(text="", icon=f"EVENT_TAB") - row.operator("bim.finish_editing_roof_path") - row.operator("bim.cancel_editing_roof_path", icon="CANCEL", text="") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_R") - row.operator("bim.cad_hotkey", text="Set Gable Roof Angle").hotkey = "S_R" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_E") - row.operator("bim.cad_hotkey", text="Extend").hotkey = "S_E" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_T") - row.operator("bim.cad_hotkey", text="Mitre").hotkey = "S_T" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_F") - row.operator("bim.cad_hotkey", text="Fillet").hotkey = "S_F" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_O") - row.operator("bim.cad_hotkey", text="Offset").hotkey = "S_O" - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="2-Point Arc", icon="EVENT_C") - - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_V") - row.operator("bim.cad_hotkey", text="3-Point Arc").hotkey = "S_V" + add_header_apply_button(layout, "Edit Roof Path", "bim.finish_editing_roof_path", "bim.cancel_editing_roof_path", ui_context) + row = layout.row(align=True) + add_layout_hotkey_operator(row, "Set Gable Roof Angle", "S_R", "Set Gable Roof Angle", ui_context) + + row = layout.row(align=True) + add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Fillet", "S_V", "Fillet", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "Offset", "S_O", "Offset", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "2-Point Arc", "S_C", "2-Point Arc", ui_context) + row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) + add_layout_hotkey_operator(row, "3-Point Arc", "S_V", "3-Point Arc", ui_context) class CadHotkey(bpy.types.Operator): @@ -196,6 +162,11 @@ class CadHotkey(bpy.types.Operator): bl_label = "CAD Hotkey" bl_options = {"REGISTER", "UNDO"} hotkey: bpy.props.StringProperty() + description: bpy.props.StringProperty() + + @classmethod + def description(cls, context, operator): + return operator.description or "" def execute(self, context): self.props = context.scene.BIMCadProperties @@ -306,3 +277,52 @@ class CadHotkey(bpy.types.Operator): and hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.subshape_type == "PROFILE" ) + + +def add_header_apply_button(layout, text, apply_operator, cancel_operator, ui_context=""): + custom_icon = custom_icon_previews.get(text.upper().replace(" ", "_"), custom_icon_previews["IFC"]).icon_id + row = layout.row(align=True) + row.label(text=f"{text} Mode", icon_value=custom_icon) + if apply_operator in ("bim.edit_arbitrary_profile", "bim.edit_extrusion_profile"): + row.operator("bim.align_view_to_profile", text="Align View" if ui_context!="TOOL_HEADER" else "", icon="AXIS_FRONT") + + row = layout.row(align=True) + row.operator(apply_operator, text="Apply" if ui_context!="TOOL_HEADER" else "", icon_value=custom_icon_previews["APPLY"].icon_id) + row.label(text="", icon="EVENT_TAB") if ui_context!="TOOL_HEADER" else row + + row = layout.row(align=True) + row.label(text="Tools") + + +def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context=""): + parts = hotkey.split("_") + modifier, key = parts + op_text = "" if ui_context == "TOOL_HEADER" else text + custom_icon = custom_icon_previews.get(text.upper().replace(" ", "_"), custom_icon_previews["IFC"]).icon_id + modifier_icon, modifier_str = MODIFIERS.get(modifier, ("NONE", "")) + + row = layout if ui_context == "TOOL_HEADER" else layout.row(align=True) + op = row.operator("bim.cad_hotkey", text=op_text, icon_value=custom_icon) + + if ui_context != "TOOL_HEADER" and len(parts) == 2: + layout = layout.row(align=True) # Create a new line for hotkey display + layout.label(text="", icon=modifier_icon) + layout.label(text="", icon=f"EVENT_{key}") + + hotkey_description = f"Hotkey: {modifier_str} {key}" + description = "\n\n".join(filter(None, [hotkey_description if description else ""])) + op.hotkey = hotkey + op.description = description or hotkey_description + + return op + + + + + +custom_icon_previews = None +display_mode = None + +MODIFIERS = { + "S": ("EVENT_SHIFT", "⇧"), +} diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 7802e64301..0c3a9f3f9b 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -73,7 +73,7 @@ class BimTool(WorkSpaceTool): bl_space_type = "VIEW_3D" bl_context_mode = "OBJECT" bl_idname = "bim.bim_tool" - bl_label = "BIM Tool" + bl_label = "Multi Object Tool" bl_description = "Create and edit elements by construction class" bl_icon = os.path.join(os.path.dirname(__file__), "ops.authoring.bim") bl_widget = None @@ -95,6 +95,7 @@ class BimTool(WorkSpaceTool): ("bim.hotkey", {"type": "Q", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_Q")]}), ("bim.hotkey", {"type": "R", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_R")]}), ("bim.hotkey", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_T")]}), + ("bim.hotkey", {"type": "U", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_U")]}), ("bim.hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_V")]}), ("bim.hotkey", {"type": "X", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_X")]}), ("bim.hotkey", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_Y")]}), @@ -107,7 +108,9 @@ class BimTool(WorkSpaceTool): def draw_settings(context, layout, ws_tool): # Unlike operators, Blender doesn't treat workspace tools as a class, so we'll create our own. - BimToolUI.draw(context, layout, ifc_element_type="all") + CreateObjectUI.draw(context, layout, ifc_element_type="all") + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout) class WallTool(BimTool): @@ -122,7 +125,9 @@ class WallTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class SlabTool(BimTool): @@ -137,7 +142,9 @@ class SlabTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class DoorTool(BimTool): @@ -152,7 +159,9 @@ class DoorTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class WindowTool(BimTool): @@ -167,7 +176,9 @@ class WindowTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class ColumnTool(BimTool): @@ -182,7 +193,9 @@ class ColumnTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class BeamTool(BimTool): @@ -197,7 +210,9 @@ class BeamTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class DuctTool(BimTool): @@ -212,7 +227,9 @@ class DuctTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class CableCarrierTool(BimTool): @@ -227,7 +244,9 @@ class CableCarrierTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class PipeTool(BimTool): @@ -242,7 +261,9 @@ class PipeTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class CableTool(BimTool): @@ -257,31 +278,28 @@ class CableTool(BimTool): @classmethod def draw_settings(cls, context, layout, ws_tool): - BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) + if context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context=""): - modifier, key = hotkey.split("_") + parts = hotkey.split("_") if hotkey else [] + modifier, key = (parts + ["", ""])[:2] - try: - custom_icon = custom_icon_previews[text.upper().replace(" ", "_")].icon_id - except KeyError: - custom_icon = custom_icon_previews["IFC"].icon_id + op_text = "" if ui_context == "TOOL_HEADER" else text + custom_icon = custom_icon_previews.get(text.upper().replace(" ", "_"), custom_icon_previews["IFC"]).icon_id + modifier_icon, modifier_str = MODIFIERS.get(modifier, ("NONE", "")) - modifier_icon, modifier_str = MODIFIERS[modifier] + row = layout.row(align=True) + op = row.operator("bim.hotkey", text=op_text, icon_value=custom_icon) - if ui_context == "TOOL_HEADER": - op = layout.operator("bim.hotkey", text="", icon_value=custom_icon) - else: - row = layout.row(align=True) - op = row.operator("bim.hotkey", text=text, icon_value=custom_icon) + if ui_context != "TOOL_HEADER": row.label(text="", icon=modifier_icon) - row.label(text="", icon=f"EVENT_{key}") + row.label(text="", icon=f"EVENT_{key}" if key else "BLANK1") - hotkey_description = f"Hotkey: {modifier_str} {key}" - if description: - description += "\n\n" - description += hotkey_description + hotkey_description = f"Hotkey: {modifier_str} {key}".strip() + description = "\n\n".join(filter(None, [description, hotkey_description])) op.hotkey = hotkey if ui_context == "TOOL_HEADER": @@ -291,7 +309,12 @@ def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context="") return op -class BimToolUI: +def format_ifc_camel_case(string): + string = string.replace("Ifc", "") + return ''.join(' ' + char if char.isupper() else char for char in string).strip() + + +class CreateObjectUI: @classmethod def draw(cls, context, layout, ifc_element_type=None): cls.layout = layout @@ -312,51 +335,71 @@ class BimToolUI: elif AuthoringData.data["ifc_element_type"] != ifc_element_type: AuthoringData.load(ifc_element_type) - if context.region.type == "TOOL_HEADER": - cls.draw_container(context) - cls.draw_type_selection_interface(context) - if context.active_object and context.selected_objects: - cls.draw_edit_object_header_interface(context) + if ifc_element_type and context.region.type == "TOOL_HEADER": + tool_name = "Multi Object Tool" if ifc_element_type == "all" else format_ifc_camel_case(ifc_element_type.removesuffix('Type')) + ' Tool' + cls.layout.label(text=tool_name, icon="TOOL_SETTINGS") - elif context.region.type in ("UI", "WINDOW"): - cls.draw_container(context) - cls.draw_thumbnail() - cls.draw_type_selection_interface(context) - if context.active_object and context.selected_objects: - cls.draw_edit_object_panel_interface(context) + cls.draw_type_manager_launcher(context) + cls.draw_thumbnail() if context.region.type != "TOOL_HEADER" else cls + cls.draw_add_object(context) + + @classmethod + def draw_container_info(cls, context): + text = AuthoringData.data["default_container"] + if context.region.type == "UI": + text = f"Container: {text}" - if not context.selected_objects: - cls.draw_create_object_interface() + cls.layout.row(align=True).label(text=text, icon="OUTLINER_COLLECTION") @classmethod - def draw_create_object_interface(cls): + def draw_type_manager_launcher(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + if not AuthoringData.data["ifc_classes"]: + if AuthoringData.data["ifc_element_type"]: + row.label(text=f"No {AuthoringData.data['ifc_element_type']} Found", icon="ERROR") + row = cls.layout.row(align=True) + op = row.operator( + "bim.add_default_type", + icon_value=custom_icon_previews["ADD_TYPE"].icon_id, + text=f"Create default {AuthoringData.data['ifc_element_type']}", + ) + op.ifc_element_type = AuthoringData.data["ifc_element_type"] + else: + row.label(text="No Element Types Found", icon="ERROR") + row = cls.layout.row(align=True) + row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="Launch Type Manager") + + @classmethod + def draw_add_object(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) if not AuthoringData.data["relating_type_id"]: return + if cls.props.ifc_class == "IfcWallType": - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl1", text="RL") - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="extrusion_depth", text="Height") - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="length", text="Length") - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle") + row.prop(data=cls.props, property="rl1", text="Relative Level" if ui_context != "TOOL_HEADER" else "RL") + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context != "TOOL_HEADER" else "H") + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="length", text="Length" if ui_context != "TOOL_HEADER" else "L") + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="x_angle", text="Slope") if ui_context != "TOOL_HEADER" else "A" + elif cls.props.ifc_class in ("IfcSlabType", "IfcRampType", "IfcRoofType"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle") - elif cls.props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="cardinal_point", text="Axis") + row.prop(data=cls.props, property="x_angle", text="Slope" if ui_context != "TOOL_HEADER" else "A", icon="FILE_3D") + + elif cls.props.ifc_class in ("IfcColumnType", "IfcMemberType"): + row.prop(data=cls.props, property="cardinal_point", text="Axis") + row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context !="TOOL_HEADER" else "H") + + elif cls.props.ifc_class in ("IfcBeamType"): + row.prop(data=cls.props, property="cardinal_point", text="Axis") + row.prop(data=cls.props, property="extrusion_depth", text="Length" if ui_context !="TOOL_HEADER" else "L") - row = cls.layout.row(align=True) - label = "Height" if cls.props.ifc_class == "IfcColumn" else "Length" - row.prop(data=cls.props, property="extrusion_depth", text=label) elif cls.props.ifc_class in ("IfcDoorType", "IfcDoorStyle"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl1", text="RL") + row.prop(data=cls.props, property="rl1", text="Relative Level" if ui_context != "TOOL_HEADER" else "RL") + elif cls.props.ifc_class in ( "IfcWindowType", "IfcWindowStyle", @@ -367,604 +410,30 @@ class BimToolUI: "IfcCableCarrierSegmentType", "IfcCableSegmentType", ): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl2", text="RL") + row.prop(data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL") + + ### this neeeds to move elif cls.props.ifc_class in ("IfcSpaceType"): - add_layout_hotkey_operator(cls.layout, "Generate", "S_G", "Generate a space at the cursor position") + add_layout_hotkey_operator(cls.layout, "Generate", "S_G", bpy.ops.bim.generate_space.__doc__, ui_context) + ### else: row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl_mode", text="RL") + row.prop(data=cls.props, property="rl_mode", text="RL Mode" if ui_context != "TOOL_HEADER" else "RL") - @classmethod - def draw_edit_object_panel_interface(cls, context): - ui_context = str(context.region.type) - if AuthoringData.data["active_material_usage"] == "LAYER2": - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="extrusion_depth", text="Height:") - op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") - op.depth = cls.props.extrusion_depth - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="length", text="Length:") - op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="") - op.length = cls.props.length - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle:") - op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") - op.x_angle = cls.props.x_angle - - cls.layout.separator() - - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected Element", ui_context) - - cls.layout.separator() - - add_layout_hotkey_operator( - cls.layout, - "Extend", - "S_E", - "Extends/ reduces Element to 3D cursor", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Butt", - "S_T", - "Intersects two non-parallel Elements to a butt corner junction", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Mitre", - "S_Y", - "Intersects two non-parallel Elements to a mitred corner junction", - ui_context, - ) - - row = cls.layout.row(align=True) - row.operator( - "bim.unjoin_walls", text="Unjoin Walls", icon_value=custom_icon_previews["UNJOIN_WALLS"].icon_id - ) - cls.layout.separator() - - add_layout_hotkey_operator(cls.layout, "Merge", "S_M", "Merge selected Elements", ui_context) - add_layout_hotkey_operator( - cls.layout, - "Split", - "S_K", - "Split selected Element into two Elements at the cursor location", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, "Rotate 90", "S_R", "Rotate the selected Element by 90 degrees", ui_context - ) - add_layout_hotkey_operator( - cls.layout, "Flip", "S_F", "Flip Element about its local axes, keep the position", ui_context - ) - - # row.operator("bim.unjoin_walls", icon="X", text="") - - elif AuthoringData.data["active_material_usage"] == "LAYER3": - if len(context.selected_objects) == 1: - add_layout_hotkey_operator( - cls.layout, "Edit Profile", "S_E", "Edit associated Profile Element", ui_context - ) - elif "LAYER2" in AuthoringData.data["selected_material_usages"]: - add_layout_hotkey_operator( - cls.layout, - "Extend Wall To Slab", - "S_E", - "Extend the selected Wall to the selected Slab", - ui_context, - ) - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle") - op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") - op.x_angle = cls.props.x_angle - - elif AuthoringData.data["active_material_usage"] == "PROFILE": - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="cardinal_point", text="Axis") - op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") - op.cardinal_point = int(cls.props.cardinal_point) - - row = cls.layout.row(align=True) - label = ( - "Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length" - ) - row.prop(data=cls.props, property="extrusion_depth", text=label) - op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="") - op.depth = cls.props.extrusion_depth - - add_layout_hotkey_operator( - cls.layout, - "Extend", - "S_E", - "Extends/ reduces element to 3D cursor", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, "Flip", "S_F", "Flip object about its local axes, keep the position", ui_context - ) - - if AuthoringData.data["active_class"] in ( - "IfcCableCarrierSegment", - "IfcCableSegment", - "IfcDuctSegment", - "IfcPipeSegment", - ): - - add_layout_hotkey_operator( - cls.layout, - "Add Fitting", - "S_Y", - "Add a Fitting based on currently selected Elements and cursor", - ui_context, - ) - cls.layout.operator("bim.mep_add_bend") - cls.layout.operator("bim.mep_add_transition") - cls.layout.operator("bim.mep_add_obstruction") - - else: - add_layout_hotkey_operator( - cls.layout, - "Edit Axis", - "A_E", - "Edit axis of element", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Butt", - "S_T", - "Intersects two non-parallel Elements to a butt corner junction", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Mitre", - "S_Y", - "Intersects two non-parallel Elements to a mitred corner junction", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, "Rotate 90", "S_R", "Rotate the selected element by 90 degrees", ui_context - ) - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected element", ui_context) - row.operator("bim.extend_profile", icon="X", text="").join_type = "" - - elif ( - tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path - ): - # NOTE: should be above "active_representation_type" = "SweptSolid" check - # because it could be a SweptSolid too - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_TAB") - row.operator("bim.enable_editing_railing_path", text="Edit Railing Path") - - elif AuthoringData.data["active_class"] in ( - "IfcWindow", - "IfcWindowStandardCase", - "IfcDoor", - "IfcDoorStandardCase", - ): - if AuthoringData.data["active_class"] in ("IfcWindow", "IfcWindowStandardCase"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl2", text="RL") - elif AuthoringData.data["active_class"] in ("IfcDoor", "IfcDoorStandardCase"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl1", text="RL") - - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected Element", ui_context) - add_layout_hotkey_operator( - cls.layout, "Flip", "S_F", "Flip object about its local axes, keep the position", ui_context - ) - - elif AuthoringData.data["active_representation_type"] == "SweptSolid": - if not tool.Model.is_parametric_window_active() and not tool.Model.is_parametric_door_active(): - add_layout_hotkey_operator( - cls.layout, "Edit Profile", "S_E", "Edit assosiated Profile Element", ui_context - ) - - elif AuthoringData.data["active_class"] in ("IfcSpace",): - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected Space", ui_context) - - elif tool.Model.is_parametric_roof_active() and not context.active_object.BIMRoofProperties.is_editing_path: - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_TAB") - row.operator("bim.enable_editing_roof_path", text="Edit Roof Path") - - if context.region.type != "TOOL_HEADER" and PortData.data["total_ports"] > 0: - add_layout_hotkey_operator( - cls.layout, - "Regen MEP", - "S_G", - "Regenerates the positions and segment lengths of a distribution element and all connected elements", - ui_context, - ) - cls.layout.operator("bim.mep_connect_elements") - - row = cls.layout.row(align=True) - if len(context.selected_objects) > 1: - row.operator("bim.add_opening", text="Apply Opening", icon_value=custom_icon_previews["VOID"].icon_id) - else: - row.operator( - "bim.add_potential_opening", text="Add Opening", icon_value=custom_icon_previews["ADD_VOID"].icon_id - ) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_O") - - if AuthoringData.data["is_voidable_element"]: - if AuthoringData.data["has_visible_openings"]: - row = cls.layout.row(align=True) - row.operator("bim.edit_openings", icon="CHECKMARK", text="") - row.operator("bim.hide_openings", icon="CANCEL", text="") - - if AuthoringData.data["active_class"] in ("IfcOpeningElement",): - row.operator("bim.edit_openings", icon="CHECKMARK", text="") - row.operator("bim.hide_openings", icon="CANCEL", text="") - if len(context.selected_objects) == 2: - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_L") - row.operator("bim.clone_opening", text="Clone Opening") - - cls.layout.row(align=True).label(text="Align") - add_layout_hotkey_operator( - cls.layout, - "Exterior", - "S_X", - "Align selected Elements to the Exterior of the last selected object", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Centerline", - "S_C", - "Align selected Elements to the Centerline of the last selected object", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Interior", - "S_V", - "Align selected Elements to the Interior of the last selected object", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Mirror", - "S_M", - "Mirrors the selected Elements along a mirror plane set by the last selected object", - ui_context, - ) - - cls.layout.row(align=True).label(text="Mode") - add_layout_hotkey_operator( - cls.layout, "Opening", "A_O", "Toggle display of Openings in the selected Elements", ui_context - ) - add_layout_hotkey_operator(cls.layout, "Decomposition", "A_D", "Select decomposition", ui_context) - - cls.layout.row(align=True).label(text="Aggregation") - add_layout_hotkey_operator(cls.layout, "Assign", "C_P", "Assign element to Aggregation", ui_context) - add_layout_hotkey_operator(cls.layout, "Unassign", "A_P", "Unassign element from Aggregation", ui_context) - - cls.layout.row(align=True).label(text="Qto") - add_layout_hotkey_operator( - cls.layout, - "Perform Quantity Take-off", - "S_Q", - "Perform a quantity take off on selected objects based of a QTO rule configuration", - ui_context, - ) - - @classmethod - def draw_edit_object_header_interface(cls, context): - ui_context = str(context.region.type) - if AuthoringData.data["active_material_usage"] == "LAYER2": - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="extrusion_depth", text="Height:") - op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") - op.depth = cls.props.extrusion_depth - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="length", text="Length:") - op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="") - op.length = cls.props.length - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle:") - op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") - op.x_angle = cls.props.x_angle - - row = cls.layout.row() - add_layout_hotkey_operator(row, "Regen", "S_G", "Regenerate selected Element", ui_context) - - row = cls.layout.row(align=True) - add_layout_hotkey_operator( - row, - "Extend", - "S_E", - "Extends/reduces Element to 3D cursor", - ui_context, - ) - add_layout_hotkey_operator( - row, - "Butt", - "S_T", - "Intersects two non-parallel Elements to a butt corner junction", - ui_context, - ) - add_layout_hotkey_operator( - row, - "Mitre", - "S_Y", - "Intersects two non-parallel Elements to a mitred corner junction", - ui_context, - ) - row.operator("bim.unjoin_walls", text="", icon_value=custom_icon_previews["UNJOIN_WALLS"].icon_id) - - row = cls.layout.row(align=True) - add_layout_hotkey_operator(row, "Merge", "S_M", "Merge selected Elements", ui_context) - add_layout_hotkey_operator( - row, "Split", "S_K", "Split selected Element into two Elements at the cursor location", ui_context - ) - add_layout_hotkey_operator(row, "Rotate 90", "S_R", "Rotate the selected Element by 90 degrees", ui_context) - add_layout_hotkey_operator( - row, "Flip", "S_F", "Flip Element about its local axes, keep the position", ui_context - ) - - elif AuthoringData.data["active_material_usage"] == "LAYER3": - if len(context.selected_objects) == 1: - add_layout_hotkey_operator( - cls.layout, "Edit Profile", "S_E", "Edit associated Profile Element", ui_context - ) - elif "LAYER2" in AuthoringData.data["selected_material_usages"]: - add_layout_hotkey_operator( - cls.layout, - "Extend Wall To Slab", - "S_E", - "Extend the selected Wall to the selected Slab", - ui_context, - ) - - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="x_angle", text="Angle") - op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") - op.x_angle = cls.props.x_angle - - elif AuthoringData.data["active_material_usage"] == "PROFILE": - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="cardinal_point", text="Axis") - op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") - op.cardinal_point = int(cls.props.cardinal_point) - - row = cls.layout.row(align=True) - label = ( - "Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length" - ) - row.prop(data=cls.props, property="extrusion_depth", text=label) - op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="") - op.depth = cls.props.extrusion_depth - - add_layout_hotkey_operator( - cls.layout, - "Extend", - "S_E", - "Extends/ reduces element to 3D cursor", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, "Flip", "S_F", "Flip object about its local axes, keep the position", ui_context - ) - - if AuthoringData.data["active_class"] in ( - "IfcCableCarrierSegment", - "IfcCableSegment", - "IfcDuctSegment", - "IfcPipeSegment", - ): - - add_layout_hotkey_operator( - cls.layout, - "Add Fitting", - "S_Y", - "Add a Fitting based on currently selected Elements and cursor", - ui_context, - ) - if context.region.type != "TOOL_HEADER": - cls.layout.operator("bim.mep_add_bend") - cls.layout.operator("bim.mep_add_transition") - cls.layout.operator("bim.mep_add_obstruction") - - else: - add_layout_hotkey_operator( - cls.layout, - "Edit Axis", - "A_E", - "Edit axis of Element", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Butt", - "S_T", - "Intersects two non-parallel Elements to a butt corner junction", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, - "Mitre", - "S_Y", - "Intersects two non-parallel Elements to a mitred corner junction", - ui_context, - ) - add_layout_hotkey_operator( - cls.layout, "Rotate 90", "S_R", "Rotate the selected element by 90 degrees", ui_context - ) - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected element", ui_context) - row.operator("bim.extend_profile", icon="X", text="").join_type = "" - - elif ( - tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path - ): - # NOTE: should be above "active_representation_type" = "SweptSolid" check - # because it could be a SweptSolid too - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_TAB") - row.operator("bim.enable_editing_railing_path", text="Edit Railing Path") - - elif AuthoringData.data["active_class"] in ( - "IfcWindow", - "IfcWindowStandardCase", - "IfcDoor", - "IfcDoorStandardCase", - ): - if AuthoringData.data["active_class"] in ("IfcWindow", "IfcWindowStandardCase"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl2", text="RL") - elif AuthoringData.data["active_class"] in ("IfcDoor", "IfcDoorStandardCase"): - row = cls.layout.row(align=True) - row.prop(data=cls.props, property="rl1", text="RL") - - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected Element", ui_context) - add_layout_hotkey_operator( - cls.layout, "Flip", "S_F", "Flip object about its local axes, keep the position", ui_context - ) - - elif AuthoringData.data["active_representation_type"] == "SweptSolid": - if not tool.Model.is_parametric_window_active() and not tool.Model.is_parametric_door_active(): - add_layout_hotkey_operator( - cls.layout, "Edit Profile", "S_E", "Edit assosiated Profile Element", ui_context - ) - - elif AuthoringData.data["active_class"] in ("IfcSpace",): - add_layout_hotkey_operator(cls.layout, "Regen", "S_G", "Regenerate selected Space", ui_context) - - elif tool.Model.is_parametric_roof_active() and not context.active_object.BIMRoofProperties.is_editing_path: - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_TAB") - row.operator("bim.enable_editing_roof_path", text="Edit Roof Path") - - if context.region.type != "TOOL_HEADER" and PortData.data["total_ports"] > 0: - add_layout_hotkey_operator( - cls.layout, - "Regen MEP", - "S_G", - "Regenerates the positions and segment lengths of a distribution element and all connected elements", - ui_context, - ) - cls.layout.operator("bim.mep_connect_elements") - - row = cls.layout.row(align=True) - if len(context.selected_objects) > 1: - row.operator("bim.add_opening", text="", icon_value=custom_icon_previews["VOID"].icon_id) - else: - row.operator("bim.add_potential_opening", text="", icon_value=custom_icon_previews["ADD_VOID"].icon_id) - - if AuthoringData.data["is_voidable_element"]: - if AuthoringData.data["has_visible_openings"]: - row = cls.layout.row(align=True) - row.operator("bim.edit_openings", icon="CHECKMARK", text="") - row.operator("bim.hide_openings", icon="CANCEL", text="") - - if AuthoringData.data["active_class"] in ("IfcOpeningElement",): - row.operator("bim.edit_openings", icon="CHECKMARK", text="") - row.operator("bim.hide_openings", icon="CANCEL", text="") - if len(context.selected_objects) == 2: - row = cls.layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_L") - row.operator("bim.clone_opening", text="Clone Opening") - - row = cls.layout.row(align=True) - add_layout_hotkey_operator( - row, "Exterior", "S_X", "Align selected Elements to the Exterior of the last selected object", ui_context - ) - add_layout_hotkey_operator( - row, - "Centerline", - "S_C", - "Align selected Elements to the Centerline of the last selected object", - ui_context, - ) - add_layout_hotkey_operator( - row, "Interior", "S_V", "Align selected Elements to the Interior of the last selected object", ui_context - ) - add_layout_hotkey_operator( - row, - "Mirror", - "S_M", - "Mirrors the selected Elements along a mirror plane set by the last selected object", - ui_context, - ) - - row = cls.layout.row(align=True) - add_layout_hotkey_operator( - row, "Opening", "A_O", "Toggle display of Openings in the selected Elements", ui_context - ) - add_layout_hotkey_operator(row, "Decomposition", "A_D", "Select decomposition", ui_context) - - row = cls.layout.row(align=True) - add_layout_hotkey_operator(row, "Assign", "C_P", "Assign element to Aggregation", ui_context) - add_layout_hotkey_operator(row, "Unassign", "A_P", "Unassign element from Aggregation", ui_context) - - row = cls.layout.row() - add_layout_hotkey_operator( - row, - "Perform Quantity Take-off", - "S_Q", - "Perform a quantity take off on selected objects based of a QTO rule configuration", - ui_context, - ) - - @classmethod - def draw_container(cls, context): - text = AuthoringData.data["default_container"] - if context.region.type == "UI": - text = f"Container: {text}" - - cls.layout.row(align=True).label(text=text, icon="OUTLINER_COLLECTION") - - @classmethod - def draw_type_selection_interface(cls, context): - # shared by both sidebar and header - ui_context = str(context.region.type) - row = cls.layout.row(align=True) if AuthoringData.data["ifc_classes"]: - if ui_context == "UI": - text = "Add" - else: - text = "" - if not AuthoringData.data["ifc_element_type"]: - prop_with_search(row, cls.props, "ifc_class", text="") - - row = cls.layout.row(align=True) + if not AuthoringData.data["ifc_element_type"]: + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + prop_with_search(row, cls.props, "ifc_class", text="Type Class" if ui_context != "TOOL_HEADER" else "") if AuthoringData.data["relating_type_id"]: - prop_with_search(row, cls.props, "relating_type_id", text="") - row.operator("bim.add_constr_type_instance", text=text, icon_value=custom_icon_previews[f"ADD"].icon_id) - + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + prop_with_search(row, cls.props, "relating_type_id", text="Relating Type" if ui_context != "TOOL_HEADER" else "") + row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="") + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Add", "S_A", bpy.ops.bim.add_constr_type_instance.__doc__, ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Draw", "S_P", bpy.ops.bim.draw_polyline_wall.__doc__, ui_context) if cls.props.ifc_class == "IfcWallType" else row else: row.label(text="No Construction Type", icon="FILE_3D") - row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="") - else: - if AuthoringData.data["ifc_element_type"]: - row.label(text=f"No {AuthoringData.data['ifc_element_type']} Found", icon="ERROR") - row = cls.layout.row() - row.prop(cls.props, "type_name") - row = cls.layout.row(align=True) - op = row.operator( - "bim.add_default_type", - icon_value=custom_icon_previews["ADD_TYPE"].icon_id, - text=f"Create {AuthoringData.data['ifc_element_type']}", - ) - op.ifc_element_type = AuthoringData.data["ifc_element_type"] - row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="") - else: - row.label(text="No Element Types Found", icon="ERROR") - row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="Launch Type Manager") @classmethod def draw_thumbnail(cls): @@ -978,9 +447,289 @@ class BimToolUI: op.ifc_class = cls.props.ifc_class +class EditObjectUI: + @classmethod + def draw(cls, context, layout, ifc_element_type=None): + cls.layout = layout + cls.props = context.scene.BIMModelProperties + + row = cls.layout.row(align=True) + row.separator() + if not tool.Ifc.get(): + row.label(text="No IFC Project", icon="ERROR") + return + + if not PortData.is_loaded: + PortData.load() + + if not AuthoringData.is_loaded: + AuthoringData.load(ifc_element_type) + elif ifc_element_type == "all" and AuthoringData.data["ifc_element_type"] is not None: + AuthoringData.load("all") + elif AuthoringData.data["ifc_element_type"] != ifc_element_type: + AuthoringData.load(ifc_element_type) + + if context.region.type == "TOOL_HEADER": + text = format_ifc_camel_case(AuthoringData.data["active_class"]) + layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF") + cls.draw_parameter_adjustments(context) + row = cls.draw_operations(context) + cls.draw_void(context, row) + cls.draw_align(context) + cls.draw_aggregation(context) + cls.draw_qto(context) + cls.draw_modes(context) + + if context.region.type in ("UI", "WINDOW"): + text = format_ifc_camel_case(AuthoringData.data["active_class"]) + layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF") + cls.draw_parameter_adjustments(context) + row = cls.draw_operations(context) + cls.draw_void(context, row) + cls.draw_align(context) + cls.draw_aggregation(context) + cls.draw_qto(context) + cls.draw_modes(context) + + @classmethod + def draw_parameter_adjustments(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + row.label(text="Parameter Adjustments") if ui_context != "TOOL_HEADER" else row + row = cls.layout.row(align=True) + + if AuthoringData.data["active_material_usage"] == "LAYER2": + row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context != "TOOL_HEADER" else "H") + op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") + op.depth = cls.props.extrusion_depth + + row = cls.layout.row(align=True)if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="length", text="Length" if ui_context != "TOOL_HEADER" else "L") + op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="") + op.length = cls.props.length + + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="x_angle", text="Slope" if ui_context != "TOOL_HEADER" else "A") + op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") + op.x_angle = cls.props.x_angle + + elif AuthoringData.data["active_material_usage"] == "LAYER3": + row.prop(data=cls.props, property="x_angle", text="Angle" if ui_context != "TOOL_HEADER" else "A") + op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") + op.x_angle = cls.props.x_angle + + elif AuthoringData.data["active_material_usage"] == "PROFILE": + row.prop(data=cls.props, property="cardinal_point", text="Axis" if ui_context != "TOOL_HEADER" else "") + op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") + op.cardinal_point = int(cls.props.cardinal_point) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + label = ("Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length") + row.prop(data=cls.props, property="extrusion_depth", text=label if ui_context != "TOOL_HEADER" else label[0]) + op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="") + op.depth = cls.props.extrusion_depth + + elif AuthoringData.data["active_class"] in ("IfcWindow","IfcWindowStandardCase","IfcDoor","IfcDoorStandardCase"): + if AuthoringData.data["active_class"] in ("IfcWindow", "IfcWindowStandardCase"): + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL") + elif AuthoringData.data["active_class"] in ("IfcDoor", "IfcDoorStandardCase"): + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.prop(data=cls.props, property="rl1", text="Relative Level (rl1)" if ui_context != "TOOL_HEADER" else "RL") + + @classmethod + def draw_operations(cls, context): + ui_context = str(context.region.type) + + row = cls.layout.row(align=True) + row.separator() + row.label(text="Operations") if ui_context != "TOOL_HEADER" else row + cls.draw_regen_operations(row) + + if AuthoringData.data["active_material_usage"] == "LAYER2": + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Butt", "S_T", "Intersects two non-parallel elements to a butt corner junction", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Mitre", "S_Y", "Intersects two non-parallel elements to a mitred corner junction", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Unjoin Walls", "S_U", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Merge", "S_M", "Merge selected Elements", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Split", "S_K", "Split selected Element into two Elements at the cursor location", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Rotate 90", "S_R", "Rotate the selected Element by 90 degrees", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Flip", "S_F", "Flip Element about its local axes, keep the position", ui_context) + + elif AuthoringData.data["active_material_usage"] == "LAYER3": + if "LAYER2" in AuthoringData.data["selected_material_usages"]: + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(cls.layout, "Extend Wall To Slab", "S_E", "", ui_context) + + elif AuthoringData.data["active_material_usage"] == "PROFILE": + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Extend", "S_E", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Flip", "S_F", bpy.ops.bim.flip_object.__doc__, ui_context) + + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + if AuthoringData.data["active_class"] in ("IfcCableCarrierSegment","IfcCableSegment","IfcDuctSegment","IfcPipeSegment"): + add_layout_hotkey_operator(row, "Add Fitting", "S_Y", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.mep_add_bend", text="Add Bend" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["ADD_BEND"].icon_id) + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.mep_add_transition", text="Add Transition" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["ADD_TRANSITION"].icon_id) + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.mep_add_obstruction", text="Add Obstruction" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["IFC"].icon_id) + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + + else: + add_layout_hotkey_operator( row, "Edit Axis", "A_E", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Butt", "S_T", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Mitre", "S_Y", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Rotate 90", "S_R", bpy.ops.bim.rotate_90.__doc__, ui_context) + + if PortData.data["total_ports"] > 0: + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.mep_connect_elements", text="Connect MEP Elements" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["CONNECT_MEP_ELEMENTS"].icon_id) + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row + + return row + + @classmethod + def draw_regen_operations(cls, row): + custom_icon = custom_icon_previews.get("REGEN", custom_icon_previews["IFC"]).icon_id + + if AuthoringData.data["active_material_usage"] == "LAYER2": + op = row.operator("bim.hotkey", text="", icon_value=custom_icon) + description = f"{bpy.ops.bim.recalculate_wall.__doc__}\n\nHotkey: S G" + op.hotkey = "S_G" + op.description = description.strip() + elif AuthoringData.data["active_material_usage"] == "PROFILE": + if AuthoringData.data["active_class"] in ("IfcCableCarrierSegment","IfcCableSegment","IfcDuctSegment","IfcPipeSegment"): + pass + else: + op = row.operator("bim.hotkey", text="", icon_value=custom_icon) + description = f"{bpy.ops.bim.recalculate_profile.__doc__}\n\nHotkey: S G" + op.hotkey = "S_G" + op.description = description.strip() + + if PortData.data["total_ports"] > 0: + op = row.operator("bim.hotkey", text="", icon_value=custom_icon) + description = f"{bpy.ops.bim.regenerate_distribution_element.__doc__}\n\nHotkey: S G" + op.hotkey = "S_G" + op.description = description.strip() + + @classmethod + def draw_void(cls, context, row): + ui_context = str(context.region.type) + + if len(context.selected_objects) > 1: + op_text = "Apply Void" if ui_context != "TOOL_HEADER" else "" + op_icon = custom_icon_previews["APPLY_VOID"].icon_id + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.add_opening", text=op_text, icon_value=op_icon) + else: + op_text = "Add Void" if ui_context != "TOOL_HEADER" else "" + op_icon = custom_icon_previews["ADD_VOID"].icon_id + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.add_potential_opening", text=op_text, icon_value=op_icon) + if ui_context != "TOOL_HEADER": + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_O") + + if AuthoringData.data["is_voidable_element"]: + if AuthoringData.data["has_visible_openings"]: + row = cls.layout.row(align=True) + row.operator("bim.edit_openings", icon="CHECKMARK", text="") + row.operator("bim.hide_openings", icon="CANCEL", text="") + + if AuthoringData.data["active_class"] in ("IfcOpeningElement",): + row = cls.layout.row(align=True) + row.operator("bim.edit_openings", icon="CHECKMARK", text="") + row.operator("bim.hide_openings", icon="CANCEL", text="") + if len(context.selected_objects) == 2: + row = cls.layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_L") + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.clone_opening", text="Clone Opening") + + @classmethod + def draw_align(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + row.separator() + row.label(text="Align") if ui_context != "TOOL_HEADER" else row + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Exterior", "S_X", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Centreline", "S_C", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Interior", "S_V", "", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Mirror", "S_M", bpy.ops.bim.mirror_elements.__doc__, ui_context) + + @classmethod + def draw_aggregation(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + row.separator() + row.label(text="Aggregation") if ui_context != "TOOL_HEADER" else row + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Assign", "C_P", bpy.ops.bim.aggregate_assign_object.__doc__, ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Unassign", "A_P", bpy.ops.bim.aggregate_unassign_object.__doc__, ui_context) + + @classmethod + def draw_qto(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + row.separator() + row.label(text="Quantity Take-off") if ui_context != "TOOL_HEADER" else row + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Perform Quantity Take-off", "S_Q", bpy.ops.bim.perform_quantity_take_off.__doc__, ui_context) + + @classmethod + def draw_modes(cls, context): + ui_context = str(context.region.type) + row = cls.layout.row(align=True) + row.separator() + row.label(text="Mode") if ui_context != "TOOL_HEADER" else row + + if AuthoringData.data["active_material_usage"] == "LAYER3": + if len(context.selected_objects) == 1: + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Edit Profile", "S_E", "", ui_context) + elif (tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path): + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + row.operator("bim.enable_editing_railing_path", text="Edit Path" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["EDIT_RAILING_PATH"].icon_id) + elif AuthoringData.data["active_material_usage"] == "PROFILE": + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Edit Axis", "A_E", "", ui_context) + + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Toggle Openings", "A_O", "Toggle openings", ui_context) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + add_layout_hotkey_operator(row, "Decomposition", "A_D", "Select decomposition", ui_context) + + class Hotkey(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.hotkey" - bl_label = "" + bl_label = "BIM Hotkey" bl_options = {"REGISTER", "UNDO"} hotkey: bpy.props.StringProperty() description: bpy.props.StringProperty() @@ -1055,9 +804,9 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): return if self.active_material_usage == "LAYER2": if bpy.ops.bim.align_wall.poll(): - bpy.ops.bim.align_wall(align_type="CENTERLINE") + bpy.ops.bim.align_wall(align_type="Centreline") else: - bpy.ops.bim.align_product(align_type="CENTERLINE") + bpy.ops.bim.align_product(align_type="Centreline") def hotkey_S_E(self): if not bpy.context.selected_objects: @@ -1227,7 +976,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): def hotkey_S_V(self): if not bpy.context.selected_objects: return - if self.active_material_usage == "LAYER2": + elif self.active_material_usage == "LAYER2": bpy.ops.bim.align_wall(align_type="INTERIOR") else: bpy.ops.bim.align_product(align_type="POSITIVE") @@ -1276,6 +1025,11 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): if AuthoringData.data["active_class"] in ("IfcOpeningElement",): if len(bpy.context.selected_objects) == 2: bpy.ops.bim.clone_opening() + + def hotkey_S_U(self): + if not bpy.context.selected_objects: + return + bpy.ops.bim.unjoin_walls() def hotkey_A_D(self): if not bpy.context.selected_objects: @@ -1306,4 +1060,5 @@ MODIFIERS = { "A": ("EVENT_ALT", "OPTION" if sys.platform == "Darwin" else "ALT"), "C": ("EVENT_CTRL", "CTRL"), "S": ("EVENT_SHIFT", "⇧"), + "E": ("EVENT_PADENTER", "ENTER" if sys.platform == "Darwin" else "RETURN"), } diff --git a/src/bonsai/scripts/bonsai_icons.svg b/src/bonsai/scripts/bonsai_icons.svg index 75f412a65b..6c9278e70a 100644 --- a/src/bonsai/scripts/bonsai_icons.svg +++ b/src/bonsai/scripts/bonsai_icons.svg @@ -25,17 +25,18 @@ inkscape:pageopacity="0" inkscape:pagecheckerboard="true" inkscape:deskcolor="#d1d1d1" - inkscape:document-units="mm" + inkscape:document-units="px" showgrid="true" - inkscape:zoom="16.000001" - inkscape:cx="26.874999" - inkscape:cy="-2.1562499" - inkscape:window-width="1842" + inkscape:zoom="19.333334" + inkscape:cx="12.775862" + inkscape:cy="21.284482" + inkscape:window-width="1839" inkscape:window-height="1421" - inkscape:window-x="1212" - inkscape:window-y="25" + inkscape:window-x="1064" + inkscape:window-y="106" inkscape:window-maximized="0" - inkscape:current-layer="g32883">