diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 57a386b15c..63e0a75112 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -8,21 +8,30 @@ from mathutils import Vector from blenderbim.bim.ifc import IfcStore -def draw_attributes(props, layout): +def draw_attributes(props, layout, copy_operator=None): for attribute in props: row = layout.row(align=True) + value = None if attribute.data_type == "string": row.prop(attribute, "string_value", text=attribute.name) + value = attribute.string_value elif attribute.data_type == "boolean": row.prop(attribute, "bool_value", text=attribute.name) + value = attribute.bool_value elif attribute.data_type == "integer": row.prop(attribute, "int_value", text=attribute.name) + value = attribute.int_value elif attribute.data_type == "float": row.prop(attribute, "float_value", text=attribute.name) + value = attribute.float_value elif attribute.data_type == "enum": row.prop(attribute, "enum_value", text=attribute.name) + value = attribute.enum_value if attribute.is_optional: row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + if copy_operator: + op = row.operator(f"{copy_operator}", text="", icon="COPYDOWN") + op.data = json.dumps({"name": attribute.name, "value": value, "is_null": attribute.is_null}) def import_attributes(ifc_class, props, data, callback=None): diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 52781c9911..73fd8860f2 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -47,6 +47,7 @@ classes = ( operator.DisableEditingTask, operator.DisableEditingTaskTime, operator.EditTask, + operator.CopyTaskAttribute, operator.AssignPredecessor, operator.AssignSuccessor, operator.UnassignPredecessor, diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 77a5e83495..0387139e19 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -533,6 +533,30 @@ class EditTask(bpy.types.Operator): return {"FINISHED"} +class CopyTaskAttribute(bpy.types.Operator): + bl_idname = "bim.copy_task_attribute" + bl_label = "Copy Task Attribute" + data: bpy.props.StringProperty() + + def execute(self, context): + data = json.loads(self.data) + self.file = IfcStore.get_file() + props = context.scene.BIMTaskTreeProperties + for task in props.tasks: + if task.is_selected: + ifcopenshell.api.run( + "sequence.edit_task", + self.file, + **{ + "task": self.file.by_id(task.ifc_definition_id), + "attributes": {data["name"]: None if data["is_null"] else data["value"]}, + }, + ) + Data.load(IfcStore.get_file()) + bpy.ops.bim.load_task_properties() + return {"FINISHED"} + + class AssignPredecessor(bpy.types.Operator): bl_idname = "bim.assign_predecessor" bl_label = "Assign Predecessor" @@ -1409,7 +1433,7 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): obj.color = (1.0, 1.0, 1.0, 1) obj.keyframe_insert(data_path="hide_viewport", frame=self.start_frame) obj.keyframe_insert(data_path="color", frame=self.start_frame) - obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"]-1) + obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"] - 1) obj.color = (1.0, 0.0, 0.0, 1) obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"]) obj.hide_viewport = True @@ -1420,7 +1444,7 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): def animate_operation(self, obj, product_frames): obj.color = (1.0, 1.0, 1.0, 1) obj.keyframe_insert(data_path="color", frame=self.start_frame) - obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"]-1) + obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"] - 1) obj.color = (0.0, 0.0, 1.0, 1) obj.keyframe_insert(data_path="color", frame=product_frames["STARTED"]) obj.color = (1.0, 1.0, 1.0, 1) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index 1e618916a7..0363bf7c0b 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -176,6 +176,7 @@ class Task(PropertyGroup): identification: StringProperty(name="Identification", update=updateTaskIdentification) ifc_definition_id: IntProperty(name="IFC Definition ID") has_children: BoolProperty(name="Has Children") + is_selected: BoolProperty(name="Is Selected") is_expanded: BoolProperty(name="Is Expanded") level_index: IntProperty(name="Level Index") duration: StringProperty(name="Duration", update=updateTaskduration) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 34949d411c..517eb643ba 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -1,4 +1,5 @@ import isodate +import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.sequence.data import Data @@ -229,36 +230,10 @@ class BIM_PT_work_schedules(Panel): op.sequence = sequence["id"] def draw_editable_sequence_attributes_ui(self): - for attribute in self.props.sequence_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + blenderbim.bim.helper.draw_attributes(self.props.sequence_attributes, self.layout) def draw_editable_sequence_time_lag_ui(self): - for attribute in self.props.time_lag_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + blenderbim.bim.helper.draw_attributes(self.props.time_lag_attributes, self.layout) def draw_editable_task_calendar_ui(self): task = Data.tasks[self.props.active_task_id] @@ -277,34 +252,12 @@ class BIM_PT_work_schedules(Panel): op.task = self.props.active_task_id def draw_editable_task_attributes_ui(self): - for attribute in self.props.task_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + blenderbim.bim.helper.draw_attributes( + self.props.task_attributes, self.layout, copy_operator="bim.copy_task_attribute" + ) def draw_editable_task_time_attributes_ui(self): - for attribute in self.props.task_time_attributes: - row = self.layout.row(align=True) - if attribute.data_type == "string": - row.prop(attribute, "string_value", text=attribute.name) - elif attribute.data_type == "boolean": - row.prop(attribute, "bool_value", text=attribute.name) - elif attribute.data_type == "integer": - row.prop(attribute, "int_value", text=attribute.name) - elif attribute.data_type == "float": - row.prop(attribute, "float_value", text=attribute.name) - elif attribute.data_type == "enum": - row.prop(attribute, "enum_value", text=attribute.name) - if attribute.is_optional: - row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") + blenderbim.bim.helper.draw_attributes(self.props.task_time_attributes, self.layout) class BIM_UL_tasks(UIList): @@ -360,6 +313,15 @@ class BIM_UL_tasks(UIList): op = row.operator("bim.assign_product", text="", icon="KEYFRAME", emboss=False) op.task = item.ifc_definition_id + if props.active_task_id and props.editing_task_type == "ATTRIBUTES": + row.prop( + item, + "is_selected", + icon="CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT", + text="", + emboss=False, + ) + if props.active_task_id == item.ifc_definition_id: if props.editing_task_type == "TASKTIME": row.operator("bim.edit_task_time", text="", icon="CHECKMARK")