a
    V$ck                    @   s  d dl 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mZmZmZmZmZ d dlmZmZ d dlZd dlZd dlZd dlmZmZmZmZ d dlm  mZ d dl m  m!Z! d dl"m  m#Z# d dl$m  m%Z% d dl&m'Z'm(Z(m)Z)m*Z* dZ+G dd	 d	e,Z-d
d Z.G dd de,Z/G dd de,Z0G dd de,Z1G dd de,Z2G dd de,Z3G dd de,Z4dZ5i a6i a7i a8i a9dd Z:g a;dd Z<ej=j>?d ddd Z@ej=j>?d ddd ZAG dd  d ej=jBjCZDejEZEe%jFZFdS )!    )divisionabsolute_importwith_statementprint_functionunicode_literals)PY2
basestringbchrbordchropenpystrrangeroundstrtobytesunicode)OptionalCallableN)TAGTEXT	PARAGRAPHDISPLAYABLE)log2visWRTLRTLONi  c                   @   s"   e Zd ZdZd	ddZdd ZdS )
Blitz
    Represents a blit command, which can be used to render a texture to a
    render. This is a rectangle with an associated alpha.
          ?Fc
           
      C   s:   || _ || _|| _|| _|| _|| _|| _|| _|	| _d S N)	xywhalphaleftrighttopbottom)
selfr    r!   r"   r#   r$   r%   r&   r'   r(    r*   renpy/text\text.py__init__2   s    zBlit.__init__c                 C   s   d | j| j| j| j| jS )Nz<Blit ({0}, {1}, {2}, {3}) {4}>)formatr    r!   r"   r#   r$   r)   r*   r*   r+   __repr__A   s    zBlit.__repr__N)r   FFFF)__name__
__module____qualname____doc__r,   r/   r*   r*   r*   r+   r   ,   s   
r   c                 C   s   | j dd d d}d}d}d}g }| D ]}|j}|j|j |d  }	|j}
|j|j |d  }|d8 }||
kr||
}|}d}|}
||kr|}||kr|}|	}|t||
|	| ||
 |j|j|j	|j
|jd	 q(|S )a  
    Given a list of blits, adjusts it for the given outline size. That means
    adding borders on the left and right of each line of blits. Returns a second
    list of blit objects.

    We assume that there are a discrete set of vertical areas that divide the
    original blits, and that no blit covers two vertical areas. So something
    like:

     _____________________________________
    |_____________________________________|
    |___________|_________________|_______|
    |_____________________|_______________|

    is fine, but:

     _____________________________________
     |              |_____________________|
     |______________|_____________________|

    is forbidden. That's an invariant that the blit_<method> functions are
    required to enforce.
    c                 S   s   | j | jfS r   )r!   r    )br*   r*   r+   <lambda>_       zoutline_blits.<locals>.<lambda>)keyr         r%   r&   r'   r(   )sortr    r"   r!   r#   appendr   r$   r%   r&   r'   r(   )blitsoutlineline_ytop_ybottom_ymax_xrvr4   x0x1y0y1r*   r*   r+   outline_blitsE   s0    4rH   c                   @   s    e Zd ZdZdZdZdZdZdS )DrawInfoa  
    This object is supplied as a parameter to the draw method of the various
    segments. It has the following fields:

    `surface`
        The surface to draw to.

    `override_color`
        If not None, a color that's used for this outline/shadow.

    `outline`
        The amount to outline the text by.

    `displayable_blits`
        If not none, this is a list of (displayable, xo, yo) tuples. The draw
        method adds displayable blits to this list when this is not None.
    Nr   )r0   r1   r2   r3   surfaceoverride_colorr>   displayable_blitsr*   r*   r*   r+   rI      s
   rI   c                   @   sR   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S )TextSegmentzb
    This represents a segment of text that has a single set of properties
    applied to it.
    Nc                 C   s   |dur|j | _ |j| _|j| _|j| _|j| _|j| _|j| _|j| _|j| _|j	| _	|j
| _
|j| _|j| _|j| _|j| _|j| _|j| _|j| _nd| _
d| _d| _d| _d| _dS )z
        Creates a new segment of text. If `source` is given, this starts off
        a copy of that source segment. Otherwise, it's up to the code that
        creates it to initialize it with defaults.
        Nr   F)	antialiasverticalfontsizebolditalic	underlinestrikethroughcolorblack_color	hyperlinkkerningcpsruby_topruby_bottomhintingoutline_colorignore)r)   sourcer*   r*   r+   r,      s0    
zTextSegment.__init__c                 C   s   dj f i | jS )Nz<TextSegment font={font}, size={size}, bold={bold}, italic={italic}, underline={underline}, color={color}, black_color={black_color}, hyperlink={hyperlink}, vertical={vertical}>)r-   __dict__r.   r*   r*   r+   r/      s    zTextSegment.__repr__c                 C   s   |j | _ |j| _|j| _|j| _|j| _|j| _|j| _|j}t|t	rV|
|| _n|jrdd| _nd| _|
|j| _|j| _|j| _d| _||j| _d| _|jdu rtjjj| _| j|j | _dS )zS
        Takes the style of this text segment from the named style object.
        r9   r   NT)rN   rO   rP   rQ   rR   rS   r]   rT   
isinstanceint	scale_intrU   rV   rW   rX   scalerY   r^   slow_cpsrenpygamepreferencestext_cpsrZ   slow_cps_multiplier)r)   stylelayoutrT   r*   r*   r+   
take_style   s,    

zTextSegment.take_stylec                 C   s   | j r
g S t| j| j| j| jd| j| j| j|j		}|
|}| jrRt|| j | jrj|D ]}| j|_q\| jr|t| n&| jdkrt| n| jrt| |S )zN
        Return the list of glyphs corresponding to unicode string s.
        r   alt)r_   rP   get_fontrQ   rR   rS   rN   rO   r]   
oversampleglyphsrY   textsupportrX   r\   mark_ruby_bottomr[   mark_altruby_topmark_ruby_top)r)   srm   forC   gr*   r*   r+   rr      s     *



zTextSegment.glyphsc           	      C   sr   |j r| jp|j }d}n| j}| j}t| j| j| j| j|j	| j
| j| j|j	}||j||||| j| j| dS )z+
        Draws the glyphs to surf.
        N)rK   r^   rV   rW   rP   rp   rQ   rR   rS   r>   rN   rO   r]   rq   drawrJ   rT   rU   )	r)   rr   dixoyorm   rV   rW   rx   r*   r*   r+   rz     s    ,zTextSegment.drawc                 C   s   t || j|S )z
        Assigns times to the glyphs. `gt` is the starting time of the first
        glyph, and it returns the starting time of the first glyph in the next
        segment.
        )rs   assign_timesrZ   r)   gtrr   r*   r*   r+   r~   "  s    zTextSegment.assign_timesc           	      c   s   | j }tjjj}|dur8tjj|d}|dur8||}t|t j	sv| j |u rZ| |fV  nt
| }||_ ||fV  dS i }||D ]<\}}||d}|du rt
| }||_ |||< ||fV  qdS )a/  
        This is called to break the current text segment up into multiple
        text segments. It yields one or more(TextSegement, string) tuples
        for each sub-segment it creates.

        This is used by the FontGroup code to create new text segments based
        on the font group.
        N)rP   rg   rh   ri   font_transformconfigfont_transformsgetrb   	FontGrouprM   segment)	r)   rw   tfr   	font_funcsegsegsfssr*   r*   r+   
subsegment+  s*    



zTextSegment.subsegmentc                 C   s6   t | j | j| j| jd| j| j| j|j	}|	||S )a7  
        Given an x, y, w, h bounding box, returns the union of the given
        bounding box and the bounding box the glyphs will actually be drawn
        into, not including any offsets or expansions.

        This is used to deal with glyphs that are on the wrong side of the
        origin point.
        r   )
rP   rp   rQ   rR   rS   rN   rO   r]   rq   bounds)r)   rr   r   rm   rx   r*   r*   r+   r   V  s    
*zTextSegment.bounds)N)r0   r1   r2   r3   r,   r/   rn   rr   rz   r~   r   r   r*   r*   r*   r+   rM      s   
"$	+rM   c                   @   s:   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdS )SpaceSegmentzL
    A segment that's used to render horizontal or vertical whitespace.
    r   c                 C   sF   t   | _}d|_d|_||_||_||_|jr:|j|_|j	| _	dS )S
        `ts`
            The text segment that this SpaceSegment follows.
        r   r9   N)
rs   Glyphglyph	characterascentline_spacingadvancewidthrX   rZ   )r)   tsr   heightr   r*   r*   r+   r,   i  s    zSpaceSegment.__init__c                 C   s   | j gS r   )r   r)   rw   rm   r*   r*   r+   rr   |  s    zSpaceSegment.glyphsc                 C   s   |S r   r*   r)   rr   r   rm   r*   r*   r+   r     s    zSpaceSegment.boundsc                 C   s   d S r   r*   r)   rr   r{   r|   r}   rm   r*   r*   r+   rz     s    zSpaceSegment.drawc                 C   s$   | j dkr|d| j  7 }|| j_|S Nr   r   )rZ   r   timer   r*   r*   r+   r~     s    
zSpaceSegment.assign_timesN)r   r   )	r0   r1   r2   r3   r,   rr   r   rz   r~   r*   r*   r*   r+   r   d  s   
r   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )DisplayableSegmentz7
    A segment that's used to render displayables.
    c                 C   sX   || _ || }| \| _| _t|tjjjr4d| _|j	| _	|j
| _
|j| _|j| _dS )r   r   N)dget_sizer   r   rb   rg   displaybehavior
CaretBlinkrX   rZ   r[   r\   )r)   r   r   rendersrendr*   r*   r+   r,     s    zDisplayableSegment.__init__c                 C   s   t | jtjjjr.| jjdkr.| jjdkr.g S t	 }|
| j}|
| j}d|_d|_||_||_||_| jrz| j|_|g}| jrt| n&| jdkrt| n| jrt| |S )Nr   i  ro   )rb   r   rg   r   rm   Nullr   r   rs   r   rd   r   r   r   r   rX   r\   rt   r[   ru   rv   )r)   rw   rm   r   r"   r#   rC   r*   r*   r+   rr     s(    *

zDisplayableSegment.glyphsc              	   C   sF   |sd S |d }|j d urB|j | j|j|j|j|j|j|jf d S Nr   )	rL   r<   r   r    r!   r   r   r   r   )r)   rr   r{   r|   r}   rm   r   r*   r*   r+   rz     s
    
zDisplayableSegment.drawc                 C   s.   |s|S | j dkr |d| j  7 }||d _|S r   )rZ   r   r   r*   r*   r+   r~     s    

zDisplayableSegment.assign_timesc                 C   s   |S r   r*   r   r*   r*   r+   r     s    zDisplayableSegment.boundsN)	r0   r1   r2   r3   r,   rr   rz   r~   r   r*   r*   r*   r+   r     s   	r   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )FlagSegmentzf
    A do-nothing segment that just exists so we can flag the start and end
    of a run of text.
    c                 C   s   g S r   r*   r   r*   r*   r+   rr     s    zFlagSegment.glyphsc                 C   s   d S r   r*   r   r*   r*   r+   rz     s    zFlagSegment.drawc                 C   s   |S r   r*   r   r*   r*   r+   r~     s    zFlagSegment.assign_timesc                 C   s   |S r   r*   r   r*   r*   r+   r     s    zFlagSegment.boundsN)r0   r1   r2   r3   rr   rz   r~   r   r*   r*   r*   r+   r     s
   r   c                   @   sj   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S )Layoutz(
    Represents the layout of text.
    FNTc           A   	      s	   fdd}t d|}t d|}|rt|sttjjrttjjrttjjj_tjjj	_
tjjj_|jjdk_d_n*d_tjjj_
tjjj_d_d_|j}	|	j_d_d_d_d_g _|_|_|}|}|	\}
}}}}|
_|_|_|_ |_!|j8 }|j8 }d	}d	}g  g }g }d
}|r|j"_"|j_|j_|j_|j#_#|j_n$|j%|	||_"|	j&}|	j'}jdu }d}t(j"D ]\}}tjj)r*|\}}nd}g }g }|D ]F\}}|+|}||f} |,|  |,|  |-|  -| q|rl|
  |D ]\}}|
  qXj,t.| |rt/0|j| | nj|	j1}!|!dks|!dkrt/2|dd	 n|!dkrt/2|dd	 n|!dkrt/3| nr|!dkrt/2|dd nX|!dkr&t/2|dd n>|!dkr@t/2|dd n$|!dkrVt/4| nt5d6|!|	j7}"|"dkrt89||| || d nt|"dks|"dkrt89||| || d nF|"dkrt/:||| ||  n$|"dkrt/;| nt5d6|"|D ]X\}}|s*j|u rd}nq|ju r:d}|rPt/<|d
| n|<||}q|rpt/=|}t/>|d	||}#|#|kr|#}t/?|||	j@|	jA\}$}|-|$ |	jBs|}qʈ|	j@}%|	j@d	k r tjjCr||% tD| 7 }n
||% 7 }||d jE |d _|	jF}&|&|j krF|&j }tGH|}t/I|||	jJ|	jK |jjL}'|r|'r|jMd	 |j }(|jMd |j })|(| }*|)| }+|'dkrd
}+n|'dkrd
}*t/N ||*|+|| |(}|)}t/O d	tP|jQj |   |j |j f \},}-}.|._M| _Q|rBdS jrpt/R |	jSj!|	jTj!|,|- d	d	||f}/|D ]\}}|U||/}/qtV|/d	  d	_WtV|/d  d	_XtV|/d | d	_YtV|/d | d	_Z|,jWjY 7 },|-jXjZ 7 }-i _[t\ }0jD ]\}1}2}3}4|1|2f}5|5j[v r>q|2dkrXg _]j]|0_]nd|0_]t^|,|1 }6t^|-|1 }7|6d @ r|6d B d n|6}6|7d @ r|7d B d n|7}7tjj_`|6|7fd}8tjajbjcr0|2r|8d|2 nT|	je}9|	jf}:|	gd! |	jf};|	g|9 d"}2|;|:kr0d#|9v r d$}2nd%|	jev r0d&}2|8|0_`|2|0_h|1|0_i|D ]2\}}|ju r` qz|||0jWjX qFtjjjrk|8 tjjl|8 tjjjm|8d'|	jndu rtjjon|	jnid(}<|<j[|5< qt/p|_q|_rjrt/s|_tng _ttjju	rjM\}=}>|=|k	s,|>|k	rtjvw \}?}@tjjxyd) tjjxyd*|?|@ tjjxyd+|||,|- tjjxyd,|jz dS )-a^  
        `text`
            The text object this layout is associated with.

        `width`, `height`
            The height of the laid-out text.

        `renders`
            A map from displayable to its render.

        `size_only`
            If true, layout will stop once the size field is filled
            out. The object will only be suitable for sizing, as it
            will be missing the textures required to render it.

        `splits_from`
            If true, line-split information will be copied from this
            Layout (which must be another Layout of the same text).
        c                     s$    D ]} | j r| jj   S qdS r   )r   r!   yoffset)ry   
all_glyphsr)   r*   r+   find_baseline
  s    z&Layout.__init__.<locals>.find_baselinei  stepTr   FNr           r   	eastasianzkorean-with-spaceswesternzjapanese-looser9   zjapanese-normalr8   zjapanese-strict   anywherezUnknown language: {0}texsubtitleztex-subtitlegreedynobreakzUnknown layout: {0}
horizontalrO      idle_   r   r   r   hover)r   r      r   selected)r   r   r   r   mipmap)
properties z"File "%s", line %d, text overflow:z+     Available: (%d, %d) Laid-out: (%d, %d)z     Text: %r){minrg   r   use_drawable_resolutiondrawable_resolution_textr   rz   draw_per_virtrq   draw_to_virtreversevirt_to_drawforwardrl   outline_scalingoutline_steppixel_perfectrenderIDENTITYrd   line_overlap_splithas_hyperlinkshas_rubystart_segmentend_segmentparagraph_glyphsr   r   figure_outlinesoutlinesxborderyborderxoffsetr   
paragraphshyperlink_targetsr   tokensfirst_indentrest_indent	enumeratertlrtl_paragraphrr   r<   extendlistrs   copy_splitslanguageannotate_unicodeannotate_westernannotate_anywhere	Exceptionr-   rm   texwraplinebreak_texlinebreak_greedylinebreak_nobreakr~   reverse_linesplace_horizontalplace_verticalr   line_leadingnewline_indentbroken_line_spacinglenr!   	min_widthmathceilalign_and_justify
text_alignjustifyadjust_spacingrQ   tweak_glyph_spacingoffset_glyphsr   baseline
place_ruby
ruby_stylealtruby_styler   maxadd_leftadd_top	add_right
add_bottomtexturesrI   rL   rc   pgrenderrJ   rh   ri   high_contrastfillprefixrV   
set_prefixrK   r>   debug_text_alignmentmake_alignment_gridmutated_surfaceload_texturer   mipmap_text	max_timesmax_timelineshyperlink_areas
hyperlinksdebug_text_overflowexportsget_filename_lineto_logwritetext)Ar)   r  r   r   r   	size_onlysplits_fromdrawable_resr   rl   r   r   r   r   r   maxxr!   par_seg_glyphsr  r   r   r   startedendedp_numpr   
par_glyphs
seg_glyphsr   rw   rr   tr   rm   r"   lr   r   r   target_xtarget_ytarget_x_deltatarget_y_deltaswshrQ   r   r{   orV   _xo_yor7   twthsurfr  prefix_color
idle_colorr   owohfilenameliner*   r   r+   r,     s   






















$






 &







,

zLayout.__init__c                 C   s   |  \}}t|D ]}t|D ]}|||fd dkr<q |dksd|dksd||d ksd||d krv|||fd q ||A d@ r|||fd q |||fd q qd S )Nr   r   r9   )r   r   r   r   r   r   r   r   r   )r   r   get_atset_at)r)   r8  r"   r#   r    r!   r*   r*   r+   r    s    (zLayout.make_alignment_gridc                 C   s   |d u r|S || j  S r   rq   r)   nr*   r*   r+   re     s    zLayout.scalec                 C   s2   |d u r|S t |tjjjr$t|S t|| j S r   )rb   rg   r   coreabsoluterc   r   rq   rC  r*   r*   r+   rd     s
    zLayout.scale_intc                 C   s   |d u r|S t |tjjjr$t|S | jrJ| jdk r8|S t|t| j S |dkrVdS t|| j }|dk rx|dkrxd}|dkr|dk rd}|S d S )Nr9   r   r   )	rb   rg   r   rE  rF  rc   r   rq   r   )r)   rD  rC   r*   r*   r+   scale_outline  s     
zLayout.scale_outlinec                 C   s   || j  || j  fS r   rB  )r)   r    r!   r*   r*   r+   unscale_pair  s    zLayout.unscale_pairc              	      s  i | _ g }g  td}|j|_|jdu s2|jdu r>tjjj|_|||  |gfdd} fdd}|D ]J\}	}
z|	t	kr|  |
  g  W qnnj|	tkr|jdur|
dkr|jt|
 }
 d |
 W qnn(|	tkr 
td |
|d	f W qn|
d
\}}}|rz|d dkrz  s|dd }tjjj|dsjtd||f td|
 n|dkrt } 
|d	f || _n|dkrt } 
|d	f || _n|dkr|  |
  g  n|dkr<t|dk rtd| | t|} 
td |dd	f nP|dkrt|dk r`td| | t|} r~|
  td |dd	fg |
  g  n|dkrn|dkrn|dkrАn|dkrސn|dkrd| _|j d }|r||}n|}|j!}t| j d }|| j |< |"|sB|#d n8tj$j%& |u rptj$j%j'|krp|#d n
|#d | }|j(}|j)}|||  ||_(||_*tj+j,r||_)|#| n|d krd| _-n|d!krd| _.n|d"kr$|r| t|| _/n| d| _/nh|d#kr:d| _0nR|d$krf| }d%|_-d%|_.d%|_/d%|_0n&|d	krt1tj2j3|}| ||  n|d&kr|| _4n|d'krt|dk rtd| |d d(v r|  j)t|7  _)nt|| _)n|d)kr6t|dk r"td| tj56|| _6nV|d*krnt|dk rZtd| tj56|| _7n|d+krt|dk rtd| | }|d d(v r|j6j8t9| }n0|d d,kr|j6j8t9|dd  }nt9|}|j6:||_6n|d-kr4t|dk rtd| | ;t9|| _<nX|d.krn| }|j(}||j=|  ||_(d|_>d| _?n|d/kr| }|j(}||j@|  ||_(d0|_>d| _?n|d1krd| _An|d2krt|dk rtd| | }|d d,kr| jt9|dd 9  _n
t9||_nr|d3kr.d| _(n^|d4krF| }d%|_(nF|d0kr^| }d|_Bn.|d5krp| }n|d d6krntd7|
 W qn ty   d8C|
|D tj_E Y qn0 qn|  |
  |S )9z
        Breaks the text up into segments. This creates a list of paragraphs,
        which each paragraph being represented as a list of TextSegment, glyph
        list tuples.
        NTc                     s   t  d }  |  | S )z
            Creates a new text segment, and pushes it onto the text segement
            stack. Returns the new text segment.
            r   )rM   r<   )r   )tssr*   r+   push  s    
zLayout.segment.<locals>.pushc                     s<    D ]} t | d tttfr d S q d d d S )Nr   r      ​)rb   rM   r   r   r   r   )ir>  rI  r*   r+   fill_empty_line  s    z'Layout.segment.<locals>.fill_empty_linerK  r   r   =r   /r9   zB{/%s} isn't valid, since the %s text tag doesn't take a close tag.z%%r closes a text tag that isn't open._start_endr(  spacezempty value supplied for tag %r)r   vspace)r   r"   fastdonenwainsensitive_hover_r   r4   rL  urw   plainFrP   rQ   z+-rV   outlinecolorr$   *krtartro   rbrZ   verthoriznoalt#zUnknown text tag %rz,While processing text tag {{{!s}}} in {!r}.:)Fr   rM   rf   rZ   rg   rh   ri   rj   rn   r   r<   r   maskr   r   r   r   r   	partitionpopr  extras	text_tagsr   r   r   r   r   rd   rc   r   r   hyperlink_functionsr  hyperlink_sensitiver  r   focusget_focusedargumentrO   rQ   rX   r   hyperlink_inherit_sizerR   rS   rT   rU   getattrstorerl   rP   easyrV   r^   r$   floatreplace_opacityre   rY   r  r[   r   r  r\   r_   r-   get_all_textexception_info)r)   r   rl   r   text_displayabler   r   rJ  rN  typer  tag_valuefsr   r   hyperlink_stylerhls
old_prefixlink
vert_stylerQ   r*   rM  r+   r     sn   	




















"



























zLayout.segmentc                 C   sN   t }g }|D ](\}}tt||\}}|||f q|tkpD|tk}||fS )a  
        Given a paragraph (a list of segment, text tuples) handles
        RTL and ligaturization. This returns the reversed RTL paragraph,
        which differers from the LTR one. It also returns a flag that is
        True if this is an rtl paragraph.
        )r   r   r   r<   r   r   )r)   r(  	directionr,  r   rw   r   r*   r*   r+   r     s    zLayout.rtl_paragraphc              	   C   sX  |j }|j}|s.|s.tjjjs.dgddddfS g }|rtt|tsF|g}|D ](\}}|d|j	| 
|| 
|f qJ|D ]0\}}}	}
|| ||| 
|	| 
|
f qxd}d}d}d}|D ]`\}}}}|| }|| }|| }|| }||k r|}||kr|}||k r|}||kr|}q|d tjjjr>ddg}||| || | | fS )a4  
        Return a list containing the outlines, including an outline
        representing the drop shadow, if we have one, also including
        an entry for the main text, with color None. Also returns the
        space reserved for outlines - to be deducted from the width
        and the height.
        )r   Nr   r   r   )r8   r?  r   r   )r   drop_shadowrg   rh   ri   r  rb   r   r<   drop_shadow_colorrd   rG  )r)   rl   style_outlinesdslistr   dsxdsyrQ   rV   r|   r}   r%   r&   r'   r(   r3  _cr    r!   r,  rr+  r4   r*   r*   r+   r     sB    	
"&


zLayout.figure_outlinesc                 C   sf  | j \}}g }| js|S d}d}| jD ]*}|j|kr8 qVt|j|j | j |}q&d}|r|tdd|||dd|du d d}|du r|S |}d}	d}
d}|j	D ]l}|j
dkrq|j
|krq||j	d u rd}
||j	d u rd}|j|j |	kr|j|j }	|j|k r|j}qt|j|j | j |}||	k rb|t|||	| || |
|||| jd u d |S )z
        Given a st and an outline, returns a list of blit objects that
        can be used to blit those objects.

        This also sets the extreme points when creating a Blit.

        r   TN)r'   r%   r&   r(   Fr   r:   )rQ   r  r  r   r!   r   r   r<   r   rr   r   r    r   )r)   str   
max_heightrC   max_yr'   r,  min_xrB   r%   r&   ry   lyr*   r*   r+   blits_typewriterZ  sJ    	


"




0zLayout.blits_typewriterc                 C   s   || j krdS dS dS )zS
        Return the time of the first glyph that should be shown after st.
        Nr   )r  r)   r  r*   r*   r+   redraw_typewriter  s    
zLayout.redraw_typewriter)FNT)r0   r1   r2   r3   r,   r  re   rd   rG  rH  r   r   r   r  r  r*   r*   r*   r+   r     s"   
   	  @;Gr   2   c                   C   s   i a i ai ai adS )z/
    Clears the old and new layout caches.
    N)layout_cache_oldlayout_cache_newvirtual_layout_cache_oldvirtual_layout_cache_newr*   r*   r*   r+   layout_cache_clear  s    r  c                   C   s   t ai a t ai ag adS )zN
    Called once per interaction, to merge the old and new layout caches.
    N)r  r  r  r  	slow_textr*   r*   r*   r+   	text_tick  s
    r  r   r9   c                       s@  e Zd ZdZdZdZdZdZdZdZ	dZ
dd ZdD fdd		Zd
d Zdd Zdd Zdd ZdEddZdFddZdd Zdd Zdd Zdd Zdd Zd d! ZeZd"d# Zd$d% Zd&d' Z fd(d)Z fd*d+ZdGd,d-ZdHd.d/Z d0d1 Z!d2d3 Z"d4d5 Z#dId8d9Z$d:d; Z%d<d= Z&d>d? Z'e(d@dA Z)dBdC Z*  Z+S )JTexta  
    :name: Text
    :doc: text
    :args: (text, slow=None, scope=None, substitute=None, slow_done=None, **properties)

    A displayable that displays text on the screen.

    `text`
        The text to display on the screen. This may be a string, or a list of
        strings and displayables.

    `slow`
        Determines if the text is displayed slowly, being typed out one character at the time.
        If None, slow text mode is determined by the :propref:`slow_cps` style property. Otherwise,
        the truth value of this parameter determines if slow text mode is used.

    `scope`
        If not None, this should be a dictionary that provides an additional scope for text
        interpolation to occur in.

    `substitute`
        If true, text interpolation occurs. If false, it will not occur. If
        None, they are controlled by :var:`config.new_substitutions`.

    `slow_done`
        If not None, and if slow text mode is enabled (see the `slow` parameter), this is a
        function or callable which is called with no arguments when the text finishes displaying.

    `**properties`
        Like other Displayables, Text takes style properties, including (among many others) the
        :propref:`mipmap` property.
       TFNc                 C   sN   |dk rd | _ |dk rJt| jts,| jg| _d | _d| _d | _d | _d| _d S )Nr   r  FT)	ctcrb   r  r   scope
substitutestartenddirty)r)   versionr*   r*   r+   after_upgrade  s    
zText.after_upgradec           
         s
  t t| jf i | t|ts&|g}|D ]:}	t|	ttjjj	fs*tj
jrZtd|	q*dg} qfq*|| _d| _d | _|| _| ||| tjjstjjjrd}|| _|| _d | _d | _d | _t|tr|j| _|j| _|j| _|j| _|j| _d | _| j| _g | _d S )NzCannot display {0!r} as text.r   TF)superr  r,   rb   r   r   rg   r   rE  Displayabler   	developerr   r-   r  r  r  rg  set_textrh   less_updatesri   self_voicingslow	slow_doner  r  r  displayables_duplicatabledisplayable_offsets)
r)   r  r  r  r  r  replacesrg  r   rL  	__class__r*   r+   r,     s<    

zText.__init__c                 C   s2   |r|j r|  | jr.| |}|  |S | S r   )args
extraneousr  _copy_unique)r)   r  rC   r*   r*   r+   
_duplicate\  s    

zText._duplicatec                 C   s>   | j s
| S |  }|jd ur.dd |jD |_d |_d|_|S )Nc                 S   s   g | ]}|  qS r*   )_in_current_store).0rL  r*   r*   r+   
<listcomp>p  r6   z*Text._in_current_store.<locals>.<listcomp>T)_uses_scoper  r  r  locked)r)   rC   r*   r*   r+   r  i  s    
zText._in_current_storec                 C   sJ   d}| j D ]6}t|tr ||7 }t|dkr
|d d d } qBq
t|S )Nr         u   …)r  rb   r   r   reprr)   rw   rL  r*   r*   r+   
_repr_infow  s    

zText._repr_infoc                 C   s&   d}| j D ]}t|tr
||7 }q
|S )z$
        Gets all the text,
        r   )r  rb   r   r  r*   r*   r+   rw    s
    


zText.get_all_textc                 C   s   | j r
dS | | j|| j|S )z=
        Called to update the scope, when necessary.
        F)r  r  text_parameterr  )r)   r  updater*   r*   r+   _scope  s    zText._scopec           
      C   s   | j r
d S tjjj| _| j}t|ts,|g}|| _g }d}|D ]R}t|t	r|durptj
|||\}}	|pn|	}t|trt|dd}|| q>|| _||krdS |r|| _| jsd| _|d urtjj| d dS )NFzutf-8replaceTr   )r  rg   rh   ri   r   r  rb   r   r  r   substitutionsr  bytesr   r<   r  r  r   r   redraw)
r)   r  r  r  r  old_textnew_text
uses_scoperL  did_subr*   r*   r+   r    s6    


zText.set_textc                 C   s@   | j tjjj kr*| js*| j| j| jdd | jj	r<t
|  d S )NT)r  r  )r   rg   rh   ri   r  r  r  r  rl   slow_abortabler  r<   r.   r*   r*   r+   per_interact  s    zText.per_interactc                 C   s   || _ d| _d S NT)r  r  )r)   r  r*   r*   r+   set_ctc  s    zText.set_ctcc                 C   s   || _ d| _d S r  )last_ctcr  )r)   r  r*   r*   r+   set_last_ctc  s    zText.set_last_ctcc                 C   s  d| _ |   | j}| jdur|d d| j }|d | j| j }|d | jd }|rb|d }|rnd| }g }|r|| || | jdurt| jtr|	| j n|| j |r|| |	|dd  |}n4| jdurt| jtr|	| j n|| j | j
durHt| j
tr<|	| j
 n|| j
 | |}tjjsttjjsttjjdur~| |}| |\| _| _| jD ],\}}|tkr|drd| _ qʐqd| _dS )	zy
        This needs to be called after text has been updated, but before
        any layout objects are created.
        FNr   z{_start}z{_end}r9   za=T)r  kill_layoutr  r  r  r<   r  rb   r   r   r  tokenizerg   r   custom_text_tagsself_closing_custom_text_tagsreplace_textapply_custom_tagsget_displayablesr   r  r   
startswith	focusable)r)   r  start_string
mid_string
end_string
text_splitr   rz  r*   r*   r+   r    sP    





"

zText.updatec                 C   s"   | j s| jd u r|   t| jS r   )r  r  r  r   r.   r*   r*   r+   visit(  s    z
Text.visitc                 C   s   g }| j D ]}t|tsq
|| q
d|}|d\}}}|d\}}}tj j	|}| j
j}|d urtjj|d|idd }|S )Nr   z{done}z{fast}r  )r  r   )r  rb   r   r<   joinrh  
rpartitionrg   rj  filter_alt_textrl   ro   r  r  )r)   rC   rL  r|  ro   r*   r*   r+   _tts/  s    


z	Text._ttsc                 C   s<   t | }t|d t|d t|d t|d dS )z]
        Kills the layout of this Text. Used when the text or style
        changes.
        N)idr  ri  r  r  r  )r)   r7   r*   r*   r+   r  I  s
    zText.kill_layoutc                 C   s,   t | }t|d}|du r(t|d}|S z>
        Gets the layout of this text, if one exists.
        N)r  r  r   r  r)   r7   rC   r*   r*   r+   
get_layoutW  s
    zText.get_layoutc                 C   s,   t | }t|d}|du r(t|d}|S r  )r  r  r   r  r  r*   r*   r+   get_virtual_layoute  s
    zText.get_virtual_layoutc                    s*   || j jkr|   tt| || d S r   )rl   r  r  r  r  set_style_prefix)r)   r  rootr  r*   r+   r  s  s    zText.set_style_prefixc                    s   t t|  }|d tkr|S |  }|d u rd}d}d}d}| jsN| jd u rV|   i }| jD ]"}tj	j

||| jj||||< q`t| |||ddd}|\}	}
}}}}}|	|
||j|||f}|S )Nr      r   Tr   r"  )r  r  get_placementBASELINEr  r  r  r  rg   r   r   rl   rQ   r   r  )r)   rC   rm   r   r   r  atr   rL  xposyposxanchoryanchorr   r   subpixelr  r*   r+   r  y  s$    
 zText.get_placementc                 C   s|   |   }|   tjj| d |du r,dS |s@tj| jj	 | jj
d }|jtjjjd}|rx|sx|durx||S dS )z6
        Called when a hyperlink gains focus.
        r   Nr8   )r  r  rg   r   r   r  r  playrl   hover_soundrl  r   r   rn  rp  )r)   defaultrm   hyperlink_focustargetr*   r*   r+   rn    s    z
Text.focusc                 C   s8   |    tjj| d | jjd }|r4|s4|dS dS )zV
        Called when a hyperlink loses focus, or isn't focused to begin with.
        r   r8   N)r  rg   r   r   r  rl   rl  )r)   r  r  r*   r*   r+   unfocus  s
    zText.unfocusc                 C   s   d| _ | jr|   d| _dS )z/
        Called when slow is finished.
        FN)r  r  r  r*   r*   r+   call_slow_done  s    zText.call_slow_donec                 C   s$   | j j}t|dk rdS |d |S )zN
        Returns true of the hyperlink is sensitive, False otherwise.
        r  Tr   )rl   rl  r   )r)   r  funcsr*   r*   r+   rm    s    zText.hyperlink_sensitivec                 C   s$  | j rDtjj|drD| jjrDtD ]}|j r"|| q"tjj	
 |  }|du rXdS | jD ]2\}}}	|||| ||	 |}
|
dur^|
  S q^|  r tjj|dr tj| jj | jjd }|dur |jtjjjd}| |sdS | jjd |}
|
du rtjj	
 |
S dS )zD
        Space, Enter, or Click ends slow, if it's enabled.
        dismissNbutton_selectr9   )r  rg   r   r   	map_eventrl   r  r  r  rE  IgnoreEventr  r  event
is_focusedr  r  activate_soundrl  r   r   rn  rp  rm  )r)   evr    r!   r  rL  rm   r   r|   r}   rC   clickedr  r*   r*   r+   r    s2    




z
Text.eventr  r   c                 C   sf   | j s| jdu r|   i }| jD ]"}tjj||| jj||||< q"t| |||ddd}|j	|j S )z
        :args: (width=4096, height=4096, st=0, at=0)

        Attempts to figure out the size of the text. The parameters are
        as for render.

        This does not rotate vertical text.
        NTr  )
r  r  r  rg   r   r   rl   rQ   r   rH  )r)   r   r   r  r  r   rL  rm   r*   r*   r+   rQ     s    
 z	Text.sizec                 C   s   |   }|du rdS |jS )zd
        Returns the amount of time, in seconds, it will take to display this
        text.
        Nr   )r  r  )r)   rm   r*   r*   r+   get_time  s    zText.get_timec           -   
   C   s"  | j jr|| }}| jd u r2| j jr,d| _nd| _| jsB| jd u rJ|   i }| jD ]"}tjj		||| j j
||||< qT|  }|d u s|j|ks|j|krt| |||ddd}tttkrt  |tt| < |  }|d u s|j|ks|j|kr*t| ||||d}tttkrt  |tt| < |j
\}	}
|j
\}}| jsrtdd||j ||j dddddg}d }n||}||}tjj	|	|
}tjjrtjj	|	|
}|d |j|_ |j |_|!|d |j"D ]\}}}}|j#||f }|r
t$||}n|}|D ]J}|j%}|j&}|j'}|j(}|dk rH||j%7 }d}|dk r^||7 }d}||| krt|| }||| kr|| }|dks|dkrq|j)r||j*7 }||7 }|j+r||j,7 }||7 }|j-r||j.7 }n
||j.7 }|j/r||j07 }n
||j07 }|1|2||||f|3|| |j4 | |j. || |j5 | |j0  qq|j6r0g | _7tjj	||}|j|_ |j |_|j6D ]\}}}}} }!}"| jr|"|krqtjj89|| ||!|: \}}|| |j4 }|| |j5 }|1|| ||f | j7;|||f q|!|d |j<D ]P\}#}$}%}&}'|3|$|j4 |%|j5 \}(})|3|&|'\}*}+|=| |#|(|)|*|+ q6| jr|d urtjj	>| t?|d n
| @| |j |_ |j|_| j jrtjj	|j|j},tA|,_ tB|,_|,!||jdf |,}|jCrd	di|_D|S )
NTF)r"  r   )r!  r   r:   )r   r   r       )r   r   r   )Erl   rO   r  rf   r  r  r  rg   r   r   rQ   r  r   r   r   r   r  LAYOUT_CACHE_SIZEclearr  r  r  r   r   r   r  r  Renderr   draw_virtual_text_boxr  r   r   blitr   r
  rH   r    r!   r"   r#   r&   r  r(   r	  r%   r  r'   r  absolute_blit
subsurfacerH  r   r   rL   r  rE  placer  r<   r  	add_focusr  r  r  VERT_FORWARDVERT_REVERSEr   r   )-r)   r   r   r  r  r   rL  virtual_layoutrm   vwvhr"   r#   r=   r  rC   r  r3  rV   r|   r}   r   oblitsr4   b_xb_yb_wb_hdrendr   r    r!   r   r   r+  rX   hxhyhwhhh_xh_yh_wh_hvrvr*   r*   r+   r   #  s    


 

&















zText.renderc                 C   s|   g }|D ]n}t |tr(|t| qt |trH|tt| qt |tjjj	rh|
t|f qtd|q|S )z9
        Convert the text into a list of tokens.
        zCan't display {0!r} as Text.)rb   r   r   rs   r  r   rg   r   rE  r  r<   r   r   r-   )r)   r  r   rL  r*   r*   r+   r    s    

zText.tokenizec                 C   s  g }| r|  d}|\}}|tkrHtjjrH|tttj|f q|tkr\|| q|d\}}}tjj	
|d}|du rtjj
|d}d}	nd}	|du r|| q|	sXg }
d| }d}| r6|  d}|\}}|tkr*|d\}}}||kr|d7 }n||kr*|d8 }|s*q6|
| q|rJtd|||||
}n
|||}g }|D ],\}}t|trt|}|||f qj||  |} q|S )	z3
        Apply new-style custom text tags.
        r   rO  NTFrP  r9   z2Text ended while the '{}' text tag was still open.)ri  r   rg   r   r  r<   r   r   rh  r  r   r  r   r-   rb   r  r   )r   rC   r+  kindr  r{  r|  r}  funcself_closingcontentsclosecountt2kind2text2tag2new_contents
new_tokensr*   r*   r+   r    sZ    








zText.apply_custom_tagsc                 C   s   t  }g }|D ]z}|\}}|tkr8|| || q|tkr~|d\}}}	|dkr~tj|	}
||
 |t|
f q|| q||fS )z
        Goes through the list of tokens. Returns the set of displayables that
        we know about, and an updated list of tokens with all image tags turned
        into displayables.
        rO  image)	setr   addr<   r   rh  rg   rt  displayable)r)   r   r  r3  r+  r(  r  r{  r|  r}  r   r*   r*   r+   r  L	  s"    


zText.get_displayables)NNNNNN)T)NFT)F)F)r  r  r   r   ),r0   r1   r2   r3   __version__r  r  r  r   rg  r  r  r,   r  r  r  rw  r  r  r  r  r  r  r  r  _tts_allr  r  r  r  r  rn  r  r  rm  r  rQ   r	  r   r  staticmethodr  r  __classcell__r*   r*   r  r+   r    sR   !@


/P

+
 <
Vr  )G
__future__r   r   r   r   r   renpy.compatr   r   r	   r
   r   r   r   r   r   r   r   r   typingr   r   r   pygame_sdl2rg   renpy.text.textsupportr   r   r   r   r  rs   renpy.text.texwrapr   renpy.text.fontrP   renpy.text.extrasrj  
_renpybidir   r   r   r   r  objectr   rH   rI   rM   r   r   r   r   r  r  r  r  r  r  r  r  r   matrixMatrix2Dr  r  rE  r  r  language_tailorParameterizedTextr*   r*   r*   r+   <module>   s`   8I =+N       D       