U
    PeT                     @   sx   d Z dZddlmZ ddlmZmZmZmZm	Z	 ddl
mZ ddlmZ ddlmZ G dd	 d	eZG d
d deZdS )al  
Scatter
=======

.. image:: images/scatter.gif
    :align: right

:class:`Scatter` is used to build interactive widgets that can be translated,
rotated and scaled with two or more fingers on a multitouch system.

Scatter has its own matrix transformation: the modelview matrix is changed
before the children are drawn and the previous matrix is restored when the
drawing is finished. That makes it possible to perform rotation, scaling and
translation over the entire children tree without changing any widget
properties. That specific behavior makes the scatter unique, but there are some
advantages / constraints that you should consider:

#. The children are positioned relative to the scatter similarly to a
   :mod:`~kivy.uix.relativelayout.RelativeLayout`. So when dragging the
   scatter, the position of the children don't change, only the position of
   the scatter does.
#. The scatter size has no impact on the size of its children.
#. If you want to resize the scatter, use scale, not size (read #2). Scale
   transforms both the scatter and its children, but does not change size.
#. The scatter is not a layout. You must manage the size of the children
   yourself.

For touch events, the scatter converts from the parent matrix to the scatter
matrix automatically in on_touch_down/move/up events. If you are doing things
manually, you will need to use :meth:`~kivy.uix.widget.Widget.to_parent` and
:meth:`~kivy.uix.widget.Widget.to_local`.

Usage
-----

By default, the Scatter does not have a graphical representation: it is a
container only. The idea is to combine the Scatter with another widget, for
example an :class:`~kivy.uix.image.Image`::

    scatter = Scatter()
    image = Image(source='sun.jpg')
    scatter.add_widget(image)

Control Interactions
--------------------

By default, all interactions are enabled. You can selectively disable
them using the do_rotation, do_translation and do_scale properties.

Disable rotation::

    scatter = Scatter(do_rotation=False)

Allow only translation::

    scatter = Scatter(do_rotation=False, do_scale=False)

Allow only translation on x axis::

    scatter = Scatter(do_rotation=False, do_scale=False,
                      do_translation_y=False)


Automatic Bring to Front
------------------------

If the :attr:`Scatter.auto_bring_to_front` property is True, the scatter
widget will be removed and re-added to the parent when it is touched
(brought to front, above all other widgets in the parent). This is useful
when you are manipulating several scatter widgets and don't want the active
one to be partially hidden.

Scale Limitation
----------------

We are using a 32-bit matrix in double representation. That means we have
a limit for scaling. You cannot do infinite scaling down/up with our
implementation. Generally, you don't hit the minimum scale (because you don't
see it on the screen), but the maximum scale is 9.99506983235e+19 (2^66).

You can also limit the minimum and maximum scale allowed::

    scatter = Scatter(scale_min=.5, scale_max=3.)

Behavior
--------

.. versionchanged:: 1.1.0
    If no control interactions are enabled, then the touch handler will never
    return True.

)ScatterScatterPlane    )radians)BooleanPropertyAliasPropertyNumericPropertyObjectPropertyBoundedNumericProperty)Vector)Widget)Matrixc                       sl  e Zd ZdZdZedZedZedZdd Z	dd Z
ee	e
ddd	Zed
d
dZedZedZedZedZedZee Zee Zdd ZeeddZdd Zdd ZeeeddZdd Zdd ZeeeddZ dd Z!dd Z"ee!e"d dZ#d!d" Z$d#d$ Z%ee$e%d dZ&d%d& Z'd'd( Z(ee'e(d dZ)d)d* Z*d+d, Z+ee*e+d dZ,d-d. Z-d/d0 Z.ee-e.d1dZ/d2d3 Z0d4d5 Z1ee0e1d6dZ2d7d8 Z3d9d: Z4ee3e4d1dZ5d;d< Z6d=d> Z7ee6e7d6dZ8 fd?d@Z9dAdB Z:dCdD Z;dEdF Z<dGdH Z=d_ fdJdK	Z>d`dMdNZ?dOdP Z@dQdR ZA fdSdTZB fdUdVZC fdWdXZDdYdZ ZEd[d\ ZF fd]d^ZG  ZHS )ar   a  Scatter class. See module documentation for more information.

    :Events:
        `on_transform_with_touch`:
            Fired when the scatter has been transformed by user touch
            or multitouch, such as panning or zooming.
        `on_bring_to_front`:
            Fired when the scatter is brought to the front.

    .. versionchanged:: 1.9.0
        Event `on_bring_to_front` added.

    .. versionchanged:: 1.8.0
        Event `on_transform_with_touch` added.
    )on_transform_with_touchon_bring_to_frontTc                 C   s   | j | jfS Ndo_translation_xdo_translation_yself r   4/tmp/pip-unpacked-wheel-xzebddm3/kivy/uix/scatter.py_get_do_translation   s    zScatter._get_do_translationc                 C   s2   t |ttfkr|\| _| _nt| | _| _d S r   )typelisttupler   r   boolr   valuer   r   r   _set_do_translation   s    zScatter._set_do_translationr   )bindcache   )minFg{Gz?g@xDc                 C   s   |  dd \}}\}}| jdfd| jf| jfD ]B}| j | \}}||k rN|}||k rZ|}||krf|}||kr0|}q0||f|| || ffS Nr   )	to_parentwidthheightsize)r   ZxminZyminZxmaxZymaxZpointxyr   r   r   	_get_bbox   s    zScatter._get_bbox)	transformr%   r&   )r   c                 C   sF   t dd}| j}t || j  || j| jd  }d||d  d S )Nr   
   g         ih  )r
   r$   posr(   r)   angle)r   Zv1tpZv2r   r   r   _get_rotation  s    
 zScatter._get_rotationc                 C   s>   | j | }t t| ddd}| j|d| j| j d d S )Nr   r!   Tpost_multiplyanchor)rotationr   rotater   apply_transformto_localcenter)r   r5   Zangle_changerr   r   r   _set_rotation	  s
    

zScatter._set_rotation)r(   r)   r+   c                 C   sV   t | dd }t | dd }||}t| drLt|t| jkrL| jS || _|S )Nr   r!   _scale_p)r
   r$   distancehasattrstrr<   )r   p1p2scaler   r   r   
_get_scale  s    

zScatter._get_scalec                 C   s6   |d | j  }| jt  |||d| j| j d d S )Ng      ?Tr2   )rB   r7   r   r8   r9   )r   rB   Zrescaler   r   r   
_set_scale)  s
    
zScatter._set_scalec                 C   s@   | j d d | j d d d  | j d d | j d d d  fS )Nr   r!          @bboxr   r   r   r   _get_center6  s    zScatter._get_centerc                 C   s>   || j krdS t| | j  }t |j|jd}| | d S )NFr   )r9   r
   r   	translater(   r)   r7   )r   r9   ttransr   r   r   _set_center:  s
    
zScatter._set_centerrF   c                 C   s
   | j d S r#   rF   r   r   r   r   _get_posC  s    zScatter._get_posc                 C   sD   | j d }||krd S t| | }t |j|jd}| | d S r#   )rG   r
   r   rI   r(   r)   r7   )r   r.   _posrJ   rK   r   r   r   _set_posF  s    
zScatter._set_posc                 C   s   | j d d S r#   rF   r   r   r   r   _get_xP  s    zScatter._get_xc                 C   s&   || j d d krdS || jf| _dS )Nr   FT)rG   r)   r.   )r   r(   r   r   r   _set_xS  s    zScatter._set_xc                 C   s   | j d d S Nr   r!   rF   r   r   r   r   _get_y[  s    zScatter._get_yc                 C   s&   || j d d krdS | j|f| _dS )Nr   r!   FT)rG   r(   r.   )r   r)   r   r   r   _set_y^  s    zScatter._set_yc                 C   s   | j | jd d  S Nr!   r   r(   rG   r   r   r   r   	get_rightf  s    zScatter.get_rightc                 C   s   || j d d  | _d S rU   rG   r(   r   r   r   r   	set_righti  s    zScatter.set_rightrV   c                 C   s   | j | jd d  S Nr!   r)   rG   r   r   r   r   get_topn  s    zScatter.get_topc                 C   s   || j d d  | _d S rZ   rG   r)   r   r   r   r   set_topq  s    zScatter.set_topr[   c                 C   s   | j | jd d d  S Nr!   r   rE   rV   r   r   r   r   get_center_xv  s    zScatter.get_center_xc                 C   s   || j d d d  | _d S r_   rX   r   r   r   r   set_center_xy  s    zScatter.set_center_xc                 C   s   | j | jd d d  S Nr!   rE   r[   r   r   r   r   get_center_y~  s    zScatter.get_center_yc                 C   s   || j d d d  | _d S rb   r]   r   r   r   r   set_center_y  s    zScatter.set_center_yc                    s"   g | _ i | _tt| jf | d S r   )_touches_last_touch_possuperr   __init__r   kwargs	__class__r   r   rh     s    zScatter.__init__c                 C   s   |  | _d S r   )Zinversetransform_inv)r   instancer   r   r   r   on_transform  s    zScatter.on_transformc                 C   sD   |  ||\}}d|  ko$| jkn  oBd|  ko>| jkS   S r#   )r8   r%   r&   r   r(   r)   r   r   r   collide_point  s    zScatter.collide_pointc                 K   s    | j ||d}|d |d fS rR   )r+   transform_pointr   r(   r)   kpr   r   r   r$     s    zScatter.to_parentc                 K   s    | j ||d}|d |d fS rR   )rm   rr   rs   r   r   r   r8     s    zScatter.to_localNc                    s   | j |}tt| |dS )Nr   r   )r+   multiplyrg   r   _apply_transform)r   mr.   rk   r   r   rx     s    zScatter._apply_transformrv   c                 C   sj   t  |d |d d}||}|t  |d  |d  d}|rX| j|| _n|| j| _dS )a  
        Transforms the scatter by applying the "trans" transformation
        matrix (on top of its current transformation state). The resultant
        matrix can be found in the :attr:`~Scatter.transform` property.

        :Parameters:
            `trans`: :class:`~kivy.graphics.transformation.Matrix`.
                Transformation matrix to be applied to the scatter widget.
            `anchor`: tuple, defaults to (0, 0).
                The point to use as the origin of the transformation
                (uses local widget space).
            `post_multiply`: bool, defaults to False.
                If True, the transform matrix is post multiplied
                (as if applied before the current transform).

        Usage example::

            from kivy.graphics.transformation import Matrix
            mat = Matrix().scale(3, 3, 3)
            scatter_instance.apply_transform(mat)

        r   r!   N)r   rI   rw   r+   )r   rK   r3   r4   rJ   r   r   r   r7     s    
"zScatter.apply_transformc                    s  d}t  j jkrvj j d   j }j j d   j }| j }| j } t	 
||d d}t  jdkr|S  fdd jD }|tj t|d d fdd	d
}t||jd
}||d k	r|S tj | }tj | }	| s|S t|	| j }
|
r0d} jt	 |
ddd|d  jr|	 |  }| j }| jk r j j }n| jkr j j } jt	 ||||d d}|S )NFr   r!   Tc                    s"   g | ]}|k	rt  j| qS r   )r
   rf   ).0rJ   r   touchr   r   
<listcomp>  s    z0Scatter.transform_with_touch.<locals>.<listcomp>c                    s   |   jS r   )r=   r.   )ru   )r|   r   r   <lambda>      z.Scatter.transform_with_touch.<locals>.<lambda>)key)r4   )lenre   translation_touchesr(   rf   r   r)   r   r7   r   rI   appendr
   r.   maxr=   Zpposlengthr   r/   do_rotationr6   do_scalerB   	scale_min	scale_max)r   r|   changedZdxZdyZpointsr4   ZfarthestZold_linenew_liner/   rB   Z	new_scaler   r{   r   transform_with_touch  sP    



zScatter.transform_with_touchc                 C   sH   | j rD| jrD| j}|jd | kr$d S ||  ||  | d| d S )Nr   r   )auto_bring_to_frontparentchildrenZremove_widgetZ
add_widgetdispatch)r   r|   r   r   r   r   _bring_to_front  s    

zScatter._bring_to_frontc                    sR   |j | jkrDd|jkrD|  || j t ||}|  |S t ||S )Nr.   )	Ztype_idZmotion_filterprofilepushapply_transform_2dr8   rg   	on_motionpop)r   etypemeretrk   r   r   r     s    zScatter.on_motionc                    s   |j |j }}| js$| ||s$dS |  || j tt| 	|r^|
  | | dS |
  | js| js| js| jsdS | jr| ||sdS d|jkrd|_| | ||  | j| |j| j|< dS )NFTmultitouch_sim)r(   r)   do_collide_after_childrenrq   r   r   r8   rg   r   on_touch_downr   r   r   r   r   r   r   r   Zgrabre   r   r.   rf   r   r|   r(   r)   rk   r   r   r     s:    



zScatter.on_touch_downc                    s   |j |j }}| ||r\|j| ks\|  || j tt| 	|rT|
  dS |
  || jkr|j| kr| |r| d| |j| j|< | ||rdS d S )NTr   )r(   r)   rq   grab_currentr   r   r8   rg   r   on_touch_mover   re   r   r   r.   rf   r   rk   r   r   r   3  s    
zScatter.on_touch_movec                 C   s   dS )a{  
        Called when a touch event has transformed the scatter widget.
        By default this does nothing, but can be overridden by derived
        classes that need to react to transformations caused by user
        input.

        :Parameters:
            `touch`:
                The touch object which triggered the transformation.

        .. versionadded:: 1.8.0
        Nr   r{   r   r   r   r   H  s    zScatter.on_transform_with_touchc                 C   s   dS )a.  
        Called when a touch event causes the scatter to be brought to the
        front of the parent (only if :attr:`auto_bring_to_front` is True)

        :Parameters:
            `touch`:
                The touch object which brought the scatter to front.

        .. versionadded:: 1.9.0
        Nr   r{   r   r   r   r   W  s    zScatter.on_bring_to_frontc                    s   |j |j }}|j| ksP|  || j tt| |rH|	  dS |	  || j
kr~|jr~||  | j|= | j
| | ||rdS d S NT)r(   r)   r   r   r   r8   rg   r   on_touch_upr   re   Z
grab_stateZungrabrf   removerq   r   rk   r   r   r   d  s    

zScatter.on_touch_up)N)Frv   )I__name__
__module____qualname____doc__Z
__events__r   r   r   r   r   r   r   Zdo_translationr	   r   r   r   r   r   r   r   r   r   r+   rm   r*   rG   r1   r;   r5   rC   rD   rB   rH   rL   r9   rM   rO   r.   rP   rQ   r(   rS   rT   r)   rW   rY   rightr\   r^   topr`   ra   Zcenter_xrc   rd   Zcenter_yrh   ro   rq   r$   r8   rx   r7   r   r   r   r   r   r   r   r   __classcell__r   r   rk   r   r   h   s   



		
 ;
	'r   c                       s(   e Zd ZdZ fddZdd Z  ZS )r   zThis is essentially an unbounded Scatter widget. It's a convenience
       class to make it easier to handle infinite planes.
    c                    s$   d|krd| _ tt| jf | d S )Nr   F)r   rg   r   rh   ri   rk   r   r   rh     s    zScatterPlane.__init__c                 C   s   dS r   r   rp   r   r   r   rq     s    zScatterPlane.collide_point)r   r   r   r   rh   rq   r   r   r   rk   r   r   z  s   r   N)r   __all__mathr   Zkivy.propertiesr   r   r   r   r	   Zkivy.vectorr
   Zkivy.uix.widgetr   Zkivy.graphics.transformationr   r   r   r   r   r   r   <module>   s   ]    