def add_mtext_columns(msp): insert = Vec3(0, 0, 0) attribs = { "layer": "STATIC", "char_height": 1, "insert": insert, } content = [ " ".join(lorem_ipsum(50)), " ".join(lorem_ipsum(100)), " ".join(lorem_ipsum(70)), ] # Create 3 static columns, the content if each column is # clearly defined: [content0, content1, content2, ...] # The height of the columns is defined by their content, ezdxf adds # an automatic column switch `\N` (R2018) between the parts. # The height argument should as big as the tallest column needs to be, # this value also determines the total height of the MTEXT entity. # # This is the simplest way to define columns without the need to render # the content to determine the required column heights. mtext = msp.add_mtext_static_columns( content, width=20, gutter_width=1, height=100, dxfattribs=attribs ) insert += Vec3(mtext.columns.total_width + 5, 0, 0) attribs["layer"] = "DYNAMIC" attribs["insert"] = insert content = " ".join(lorem_ipsum(300)) # Create as much columns as needed for the given common fixed height: # Easy for R2018, very hard for <R2018 # Passing count is required to calculate the correct total width. # The get the correct column count requires an exact MTEXT rendering # like AutoCAD/BricsCAD, which does not exist yet. mtext = msp.add_mtext_dynamic_auto_height_columns( content, width=20, gutter_width=1, height=50, count=3, dxfattribs=attribs, ) insert += Vec3(mtext.columns.total_width + 5, 0, 0) attribs["insert"] = insert # Create 3 columns with given individual column heights, # the last column height is required but ignored and therefore 0, # because the last column contains as much of the remaining content # as needed. # Easy for R2018, very hard for <R2018 msp.add_mtext_dynamic_manual_height_columns( content, width=20, gutter_width=1, heights=[20, 30, 0], dxfattribs=attribs, )
def profile(text, func, runs): content = " ".join(lorem_ipsum(1000)) t0 = time.perf_counter() for _ in range(runs): func(REPLACE, content) t1 = time.perf_counter() t = t1 - t0 print(f"{text} {t:.3f}s")
def random_sized_content(count: int) -> Content: """Create content with randomized text size.""" def size(): return random.choice([0, 1, 1, 1, 1, 1, 2, 3]) for word in tl.lorem_ipsum(count): font = fix_sized_fonts[size()] yield Word(word, font) yield tl.Space(font.space)
def indent_first_line(msp, location): # Indentation is a multiple of the default text height (MTEXT char_height) attribs = dict(ATTRIBS) attribs["char_height"] = 0.25 attribs["width"] = 7.5 editor = MTextEditor("Indent the first line:" + NP) props = ParagraphProperties( indent=1, # indent first line = 1x0.25 drawing units align=MTextParagraphAlignment.JUSTIFIED) editor.paragraph(props) editor.append(" ".join(lorem_ipsum(100))) msp.add_mtext(str(editor), attribs).set_location(insert=location)
def indent_except_fist_line(msp, location): # Indentation is a multiple of the default text height (MTEXT char_height) attribs = dict(ATTRIBS) attribs["char_height"] = 0.25 attribs["width"] = 7.5 editor = MTextEditor("Indent left paragraph side:" + NP) indent = 0.7 # 0.7 * 0.25 = 0.175 drawing units props = ParagraphProperties( # first line indentation is relative to "left", this reverses the # left indentation: indent=-indent, # first line # indent left paragraph side: left=indent, align=MTextParagraphAlignment.JUSTIFIED) editor.paragraph(props) editor.append(" ".join(lorem_ipsum(100))) msp.add_mtext(str(editor), attribs).set_location(insert=location)
def numbered_list(msp, location): attribs = dict(ATTRIBS) attribs["char_height"] = 0.25 attribs["width"] = 7.5 # There are no special commands to build numbered list, the list is build of # indentation and a tabulator stop. There is no automatic numbering, # but therefore the absolute freedom for using any string as list marker: editor = MTextEditor("Numbered List:" + NP) editor.bullet_list(indent=1, bullets=["1.", "2.", "3."], content=[ "First item", "Second item", " ".join(lorem_ipsum(30)), ]) # Indentation and tab stops are multiples of the default text height (MTEXT # char_height)! msp.add_mtext(str(editor), attribs).set_location(insert=location)
def bullet_list(msp, location): attribs = dict(ATTRIBS) attribs["char_height"] = 0.25 attribs["width"] = 7.5 # There are no special commands to build bullet list, the list is build of # indentation and a tabulator stop. Each list item needs a marker as an # arbitrary string. bullet = "•" # alt + numpad 7 editor = MTextEditor("Bullet List:" + NP) editor.bullet_list( indent=1, bullets=[bullet] * 3, # each list item needs a marker content=[ "First item", "Second item", " ".join(lorem_ipsum(30)), ]) msp.add_mtext(str(editor), attribs).set_location(insert=location)
def stroked_content(count: int, size: int = 1) -> Content: """Create content with one text size and groups of words with or without strokes. """ font = fix_sized_fonts[size] groups = stroke_groups(tl.lorem_ipsum(count)) for group, stroke in groups: # strokes should span across spaces in between words: # Spaces between words are bound to the preceding content box renderer, # MText is more flexible, but this implementation is easy and good # enough, otherwise spaces would need a distinct height and a rendering # object, both are not implemented for glue objects. continue_stroke = stroke + 8 if stroke else 0 for word in group[:-1]: yield Word(word, font=font, stroke=continue_stroke) yield tl.Space(font.space) # strokes end at the last word, without continue stroke: yield Word(group[-1], font=font, stroke=stroke) yield tl.Space(font.space)
def uniform_content(count: int, size: int = 1) -> Content: """Create content with one text size.""" font = fix_sized_fonts[size] for word in tl.lorem_ipsum(count): yield Word(word, font) yield tl.Space(font.space)