
    Og                    R   d Z ddlmZ ddlmZmZmZmZmZm	Z	m
Z
mZ ddlZddlZddlZddlmZmZ ddlmZmZmZmZmZmZ ddlmZmZmZmZmZmZm Z  ddl!m"Z"m#Z#m$Z$ dd	l%m&Z&m'Z'm(Z( erdd
l)m*Z*m+Z+m,Z, ddl-m.Z. ddl/m0Z0 dZ1 G d d      Z2dGdZ3dHdZ4dIdZ5dJdZ6dZ7dKdLdZ8dJdZ9dMdNdZ:	 	 dO	 	 	 	 	 dPdZ;dJdZ<dQdRdZ=dSdZ>	 	 	 	 	 	 	 	 dTdZ?dUdZ@ej                  dej4                  dej8                  d ej6                  d!ej                  d"ej                  d#iZDd$ZEd%ZFdVd&ZG G d' d(e
      ZH G d) d*      ZI G d+ d,eJ      ZK G d- d.      ZL G d/ d0      ZM G d1 d2ej                        ZO G d3 d4      ZP ej                  d5      ZR ej                  d6      ZSej4                  ej8                  ej6                  ej                  ej                  d7ZT G d8 d9      ZUdWd:ZVdXd;ZWdYdZd<ZXdYd[d=ZYd\d]d>ZZd^d?Z[d@a\d_dAZ]d`dBZ^	 	 da	 	 	 	 	 	 	 	 	 dbdCZ_e fdcdDZ` eadE      ZbdddFZcy)ezL
Tools in this module should be as independent of DXF entities as possible!
    )annotations)IterableIteratorTYPE_CHECKINGUnionOptionalCallable
NamedTupleAnyN)	validatorconst)TextEntityAlignment
TextHAlignMTextParagraphAlignmentMTextLineAlignmentMTextStrokeMAP_MTEXT_ALIGN_TO_FLAGS)LEFTCENTERRIGHTBASELINEMIDDLETOPMAX_STR_LEN)Vec3Vec2UVec)rgb2intRGBint2rgb)TextMText	DXFEntity)Tagsfonts   c                     e Zd ZdZddZddZedd       Zedd       ZddZ		 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 dd	Z
	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 dd
Z	 	 	 	 	 	 	 	 ddZe eddd      ddddf	 	 	 	 	 	 	 	 	 	 	 	 	 dd       Zy)TextLinea  Helper class which represents a single line text entity
    (e.g. :class:`~ezdxf.entities.Text`).

    Args:
        text: content string
        font: ezdxf font definition like :class:`~ezdxf.fonts.fonts.MonospaceFont`
            or :class:`~ezdxf.fonts.fonts.TrueTypeFont`

    c                Z    || _         |j                  |      | _        d| _        d| _        y )N      ?)_font
text_width_text_width
_stretch_x
_stretch_y)selftextfonts      U/var/www/html/public_html/myphp/venv/lib/python3.12/site-packages/ezdxf/tools/text.py__init__zTextLine.__init__?   s(    
"&//$"7!$!$    c                   t        |t              sJ d}d}|t        j                  t        j                  fv rB||z
  j                  }| j
                  dkD  r$|| j
                  z  }|t        j                  k(  r|}|| _        || _        y)zSet stretch factors for FIT and ALIGNED alignments to fit the
        text between `p1` and `p2`, only the distance between these points is
        important. Other given `alignment` values are ignore.

        r+   g&.>N)
isinstancer   FITALIGNED	magnituder.   r/   r0   )r1   	alignmentp1p2sxsydefined_lengths          r4   stretchzTextLine.stretchE   s     )%8999,002E2M2MNN%'"W$7$7N$&#d&6&66 3 ; ;;Br6   c                4    | j                   | j                  z  S )z)Returns the final (stretched) text width.)r.   r/   r1   s    r4   widthzTextLine.widthW   s     $//11r6   c                \    | j                   j                  j                  | j                  z  S )z*Returns the final (stretched) text height.)r,   measurementstotal_heightr0   rD   s    r4   heightzTextLine.height\   s#     zz&&33dooEEr6   c                `    | j                   j                  j                  | j                        S )z%Returns the scaled font measurements.)r,   rG   scaler0   rD   s    r4   font_measurementszTextLine.font_measurementsa   s!    zz&&,,T__==r6   r      rN   c                    | j                         }t        d|j                        t        | j                  |j                        g}| j	                  |||      }t
        j                  |||||      S )az  Returns the left and the right baseline vertex of the text line.

        Args:
            insert: insertion location
            halign: horizontal alignment left=0, center=1, right=2
            valign: vertical alignment baseline=0, bottom=1, middle=2, top=3
            angle: text rotation in radians
            scale: scale in x- and y-axis as 2-tuple of float

        r   )rL   r   baselinerE   _shift_vectorr)   transform_2d)	r1   inserthalignvalignanglerK   fmverticesshifts	            r4   baseline_verticeszTextLine.baseline_verticese   sj    $ ##%BKK R[[)
 ""6626 $$XvueUKKr6   c                P   | j                         }t        d|j                        t        | j                  |j                        t        | j                  |j                        t        d|j                        g}| j                  |||      }	t        j                  |||	|||      S )a  Returns the corner vertices of the text line in the order
        bottom left, bottom right, top right, top left.

        Args:
            insert: insertion location
            halign: horizontal alignment left=0, center=1, right=2
            valign: vertical alignment baseline=0, bottom=1, middle=2, top=3
            angle: text rotation in radians
            scale: scale in x- and y-axis as 2-tuple of float
            oblique: shear angle (slanting) in x-direction in radians

        r   )rL   r   bottomrE   cap_toprQ   r)   rR   )
r1   rS   rT   rU   rV   rK   obliquerW   rX   rY   s
             r4   corner_verticeszTextLine.corner_vertices   s    * ##%BIIRYY'RZZ(BJJ	
 ""6626$$XvueUGTTr6   c                F    t        | j                  |      t        ||      fS N)_shift_xrE   _shift_y)r1   rT   rU   rW   s       r4   rQ   zTextLine._shift_vector   s!     

F+Xb&-AAAr6   )r   r   c                @  	
 t        j                  |       }|r t        j                  |      fd|D        }t        |      

r
fd|D        }|\  	dk7  s	dk7  r	fd|D        }rfd|D        }t	        |      }|D cg c]  }||z   	 c}S c c}w )a  Transform any vertices from the text line located at the base
        location at (0, 0) and alignment LEFT.

        Args:
            vertices: iterable of vertices
            insert: insertion location
            shift: (shift-x, shift-y) as 2-tuple of float
            rotation: text rotation in radians
            scale: (scale-x, scale-y)  as 2-tuple of float
            oblique: shear angle (slanting) in x-direction in radians

        c              3  ~   K   | ]4  }t        |j                  |j                  z  z   |j                         6 y wra   r   xy).0vslant_xs     r4   	<genexpr>z(TextLine.transform_2d.<locals>.<genexpr>   s-     KAaccACC'M11337Ks   :=c              3  (   K   | ]	  }|z     y wra    )ri   rj   shift_vectors     r4   rl   z(TextLine.transform_2d.<locals>.<genexpr>   s     =a\)=s   rN   c              3  j   K   | ]*  }t        |j                  z  |j                  z         , y wra   rf   )ri   rj   scale_xscale_ys     r4   rl   z(TextLine.transform_2d.<locals>.<genexpr>   s(     OaccGmQSS7];Os   03c              3  @   K   | ]  }|j                          y wra   )rotate)ri   rj   rotations     r4   rl   z(TextLine.transform_2d.<locals>.<genexpr>   s     ?(+?s   )r   generatemathtanr   )rX   rS   rY   ru   rK   r^   	vertices_rj   rq   rr   ro   rk   s      `    @@@@r4   rR   zTextLine.transform_2d   s    D %)MM($;	 hhw'GKKI E{=9=I !a<7a<OYOI ?Y?I f$-.q
...s   BN)r2   strr3   fonts.AbstractFont)r<   r   r=   r   r>   r   returnNoner|   float)r|   fonts.FontMeasurements)r   r   r   rM   )rS   r   rT   intrU   r   rV   r   rK   tuple[float, float]r|   
list[Vec3])r   r   r   rM   r   )rS   r   rT   r   rU   r   rV   r   rK   r   r^   r   r|   r   )rT   r   rU   r   rW   r   r|   r   )rX   zIterable[UVec]rS   r   rY   r   ru   r   rK   r   r^   r   r|   r   )__name__
__module____qualname____doc__r5   rB   propertyrE   rI   rL   rZ   r_   rQ   staticmethodr   rR   rn   r6   r4   r)   r)   4   s   %$ 2 2 F F> %+LL L 	L
 L #L 
L> %+UU U 	U
 U #U U 
U>BB#&B,BB	B
  Aq!}%+%+8/ 8/8/ #8/ 	8/
 #8/ 8/ 
8/ 8/r6   r)   c                :    |t         k(  r|  dz  S |t        k(  r|  S y)Ng       @        )r   r   )total_widthrT   s     r4   rb   rb      s)    |c!!|r6   c                
   |t         k(  r| j                  S |t        k(  r| j                   | j                  dz  z   S |t
        k(  r| j                   | j                  dz  z   S |t        k(  r| j                   S | j                   S )N   )	r   rP   r   r]   
cap_heightX_MIDDLErH   r   r\   )rW   rU   s     r4   rc   rc      sw    {{

{R]]Q...

{R__q000}

{II:r6   c                   | j                         }|dv r| j                  j                  }| j                  j                  }|t        j
                  t        j                  fv rt        }t        }||fS |t        j                  k(  rt        }t        }||fS |dk(  r4t        j                  | j                  j                  t        t        f      S t!        d|       )zReturn unified horizontal and vertical alignment.

    horizontal alignment: left=0, center=1, right=2

    vertical alignment: baseline=0, bottom=1, middle=2, top=3

    Returns:
        tuple(halign, valign)

    )TEXTATTRIBATTDEFMTEXTzinvalid DXF )dxftypedxfrT   rU   r   r:   r9   r   r   r   r   r   getattachment_pointr   r   	TypeError)entityr   rT   rU   s       r4   unified_alignmentr      s     nnG..""""j((*..99 FF v~ z(((FFv~''++FJJ,G,G$PSUU
l7),
--r6   c                   d}t        t        j                  t        |                   }|j                  r|j                         }|dk(  r|j                  d      dk(  rm|j                  d      j                         }t        j                  j                  |      }|r|j                  d       ||z  }|dv r|j                  d       |j                  d       ||z  }|j                  r|S )zReturns the plain text for :class:`~ezdxf.entities.Text`,
    :class:`~ezdxf.entities.Attrib` and :class:`~ezdxf.entities.Attdef` content.
     %rN   r      kou)TextScannerr   fix_one_line_textcaret_decodehas_datapeeklowerr   SPECIAL_CHAR_ENCODINGr   consume)r2   resultscannercharcodeletters         r4   
plain_textr     s     F)55l46HIJG


||~3;||A#%||A,,.4488>OOA&f$F5= OOA&$# 

$ Mr6   	PNLlOoKkXc                   g }t        t        t        |                   }|rv|j                         }|dk(  r	 |j                         }|dv r|j                  |       n5|t        v r0|dk(  r|j                  d       n|dk(  r|j                  d       n|dk(  }|}|j                         }	 |dk7  r.|j                         }|r|dk7  r|j                  |       |dk7  r.|}n|d	v rn|d
k(  r|r|d   d
k(  rx|j                          |r|j                         }t        j                  j                  |j                               }	|	r|j                  |	       n8|j                  d
d
|f       n#|j                  |       n|j                  |       |rvdj                  |      }
|r|
j                  d      S |
S # t        $ r Y 1w xY w# t        $ r% |j                  d       |j                  |       Y fw xY w)a  Returns the plain MTEXT content as a single string or  a list of
    strings if `split` is ``True``. Replaces ``\P`` by ``\n`` and removes
    other controls chars and inline codes.

    This function is more than 4x faster than :func:`plain_mtext`, but does not
    remove single letter inline commands with arguments without a terminating
    semicolon like this ``"\C1red text"``.

    .. note::

        Well behaved CAD applications and libraries always create inline codes
        for commands with arguments with a terminating semicolon like this
        ``"\C1;red text"``!

    Args:
        text: MTEXT content string
        split: split content at line endings ``\P``

    \\{}P
N S;z{}r   r   )listreversedr   pop
IndexErrorappendONE_CHAR_COMMANDScopyr   r   r   r   extendjoinsplit)r2   r   chars	raw_charsr   stacking
first_charsearch_charsr   r   r   s              r4   fast_plain_mtextr     s   ( EXl4012I
}}4< }} v~T"**3;LL&S[ LL%  3;!
(~~/
-#++//1#!LL.	 #+
 !-I
 T\S[Yr]c1$==?D"88<<TZZ\JFV,c3%56T"LLa d WWU^F!&6<<2F2]  0 " -LL&LL,-s)   F? 02G #G ?	G
G+G<;G<c                8    dd}t        j                  d||       S )zDXF stores some special characters using caret notation. This function
    decodes this notation to normalize the representation of special characters
    in the string.

    see: https://en.wikipedia.org/wiki/Caret_notation

    c                X    t        | j                  d            }t        |dz
  dz        S )NrN   @   ~   )ordgroupchr)matchcs     r4   replace_matchz#caret_decode.<locals>.replace_match  s'    AAFc>""r6   z\^(.))r   zre.Matchr|   rz   )resub)r2   r   s     r4   r   r     s    # 66(M400r6   c                    g }d}	 | |||z    }t        |      rJt        |      |k  r|j                  |       |S ||z  }|d   dk(  r
|dd }|dz  }|j                  |       n|S `)z9Split the MTEXT content string into chunks of max `size`.r   r   ^NrN   )lenr   )ssizechunksposchunks        r4   split_mtext_stringr      s    F
C
#d
#u:5zD e$4KCRyCcr
qMM% M r6   c           	     b   g }g }t        t              ^}}}}}	}
}}}d|z  }t        |       D ]  }|j                  }||k(  r|j	                  |j
                         0||k(  s||	k(  r|j	                  d       L||k(  s||k(  r1|j	                  dj                  |             |j                          ||
k(  r|j	                  |       ||k(  s|j
                  \  }}}|j	                  ||z   |z           |r |j	                  dj                  |             |r|S dj                  |      S )a  Returns the plain MTEXT content as a single string or a list of
    strings if `split` is ``True``. Replaces ``\P`` by ``\n`` and removes
    other controls chars and inline codes.

    This function is much slower than :func:`fast_plain_mtext`, but removes all
    inline codes.

    Args:
        text: MTEXT content string
        split: split content at line endings ``\P``
        tabsize: count of replacement spaces for tabulators ``^I``

    r   r   r   )iter	TokenTypeMTextParsertyper   datar   clear)r2   r   tabsizecontent	paragraph_wordstackspacenbsp	tabulatornew_paragraph
new_columntab_replacementtokentuprlwrdividers                      r4   plain_mtextr     s4   $ GI 	Y
		
GmO T" 2JJ9UZZ(%Z19S!-1
?NN2779-.OO)^_-%Z %

CgS7]S012 rwwy)*99Wr6   c                F    | j                  dd      j                  dd      S )Nr   r   \Preplacer2   s    r4   escape_dxf_line_endingsr   N  s"     <<b!))$66r6   c                8    dj                  fd| D              S )Nr   c              3  <   K   | ]  }t        |      rn|  y wra   )is_non_printable_char)ri   r   replacements     r4   rl   z3replace_non_printable_characters.<locals>.<genexpr>U  s     Pa"7":;APs   )r   )r2   r  s    `r4    replace_non_printable_charactersr  T  s    77P4PPPr6   c                B    dt        |       cxk  xr dk  nc xr | dk7  S )Nr       	)r   )r   s    r4   r  r  X  s    D	B/44</r6   c                `   | r| j                         rg S t        j                  d|       }|D cg c]"  }t        j                  d|      D ]  }|s|	 $ }}}g }d}d}	|D ]  }| }
|dk(  r|	rd}	|dk(  r"|j                  |j	                                d}7|j                         r|s|
sL||z  }R|: |||z         |kD  r,|s||z  }j|j                  |j	                                |}d}	||z  } |r/|j                         s|j                  |j	                                |S c c}}w )a  Wrap text at ``\n`` and given `box_width`. This tool was developed for
    usage with the MTEXT entity. This isn't the most straightforward word
    wrapping algorithm, but it aims to match the behavior of AutoCAD.

    Args:
        text: text to wrap, included ``\n`` are handled as manual line breaks
        box_width: wrapping length, ``None`` to just wrap at ``\n``
        get_text_width: callable which returns the width of the given string

    z(\n)z(\s+)r   Fr   T)isspacer   r   r   rstrip)r2   	box_widthget_text_widthmanual_linesliner   tokenslinescurrent_lineline_just_wrappedon_first_lines              r4   	text_wrapr  \  s@   " 4<<>	88GT*L(PD"((8T2JPQaaPaPFPEL "!	9*!9LL,,./LYY[}!$q8H)II)U# A%LLL!4!4!67#$L(,%!)", L002\((*+L; Qs    D*D*c                   | j                  d      st        | j                          d      | j                  rG| j                  j                  j                  | j                  j                        }|r|j                  S y)zhReturns ``True`` if the associated text :class:`~ezdxf.entities.Textstyle`
    is vertical stacked.
    stylez& does not support the style attribute.F)	is_supported_dxf_attribr   r   docstylesr   r   r  is_vertical_stacked)r2   r  s     r4   is_text_vertical_stackedr    se     ''04<<>**PQRRxx##DHHNN3,,,r6   r   lrr   jd,01234567890c                :    t        | t        t        f      r| dS | S )Ng)r8   r   r   )r   s    r4   rstrip0r$    s    !c5\"AHr6   c                  ~    e Zd ZU dZdZded<   dZded<   dZded<   ej                  Z
ded<    e       Zd	ed
<   ddZy)ParagraphPropertiesa<  Stores all known MTEXT paragraph properties in a :class:`NamedTuple`.
    Indentations and tab stops are multiples of the default text height
    :attr:`MText.dxf.char_height`. E.g. :attr:`char_height` is 0.25 and
    :attr:`indent` is 4, the real indentation is 4 x 0.25 = 1 drawing unit.
    The default tabulator stops are 4, 8, 12, ... if no tabulator stops are
    explicit defined.

    Args:
         indent (float): left indentation of the first line, relative to :attr:`left`,
            which means an :attr:`indent` of 0 has always the same indentation
            as :attr:`left`
         left (float): left indentation of the paragraph except for the first line
         right (float): left indentation of the paragraph
         align: :class:`~ezdxf.lldxf.const.MTextParagraphAlignment` enum
         tab_stops: tuple of tabulator stops, as ``float`` or as ``str``,
            ``float`` values are left aligned tab stops, strings with prefix
            ``"c"`` are center aligned tab stops and strings with prefix ``"r"``
            are right aligned tab stops

    r   r   indentleftrightr   aligntuple	tab_stopsc           	     >   g }| j                   r4|j                  d| j                   d       |j                  t               | j                  r4|j                  d| j                  d       |j                  t               | j                  r4|j                  d| j                  d       |j                  t               | j
                  r:|j                  dt        | j
                             |j                  t               | j                  rT|j                  dt        j                  t        t        | j                                      |j                  t               |r3|d   t        k(  r|j                          dd	j                  |      z   d
z   S y	)zdReturns the MTEXT paragraph properties as MTEXT inline code
        e.g. ``"\pxi-2,l2;"``.

        ir#  r  r  qr   r   z\pxr   r   )r'  r   COMMAr(  r)  r*  _alignment_charr,  r   mapr$  r   )r1   argss     r4   tostringzParagraphProperties.tostring  s+   
 ;;KK!DKK?+,KK99KK!DIIa=)*KK::KK!DJJq>*+KK::KK!ODJJ789:KK>>KK!EJJs7DNN'CDEFGKKBx5 
BGGDM)C//r6   Nr|   rz   )r   r   r   r   r'  __annotations__r(  r)  r   DEFAULTr*  r+  r,  r4  rn   r6   r4   r&  r&    sJ    , FED%OE5%<%D%DE"D wIur6   r&  c                     e Zd ZdZd'd(dZdZdZdZdZdZ	dZ
dZd	Zd
ZdZdZdZdZdZdZdZd)dZd)dZd*dZd Zd+d,dZd-dZd.dZd-dZd-dZd/dZd0dZd1dZ d2dZ!d3d4dZ"d)d Z#d)d!Z$d)d"Z%d)d#Z&d5d$Z'	 	 	 	 	 	 	 	 d6d%Z(y&)7MTextEditora  The :class:`MTextEditor` is a helper class to build MTEXT content
    strings with support for inline codes to change color, font or
    paragraph properties. The result is always accessible by the :attr:`text`
    attribute or the magic :func:`__str__` function as
    :code:`str(MTextEditor("text"))`.

    All text building methods return `self` to implement a floating interface::

        e = MTextEditor("This example ").color("red").append("switches color to red.")
        mtext = msp.add_mtext(str(e))

    The initial text height, color, text style and so on is determined by the
    DXF attributes of the :class:`~ezdxf.entities.MText` entity.

    .. warning::

        The :class:`MTextEditor` assembles just the inline code, which has to be
        parsed and rendered by the target CAD application, `ezdxf` has no influence
        to that result.

        Keep inline formatting as simple as possible, don't test the limits of its
        capabilities, this will not work across different CAD applications and keep
        the formatting in a logic manner like, do not change paragraph properties
        in the middle of a paragraph.

        **There is no official documentation for the inline codes!**

    Args:
        text: init value of the MTEXT content string.

    c                $    t        |      | _        y ra   )rz   r2   r1   r2   s     r4   r5   zMTextEditor.__init__  s    I	r6   r   z\N\L\l\O\o\K\k{}z\A0;z\A1;z\A2;\~z^Ic                0    | xj                   |z  c_         | S )zAppend `text`.r   r;  s     r4   r   zMTextEditor.append*  s    		T	r6   c                0    | xj                   |z  c_         | S )z}
        Append `text`::

            e = MTextEditor("First paragraph.\P")
            e += "Second paragraph.\P")

        r   r;  s     r4   __iadd__zMTextEditor.__iadd__/  s     			T	r6   c                    | j                   S )z1Returns the MTEXT content attribute :attr:`text`.r   rD   s    r4   __str__zMTextEditor.__str__:      yyr6   c                    d| _         y)z%Reset the content to an empty string.r   Nr   rD   s    r4   r   zMTextEditor.clear>  s	    	r6   c           
     \    | j                  d| dt        |       dt        |       d      S )a  Set the text font by the font family name. Changing the font height
        should be done by the :meth:`height` or the :meth:`scale_height` method.
        The font family name is the name shown in font selection widgets in
        desktop applications: "Arial", "Times New Roman", "Comic Sans MS".
        Switching the codepage is not supported.

        Args:
            name: font family name
            bold: flag
            italic: flag

        z\fz|bz|ir   r   r   )r1   namebolditalics       r4   r3   zMTextEditor.fontB  s0    & {{bbT2c&k]!DEEr6   c                @    | j                  dt        |d       d      S )a  Scale the text height by a `factor`. This scaling will accumulate,
        which means starting at height 2.5 and scaling by 2 and again by 3 will
        set the text height to 2.5 x 2 x 3 = 15. The current text height is not
        stored in the :class:`MTextEditor`, you have to track the text height by
        yourself! The initial text height is stored in the
        :class:`~ezdxf.entities.MText` entity as DXF attribute
        :class:`~ezdxf.entities.MText.dxf.char_height`.

        \Hr   zx;r   roundr1   factors     r4   scale_heightzMTextEditor.scale_heightW  s$     {{bvq!1 2"566r6   c                @    | j                  dt        |d       d      S )z.Set the absolute text height in drawing units.rR  r   r   rS  )r1   rI   s     r4   rI   zMTextEditor.heightc  "    {{bvq!1 2!455r6   c                @    | j                  dt        |d       d      S )z#Set the absolute text width factor.z\Wr   r   rS  rU  s     r4   width_factorzMTextEditor.width_factorg  rY  r6   c                @    | j                  dt        |d       d      S )z+Set the absolute character tracking factor.z\Tr   r   rS  rU  s     r4   char_tracking_factorz MTextEditor.char_tracking_factork  rY  r6   c                >    | j                  dt        |       d      S )zSet the text oblique angle in degrees, vertical is 0, a value of 15
        will lean the text 15 degree to the right.

        z\Qr   rM  )r1   rV   s     r4   r^   zMTextEditor.obliqueo  s     
 {{bUA.//r6   c                b    | j                  t        j                  |j                                  S )zsSet the text color by color name: "red", "yellow", "green", "cyan",
        "blue", "magenta" or "white".

        )acir   MTEXT_COLOR_INDEXr   )r1   rN  s     r4   colorzMTextEditor.colorv  s$    
 xx//

=>>r6   c                r    d|cxk  rdk  r"n t        d      | j                  d| d      S t        d      )z3Set the text color by :ref:`ACI` in range [0, 256].r      z\Cr   zaci not in range [0, 256])r   
ValueErrorr1   r`  s     r4   r`  zMTextEditor.aci}  s>    ?s?455 ;;"SE|,,455r6   c                P    |\  }}}| j                  dt        |||f       d      S )z Set the text color as RGB value.z\cr   )r   r   )r1   rgbr  r#  bs        r4   rh  zMTextEditor.rgb  s1    1a{{b!Q!3 4A677r6   c                l    |dvrt        d|       |dk(  r|dz  }| j                  d| | | d      S )a"  Append stacked text `upr` over `lwr`, argument `t` defines the
        kind of stacking, the space " " after the "^" will be added
        automatically to avoid caret decoding:

        .. code-block:: none

            "^": vertical stacked without divider line, e.g. \SA^ B:
                 A
                 B

            "/": vertical stacked with divider line,  e.g. \SX/Y:
                 X
                 -
                 Y

            "#": diagonal stacked, with slanting divider line, e.g. \S1#4:
                 1/4

        ^/#zinvalid type symbol: r   r   z\Sr   )re  r   )r1   r   r   r   s       r4   r   zMTextEditor.stack  sN    ( E>4QC8998HA{{baSQ/00r6   c                ,    | j                  d| d      S )zGroup `text`, all properties changed inside a group are reverted at
        the end of the group. AutoCAD supports grouping up to 8 levels.

        rB  rC  r   r;  s     r4   r   zMTextEditor.group  s    
 {{RvR=))r6   c                ,    | j                  d| d      S )z)Append `text` with a line below the text.r<  r=  rm  r;  s     r4   	underlinezMTextEditor.underline      {{bb>**r6   c                ,    | j                  d| d      S )z)Append `text` with a line above the text.r>  r?  rm  r;  s     r4   overlinezMTextEditor.overline  rp  r6   c                ,    | j                  d| d      S )z+Append `text` with a line through the text.r@  rA  rm  r;  s     r4   strike_throughzMTextEditor.strike_through  rp  r6   c                @    | j                  |j                               S )zBSet paragraph properties by a :class:`ParagraphProperties` object.)r   r4  )r1   propss     r4   r   zMTextEditor.paragraph  s    {{5>>+,,r6   c           	          t               j                  t        | dz  ||f            }|j                  dj	                   fdt        ||      D                      j                  t        |            S )u/  Build bulleted lists by utilizing paragraph indentation and a
        tabulator stop. Any string can be used as bullet. Indentation is
        a multiple of the initial MTEXT char height (see also docs about
        :class:`ParagraphProperties`), which means indentation in
        drawing units is :attr:`MText.dxf.char_height` x `indent`.

        Useful UTF bullets:

        - "bull" U+2022 = • (Alt Numpad 7)
        - "circle" U+25CB = ○ (Alt Numpad 9)

        For numbered lists just use numbers as bullets::

            MTextEditor.bullet_list(
                indent=2,
                bullets=["1.", "2."],
                content=["first", "second"],
            )

        Args:
            indent: content indentation as multiple of the initial MTEXT char height
            bullets: iterable of bullet strings, e.g. :code:`["-"] * 3`,
                for 3 dashes as bullet strings
            content: iterable of list item strings, one string per list item,
                list items should not contain new line or new paragraph commands.

        g      ?)r'  r(  r,  r   c              3  b   K   | ]&  \  }}|j                   z   |z   j                  z    ( y wra   )TABNEW_PARAGRAPH)ri   ri  r   r1   s      r4   rl   z*MTextEditor.bullet_list.<locals>.<genexpr>  s2      :>!QDHHq 4#5#55s   ,/)r9  r   r&  r   r   zipr   rz   )r1   r'  bulletsr   itemss   `    r4   bullet_listzMTextEditor.bullet_list  ss    < ''w~!)
 	GG BEgwBW 	

 zz#e*%%r6   N)r   r2   rz   )r2   rz   r|   r9  r5  )FF)rN  rz   rO  boolrP  r  r|   r9  )rV  r   r|   r9  )rI   r   r|   r9  )rV   r   r|   r9  )rN  rz   r|   r9  )r`  r   r|   r9  )rh  r   r|   r9  )r   )r   rz   r   rz   r   rz   r|   r9  )rv  r&  r|   r9  )r'  r   r|  Iterable[str]r   r  r|   r9  ))r   r   r   r   r5   NEW_LINErz  
NEW_COLUMNUNDERLINE_STARTUNDERLINE_STOPOVERSTRIKE_STARTOVERSTRIKE_STOPSTRIKE_STARTSTRIKE_STOPGROUP_START	GROUP_ENDALIGN_BOTTOMALIGN_MIDDLE	ALIGN_TOPNBSPry  r   rG  rI  r   r3   rW  rI   r[  r]  r^   rb  r`  rh  r   r   ro  rr  rt  r   r~  rn   r6   r4   r9  r9    s    @ HMJONOLKKILLID
C
	F*
76660?68
16*+++-*&*&&3*&>K*&	*&r6   r9  c                      e Zd Zy)UnknownCommandN)r   r   r   rn   r6   r4   r  r    s    r6   r  c                  .   e Zd ZdZddZddZeZd ZddZe	dd       Z
e
j                  dd       Z
dddZe	dd	       Zej                  dd
       Ze	dd       Zej                  dd       Ze	dd       Zej                  dd       Ze	dd       Zy)MTextContextz0Internal class to store the MTEXT context state.c                    ddl m} d| _        d| _        d| _        d | _        t        j                  | _         |j                         | _
        d| _        d| _        d| _        d| _        t               | _        y )Nr   r%   F   r+   r   )ezdxf.fontsr&   _strokecontinue_stroke_acirh  r   BOTTOMr*  FontFace	font_facer   r[  r]  r^   r&  r   )r1   r&   s     r4   r5   zMTextContext.__init__  sg    %%*	"&'..
')!$#&+.!!,.r6   c                   t               }| j                  |_        | j                  |_        | j                  |_        | j                  |_        | j
                  |_        | j                  |_        | j                  |_        | j                  |_        | j                  |_	        | j                  |_
        | j                  |_        |S ra   )r  r  r  r  rh  r*  r  r   r[  r]  r^   r   )r1   ps     r4   __copy__zMTextContext.__copy__  s    NLL	 00**nn**!%!:!:LL	nnr6   c                
   t        | j                  | j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  f      S ra   )hashr  r  r  rh  r*  r  r   r[  r]  r^   r   rD   s    r4   __hash__zMTextContext.__hash__  sg    $$		

!!))
 	
r6   c                0    t        |       t        |      k(  S ra   )r  )r1   others     r4   __eq__zMTextContext.__eq__  s    DzT%[((r6   c                    | j                   S ra   )r  rD   s    r4   r`  zMTextContext.aci"  rJ  r6   c                f    d|cxk  rdk  rn t        d      || _         d | _        y t        d      )Nr   rd  zaci not in range[0,256])r  rh  re  rf  s     r4   r`  zMTextContext.aci&  s7    ?s? 677 DIDH677r6   c                `    |r| xj                   |z  c_         y| xj                   | z  c_         y)zSet/clear binary `stroke` flag in `self._stroke`.

        Args:
            stroke: set/clear stroke flag
            state: ``True`` for setting, ``False`` for clearing

        N)r  )r1   strokestates      r4   _set_stroke_statezMTextContext._set_stroke_state.  s%     LLF"LLLVG#Lr6   c                N    t        | j                  t        j                  z        S ra   )r  r  r   	UNDERLINErD   s    r4   ro  zMTextContext.underline;  s    DLL;#8#8899r6   c                D    | j                  t        j                  |       y ra   )r  r   r  r1   values     r4   ro  zMTextContext.underline?  s    {44e<r6   c                N    t        | j                  t        j                  z        S ra   )r  r  r   STRIKE_THROUGHrD   s    r4   rt  zMTextContext.strike_throughC  s    DLL;#=#==>>r6   c                D    | j                  t        j                  |       y ra   )r  r   r  r  s     r4   rt  zMTextContext.strike_throughG  s    {995Ar6   c                N    t        | j                  t        j                  z        S ra   )r  r  r   OVERLINErD   s    r4   rr  zMTextContext.overlineK  s    DLL;#7#7788r6   c                D    | j                  t        j                  |       y ra   )r  r   r  r  s     r4   rr  zMTextContext.overlineO  s    {33U;r6   c                ,    t        | j                        S ra   )r  r  rD   s    r4   has_any_strokezMTextContext.has_any_strokeS  s    DLL!!r6   Nr|   r}   )r|   r  r|   r  r|   r   )r`  r   )T)r  r   r  r  r|   r}   )r  r  r|   r}   )r   r   r   r   r5   r  r   r  r  r   r`  setterr  ro  rt  rr  r  rn   r6   r4   r  r    s    :/ D
")   	ZZ8 8$ : : = = ? ? B B 9 9 __< < " "r6   r  c                      e Zd ZdZddZedd       Zedd       ZddZdddZ	dddZ
dddZddd	Zddd
ZddZddZddZddZy)r   )_text	_text_len_indexc                f    t        |      | _        t        | j                        | _        d| _        y )Nr   )rz   r  r   r  r  r;  s     r4   r5   zTextScanner.__init__[  s#    Y
TZZr6   c                4    | j                   | j                  k\  S ra   r  r  rD   s    r4   is_emptyzTextScanner.is_empty`  s    {{dnn,,r6   c                4    | j                   | j                  k  S ra   r  rD   s    r4   r   zTextScanner.has_datad  s    {{T^^++r6   c                    	 | j                   | j                     }| xj                  dz  c_        |S # t        $ r Y yw xY w)NrN   r   r  r  r   )r1   r   s     r4   r   zTextScanner.geth  sB    	::dkk*DKK1K   		s   .2 	>>c                N    |dk  rt        |      | xj                  |z  c_        y )NrN   )re  r  r1   counts     r4   r   zTextScanner.consumep  s"    19U##ur6   c                .    | xj                   |z  c_         y)zconsume() without safety checkNr  r  s     r4   fast_consumezTextScanner.fast_consumeu  s    ur6   c                z    |dk  rt        |      	 | j                  | j                  |z      S # t        $ r Y yw xY w)Nr   r   )re  r  r  r   r1   offsets     r4   r   zTextScanner.peeky  sC    A:V$$	::dkkF233 		s   . 	::c                Z    	 | j                   | j                  |z      S # t        $ r Y yw xY w)zpeek() without safety checkr   r  r  s     r4   	fast_peekzTextScanner.fast_peek  s1    	::dkkF233 		s    	**c                ^   | j                  | j                  | j                  d       }|j                  ry|j	                         }|r+|dk(  r&|j	                  d      |k(  r|j                  d       I||k(  r| j                  |j                  z   S |j                  d       |j                  ryy)at  Return the index of the next `char`. If `escape` is True, backslash
        escaped `chars` will be ignored e.g. "\;;" index of the next ";" is 1
        if `escape` is False and 2 if `escape` is True. Returns -1 if `char`
        was not found.

        Args:
            char: single letter as string
            escape: ignore backslash escaped chars if True.

        Nr   rN   r   r   )	__class__r  r  r   r   r   )r1   r   escaper   r   s        r4   findzTextScanner.find  s     ..DKKM!:;A!t)Q4(?"Dy{{W^^33OOA  r6   c                h    || j                   k  rt        |      | j                  | j                   | S )zCReturns the substring from the current location until index < stop.)r  r   r  )r1   stops     r4   substrzTextScanner.substr  s.    $++T""zz$++--r6   c                4    | j                   | j                  d S )z,Returns the unprocessed part of the content.N)r  r  rD   s    r4   tailzTextScanner.tail  s    zz$++-((r6   c                    | j                   S ra   r  rD   s    r4   indexzTextScanner.index  s    {{r6   c                     | j                   || S ra   )r  )r1   startr  s      r4   substr2zTextScanner.substr2  s    zz%%%r6   Nr  r  r5  )rN   )r  r   r|   r}   )r   )r  r   r|   rz   F)r   rz   r|   r   )r  r   r|   rz   r  )r  r   r  r   r|   rz   )r   r   r   	__slots__r5   r   r  r   r   r   r  r   r  r  r  r  r  r  rn   r6   r4   r   r   X  sf    0I
 - - , ,
..)&r6   r   c                  4    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
Zy)r   r   rN   r   r   r'         r     	   N)r   r   r   NONEWORDSTACKSPACEr  	TABULATORrz  r  WRAP_AT_DIMLINEPROPERTIES_CHANGEDrn   r6   r4   r   r     s5    DDEEDIMJOr6   r   c                      e Zd ZdZdddZy)
MTextTokenr   ctxr   Nc                .    || _         || _        || _        y ra   r  )r1   r   r  r   s       r4   r5   zMTextToken.__init__  s     	!$	r6   ra   )r   r   r  r  )r   r   r   r  r5   rn   r6   r4   r  r    s    'Ir6   r  z#[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?z)[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?([x]?))r  r  r   r  r  c                      e Zd ZdZ	 	 d	 	 	 ddZddZddZddZddZddZ	dd	Z
dd
ZddZddZddZddZddZddZddZd d!dZd!dZd d!dZddZddZd Zy)"r   a  Parses the MText content string and yields the content as tokens and
    the current MText properties as MTextContext object. The context object is
    treated internally as immutable object and should be treated by the client
    the same way.

    The parser works as iterator and yields MTextToken objects.

    Args:
        content: MText content string
        ctx: initial MText context
        yield_property_commands: yield commands that change properties or context,
            default is ``False``

    Nc                    |
t               }|| _        t        t        |            | _        g | _        d| _        t        |      | _        y NF)	r  r  r   r   r   
_ctx_stack_continue_stroker  _yield_property_commands)r1   r   r  yield_property_commandss       r4   r5   zMTextParser.__init__  sE     ;.C"<#89.0 %(,-D(E%r6   c                "    | j                         S ra   )parserD   s    r4   __iter__zMTextParser.__iter__  s    zz|r6   c                N    | j                   j                  | j                         y ra   )r  r   r  rD   s    r4   push_ctxzMTextParser.push_ctx  s    txx(r6   c                \    | j                   r | j                   j                         | _        y y ra   )r  r   r  rD   s    r4   pop_ctxzMTextParser.pop_ctx  s"    ??**,DH r6   c              #  X   	
K    j                   j                  j                  d t        j                  t        j
                  

fd	d 	
fd}	  |       \  }}|r7t        | j                  |       rt         j                  d        d ny Ew)Nc                *             | r|| fS |d fS ra   rn   )r   r   r   followup_token
word_tokens     r4   word_and_tokenz)MTextParser.parse.<locals>.word_and_token  s%    I!&!4''$;r6   c                    d} 	j                   r#d}        }	j                         }|dk(  r d      dv rd}                 }n| r| fS          	j                         }|dk(  rt        j                  d fS |dk(  rt        j
                  d fS |d	k(  rt        j                  d fS |d
k(  rt        j                  d fS |dk(  r
j                         S |rN	 
j                  |       
j                  r0t        j                  	j                  |	j                               fS &|dk  r;|dk(  r | t        j                        S |dk(  r | t        j
                        S d}nQ|dk(  rL d      dk(  rA d      j                         }t         j"                  j                  |      }|r
 d       |}|dk(  r	 |       S |sJ|dk(  r | r| fS  d       
j%                          |dk(  r | r| fS  d       
j'                                   |dk\  r| |z  } 	j                   r#| r| fS t        j(                  d fS # t        $ r | ||z   z  } Y 8w xY w)Nr   Fr   rN   r   T~r   r   Xr   r   r  r   r   r   rB  rC  )r   r  r   r   r  rz  r  r  parse_stackingparse_propertiesr  r  r  r  r  r   r   r   r  r  r  )r   r  r   cmd_start_indexcmdr   special_charr   r   r   r1   space_tokenr  r  s          r4   
next_tokenz%MTextParser.parse.<locals>.next_token  s   D""")--/T>Aw&(!%	!%  #-t#33	%kkm#:#,>>4#77#:#,#:#:D#@@#:#,#7#7#==#:#,#<#<d#BB#:#'#6#6#88& $ 5 5c :
 $(#@#@(1(D(D(/,;W]]_)*,& %& ! C<~-dI4G4GHH~-dI4K4KLL Fs]tAw#~7==?D#(#>#>#B#B4#HL#
!-S=)$<<}#-t#33#AJ MMO$3#-t#33#AJ LLN$ 	S=FNDa ""d !4'' ~~t++o $2 5 $ 45s   I I! I!r|   ztuple[TokenType, Any])r   r  r  r   r  r  r  r  )r1   r  type_r   r   r  r   r   r  r  r  s   `   @@@@@@@r4   r  zMTextParser.parse  s      ,,&&  .2oo^^
	X	, X	,t $,KE4 $77!$^TXXtDD%)N s   B B*c                    fdfddfd}d	fd}t        | j                  d             |       \  }}|r |       nd}t        j                  |||ffS )
a  Returns a tuple of strings: (numerator, denominator, type).
        The numerator and denominator is always a single and can contain spaces,
        which are not decoded as separate tokens. The type string is "^" for
        a limit style fraction without a line, "/" for a horizontal fraction
        and "#" for a diagonal fraction. If the expression does not contain
        any stacking type char, the type and denominator string are empty "".

        c                 H    j                         } t        |       dk  rd} | S )Nr  r   )r   r   )r   stacking_scanners    r4   	peek_charz-MTextParser.parse_stacking.<locals>.peek_charz  s&     %%'A1v{Hr6   c                 ~    d}         }|dk(  rd} j                  d               }j                  d       || fS )NFr   TrN   )r   )r  r   r  r  s     r4   get_next_charz1MTextParser.parse_stacking.<locals>.get_next_char  sH    FADy ((+K$$Q'f9r6   c                 t    d} j                   r&        \  }}|s|dv r| |fS | |z  } j                   r&| dfS )Nr   rk  r   )r   r   r  r  r  s      r4   parse_numeratorz3MTextParser.parse_stacking.<locals>.parse_numerator  sM    D"++)O	6!u*7N		 #++
 8Or6   c                 X    d} j                   r|         d   z  } j                   r| S )Nr   r   r  )r   r  r  s    r4   parse_denominatorz5MTextParser.parse_stacking.<locals>.parse_denominator  s2    D"++** #++Kr6   Tr  r   )r|   ztuple[str, str]r5  )r   extract_expressionr   r  )	r1   r  r  	numeratorstacking_typedenominatorr  r  r  s	         @@@r4   r
  zMTextParser.parse_stackingp  sb    					 't'>'>d'>'KL#2#4 	=-:')K GGGr6   c                r   | j                   j                         }|dk(  rd|_        d| _        np|dk(  rd|_        |j                  sWd| _        nN|dk(  rd|_        d| _        n9|dk(  rd|_        |j                  s d| _        n|dk(  rd|_        d| _        n|dk(  rd|_        |j                  sd| _        n|d	k(  r| j                  |       n|d
k(  r| j                  |       n|dk(  r| j                  |       n|dk(  r| j                  |       n|dk(  r| j                  |       no|dk(  r| j                  |       nX|dk(  r| j                  |       nA|dk(  r| j                  |       n*|dk(  s|dk(  r| j                  |       nt!        d|       | j                  |_        || _         y )NLTr  FOoKkACr   HWQTr  fFzunknown command: )r  r   ro  r  r  rr  rt  parse_alignparse_aci_colorparse_rgb_colorparse_heightparse_widthparse_obliqueparse_char_trackingparse_paragraph_propertiesparse_font_propertiesr  r  )r1   r  new_ctxs      r4   r  zMTextParser.parse_properties  s    ((--/#: $G$(D!CZ %G))(-%CZ#G$(D!CZ$G))(-%CZ%)G"$(D!CZ%*G"))(-%CZW%CZ  )CZ  )CZg&CZW%CZw'CZ$$W-CZ++G4CZ3#:&&w/ #4SE!:;;"&"7"7r6   c                    | j                   j                         }|dv rt        t        |            |_        nt        j
                  |_        | j                          y )N012)r   r   r   r   r*  r  consume_optional_terminator)r1   r  r   s      r4   r1  zMTextParser.parse_align  sD    ||!5=*3t95CI*11CI((*r6   c                d    | j                  |j                        |_        | j                          y ra   )parse_float_value_or_factorr   r=  r1   r  s     r4   r4  zMTextParser.parse_height  s$    99#..I((*r6   c                d    | j                  |j                        |_        | j                          y ra   )r?  r[  r=  r@  s     r4   r5  zMTextParser.parse_width  s'    ;;C<L<LM((*r6   c                d    | j                  |j                        |_        | j                          y ra   )r?  r]  r=  r@  s     r4   r7  zMTextParser.parse_char_tracking  s,    #'#C#C$$$
  	((*r6   c                    | j                  d      }|rC|j                  d      rt        |d d       }|t        |      z  }|S t        t        |            }|S )NTrelativerg   r   )extract_float_expressionendswithr   abs)r1   r  exprrV  s       r4   r?  z'MTextParser.parse_float_value_or_factor  s^    ,,d,;}}S!tCRy)V$  E$K(r6   c                l    | j                  d      }|rt        |      |_        | j                          y )NFrD  )rF  r   r^   r=  )r1   r  oblique_exprs      r4   r6  zMTextParser.parse_oblique  s0    44e4D-CK((*r6   c                    | j                         }|rt        |      }|dk  r||_        d |_        | j	                          y )Ni  )extract_int_expressionr   r`  rh  r=  )r1   r  aci_exprr`  s       r4   r2  zMTextParser.parse_aci_color  s=    ..0h-CSy((*r6   c                    | j                         }|r-t        t        |      dz        \  }}}t        |||      |_        | j                          y )Ni )rM  r    r   r   rh  r=  )r1   r  rgb_exprri  r#  r  s         r4   r3  zMTextParser.parse_rgb_color  sG    ..0c(mh67GAq!!QlCG((*r6   c                    d}| j                   j                         }|rt        nt        }t	        j
                  ||      }|r3|j                         \  }}||| }| j                   j                  |       |S Nr   )r   r  
RE_FLOAT_XRE_FLOATr   r   spanr   )r1   rE  r   r  patternr   r  ends           r4   rF  z$MTextParser.extract_float_expression  sf    ||  " (*h$'JE3%_FLL  %r6   c                    d}| j                   j                         }t        j                  d|      }|r3|j	                         \  }}||| }| j                   j                  |       |S )Nr   z\d+)r   r  r   r   rU  r   )r1   r   r  r   r  rW  s         r4   rM  z"MTextParser.extract_int_expression  s]    ||  "&JE3%_FLL  %r6   c                   | j                   j                  d|      }|dk  r| j                   j                         }n| j                   j                  |      }| j                   j	                  t        |      dz          |S )zReturns the next expression from the current location until
        the terminating ";". The terminating semicolon is not included.
        Skips escaped "\;" semicolons if `escape` is True.

        r   r  r   rN   )r   r  r  r  r   r   )r1   r  r  rI  s       r4   r  zMTextParser.extract_expression  si     ||  V 4!8<<$$&D<<&&t,DSY]+r6   c           	         dfd}dfdfdt        | j                               |j                  \  }}}}}j                  r$j	                         }|dk(  r |       }n|dk(  r |       }n|dk(  r |       }n|dk(  rn|dk(  r<j	                         }	t
        j	                  |	t        j                        }         n|d	k(  rg }j                  rj                         }
|
dk(  s|
d
k(  r*j                          |j                  |
        z          n4        }|r|j                  t        |             nj                          j                  rj                  r$t        ||||t        |            |_        y )Nc                 4    d}         }|rt        |      } | S )Nr   )r   )r  rI  parse_float_exprs     r4   parse_floatz;MTextParser.parse_paragraph_properties.<locals>.parse_float+  s!    E#%DdLr6   c                     d} j                         }t        j                  t        |      }|r0|j	                         \  }}||| } j                  |                | S rR  )r  r   r   rT  rU  r   )rI  r  r   r  rW  paragraph_scannerskip_commass        r4   r\  z@MTextParser.parse_paragraph_properties.<locals>.parse_float_expr2  s[    D$))+DHHXt,E"ZZ\
sE#!))#.Kr6   c                 x     j                         dk(  r& j                  d        j                         dk(  r%y y )Nr   rN   )r   r   )r_  s   r4   r`  z;MTextParser.parse_paragraph_properties.<locals>.skip_commas=  s5    #((*c1!))!, $((*c1r6   r.  r  r  rg   r/  r   r   r~   r5  )r   r  r   r   r   CHAR_TO_ALIGNr   r7  r   r   r   r   r&  r+  )r1   r  r]  r'  r(  r)  r*  r,  r  
adjustmentr  
float_exprr_  r\  r`  s               @@@r4   r8  z&MTextParser.parse_paragraph_properties*  sm   				- ((?(?(AB03-eUI((#'')Ccz$"}#.224
%))*6M6U6UV	'00-224E|u|)113!((1A1C)CD%5%7
%%,,U:->? .557 (00!  ((: ,D%i(8
r6   c                
   ddl m} | j                         j                  d      }|r\|d   rV|d   }d}d}|dd  D ]*  }|j	                  d      rd}|j	                  d	      s)d
},  |j
                  |||      |_        y y y )Nr   r%   |Regulari  rN   b1i  i1Italic)familyr  weight)r  r&   r  r   
startswithr  r  )r1   r  r&   partsrN  r  rl  parts           r4   r9  z!MTextParser.parse_font_propertiesd  s    %'')//4U1X8DEF ab	 %??4( F__T*$E	%
 +ENN$eFSCM 5r6   c                v    | j                   j                         dk(  r| j                   j                  d       y y )Nr   rN   )r   r   r   rD   s    r4   r=  z'MTextParser.consume_optional_terminatorv  s.    <<#%LL  # &r6   r  )r   rz   r  zOptional[MTextContext])r|   zIterator[MTextToken]r  r  )r  rz   r|   r}   )r  r  r~   r  r5  )r   r   r   r   r5   r  r  r  r  r
  r  r1  r4  r5  r7  r?  r6  r2  r3  rF  rM  r  r8  r9  r=  rn   r6   r4   r   r     s    $ '+ %	FF $F)-tl-H^.`+++++++	8
tT$$r6   r   c                `    d}d}| D ]  \  }}|dk(  r|}|dk(  s||z  } t        ||z         S )Nr   rN   r   )r   )tagsr  r   r   r  s        r4   load_mtext_contentrs  {  sM    DG e19DQYuG	
 #7T>22r6   c                J    d| j                  dd      j                  dd      v S )zDReturns `True` if `text` contains any MTEXT inline formatting codes.r   r   r   rD  r   r   s    r4   has_inline_formatting_codesru    s0     4<<rgr r6   c                8    | dz  } d|z   | cxk  xr d|z
  k  S c S )u  Returns ``True`` if the given text `angle` in degrees causes an upside
    down text in the :ref:`WCS`. The strict flip range is 90° < `angle` < 270°,
    the tolerance angle `tol` extends this range to: 90+tol < `angle` < 270-tol.
    The angle is normalized to [0, 360).

    Args:
        angle: text angle in degrees
        tol: tolerance range in which text flipping will be avoided

         v@g     V@g     p@rn   rV   tols     r4   is_upside_down_text_anglerz    s+     
UNE#:+++++r6   c                .    t        | |      r| dz  } | dz  S )a   Returns a readable (upright) text angle in the range `angle` <= 90+tol or
    `angle` >= 270-tol. The angle is normalized to [0, 360).

    Args:
        angle: text angle in degrees
        tol: tolerance range in which text flipping will be avoided

    g     f@rw  )rz  rx  s     r4   upright_text_angler|    s!     !,5=r6   c                    | dz  |z  S )zReturns the distance from baseline to baseline.

    Args:
        cap_height: cap height of the line
        line_spacing: line spacing factor as percentage of 3-on-5 spacing

    gy&1?rn   )r   line_spacings     r4   leadingr    s     ,,r6   c                     d fd}t         j                   |        j                  j                  dd       j                  j	                  d            S )a\  Estimate the width and height of a single column
    :class:`~ezdxf.entities.MText` entity.

    This function is faster than the :func:`~ezdxf.tools.text_size.mtext_size`
    function, but the result is very inaccurate if inline codes are used or
    line wrapping at the column border is involved!

    Returns:
        Tuple[width, height]

    c                 4   ddl m}  j                  j                  d      }j                  }|rG|j
                  j                  j                  j                  d            }||j                  |      S  | j                  t        j                  |      S )Nr   r%   char_heightr  )r   )
r  r&   r   get_defaultr  r  r   	make_fontr   DEFAULT_TTF)r&   r   r  r  mtexts       r4   
_make_fontz*estimate_mtext_extents.<locals>._make_font  su    %!II11-@
iiJJNN599#8#8#ABE z22uu00ZHHr6   rE   r   line_spacing_factor)r   r3   column_widthr  )r|   r{   )estimate_mtext_content_extentsr2   r   r   r  )r  r  s   ` r4   estimate_mtext_extentsr    sI    	I *

\YY]]7C0!II112GH	 r6   )\(?c                    | a y)z7Set the global safety factor for MTEXT size estimation.N_SAFETY_FACTOR)rV  s    r4   set_estimation_safety_factorr    s	     Nr6   c                     da y)zbReset the global safety factor for MTEXT size estimation to the hard coded
    default value.
    r  Nr  rn   r6   r4   reset_estimation_safety_factorr    s	    
 Nr6   c                   d}d}|j                   j                  }|dkD  }t        | d      }t        |      rd}	|D ]q  }
|j	                  |
      }|dk(  r|
rt        |
      |j                         z  }|r(|	t        j                  ||z        z  }	t        ||      }n|	dz  }	t        ||      }s t        ||      |z
  }||	z  ||	dz
  z  z   }|t        z  |fS )ac  Estimate the width and height of the :class:`~ezdxf.entities.MText`
    content string. The result is very inaccurate if inline codes are used or
    line wrapping at the column border is involved!
    Column breaks ``\N`` will be ignored.

    Args:
        content: the :class:`~ezdxf.entities.MText` content string
        font: font abstraction based on :class:`ezdxf.tools.fonts.AbstractFont`
        column_width: :attr:`MText.dxf.width` or 0.0 for an unrestricted column
            width
        line_spacing_factor: :attr:`MText.dxf.line_spacing_factor`

    Returns:
        tuple[width, height]

    r   T)r   r   rN   )rG   r   r   anyr-   r   space_widthrw   ceilminmaxr  r  )r   r3   r  r  	max_widthrI   r   has_column_widthr  
line_countr  
line_widthspacings                r4   r  r    s    , IF))44J)C/'t<E
5z
 	3D.JQ4 !Y)9)9);;
dii
\(ABB
 \:
a
 Iz2I	3" *&9:ZGj(7j1n+EE~%v--r6   c                @    t        | t              rt        |       d| S y)ziReturns a string with line breaks ``\n`` replaced by ``\P`` and the
    length limited to `max_len`.
    Nr   )r8   rz   r   )r   max_lens     r4   safe_stringr  %  s#     !S&q)(733r6   z0123456789.c                    dfd}d| vr| S t              | j                  d      }|d   g}|dd D ]  }|j                   ||d              dj                  |      S )zGScale all inline commands which define an absolute value by a `factor`.c                    d}	 | |   t         v r|dz  }| |   t         v r| |   dk(  r| |  S 	 	 t        | d |       z  }|d}| | | |d   S # t        $ r Y ,w xY w# t        $ r d}Y 'w xY w)Nr   rN   rg   z.3gr   )VALID_HEIGHT_CHARSr   r   re  )r  prefixr  new_sizer  rV  s        r4   _scale_leading_numberz:scale_mtext_inline_commands.<locals>._scale_leading_number4  s    	-#55
 -#55e}# &** $	VFU^,v5HnE (5'&.!122  		
  	E	s'   A A A  	AA A.-A.rR  r   rN   Nr   )r  rz   r  rz   r|   rz   )rH  r   r   r   )r   rV  r  	old_parts	new_partsro  s    `    r4   scale_mtext_inline_commandsr  1  su    3$ G[Fe$I%aL>I!" =.tU;<= 779r6   )r   r   rT   r   r|   r   )rW   r   rU   r   r|   r   )r   zUnion[Text, MText]r|   ztuple[int, int])r2   rz   r|   rz   r  )r2   rz   r|   Union[list[str], str])   )r   rz   r   r   r|   	list[str])Fr'   )r2   rz   r   r   r|   r  )u   ▯)r2   rz   r  rz   r|   rz   )r   rz   r|   r  )r2   rz   r  zOptional[float]r  zCallable[[str], float]r|   r  )r2   r#   r|   r  )r   rz   r|   rz   )rr  r$   r|   rz   )r2   rz   r|   r  )g      @)rV   r   ry  r   r|   r  )rV   r   ry  r   r|   r   )r+   )r   r   r~  r   r|   r   )r  r"   r|   r   )rV  r   r|   r}   r  )r   r+   )
r   rz   r3   r{   r  r   r  r   r|   r   )r   zOptional[str]r  r   r|   rz   )r   rz   rV  r   r|   rz   )dr   
__future__r   typingr   r   r   r   r   r	   r
   r   enumr   rw   ezdxf.lldxfr   r   ezdxf.enumsr   r   r   r   r   r   ezdxf.lldxf.constr   r   r   r   r   r   r   
ezdxf.mathr   r   r   ezdxf.colorsr   r   r    ezdxf.entitiesr!   r"   r#   ezdxf.lldxf.tagsr$   r  r&   r   r)   rb   rc   r   r   r   r   r   r   r   r   r  r  r  r  r7  	JUSTIFIEDDISTRIBUTEDr1  r0  DIGITSr$  r&  r9  	Exceptionr  r  r   IntEnumr   r  compilerT  rS  rb  r   rs  ru  rz  r|  r  r  r  r  r  r  r  setr  r  rn   r6   r4   <module>r     s   #	 	 	  	  (    ( ' . . 55%!j/ j/Z	.:<   dK3\1 , 7
7 7 	7t7Q01
11 +1 	1h ##R  #!!3""C%%s'' 		=* =Ho& o&d	Y 	j" j"ZU& U&p
 
  2::<=RZZDE
 
!	%	%	 	&	&	 	'	'	 	*	*	 	,	,f$ f$R3,
-@  !$	2.2.
2. 2. 	2.
 2.j 2=  ' r6   