diff --git a/src/bonsai/bonsai/bim/data/pset/Psets_BBIM_Annotation.ifc b/src/bonsai/bonsai/bim/data/pset/Psets_BBIM_Annotation.ifc index 9d04b9c00c..37278587a9 100644 --- a/src/bonsai/bonsai/bim/data/pset/Psets_BBIM_Annotation.ifc +++ b/src/bonsai/bonsai/bim/data/pset/Psets_BBIM_Annotation.ifc @@ -1,11 +1,11 @@ ISO-10303-21; HEADER; -FILE_DESCRIPTION((),'2;1'); -FILE_NAME('Psets_BBIM_Annotation.ifc','2020-01-01T00:00:00',(),(),'Psets_BBIM_Annotation','Psets_BBIM_Annotation',$); +FILE_DESCRIPTION($,'2;1'); +FILE_NAME('Psets_BBIM_Annotation.ifc','2020-01-01T00:00:00',$,$,'Psets_BBIM_Annotation','Psets_BBIM_Annotation',$); FILE_SCHEMA(('IFC4')); ENDSEC; DATA; -#1=IFCPROPERTYSETTEMPLATE('3VuPUwdCD2Qx3XDDRs0R1N',$,'EPset_Annotation','',.PSET_TYPEDRIVENOVERRIDE.,'IfcAnnotation,IfcTypeProduct',(#2,#3,#4)); +#1=IFCPROPERTYSETTEMPLATE('3VuPUwdCD2Qx3XDDRs0R1N',$,'EPset_Annotation','',.PSET_TYPEDRIVENOVERRIDE.,'IfcAnnotation,IfcTypeProduct',(#2,#3,#4,#29)); #2=IFCSIMPLEPROPERTYTEMPLATE('2P7JN79n96Q9pElZ83LKe4',$,'ZIndex','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.); #3=IFCSIMPLEPROPERTYTEMPLATE('1Wpx_r2xj1_9w5JpI0QRJy',$,'Symbol','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.); #4=IFCSIMPLEPROPERTYTEMPLATE('3q0oxMUKP47vZ4jnyG$dDb',$,'Classes','Classes separarated by spaces that end up in classes for this element in svg. Can be used to specify the text font size: small - 1.8mm; regular - 2.5mm; large - 3.5mm; header - 5mm; title - 7mm. By default regular size is used.',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.); @@ -33,6 +33,6 @@ DATA; #26=IFCSIMPLEPROPERTYTEMPLATE('0SVyOfB0rC2xNfdRYf3XvY',$,'SuppressZeroInches','Suppress 0 inch values in dimension annotation text (for example: 12'' - 0" -> 12'')',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.); #27=IFCSIMPLEPROPERTYTEMPLATE('2bUmj458PBqPAtUoI3MXsb',$,'TextPrefix','Text to add before annotation measurement value',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.); #28=IFCSIMPLEPROPERTYTEMPLATE('0bnzttUb9BPuN597uNTXOE',$,'TextSuffix','Text to add after annotation measurement value',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.); - +#29=IFCSIMPLEPROPERTYTEMPLATE('2pJmUDpB50VBdCOib1zcJJ',$,'Newline_At','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.); ENDSEC; END-ISO-10303-21; diff --git a/src/bonsai/bonsai/bim/module/drawing/decoration.py b/src/bonsai/bonsai/bim/module/drawing/decoration.py index d099ea03ba..a953e76513 100644 --- a/src/bonsai/bonsai/bim/module/drawing/decoration.py +++ b/src/bonsai/bonsai/bim/module/drawing/decoration.py @@ -605,8 +605,16 @@ class BaseDecorator: font_size_mm = text_data["FontSize"] * text_scale for literal_data in literals_data: box_alignment = literal_data["BoxAlignment"] + text = literal_data["CurrentValue"] - for line in literal_data["CurrentValue"].split("\n"): + newline_at = props.newline_at + + if newline_at != 0: + text = helper.add_newline_between_words (text, newline_at) + + multiple_lines = text.split("\n") + + for line in multiple_lines: self.draw_label( context, line, @@ -622,6 +630,8 @@ class BaseDecorator: line_i += 1 if not reverse_lines_order else -1 + + class DimensionDecorator(BaseDecorator): """Decorator for dimension objects - each edge of a segment with arrow diff --git a/src/bonsai/bonsai/bim/module/drawing/helper.py b/src/bonsai/bonsai/bim/module/drawing/helper.py index 39b2250371..1d5c7aa0d1 100644 --- a/src/bonsai/bonsai/bim/module/drawing/helper.py +++ b/src/bonsai/bonsai/bim/module/drawing/helper.py @@ -414,3 +414,30 @@ def elevate_segment(bounds, segm): return None x = p1.x return [Vector((x, ymin, zmin)), Vector((x, ymax, zmin))] + + +def add_newline_between_words(text, newline_at): + result = [] + start = 0 + + while start < len(text): + # Find the end index considering the limit newline_at + end = start + newline_at + if end >= len(text): # If we're at the end of the string + result.append(text[start:]) + break + + # Look for the nearest space around the newline_at limit + space_index = text.rfind(' ', start, end) # Try to break before newline_at + if space_index == -1: # No space found, force a break at newline_at + space_index = text.find(' ', end) # Try to break after newline_at + + if space_index == -1: # If there's still no space, take the rest of the text + result.append(text[start:]) + break + + # Add the chunk and update the start position + result.append(text[start:space_index]) + start = space_index + 1 # Skip the space itself + + return '\n'.join(result) \ No newline at end of file diff --git a/src/bonsai/bonsai/bim/module/drawing/prop.py b/src/bonsai/bonsai/bim/module/drawing/prop.py index 882e4b3165..98ea4c99d7 100644 --- a/src/bonsai/bonsai/bim/module/drawing/prop.py +++ b/src/bonsai/bonsai/bim/module/drawing/prop.py @@ -522,6 +522,7 @@ class BIMTextProperties(PropertyGroup): default="2.5", name="Font Size", ) + newline_at: IntProperty(name="Newline At") def get_text_edited_data(self): """should be called only if `is_editing` diff --git a/src/bonsai/bonsai/bim/module/drawing/svgwriter.py b/src/bonsai/bonsai/bim/module/drawing/svgwriter.py index b61ef88562..01e6bfdcff 100644 --- a/src/bonsai/bonsai/bim/module/drawing/svgwriter.py +++ b/src/bonsai/bonsai/bim/module/drawing/svgwriter.py @@ -841,6 +841,7 @@ class SvgWriter: self.draw_symbol(symbol, symbol_transform) line_number = 0 + newline_at = text_obj.BIMTextProperties.newline_at for text_literal in text_literals: text = tool.Drawing.replace_text_literal_variables(text_literal.Literal, product or element) text_tags = self.create_text_tag( @@ -851,6 +852,7 @@ class SvgWriter: classes_str, fill_bg=fill_bg, line_number_start=line_number, + newline_at = newline_at, ) for tag in text_tags: self.svg.add(tag) @@ -1373,6 +1375,7 @@ class SvgWriter: multiline_to_bottom=True, fill_bg=False, line_number_start=0, + newline_at=0, ): """returns list of created text tags""" text_tags = [] @@ -1402,6 +1405,8 @@ class SvgWriter: text_tag = self.svg.text("", **text_kwargs, **base_text_attrs) text_tags.append(text_tag) + if newline_at != 0: + text = helper.add_newline_between_words (text, newline_at) text_lines = text.replace("\\n", "\n").split("\n") text_lines = text_lines if multiline_to_bottom else text_lines[::-1] diff --git a/src/bonsai/bonsai/bim/module/drawing/ui.py b/src/bonsai/bonsai/bim/module/drawing/ui.py index 58d1a990f2..9f72c1da82 100644 --- a/src/bonsai/bonsai/bim/module/drawing/ui.py +++ b/src/bonsai/bonsai/bim/module/drawing/ui.py @@ -533,6 +533,8 @@ class BIM_PT_text(Panel): row = self.layout.row(align=True) row.prop(props, "font_size") + row = self.layout.row(align=True) + row.prop(props, "newline_at") for i, literal_props in enumerate(props.literals): box = self.layout.box() @@ -574,6 +576,9 @@ class BIM_PT_text(Panel): row = self.layout.row(align=True) row.label(text="FontSize") row.label(text=str(text_data["FontSize"])) + row = self.layout.row(align=True) + row.label(text="Newline_At") + row.label(text=str(props.newline_at)) for literal_data in text_data["Literals"]: box = self.layout.box() diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index b9a0b99e6c..61e94f1705 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -39,6 +39,7 @@ def disable_editing_text(drawing: tool.Drawing, obj: bpy.types.Object) -> None: def edit_text(drawing: tool.Drawing, obj: bpy.types.Object) -> None: drawing.synchronise_ifc_and_text_attributes(obj) drawing.update_text_size_pset(obj) + drawing.update_newline_at(obj) drawing.update_text_value(obj) drawing.disable_editing_text(obj) diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index cdb6e91334..fa67fa8798 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -1021,6 +1021,21 @@ class Drawing(bonsai.core.tool.Drawing): properties={"Classes": classes}, ) + @classmethod + def update_newline_at(cls, obj: bpy.types.Object) -> None: + props = obj.BIMTextProperties + element = tool.Ifc.get_entity(obj) + newline_at = int(props.newline_at) + ifc_file = tool.Ifc.get() + pset = tool.Pset.get_element_pset(element, "EPset_Annotation") + if not pset: + pset = ifcopenshell.api.run("pset.add_pset", ifc_file, product=element, name="EPset_Annotation") + ifcopenshell.api.run( + "pset.edit_pset", + ifc_file, + pset=pset, + properties={"Newline_At": newline_at}, + ) # TODO below this point is highly experimental prototype code with no tests @classmethod