U
    Pe3                     @   s   d Z dZddlmZ ddlmZmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZ d	ZG d
d deZG dd deZedkrddlmZ ddlmZ dd Zdd ZeddddZejeed ee dS )a  
Drop-Down List
==============

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

.. versionadded:: 1.4.0

A versatile drop-down list that can be used with custom widgets. It allows you
to display a list of widgets under a displayed widget. Unlike other toolkits,
the list of widgets can contain any type of widget: simple buttons,
images etc.

The positioning of the drop-down list is fully automatic: we will always try to
place the dropdown list in a way that the user can select an item in the list.

Basic example
-------------

A button with a dropdown list of 10 possible values. All the buttons within the
dropdown list will trigger the dropdown :meth:`DropDown.select` method. After
being called, the main button text will display the selection of the
dropdown. ::

    from kivy.uix.dropdown import DropDown
    from kivy.uix.button import Button
    from kivy.base import runTouchApp

    # create a dropdown with 10 buttons
    dropdown = DropDown()
    for index in range(10):
        # When adding widgets, we need to specify the height manually
        # (disabling the size_hint_y) so the dropdown can calculate
        # the area it needs.

        btn = Button(text='Value %d' % index, size_hint_y=None, height=44)

        # for each button, attach a callback that will call the select() method
        # on the dropdown. We'll pass the text of the button as the data of the
        # selection.
        btn.bind(on_release=lambda btn: dropdown.select(btn.text))

        # then add the button inside the dropdown
        dropdown.add_widget(btn)

    # create a big main button
    mainbutton = Button(text='Hello', size_hint=(None, None))

    # show the dropdown menu when the main button is released
    # note: all the bind() calls pass the instance of the caller (here, the
    # mainbutton instance) as the first argument of the callback (here,
    # dropdown.open.).
    mainbutton.bind(on_release=dropdown.open)

    # one last thing, listen for the selection in the dropdown list and
    # assign the data to the button text.
    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))

    runTouchApp(mainbutton)

Extending dropdown in Kv
------------------------

You could create a dropdown directly from your kv::

    #:kivy 1.4.0
    <CustomDropDown>:
        Button:
            text: 'My first Item'
            size_hint_y: None
            height: 44
            on_release: root.select('item1')
        Label:
            text: 'Unselectable item'
            size_hint_y: None
            height: 44
        Button:
            text: 'My second Item'
            size_hint_y: None
            height: 44
            on_release: root.select('item2')

And then, create the associated python class and use it::

    class CustomDropDown(DropDown):
        pass

    dropdown = CustomDropDown()
    mainbutton = Button(text='Hello', size_hint=(None, None))
    mainbutton.bind(on_release=dropdown.open)
    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
)DropDown    )
ScrollView)ObjectPropertyNumericPropertyBooleanProperty)Window)Builder)Clock)ConfigzP
GridLayout:
    size_hint_y: None
    height: self.minimum_size[1]
    cols: 1
c                   @   s   e Zd ZdZdS )DropDownExceptionzDropDownException class.
    N)__name__
__module____qualname____doc__ r   r   5/tmp/pip-unpacked-wheel-xzebddm3/kivy/uix/dropdown.pyr   p   s   r   c                       s   e Zd ZdZedZedddZedZedZ	edZ
eddZe ZdZdZ f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 fddZ fddZ fddZ fdd Z fd!d"Z fd#d$Z fd%d&Zd'd( Z   Z!S ))r   a  DropDown class. See module documentation for more information.

    :Events:
        `on_select`: data
            Fired when a selection is done. The data of the selection is passed
            in as the first argument and is what you pass in the :meth:`select`
            method as the first argument.
        `on_dismiss`:
            .. versionadded:: 1.8.0

            Fired when the DropDown is dismissed, either on selection or on
            touching outside the widget.
    TN)Z	allownoner   )	on_select
on_dismissc                    s   d | _ d|kr ttdd| _d|kr:tt }| _nd }d|krLd| _	d|krpd|krbd | _
d|krpd | _tt| jf | |d k	rtt| | | | | tj| j| jd	 | d
| j d S )Nmin_state_timeZgraphics	containerdo_scroll_xF	size_hintsize_hint_xsize_hint_y)on_key_downsizer   )_winfloatr
   getr   r   load_string_grid_kvr   r   r   r   superr   __init__
add_widgeton_containerr   bindr   _repositionZfbind)selfkwargsc	__class__r   r   r"      s0    
zDropDown.__init__c                 C   s    |dkr|   r|   dS d S )N   T)get_parent_windowdismiss)r'   instancekeyZscancode	codepoint	modifiersr   r   r   r      s    zDropDown.on_key_downc                 C   s   |d k	r| j j| jd d S )N)Zminimum_size)r   r%   r&   )r'   r/   valuer   r   r   r$      s    zDropDown.on_containerc                 C   s^   | j dk	r|   | | _| jdkr.td|| _ |j| j| jd |   | j|  dS )zOpen the dropdown list and attach it to a specific widget.
        Depending on the position of the widget within the window and
        the height of the dropdown, the dropdown might be above or below
        that widget.
        Nz.Cannot open a dropdown list on a hidden widgetposr   )	attach_tor.   r-   r   r   r%   r&   r#   )r'   widgetr   r   r   open   s    


zDropDown.openc                 G   s   t | j| j dS )zcRemove the dropdown widget from the window and detach it from
        the attached widget.
        N)r	   Zschedule_once_real_dismissr   r'   largsr   r   r   r.      s    zDropDown.dismissc                 G   s@   | j r| j |  | jr2| jj| j| jd d | _| d d S )Nr4   r   )parentremove_widgetr6   Zunbindr&   dispatchr:   r   r   r   r9     s    zDropDown._real_dismissc                 C   s   d S Nr   )r'   r   r   r   r     s    zDropDown.on_dismissc                 C   s   |  d| | jr|   dS )zCall this method to trigger the `on_select` event with the `data`
        selection. The `data` can be anything you want.
        r   N)r>   dismiss_on_selectr.   r'   datar   r   r   select  s    zDropDown.selectc                 C   s   d S r?   r   rA   r   r   r   r     s    zDropDown.on_selectc                    s&   | j r| j j||S tt| j||S r?   )r   r#   r!   r   r'   argsr(   r*   r   r   r#     s    zDropDown.add_widgetc                    s&   | j r| j j||S tt| j||S r?   )r   r=   r!   r   rD   r*   r   r   r=   !  s    zDropDown.remove_widgetc                    s&   | j r| j j||S tt| j||S r?   )r   clear_widgetsr!   r   rD   r*   r   r   rF   &  s    zDropDown.clear_widgetsc                    s   t  || dS NT)r!   	on_motion)r'   etypemer*   r   r   rH   +  s    zDropDown.on_motionc                    s.   | j |j | _| jr| jr*tt| | dS rG   )Zcollide_pointr5   _touch_started_insideauto_dismissr!   r   on_touch_downr'   touchr*   r   r   rM   /  s    zDropDown.on_touch_downc                    s    | j r| jrtt| | dS rG   )rL   rK   r!   r   on_touch_moverN   r*   r   r   rP   5  s    zDropDown.on_touch_movec                    s4   | j r| jdkr|   ntt| | d | _dS )NFT)rL   rK   r.   r!   r   on_touch_uprN   r*   r   r   rQ   :  s
    
zDropDown.on_touch_upc                 G   s  | j }|sd S | j}|r | s$d S |j|j \}}||j|j\}}| jrX|| | _|}|| j |jkrx|j| j }|dk rd}|| _	| j
d k	rt| j
| jj}	n| jj}	||	 }
|j||	  }|
dkr|| _|	| _n@|dkr|| _|	| _n*||
k r| | _| _n|| _|j| | _d S )Nr   )r   r6   r-   Z	to_windowr5   righttop
auto_widthwidthx
max_heightminr   Zminimum_heightheighty)r'   r;   winr7   ZwxZwyZwrightZwtoprV   rY   Zh_bottomZh_topr   r   r   r&   C  s>    


zDropDown._reposition)"r   r   r   r   r   rT   r   rW   r@   rL   r   r   r6   r   rK   Z
__events__r"   r   r$   r8   r.   r9   r   rC   r   r#   r=   rF   rH   rM   rP   rQ   r&   __classcell__r   r   r*   r   r   v   s6   	
	r   __main__)Button)runTouchAppc                    sf   t  j fddd tdD ]4}td| d dd}|jfddd	 | q"  d S )
Nc                    s   t  d|S )Ntext)setattr)r/   rV   )buttonr   r   <lambda>z      zshow_dropdown.<locals>.<lambda>)r   
   zhello %d,   )r`   r   rY   c                    s     | jS r?   )rC   r`   )btn)dpr   r   rc   }  rd   )
on_release)r   r%   ranger^   r#   r8   )rb   r;   iitemr   )rb   rh   r   show_dropdownx  s    rm   c                 C   s   |j | _d S r?   )r5   center)r/   rO   r   r   r   
touch_move  s    ro   ZSHOW)NN)i,     )r`   r   r5   )ri   rP   N)r   __all__Zkivy.uix.scrollviewr   Zkivy.propertiesr   r   r   Zkivy.core.windowr   Z	kivy.langr   Z
kivy.clockr	   Zkivy.configr
   r    	Exceptionr   r   r   Zkivy.uix.buttonr^   Z	kivy.baser_   rm   ro   rg   r%   r   r   r   r   <module>   s(   ^   	