U
    g`D                     @   s^  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m	Z	 ddl
mZ ddlmZ dd	d
dddddg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Union)ConfigurableMixin)ConfigurationErrorLayoutErrorBoxSpecificationErrorBoxConstraintsAxisAlignmentMarginsInnerScalingSimpleBoxLayoutRulePositioningc                       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-owvgwkas/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	ee
df e	ee
df e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)widthheightaspect_ratioc                 C   s   |d k	rt |nd }|d k	r$t |nd }|| _|| _d}d | _|d krZ|d krZ|d krZd S |d k	r|d k	r|d k	rvtt||| _d}nD|d k	r|| _|d k	rt t|| | _n|d k	rt t|| | _|| _d S )NFT)intr!   r"   r#   r	   r   roundr$   )r   r%   r&   r'   Z	int_widthZ
int_heightZfully_specifiedr   r   r   r   7   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   _recalculateU   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%   a   s    
zBoxConstraints.widthc                 C   s"   | j d kr|| _ |   ntd S r   )r!   r+   r	   r   r%   r   r   r   r%   n   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_definedv   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&      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   floatr   r+   propertyr%   setterr.   r&   r0   r'   r1   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   )clsr7   r   r   r   from_config   s    
zInnerScaling.from_configN)r   r   r   r   enumautor:   r;   r<   r=   classmethodr   rA   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rightr9   zO' is not a valid horizontal alignment; valid values are 'left', 'mid', 'right'.Nr   	ALIGN_MIN	ALIGN_MID	ALIGN_MAXr>   r?   r   r@   rE   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.
        )bottomrG   topr9   zM' is not a valid vertical alignment; valid values are 'bottom', 'mid', 'top'.NrI   rM   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 t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   rL   rJ   loggerwarningrK   	TypeError)r   rT   rU   
pre_marginpost_marginZeffective_max_lenZinner_offsetr   r   r   align'  s&       


zAxisAlignment.alignN)r   r   r   r   rB   rC   rJ   rK   rL   rD   r   rN   rQ   r5   rS   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)rc   rd   ra   rb   r*   r   r   r   as_cm^  s    	zPositioning.as_cmN)r   r   r   r   r(   r2   r4   re   r   r   r   r   r   L  s   
	alignmentcontainer_boxinner_nat_widthr]   r^   c                 C   s.   |j r| |j|||S || | |_|S d S r   )r.   r_   r%   rf   r   r   r   
_aln_widtho  s       rj   rg   rh   inner_nat_heightr]   r^   c                 C   s.   |j r| |j|||S || | |_|S d S r   )r0   r_   r&   rk   r   r   r   _aln_height  s       rm   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   rF   rH   rP   rO   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 (rW   z) too wide for container  .)r   )Zdim_namerT   prepostZeffr   r   r   rY     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   rY   rF   rH   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   rY   rO   rP   r/   r   r   r   effective_height  s    zMargins.effective_heightc                    s$   t |trttd|}t |S )N)rF   rH   rP   rO   )
isinstancelistdictzipr   rA   )r@   config_dictr   r   r   rA     s
    
zMargins.from_config)r   r   r   r   rF   r(   r2   rH   rP   rO   rD   ro   staticmethodrY   rt   ru   rA   r    r   r   r   r   r     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 )Nr|   r}   r   )	getr   rK   rv   r   rN   rQ   r   rA   )r@   rz   r|   r}   scalingr   r   r   process_entries  s    



z#SimpleBoxLayoutRule.process_entries)new_marginsr,   c                 C   s   t | j| j|| jdS )N)r|   r}   r~   r   )r   r|   r}   r   )r   r   r   r   r   substitute_margins  s    z&SimpleBoxLayoutRule.substitute_margins)rh   ri   rl   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   )ra   rb   rc   rd   )r~   r   r   r:   r.   r0   rt   r%   ru   r&   r<   minr=   rj   r|   rF   rH   rm   r}   rO   rP   r   )r   rh   ri   rl   r~   r   rc   rd   Z	eff_widthZ
eff_heightra   rb   r   r   r   fit  sN    

   zSimpleBoxLayoutRule.fitN)r   r   r   r   r   r2   r   r~   r   r=   r   rD   r   r   r
   r(   r   r   r   r   r   r   r     s   


)#r   rB   loggingZdataclassesr   Z	fractionsr   typingr   r   Zpyhanko.config.apir   Zpyhanko.config.errorsr   __all__	getLoggerr   rZ   
ValueErrorr   r	   r
   Enumr   r   rK   rJ   rL   rR   r   r(   rj   rm   r   r   r   r   r   r   <module>   s`   
 /c   #F