U
    cfB                     @   sR  d Z ddlZddlZddlmZ ddlmZ ddlmZ dddd	d
dddgZ	ddl
mZmZ eeZG dd deZG dd deZG dd dZG dd dejZG dd	 d	ejZejejejejejejiZeddG dd deZeeeeedddZeeeeedddZeddG dd
 d
eZeddG dd deZ dS )z!Layout utilities (to be expanded)    N)	dataclass)Fraction)OptionalLayoutErrorBoxSpecificationErrorBoxConstraintsAxisAlignmentMarginsInnerScalingSimpleBoxLayoutRulePositioning)ConfigurableMixinConfigurationErrorc                       s&   e Zd ZdZed fddZ  ZS )r   z+Indicates an error in a layout computation.msgc                    s   || _ t j|f|  d S N)r   super__init__)selfr   args	__class__ </tmp/pip-unpacked-wheel-0kb_yl26/pyhanko/pdf_utils/layout.pyr      s    zLayoutError.__init__)__name__
__module____qualname____doc__strr   __classcell__r   r   r   r   r      s   c                       s,   e Zd ZdZdee d fddZ  ZS )r   z4Raised when a box constraint is over/underspecified.Nr   c                    s   t  j|pdd d S )Nz%box constraint is over/underspecifiedr   )r   r   )r   r   r   r   r   r      s    zBoxSpecificationError.__init__)N)r   r   r   r   r   r   r   r   r   r   r   r   r      s   c                   @   s   e Zd ZU dZee ed< ee ed< ee ed< eed< deddd	Z	d
d Z
eedddZejdd ZeedddZeedddZejdd ZeedddZeedddZeedddZdS )r   a)  Represents a box of potentially variable width and height.
    Among other uses, this can be leveraged to produce a variably sized
    box with a fixed aspect ratio.

    If width/height are not defined yet, they can be set by assigning to the
    :attr:`width` and :attr:`height` attributes.
    _width_height_ar_fully_specifiedN)aspect_ratioc                 C   s   |d k	rt |nd | _|d k	r&t |nd | _d}d | _|d krR|d krR|d krRd S |d k	r|d k	r|d k	rntt| j| j| _d}n4|d k	r|| _|d k	r|| | _n|d k	r|| | _|| _d S )NFT)intr    r!   r"   r   r   r#   )r   widthheightr$   Zfully_specifiedr   r   r   r   0   s$    
zBoxConstraints.__init__c                 C   s   | j d k	r,| jd k	r,t| j | j| _d| _nP| jd k	r|| jd k	rZt| j| j | _ d| _n"| j d k	r|t| j | j | _d| _d S )NT)r    r!   r   r"   r#   r%   r   r   r   r   _recalculateG   s    


zBoxConstraints._recalculate)returnc                 C   s   | j dk	r| j S tdS )z
        :return:
            The width of the box.
        :raises BoxSpecificationError:
            if the box's width could not be determined.
        N)r    r   r(   r   r   r   r&   S   s    
zBoxConstraints.widthc                 C   s"   | j d kr|| _ |   ntd S r   )r    r)   r   r   r&   r   r   r   r&   `   s    

c                 C   s
   | j dk	S )z
        :return:
            ``True`` if the box currently has a well-defined width,
            ``False`` otherwise.
        N)r    r(   r   r   r   width_definedh   s    zBoxConstraints.width_definedc                 C   s   | j dk	r| j S tdS )z
        :return:
            The height of the box.
        :raises BoxSpecificationError:
            if the box's height could not be determined.
        N)r!   r   r(   r   r   r   r'   q   s    
zBoxConstraints.heightc                 C   s"   | j d kr|| _ |   ntd S r   )r!   r)   r   r   r'   r   r   r   r'   ~   s    

c                 C   s
   | j dk	S )z
        :return:
            ``True`` if the box currently has a well-defined height,
            ``False`` otherwise.
        N)r!   r(   r   r   r   height_defined   s    zBoxConstraints.height_definedc                 C   s   | j dk	r| j S tdS )z
        :return:
            The aspect ratio of the box.
        :raises BoxSpecificationError:
            if the box's aspect ratio could not be determined.
        N)r"   r   r(   r   r   r   r$      s    
zBoxConstraints.aspect_ratioc                 C   s
   | j dk	S )z
        :return:
            ``True`` if the box currently has a well-defined aspect ratio,
            ``False`` otherwise.
        N)r"   r(   r   r   r   aspect_ratio_defined   s    z#BoxConstraints.aspect_ratio_defined)NNN)r   r   r   r   r   r%   __annotations__r   boolr   r)   propertyr&   setterr,   r'   r.   r$   r/   r   r   r   r   r   "   s.   


c                   @   sD   e Zd ZdZe Ze Ze Ze Z	e
ed dddZdS )r
   z(Class representing a scaling convention.)
config_strr*   c                 C   sJ   z t jt jt jt jd|  W S  tk
rD   td| dY nX dS )a   
        Convert from a configuration string.

        :param config_str:
            A string: 'none', 'stretch-fill', 'stretch-to-fit', 'shrink-to-fit'
        :return:
            An :class:`.InnerScaling` value.
        :raise ConfigurationError: on unexpected string inputs.
        )nonezstretch-fillzstretch-to-fitzshrink-to-fit'zs' is not a valid inner scaling setting; valid values are 'none', 'stretch-fill', 'stretch-to-fit', 'shrink-to-fit'.N)r
   
NO_SCALINGSTRETCH_FILLSTRETCH_TO_FITSHRINK_TO_FITlowerKeyErrorr   )clsr4   r   r   r   from_config   s    
zInnerScaling.from_configN)r   r   r   r   enumautor7   r8   r9   r:   classmethodr   r>   r   r   r   r   r
      s   c                   @   sn   e Zd ZdZe Ze Ze Ze	e
d dddZe	e
d dddZedd Zeeed	d
dZdS )r   z;Class representing one-dimensional alignment along an axis.)	align_strr*   c                 C   sF   zt jt jt jd|  W S  tk
r@   td| dY nX dS )a  
        Convert from a horizontal alignment config string.

        :param align_str:
            A string: 'left', 'mid' or 'right'.
        :return:
            An :class:`.AxisAlignment` value.
        :raise ConfigurationError: on unexpected string inputs.
        )leftmidrightr6   zO' is not a valid horizontal alignment; valid values are 'left', 'mid', 'right'.Nr   	ALIGN_MIN	ALIGN_MID	ALIGN_MAXr;   r<   r   r=   rB   r   r   r   from_x_align   s    
zAxisAlignment.from_x_alignc                 C   sF   zt jt jt jd|  W S  tk
r@   td| dY nX dS )a  
        Convert from a vertical alignment config string.

        :param align_str:
            A string: 'bottom', 'mid' or 'top'.
        :return:
            An :class:`.AxisAlignment` value.
        :raise ConfigurationError: on unexpected string inputs.
        )bottomrD   topr6   zM' is not a valid vertical alignment; valid values are 'bottom', 'mid', 'top'.NrF   rJ   r   r   r   from_y_align   s    
zAxisAlignment.from_y_alignc                 C   s   t |  S r   )_alignment_oppositesr(   r   r   r   flipped  s    zAxisAlignment.flipped)container_len	inner_lenr*   c                 C   s   t d|||}| tjkr&|| | S | tjkr4|S ||krdtd| d| d| d| d	 |S | tjkr|| d }|| S d S )NlengthzContent box width/height z  is too wide for container size z with margins (, z); post_margin will be ignored   )r	   	effectiver   rI   rG   loggerwarningrH   )r   rQ   rR   
pre_marginpost_marginZeffective_max_lenZinner_offsetr   r   r   align  s$       


zAxisAlignment.alignN)r   r   r   r   r?   r@   rG   rH   rI   rA   r   rK   rN   r2   rP   r%   r[   r   r   r   r   r      s   
T)frozenc                   @   s:   e Zd ZU dZeed< eed< eed< eed< dd ZdS )	r   zP
    Class describing the position and scaling of an object in a container.
    x_posy_posx_scaley_scalec                 C   s   d| j | j| j| jf S )z
        Convenience method to convert this :class:`.Positioning` into a PDF
        ``cm`` operator.

        :return:
            A byte string representing the ``cm`` operator corresponding
            to this :class:`.Positioning`.
        s   %g 0 0 %g %g %g cm)r_   r`   r]   r^   r(   r   r   r   as_cmO  s    	   zPositioning.as_cmN)r   r   r   r   r%   r0   floatra   r   r   r   r   r   =  s   
	alignmentcontainer_boxinner_nat_widthrY   rZ   c                 C   s.   |j r| |j|||S || | |_|S d S r   )r,   r[   r&   rc   r   r   r   
_aln_width]  s       rg   rd   re   inner_nat_heightrY   rZ   c                 C   s.   |j r| |j|||S || | |_|S d S r   )r.   r[   r'   rh   r   r   r   _aln_heighth  s       rj   c                       s~   e Zd ZU dZdZeed< dZeed< dZeed< dZ	eed< e
dd Zed	d
 Zdd Zdd Ze
 fddZ  ZS )r	   z"Class describing a set of margins.r   rC   rE   rM   rL   c                 C   s   t ||||S )z
        Return a set of uniform margins.

        :param num:
            The uniform margin to apply to all four sides.
        :return:
            ``Margins(num, num, num, num)``
        )r	   )r=   numr   r   r   uniform  s    
zMargins.uniformc              
   C   s:   || | }|dk r6t d| d| d|  d| d	|S )z4Internal helper method to compute effective margins.r   z	Margins (rT   z) too wide for container  .)r   )Zdim_namerQ   prepostZeffr   r   r   rV     s    zMargins.effectivec                 C   s   t d|| j| jS )a&  
        Compute width without margins.

        :param width:
            The container width.
        :return:
            The width after subtracting the left and right margins.
        :raises LayoutError:
            if the container width is too short to accommodate the margins.
        r&   )r	   rV   rC   rE   r+   r   r   r   effective_width  s    zMargins.effective_widthc                 C   s   t d|| j| jS )a+  
        Compute height without margins.

        :param height:
            The container height.
        :return:
            The height after subtracting the top and bottom margins.
        :raises LayoutError:
            if the container height is too short to accommodate the margins.
        r'   )r	   rV   rL   rM   r-   r   r   r   effective_height  s    zMargins.effective_heightc                    s$   t |trttd|}t |S )N)rC   rE   rM   rL   )
isinstancelistdictzipr   r>   )r=   config_dictr   r   r   r>     s
    
zMargins.from_config)r   r   r   r   rC   r%   r0   rE   rM   rL   rA   rl   staticmethodrV   rq   rr   r>   r   r   r   r   r   r	   s  s   



c                   @   sn   e Zd ZU dZeed< eed< e Zeed< ej	Z
eed< edd Zed dd	d
ZeeeedddZdS )r   zk
    Class describing alignment, scaling and margin rules for a box
    positioned inside another box.
    x_aligny_alignmarginsinner_content_scalingc                 C   sz   | dtj}t|tr"t|}||d< | dtj}t|trLt|}||d< | dd }|d k	rvt||d< d S )Nry   rz   r|   )	getr   rH   rs   r   rK   rN   r
   r>   )r=   rw   ry   rz   scalingr   r   r   process_entries  s    



z#SimpleBoxLayoutRule.process_entries)new_marginsr*   c                 C   s   t | j| j|| jdS )N)ry   rz   r{   r|   )r   ry   rz   r|   )r   r   r   r   r   substitute_margins  s     z&SimpleBoxLayoutRule.substitute_margins)re   rf   ri   r*   c                 C   s   | j }| j}d }}|tjkr|jr|jr||j}||j	}	|dkrR|| nd}|dkrf|	| nd}|tj
krt|| }}n|tjkrt||d }}t| j||| |j|j}
t| j||| |j|j}t|
|||dS )a  
        Position and possibly scale a box within a container, according
        to this layout rule.

        :param container_box:
            :class:`.BoxConstraints` describing the container.
        :param inner_nat_width:
            The inner box's natural width.
        :param inner_nat_height:
            The inner box's natural height.
        :return:
            A :class:`.Positioning` describing the scaling & position of the
            lower left corner of the inner box.
           r   )r]   r^   r_   r`   )r{   r|   r
   r7   r,   r.   rq   r&   rr   r'   r9   minr:   rg   ry   rC   rE   rj   rz   rL   rM   r   )r   re   rf   ri   r{   r~   r_   r`   Z	eff_widthZ
eff_heightr]   r^   r   r   r   fit  sT    




       zSimpleBoxLayoutRule.fitN)r   r   r   r   r   r0   r	   r{   r
   r:   r|   rA   r   r   r   r%   r   r   r   r   r   r   r     s   

  )!r   r?   loggingZdataclassesr   Z	fractionsr   typingr   __all__Zpyhanko.pdf_utils.config_utilsr   r   	getLoggerr   rW   
ValueErrorr   r   r   Enumr
   r   rH   rG   rI   rO   r   r%   rg   rj   r	   r   r   r   r   r   <module>   sZ        
 /b       F