diff --git a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py index ba1d9a4f870..f3395ece67f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py @@ -24,13 +24,14 @@ operator.ActivateDrawingStyle, operator.ActivateModel, operator.AddAnnotation, + operator.AddAnnotationType, operator.AddDrawing, operator.AddDrawingStyle, operator.AddDrawingStyleAttribute, operator.AddDrawingToSheet, + operator.AddReferenceToSheet, operator.AddSchedule, operator.AddScheduleToSheet, - operator.AddReferenceToSheet, operator.AddSheet, operator.AddTextLiteral, operator.BuildSchedule, @@ -38,6 +39,7 @@ operator.ContractSheet, operator.CreateDrawing, operator.CreateSheets, + operator.DisableAddAnnotationType, operator.DisableEditingAssignedProduct, operator.DisableEditingDrawings, operator.DisableEditingSchedules, @@ -47,6 +49,7 @@ operator.EditAssignedProduct, operator.EditSheet, operator.EditText, + operator.EnableAddAnnotationType, operator.EditTextPopup, operator.EnableEditingAssignedProduct, operator.EnableEditingText, @@ -102,6 +105,7 @@ gizmos.DimensionLabelGizmo, gizmos.ExtrusionGuidesGizmo, gizmos.ExtrusionWidget, + workspace.LaunchAnnotationTypeManager, workspace.Hotkey, ) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/data.py b/src/blenderbim/blenderbim/bim/module/drawing/data.py index dc79067c5bb..01561bcd12f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/data.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/data.py @@ -335,18 +335,31 @@ class AnnotationData: def load(cls): cls.is_loaded = True cls.props = bpy.context.scene.BIMAnnotationProperties - cls.data["relating_types"] = cls.get_relating_types() + cls.data["relating_type_id"] = cls.relating_type_id() + cls.data["relating_types"] = cls.relating_types() @classmethod - def get_relating_types(cls): + def relating_type_id(cls): object_type = cls.props.object_type relating_types = [] for relating_type in tool.Ifc.get().by_type("IfcTypeProduct"): if tool.Drawing.is_annotation_object_type(relating_type, object_type): relating_types.append(relating_type) - enum_items = [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in relating_types] + results = [("0", "Untyped", "")] + results.extend([(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in relating_types]) + return results - # item to create anootations without relating types - enum_items.insert(0, ("0", "-", "")) - return enum_items + @classmethod + def relating_types(cls): + object_type = cls.props.object_type + relating_types = [] + for relating_type in tool.Ifc.get().by_type("IfcTypeProduct"): + if tool.Drawing.is_annotation_object_type(relating_type, object_type): + relating_types.append({ + "id": relating_type.id(), + "name": relating_type.Name or "Unnamed", + "description": relating_type.Description or "No Description", + }) + + return sorted(relating_types, key=lambda x: x["name"]) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 2c600154b98..b7f7b410fae 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -84,6 +84,52 @@ def execute(self, context): return {"FINISHED"} +class AddAnnotationType(bpy.types.Operator, Operator): + bl_idname = "bim.add_annotation_type" + bl_label = "Add Annotation Type" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + props = context.scene.BIMAnnotationProperties + object_type = props.object_type + has_representation = props.create_representation_for_type + drawing = tool.Ifc.get_entity(bpy.context.scene.camera) + + if props.create_representation_for_type: + obj = tool.Drawing.create_annotation_object(drawing, object_type) + else: + obj = bpy.data.objects.new(object_type, None) + + obj.name = props.type_name + element = tool.Drawing.run_root_assign_class( + obj=obj, + ifc_class="IfcTypeProduct", + predefined_type=object_type, + should_add_representation=has_representation, + context=ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Annotation", "MODEL_VIEW"), + ifc_representation_class=tool.Drawing.get_ifc_representation_class(object_type), + ) + element.ApplicableOccurrence = f"IfcAnnotation/{object_type}" + + +class EnableAddAnnotationType(bpy.types.Operator, Operator): + bl_idname = "bim.enable_add_annotation_type" + bl_label = "Enable Add Annotation Type" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + bpy.context.scene.BIMAnnotationProperties.is_adding_type = True + + +class DisableAddAnnotationType(bpy.types.Operator, Operator): + bl_idname = "bim.disable_add_annotation_type" + bl_label = "Disable Add Annotation Type" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + bpy.context.scene.BIMAnnotationProperties.is_adding_type = False + + class AddDrawing(bpy.types.Operator, Operator): bl_idname = "bim.add_drawing" bl_label = "Add Drawing" diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index ed9791ddab3..afb7fd0dc4e 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -499,7 +499,7 @@ class BIMAssignedProductProperties(PropertyGroup): "PLAN_LEVEL": ("Level (Plan)", "", "SORTBYEXT", "curve"), "SECTION_LEVEL": ("Level (Section)", "", "TRIA_DOWN", "curve"), "BREAKLINE": ("Breakline", "", "FCURVE", "mesh"), - "LINEWORK": ("Line", "", "MESH_MONKEY", "mesh"), + "LINEWORK": ("Line", "", "SNAP_MIDPOINT", "mesh"), "BATTING": ("Batting", "Add batting annotation.\nThickness could be changed through Thickness property of BBIM_Batting property set", "FORCE_FORCE", "mesh"), "REVISION_CLOUD":("Revision Cloud", "Add revision cloud", "VOLUME_DATA", "mesh"), "FILL_AREA": ("Fill Area", "", "NODE_TEXTURE", "mesh"), @@ -510,13 +510,10 @@ class BIMAssignedProductProperties(PropertyGroup): annotation_classes = [(x, *ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(ANNOTATION_TYPES_DATA)] -def get_annotation_data_prop(prop_name): - def function(self, context): - if not AnnotationData.is_loaded: - AnnotationData.load() - return AnnotationData.data[prop_name] - - return function +def get_relating_type_id(self, context): + if not AnnotationData.is_loaded: + AnnotationData.load() + return AnnotationData.data["relating_type_id"] def update_annotation_object_type(self, context): @@ -533,12 +530,12 @@ class BIMAnnotationProperties(PropertyGroup): object_type: bpy.props.EnumProperty( name="Annotation Object Type", items=annotation_classes, default="TEXT", update=update_annotation_object_type ) - relating_type_id: bpy.props.EnumProperty( - name="Relating Annotation Type", items=get_annotation_data_prop("relating_types") - ) + relating_type_id: bpy.props.EnumProperty(name="Relating Annotation Type", items=get_relating_type_id) create_representation_for_type: bpy.props.BoolProperty( name="Create Representation For Type", default=False, description='Whether "Add type" should define a representation for the type \n' "or allow occurences to have their own", ) + is_adding_type: bpy.props.BoolProperty(default=False) + type_name: bpy.props.StringProperty(name="Name", default="TYPEX") diff --git a/src/blenderbim/blenderbim/bim/module/drawing/workspace.py b/src/blenderbim/blenderbim/bim/module/drawing/workspace.py index 7df3a3b05eb..396f9a72736 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/workspace.py @@ -30,7 +30,8 @@ import blenderbim.bim.handler -# declaring it here to avoid circular import problems +# TODO: Fix circular import. +# Declaring it here to avoid circular import problems class Operator: def execute(self, context): IfcStore.execute_ifc_operator(self, context) @@ -38,6 +39,76 @@ def execute(self, context): return {"FINISHED"} +class LaunchAnnotationTypeManager(bpy.types.Operator): + bl_idname = "bim.launch_annotation_type_manager" + bl_label = "Launch Annotation Type Manager" + bl_options = {"REGISTER"} + bl_description = "Manage annotation types and templates" + + def execute(self, context): + return {"FINISHED"} + + def invoke(self, context, event): + return context.window_manager.invoke_popup(self, width=550) + + def draw(self, context): + if not AnnotationData.is_loaded: + AnnotationData.load() + + props = context.scene.BIMAnnotationProperties + + columns = self.layout.column_flow(columns=3) + row = columns.row() + row.alignment = "LEFT" + row.label(text=f"{len(AnnotationData.data['relating_types'])} Types", icon="FILE_VOLUME") + + row = columns.row(align=True) + row.alignment = "CENTER" + # In case you want something here in the future + + row = columns.row(align=True) + row.alignment = "RIGHT" + # In case you want something here in the future + + if props.is_adding_type: + row = self.layout.row() + box = row.box() + row = box.row() + row.prop(props, "type_name") + row = box.row() + row.prop(props, "create_representation_for_type", text="Geometric Type") + row = box.row(align=True) + row.operator("bim.add_annotation_type", icon="CHECKMARK", text="Save New Type") + row.operator("bim.disable_add_annotation_type", icon="CANCEL", text="") + else: + row = self.layout.row() + row.operator("bim.enable_add_annotation_type", icon="ADD", text="Create New Type") + + flow = self.layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True) + + for relating_type in AnnotationData.data["relating_types"]: + outer_col = flow.column() + box = outer_col.box() + + row = box.row() + row.alignment = "CENTER" + row.label(text=relating_type["name"], icon="FILE_3D") + + row = box.row() + row.alignment = "CENTER" + row.label(text=relating_type["description"]) + + row = box.row(align=True) + + op = row.operator("bim.select_type", icon="OBJECT_DATA") + op.relating_type = relating_type["id"] + op = row.operator("bim.duplicate_type", icon="DUPLICATE", text="") + op.element = relating_type["id"] + op = row.operator("bim.remove_type", icon="X", text="") + op.element = relating_type["id"] + + + class AnnotationTool(WorkSpaceTool): bl_space_type = "VIEW_3D" bl_context_mode = "OBJECT" @@ -89,42 +160,8 @@ def add_layout_hotkey_operator(layout, text, hotkey, description): return op, row -# TODO: move to operator -def create_annotation_type(context): - # just empty to store parameters - props = context.scene.BIMAnnotationProperties - object_type = props.object_type - create_representation = props.create_representation_for_type - drawing = tool.Ifc.get_entity(bpy.context.scene.camera) - - if props.create_representation_for_type: - obj = tool.Drawing.create_annotation_object(drawing, object_type) - else: - obj = bpy.data.objects.new(object_type, None) - - obj.name = f"{object_type}_TYPE" - obj.location = context.scene.cursor.location - tool.Drawing.ensure_annotation_in_drawing_plane(obj) - - drawing = tool.Ifc.get_entity(context.scene.camera) - ifc_context = tool.Drawing.get_annotation_context(tool.Drawing.get_drawing_target_view(drawing), object_type) - - element = tool.Drawing.run_root_assign_class( - obj=obj, - ifc_class="IfcTypeProduct", - predefined_type=object_type, - should_add_representation=create_representation, - context=ifc_context, - ifc_representation_class=tool.Drawing.get_ifc_representation_class(object_type), - ) - element.ApplicableOccurrence = f"IfcAnnotation/{object_type}" - - tool.Blender.select_and_activate_single_object(context, obj) - - # TODO: move to operator def create_annotation_occurence(context): - # object_type = context.scene.BIMAnnotationProperties.object_type props = context.scene.BIMAnnotationProperties relating_type = tool.Ifc.get().by_id(int(props.relating_type_id)) object_type = props.object_type @@ -171,6 +208,11 @@ def draw(cls, context, layout): row.label(text="No IFC Project", icon="ERROR") return + drawing = tool.Ifc.get_entity(context.scene.camera) + if not drawing: + row.label(text="No Active Drawing", icon="ERROR") + return + if not AnnotationData.is_loaded: AnnotationData.load() @@ -182,11 +224,6 @@ def draw(cls, context, layout): @classmethod def draw_create_object_interface(cls): - row = cls.layout.row(align=True) - op, row = add_layout_hotkey_operator(cls.layout, "Add Type", "S_C", "Create a new annotation type") - selected_icon = "CHECKBOX_HLT" if cls.props.create_representation_for_type else "CHECKBOX_DEHLT" - row.prop(cls.props, "create_representation_for_type", text="", icon=selected_icon) - row = cls.layout.row(align=True) row.prop(bpy.context.scene.DocProperties, "should_draw_decorations", text="Viewport Annotations") @@ -207,10 +244,9 @@ def draw_type_selection_interface(cls): row = cls.layout.row(align=True) row.label(text="", icon="FILE_3D") prop_with_search(row, cls.props, "relating_type_id", text="") + row.operator("bim.launch_annotation_type_manager", icon="LIGHTPROBE_GRID", text="") - create_type_occurence = cls.props.relating_type_id != "0" - label = "Add Type Occurence" if create_type_occurence else "Add Annotation" - add_layout_hotkey_operator(cls.layout, label, "S_A", "Create a new annotation") + add_layout_hotkey_operator(cls.layout, "Add", "S_A", "Create a new annotation") if object_type in ("TEXT", "STAIR_ARROW"): add_layout_hotkey_operator( @@ -284,6 +320,3 @@ def hotkey_S_G(self): related_object = tool.Ifc.get_object(related_product) tool.Drawing.setup_annotation_object(obj, element.ObjectType, related_object) - - def hotkey_S_C(self): - create_annotation_type(bpy.context) diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index 46fe3131ec9..fda53d560a4 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -200,7 +200,7 @@ def execute(self, context): class AddType(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_type" bl_label = "Add Type" - bl_options = {"REGISTER"} + bl_options = {"REGISTER", "UNDO"} def _execute(self, context): props = context.scene.BIMModelProperties