U
    Pe                     @   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mZmZ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 ddlmZ dd	lmZ dd
lmZ ddl m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z' i Z(dd Z)G dd de*Z+G dd de,Z-e-defi Z.G dd de.Z/dS )ae!  
Widget class
============

The :class:`Widget` class is the base class required for creating Widgets.
This widget class was designed with a couple of principles in mind:

* *Event Driven*

  Widget interaction is built on top of events that occur. If a property
  changes, the widget can respond to the change in the 'on_<propname>'
  callback. If nothing changes, nothing will be done. That's the main
  goal of the :class:`~kivy.properties.Property` class.

* *Separation Of Concerns (the widget and its graphical representation)*

  Widgets don't have a `draw()` method. This is done on purpose: The idea
  is to allow you to create your own graphical representation outside the
  widget class.
  Obviously you can still use all the available properties to do that, so
  that your representation properly reflects the widget's current state.
  Every widget has its own :class:`~kivy.graphics.Canvas` that you
  can use to draw. This separation allows Kivy to run your
  application in a very efficient manner.

* *Bounding Box / Collision*

  Often you want to know if a certain point is within the bounds of your
  widget. An example would be a button widget where you only want to
  trigger an action when the button itself is actually touched.
  For this, you can use the :meth:`~Widget.collide_point` method, which
  will return True if the point you pass to it is inside the axis-aligned
  bounding box defined by the widget's position and size.
  If a simple AABB is not sufficient, you can override the method to
  perform the collision checks with more complex shapes, e.g. a polygon.
  You can also check if a widget collides with another widget with
  :meth:`~Widget.collide_widget`.


We also have some default values and behaviors that you should be aware of:

* A :class:`Widget` is not a :class:`~kivy.uix.layout.Layout`: it will not
  change the position or the size of its children. If you want control over
  positioning or sizing, use a :class:`~kivy.uix.layout.Layout`.

* The default size of a widget is (100, 100). This is only changed if the
  parent is a :class:`~kivy.uix.layout.Layout`.
  For example, if you add a :class:`Label` inside a
  :class:`Button`, the label will not inherit the button's size or position
  because the button is not a *Layout*: it's just another *Widget*.

* The default size_hint is (1, 1). If the parent is a :class:`Layout`, then the
  widget size will be the parent layout's size.

* :meth:`~Widget.on_touch_down`, :meth:`~Widget.on_touch_move`,
  :meth:`~Widget.on_touch_up` don't do any sort of collisions. If you want to
  know if the touch is inside your widget, use :meth:`~Widget.collide_point`.

Using Properties
----------------

When you read the documentation, all properties are described in the format::

    <name> is a <property class> and defaults to <default value>.

e.g.

    :attr:`~kivy.uix.label.Label.text` is a
    :class:`~kivy.properties.StringProperty` and defaults to ''.

If you want to be notified when the pos attribute changes, i.e. when the
widget moves, you can bind your own callback function like this::

    def callback_pos(instance, value):
        print('The widget', instance, 'moved to', value)

    wid = Widget()
    wid.bind(pos=callback_pos)

Read more about :doc:`/api-kivy.properties`.

Basic drawing
-------------

Widgets support a range of drawing instructions that you can use to customize
the look of your widgets and layouts. For example, to draw a background image
for your widget, you can do the following:

.. code-block:: python

    def redraw(self, args):
        self.bg_rect.size = self.size
        self.bg_rect.pos = self.pos

    widget = Widget()
    with widget.canvas:
        widget.bg_rect = Rectangle(source="cover.jpg", pos=self.pos, size=self.size)
    widget.bind(pos=redraw, size=redraw)

To draw a background in kv:

.. code-block:: kv

    Widget:
        canvas:
            Rectangle:
                source: "cover.jpg"
                size: self.size
                pos: self.pos

These examples only scratch the surface. Please see the :mod:`kivy.graphics`
documentation for more information.

.. _widget-event-bubbling:

Widget touch event bubbling
---------------------------

When you catch touch events between multiple widgets, you often
need to be aware of the order in which these events are propagated. In Kivy,
events bubble up from the first child upwards through the other children.
If a widget has children, the event is passed through its children before
being passed on to the widget after it.

As the :meth:`~kivy.uix.widget.Widget.add_widget` method inserts widgets at
index 0 by default, this means the event goes from the most recently added
widget back to the first one added. Consider the following:

.. code-block:: python

    box = BoxLayout()
    box.add_widget(Label(text="a"))
    box.add_widget(Label(text="b"))
    box.add_widget(Label(text="c"))

The label with text "c" gets the event first, "b" second and "a" last. You can
reverse this order by manually specifying the index:

.. code-block:: python

    box = BoxLayout()
    box.add_widget(Label(text="a"), index=0)
    box.add_widget(Label(text="b"), index=1)
    box.add_widget(Label(text="c"), index=2)

Now the order would be "a", "b" then "c". One thing to keep in mind when using
kv is that declaring a widget uses the
:meth:`~kivy.uix.widget.Widget.add_widget` method for insertion. Hence, using

.. code-block:: kv

    BoxLayout:
        MyLabel:
            text: "a"
        MyLabel:
            text: "b"
        MyLabel:
            text: "c"

would result in the event order "c", "b" then "a" as "c" was actually the last
added widget. It thus has index 0, "b" index 1 and "a" index 2. Effectively,
the child order is the reverse of its listed order.

This ordering is the same for the :meth:`~kivy.uix.widget.Widget.on_touch_move`
and :meth:`~kivy.uix.widget.Widget.on_touch_up` events.

In order to stop this event bubbling, a method can return `True`. This tells
Kivy the event has been handled and the event propagation stops. For example:

.. code-block:: python

    class MyWidget(Widget):
        def on_touch_down(self, touch):
            If <some_condition>:
                # Do stuff here and kill the event
                return True
            else:
                return super(MyWidget, self).on_touch_down(touch)

This approach gives you good control over exactly how events are dispatched
and managed. Sometimes, however, you may wish to let the event be completely
propagated before taking action. You can use the
:class:`~kivy.clock.Clock` to help you here:

.. code-block:: python

    class MyWidget(Label):
        def on_touch_down(self, touch, after=False):
            if after:
                print "Fired after the event has been dispatched!"
            else:
                Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))
                return super(MyWidget, self).on_touch_down(touch)

Usage of :attr:`Widget.center`, :attr:`Widget.right`, and :attr:`Widget.top`
----------------------------------------------------------------------------

A common mistake when using one of the computed properties such as
:attr:`Widget.right` is to use it to make a widget follow its parent with a
KV rule such as `right: self.parent.right`. Consider, for example:

.. code-block:: kv

    FloatLayout:
        id: layout
        width: 100
        Widget:
            id: wid
            right: layout.right

The (mistaken) expectation is that this rule ensures that wid's right will
always be whatever layout's right is - that is wid.right and layout.right will
always be identical. In actual fact, this rule only says that "whenever
layout's `right` changes, wid's right will be set to that value". The
difference being that as long as `layout.right` doesn't change, `wid.right`
could be anything, even a value that will make them different.

Specifically, for the KV code above, consider the following example::

    >>> print(layout.right, wid.right)
    (100, 100)
    >>> wid.x = 200
    >>> print(layout.right, wid.right)
    (100, 300)

As can be seen, initially they are in sync, however, when we change `wid.x`
they go out of sync because `layout.right` is not changed and the rule is not
triggered.

The proper way to make the widget follow its parent's right is to use
:attr:`Widget.pos_hint`. If instead of `right: layout.right` we did
`pos_hint: {'right': 1}`, then the widgets right will always be set to be
at the parent's right at each layout update.
)WidgetWidgetException    )EventDispatcher)MODE_DONT_DISPATCHMODE_FILTERED_DISPATCHMODE_DEFAULT_DISPATCH)Factory)NumericPropertyStringPropertyAliasPropertyReferenceListPropertyObjectPropertyListPropertyDictPropertyBooleanProperty)Canvas	TranslateFbo
ClearColorClearBuffersScale)Matrix)	EventLoop)Builder)get_current_context)	WeakProxy)partial)islicec                 C   s   t | = t|  d S N)_widget_destructorsr   Zunbind_widget)uidr r"   3/tmp/pip-unpacked-wheel-xzebddm3/kivy/uix/widget.py_widget_destructor	  s    r$   c                   @   s   e Zd ZdZdS )r   z-Fired when the widget gets an exception.
    N)__name__
__module____qualname____doc__r"   r"   r"   r#   r     s   r   c                       s    e Zd ZdZ fddZ  ZS )WidgetMetaclasszMetaclass to automatically register new widgets for the
    :class:`~kivy.factory.Factory`.

    .. warning::
        This metaclass is used by the Widget. Do not use it directly!
    c                    s&   t t| ||| tj|| d d S )N)cls)superr)   __init__r   register)Zmcsnamebasesattrs	__class__r"   r#   r,     s    zWidgetMetaclass.__init__)r%   r&   r'   r(   r,   __classcell__r"   r"   r1   r#   r)     s   r)   
WidgetBasec                       s  e Zd ZdZeZdZdZ fddZe	dd Z
dd	 Zde d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djddZdd Zdkdd Zd!d" Zd#d$ Zdld%d&Zdmd'd(Zd)d* Zd+d, Zd-d. Zd/d0 Zdnd2d3Z dod4d5Z!dpd6d7Z"dqd8d9Z#drd:d;Z$dsd=d>Z%dtd?d@Z&dudAdBZ'dvdCdDZ(dwdEdFZ)e*dZ+e*dZ,e*dGZ-e*dGZ.e/e+e,Z0e/e-e.Z1dHdI Z2dJdK Z3e4e2e3dLd<d1dMZ5dNdO Z6dPdQ Z7e4e6e7dRd<d1dMZ8dSdT Z9dUdV Z:e4e9e:dLd<d1dMZ;dWdX Z<dYdZ Z=e4e<e=dRd<d1dMZ>e/e;e>Z?e@g ZAe@g ZBeCdd<d<d[ZDe*d\d<d]ZEe*d\d<d]ZFe/eEeFZGeCi ZHe*dd<d]ZIe*dd<d]ZJe/eIeJZKe*dd<d]ZLe*dd<d]ZMe/eLeMZNeOi ZPe*d^ZQd_d` ZRdZSdadb ZTdcdd ZUdxdedfZVdydgdhZWe4eTeUd1diZXeO ZY  ZZS )zr   a  Widget class. See module documentation for more information.

    :Events:
        `on_touch_down`: `(touch, )`
            Fired when a new touch event occurs. `touch` is the touch object.
        `on_touch_move`: `(touch, )`
            Fired when an existing touch moves. `touch` is the touch object.
        `on_touch_up`: `(touch, )`
            Fired when an existing touch disappears. `touch` is the touch
            object.
        `on_kv_post`: `(base_widget, )`
            Fired after all the kv rules associated with the widget
            and all other widgets that are in any of those rules have had
            all their kv rules applied. `base_widget` is the base-most widget
            whose instantiation triggered the kv rules (i.e. the widget
            instantiated from Python, e.g. ``MyWidget()``).

            .. versionchanged:: 1.11.0

    .. warning::
        Adding a `__del__` method to a class derived from Widget with Python
        prior to 3.4 will disable automatic garbage collection for instances
        of that class. This is because the Widget class creates reference
        cycles, thereby `preventing garbage collection
        <https://docs.python.org/2/library/gc.html#gc.garbage>`_.

    .. versionchanged:: 1.0.9
        Everything related to event properties has been moved to the
        :class:`~kivy.event.EventDispatcher`. Event properties can now be used
        when constructing a simple class without subclassing :class:`Widget`.

    .. versionchanged:: 1.5.0
        The constructor now accepts on_* arguments to automatically bind
        callbacks to properties or events, as in the Kv language.
    )	on_motionon_touch_downon_touch_moveon_touch_up
on_kv_postNc                    s   t   t| dst | _d|k}d| _|r2|d= dd | D }|D ]
}||= qHd| _tt	| j
f | | jd krt| jd| _|sg }| j| j|d |D ]}|d	|  q| d	|  |r| jf | d S )
N_contextZ__no_builderFc                 S   s&   i | ]\}}|d d dkr||qS )N   Zon_r"   ).0kvr"   r"   r#   
<dictcomp>_  s       z#Widget.__init__.<locals>.<dictcomp>r   )opacityignored_constsrule_childrenr9   )r   Zensure_windowhasattrr   r:   _disabled_valueitems_disabled_countr+   r   r,   canvasr   r@   apply_class_lang_rulesZ_kwargs_applied_initdispatchbind)selfkwargsZ
no_builderZon_argskeyrC   widgetr1   r"   r#   r,   S  s2    

zWidget.__init__c                 C   s@   | j }|dk	r|S tt| j}t| | | _ }||ft| j< |S )a  Return a proxy reference to the widget, i.e. without creating a
        reference to the widget. See `weakref.proxy
        <http://docs.python.org/2/library/weakref.html?highlight        =proxy#weakref.proxy>`_ for more information.

        .. versionadded:: 1.7.2
        N)
_proxy_refr   r$   r    r   r   )rL   rP   fr"   r"   r#   	proxy_refz  s    	zWidget.proxy_refc                 C   s   t | S r   )idrL   r"   r"   r#   __hash__  s    zWidget.__hash__c                 C   s   t j| ||d dS )a#	  
        Method that is called by kivy to apply the kv rules of this widget's
        class.

        :Parameters:
            `root`: :class:`Widget`
                The root widget that instantiated this widget in kv, if the
                widget was instantiated in kv, otherwise ``None``.
            `ignored_consts`: set
                (internal) See :meth:`~kivy.lang.builder.BuilderBase.apply`.
            `rule_children`: list
                (internal) See :meth:`~kivy.lang.builder.BuilderBase.apply`.

        This is useful to be able to execute code before/after the class kv
        rules are applied to the widget. E.g. if the kv code requires some
        properties to be initialized before it is used in a binding rule.
        If overwriting remember to call ``super``, otherwise the kv rules will
        not be applied.

        In the following example,

        .. code-block:: python

            class MyWidget(Widget):
                pass

            class OtherWidget(MyWidget):
                pass

        .. code-block:: kv

        <MyWidget>:
            my_prop: some_value

        <OtherWidget>:
            other_prop: some_value

        When ``OtherWidget`` is instantiated with ``OtherWidget()``, the
        widget's :meth:`apply_class_lang_rules` is called and it applies the
        kv rules of this class - ``<MyWidget>`` and ``<OtherWidget>``.

        Similarly, when the widget is instantiated from kv, e.g.

        .. code-block:: kv

            <MyBox@BoxLayout>:
                height: 55
                OtherWidget:
                    width: 124

        ``OtherWidget``'s :meth:`apply_class_lang_rules` is called and it
        applies the kv rules of this class - ``<MyWidget>`` and
        ``<OtherWidget>``.

        .. note::

            It applies only the class rules not the instance rules. I.e. in the
            above kv example in the ``MyBox`` rule when ``OtherWidget`` is
            instantiated, its :meth:`apply_class_lang_rules` applies the
            ``<MyWidget>`` and ``<OtherWidget>`` rules to it - it does not
            apply the ``width: 124`` rule. The ``width: 124`` rule is part of
            the ``MyBox`` rule and is applied by the ``MyBox``'s instance's
            :meth:`apply_class_lang_rules`.

        .. versionchanged:: 1.11.0
        rA   N)r   apply)rL   rootrB   rC   r"   r"   r#   rI     s
    D zWidget.apply_class_lang_rulesc                 C   s8   | j |  ko| jkn  o6| j|  ko2| jkS   S )a  
        Check if a point (x, y) is inside the widget's axis aligned bounding
        box.

        :Parameters:
            `x`: numeric
                x position of the point (in parent coordinates)
            `y`: numeric
                y position of the point (in parent coordinates)

        :Returns:
            A bool. True if the point is inside the bounding box, False
            otherwise.

        .. code-block:: python

            >>> Widget(pos=(10, 10), size=(50, 50)).collide_point(40, 40)
            True
        )xrightytop)rL   rX   rZ   r"   r"   r#   collide_point  s    zWidget.collide_pointc                 C   sD   | j |jk rdS | j|j kr dS | j|jk r0dS | j|jkr@dS dS )a  
        Check if another widget collides with this widget. This function
        performs an axis-aligned bounding box intersection test by default.

        :Parameters:
            `wid`: :class:`Widget` class
                Widget to test collision with.

        :Returns:
            bool. True if the other widget collides with this widget, False
            otherwise.

        .. code-block:: python

            >>> wid = Widget(size=(50, 50))
            >>> wid2 = Widget(size=(50, 50), pos=(25, 25))
            >>> wid.collide_widget(wid2)
            True
            >>> wid2.pos = (55, 55)
            >>> wid.collide_widget(wid2)
            False
        FT)rY   rX   r[   rZ   )rL   Zwidr"   r"   r#   collide_widget  s    zWidget.collide_widgetc                 C   s   | j s|jtkrdS |j| jkr$dS | j|j }|d | krLt|dkrLdS |jtkr|d }| jdd D ]&}|d||r dS ||krl dS ql|jt	kr|d | kr|dd n
|dd }|D ]}|d||r dS qdS )a  Called when a motion event is received.

        :Parameters:
            `etype`: `str`
                Event type, one of "begin", "update" or "end"
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                Received motion event
        :Returns: `bool`
            `True` to stop event dispatching

        .. versionadded:: 2.1.0

        .. warning::
            This is an experimental method and it remains so while this warning
            is present.
        Nr      r5   T)
disabledZdispatch_moder   type_idmotion_filterlenr   childrenrJ   r   )rL   etypemefilteredZlast_filteredrO   widgetsr"   r"   r#   r5     s&    

$zWidget.on_motionc                 C   s@   | j r| j|j rdS | jdd D ]}|d|r$ dS q$dS )a  Receive a touch down event.

        :Parameters:
            `touch`: :class:`~kivy.input.motionevent.MotionEvent` class
                Touch received. The touch is in parent coordinates. See
                :mod:`~kivy.uix.relativelayout` for a discussion on
                coordinate systems.

        :Returns: bool
            If True, the dispatching of the touch event will stop.
            If False, the event will continue to be dispatched to the rest
            of the widget tree.
        TNr6   )r`   r\   posrd   rJ   rL   touchchildr"   r"   r#   r6   <  s
    zWidget.on_touch_downc                 C   s4   | j r
dS | jdd D ]}|d|r dS qdS )zReceive a touch move event. The touch is in parent coordinates.

        See :meth:`on_touch_down` for more information.
        Nr7   Tr`   rd   rJ   rj   r"   r"   r#   r7   P  s
    zWidget.on_touch_movec                 C   s4   | j r
dS | jdd D ]}|d|r dS qdS )zReceive a touch up event. The touch is in parent coordinates.

        See :meth:`on_touch_down` for more information.
        Nr8   Trm   rj   r"   r"   r#   r8   [  s
    zWidget.on_touch_upc                 C   s   d S r   r"   )rL   Zbase_widgetr"   r"   r#   r9   f  s    zWidget.on_kv_postr   c           	      C   sn  t |tstd|j}|| kr(td|j}|rBtd||f |  |_}|| j |dkrh| jjn|dkrx| jj	n| j}|dkst
| jdkr| jd| ||j n| j}| j}|t
|krt
|}||d j}n0|| }||j}|dkr
| }n|d7 }||| |dkr4|jr4d}|||j |jD ]}| || qH|d	| j d
S )aI  Add a new widget as a child of this widget.

        :Parameters:
            `widget`: :class:`Widget`
                Widget to add to our list of children.
            `index`: int, defaults to 0
                Index to insert the widget in the list. Notice that the default
                of 0 means the widget is inserted at the beginning of the list
                and will thus be drawn on top of other sibling widgets. For a
                full discussion of the index and widget hierarchy, please see
                the :doc:`Widgets Programming Guide <guide/widgets>`.

                .. versionadded:: 1.0.5
            `canvas`: str, defaults to None
                Canvas to add widget's canvas to. Can be 'before', 'after' or
                None for the default canvas.

                .. versionadded:: 1.9.0

    .. code-block:: python

        >>> from kivy.uix.button import Button
        >>> from kivy.uix.slider import Slider
        >>> root = Widget()
        >>> root.add_widget(Button())
        >>> slider = Slider()
        >>> root.add_widget(slider)

        zAadd_widget() can be used only with instances of the Widget class.z/Widget instances cannot be added to themselves.z)Cannot add %r, it already has a parent %rbeforeafterr   r_   r^   rb   N)
isinstancer   r   __self__parentinc_disabledrG   rH   rn   ro   rc   rd   insertaddindexoflengthZ
has_beforerb   register_for_motion_eventZfbind_update_motion_filter)	rL   rO   indexrH   rr   rd   Z
next_indexZ
next_childra   r"   r"   r#   
add_widgetl  sN    




zWidget.add_widgetc                 C   s   || j krdS | j | |j| jj kr8| j|j nB|j| jjj krZ| jj|j n |j| jjj krz| jj|j |jD ]}| || q|d| j d|_	|
| j dS )a  Remove a widget from the children of this widget.

        :Parameters:
            `widget`: :class:`Widget`
                Widget to remove from our children list.

    .. code-block:: python

        >>> from kivy.uix.button import Button
        >>> root = Widget()
        >>> button = Button()
        >>> root.add_widget(button)
        >>> root.remove_widget(button)
        Nrb   )rd   removerH   ro   rn   rb   unregister_for_motion_eventZfunbindry   rr   dec_disabledrG   )rL   rO   ra   r"   r"   r#   remove_widget  s    

zWidget.remove_widgetc                 C   s<   |dks|| j kr | j dd }| j}|D ]}|| q*dS )a8  
        Remove all (or the specified) :attr:`~Widget.children` of this widget.
        If the 'children' argument is specified, it should be a list (or
        filtered list) of children of the current widget.

        .. versionchanged:: 1.8.0
            The `children` argument can be used to specify the children you
            want to remove.
        .. versionchanged:: 2.1.0

            Specifying an empty ``children`` list leaves the widgets unchanged.
            Previously it was treated like ``None`` and all children were
            removed.
        N)rd   r   )rL   rd   r   rl   r"   r"   r#   clear_widgets  s
    zWidget.clear_widgetsc                 C   sj   g }| j  D ]\}}||kr|| q|D ]}||kr.| || q.|D ]}||krL| || qLd S r   )rb   rF   appendr}   rx   )rL   Zchild_widgetZchild_motion_filterZ
old_eventsra   rh   r"   r"   r#   ry     s    zWidget._update_motion_filterc                 C   st   || krdS | j j}||d }| j| }|d | kr:dnd}t|t|D ]"}||| |k rj|d7 }qL qpqL|S )Nr   r^   )rd   rz   rb   rangerc   )rL   ra   rO   Z
find_indexZ	max_indexZmotion_widgetsZinsert_indexrz   r"   r"   r#   _find_index_in_motion_filter  s    

z#Widget._find_index_in_motion_filterc                 C   sN   |p| }| j }||kr"|g||< n(||| krJ| ||}|| || dS )ah  Register to receive motion events of `type_id`.

        Override :meth:`on_motion` or bind to `on_motion` event to handle
        the incoming motion events.

        :Parameters:
            `type_id`: `str`
                Motion event type id (eg. "touch", "hover", etc.)
            `widget`: `Widget`
                Child widget or `self` if omitted

        .. versionadded:: 2.1.0

        .. note::
            Method can be called multiple times with the same arguments.

        .. warning::
            This is an experimental method and it remains so while this warning
            is present.
        N)rb   r   rt   )rL   ra   rO   a_widgetrb   rz   r"   r"   r#   rx     s    z Widget.register_for_motion_eventc                 C   sB   |p| }| j }||kr>||| kr>|| | || s>||= dS )a  Unregister to receive motion events of `type_id`.

        :Parameters:
            `type_id`: `str`
                Motion event type id (eg. "touch", "hover", etc.)
            `widget`: `Widget`
                Child widget or `self` if omitted

        .. versionadded:: 2.1.0

        .. note::
            Method can be called multiple times with the same arguments.

        .. warning::
            This is an experimental method and it remains so while this warning
            is present.
        N)rb   r|   )rL   ra   rO   r   rb   r"   r"   r#   r}   $  s    z"Widget.unregister_for_motion_eventc                 O   s   | j ||j|dd dS )a  Saves an image of the widget and its children in png format at the
        specified filename. Works by removing the widget canvas from its
        parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling
        :meth:`~kivy.graphics.texture.Texture.save`.

        .. note::

            The image includes only this widget and its children. If you want
            to include widgets elsewhere in the tree, you must call
            :meth:`~Widget.export_to_png` from their common parent, or use
            :meth:`~kivy.core.window.WindowBase.screenshot` to capture the
            whole window.

        .. note::

            The image will be saved in png format, you should include the
            extension in your filename.

        .. versionadded:: 1.9.0

        :Parameters:
            `filename`: str
                The filename with which to save the png.
            `scale`: float
                The amount by which to scale the saved image, defaults to 1.

                .. versionadded:: 1.11.0
        F)ZflippedN)export_as_imagesave)rL   filenameargsrM   r"   r"   r#   export_to_png>  s    zWidget.export_to_pngc              	   O   s  ddl m} |dd}| jdk	rJ| jj| j}|dkrJ| jj| j t| j| | j	| fdd}|L t
dddd t  tddd t||d t| j | j | j	 d W 5 Q R X || j |  ||j}|| j | jdk	r|dkr| jj|| j |S )	zwReturn an core :class:`~kivy.core.image.Image` of the actual
        widget.

        .. versionadded:: 1.11.0
        r   )Imagescaler^   Nr_   T)sizeZwith_stencilbuffer)Zkivy.core.imager   getrr   rH   rv   r|   r   widthheightr   r   r   r   rX   rZ   ru   ZdrawZtexturert   )rL   r   rM   r   r   Zcanvas_parent_indexZfboimgr"   r"   r#   r   ]  s,    
$
zWidget.export_as_imagec                 C   s   | j r| j  S dS )zReturn the root window.

        :Returns:
            Instance of the root window. Can be a
            :class:`~kivy.core.window.WindowBase` or
            :class:`Widget`.
        N)rr   get_root_windowrT   r"   r"   r#   r     s    zWidget.get_root_windowc                 C   s   | j r| j  S dS )zReturn the parent window.

        :Returns:
            Instance of the parent window. Can be a
            :class:`~kivy.core.window.WindowBase` or
            :class:`Widget`.
        N)rr   get_parent_windowrT   r"   r"   r#   r     s    zWidget.get_parent_windowFc                 c   s   |d krt | j}| V  t| jd | D ]}|jddD ]
}|V  q:q*|s| j}z&|d ksft|tsjt|j| }W n& tk
r   |sY d S | }d }Y nX |j||dD ]
}|V  qd S )NT)restrict)loopbackrz   )	rc   rd   reversed_walkrr   rp   r   
ValueErrorrz   )rL   r   r   rz   rl   
walk_childrr   r"   r"   r#   r     s&    


zWidget._walkc                 c   s8   |  ||}t|V  |D ]}|| kr, dS |V  qdS )ak   Iterator that walks the widget tree starting with this widget and
        goes forward returning widgets in the order in which layouts display
        them.

        :Parameters:
            `restrict`: bool, defaults to False
                If True, it will only iterate through the widget and its
                children (or children of its children etc.). Defaults to False.
            `loopback`: bool, defaults to False
                If True, when the last widget in the tree is reached,
                it'll loop back to the uppermost root and start walking until
                we hit this widget again. Naturally, it can only loop back when
                `restrict` is False. Defaults to False.

        :return:
            A generator that walks the tree, returning widgets in the
            forward layout order.

        For example, given a tree with the following structure:

        .. code-block:: kv

            GridLayout:
                Button
                BoxLayout:
                    id: box
                    Widget
                    Button
                Widget

        walking this tree:

        .. code-block:: python

            >>> # Call walk on box with loopback True, and restrict False
            >>> [type(widget) for widget in box.walk(loopback=True)]
            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,
                <class 'Widget'>, <class 'GridLayout'>, <class 'Button'>]
            >>> # Now with loopback False, and restrict False
            >>> [type(widget) for widget in box.walk()]
            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,
                <class 'Widget'>]
            >>> # Now with restrict True
            >>> [type(widget) for widget in box.walk(restrict=True)]
            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>]

        .. versionadded:: 1.9.0
        N)r   next)rL   r   r   gennoder"   r"   r#   walk  s    1
zWidget.walkc                 c   s   | }d}|rh| j }z*|d ks&t|ts*t|j| d }W n* tk
rf   |sVY d S d}d}| }Y nX t|j|d D ]}|j|dD ]
}|V  qqv|V  |r|j||dD ]
}|V  qd S )Nr   r^   F)r   r   go_up)rr   rp   r   r   rd   rz   r   _walk_reverse)rL   r   r   rW   rz   rl   r   r"   r"   r#   r     s.    


zWidget._walk_reversec                 c   s,   | j |ddD ]}|V  || kr dS qdS )a#   Iterator that walks the widget tree backwards starting with the
        widget before this, and going backwards returning widgets in the
        reverse order in which layouts display them.

        This walks in the opposite direction of :meth:`walk`, so a list of the
        tree generated with :meth:`walk` will be in reverse order compared
        to the list generated with this, provided `loopback` is True.

        :Parameters:
            `loopback`: bool, defaults to False
                If True, when the uppermost root in the tree is
                reached, it'll loop back to the last widget and start walking
                back until after we hit widget again. Defaults to False.

        :return:
            A generator that walks the tree, returning widgets in the
            reverse layout order.

        For example, given a tree with the following structure:

        .. code-block:: kv

            GridLayout:
                Button
                BoxLayout:
                    id: box
                    Widget
                    Button
                Widget

        walking this tree:

        .. code-block:: python

            >>> # Call walk on box with loopback True
            >>> [type(widget) for widget in box.walk_reverse(loopback=True)]
            [<class 'Button'>, <class 'GridLayout'>, <class 'Widget'>,
                <class 'Button'>, <class 'Widget'>, <class 'BoxLayout'>]
            >>> # Now with loopback False
            >>> [type(widget) for widget in box.walk_reverse()]
            [<class 'Button'>, <class 'GridLayout'>]
            >>> forward = [w for w in box.walk(loopback=True)]
            >>> backward = [w for w in box.walk_reverse(loopback=True)]
            >>> forward == backward[::-1]
            True

        .. versionadded:: 1.9.0

        Tr   N)r   )rL   r   r   r"   r"   r#   walk_reverse  s    2zWidget.walk_reversec                 C   s(   | j r| j ||\}}| j|||dS )zConvert the coordinate from window to local (current widget)
        coordinates.

        See :mod:`~kivy.uix.relativelayout` for details on the coordinate
        systems.
        relative)rr   	to_widgetto_localrL   rX   rZ   r   r"   r"   r#   r   C  s    zWidget.to_widgetTc                 C   s:   |s| j |||d\}}| jr2| jj||d|dS ||fS )a,  If ``initial`` is True, the default, it transforms **parent**
        coordinates to window coordinates. Otherwise, it transforms **local**
        (current widget) coordinates to window coordinates.

        See :mod:`~kivy.uix.relativelayout` for details on the coordinate
        systems.
        r   F)initialr   )	to_parentrr   	to_window)rL   rX   rZ   r   r   r"   r"   r#   r   N  s    zWidget.to_windowc                 C   s    |r|| j  || j fS ||fS )ar  Transform local (current widget) coordinates to parent coordinates.

        See :mod:`~kivy.uix.relativelayout` for details on the coordinate
        systems.

        :Parameters:
            `relative`: bool, defaults to False
                Change to True if you want to translate relative positions from
                a widget to its parent coordinates.
        rX   rZ   r   r"   r"   r#   r   ]  s    zWidget.to_parentc                 C   s    |r|| j  || j fS ||fS )ab  Transform parent coordinates to local (current widget) coordinates.

        See :mod:`~kivy.uix.relativelayout` for details on the coordinate
        systems.

        :Parameters:
            `relative`: bool, defaults to False
                Change to True if you want to translate coordinates to
                relative widget coordinates.
        r   r   r"   r"   r#   r   l  s    zWidget.to_localc                 C   sP   | j rL| j j| j|p| j ddi\}}|||d | j rH| j |n|}|S )Nr   Tr   )rr   r   r   ri   	translate_apply_transform)rL   mri   rX   rZ   r"   r"   r#   r   {  s    zWidget._apply_transformc                 C   s"   t  }|||d | |}|S )a2  Calculate the transformation matrix to convert between window and
        widget coordinates.

        :Parameters:
            `x`: float, defaults to 0
                Translates the matrix on the x axis.
            `y`: float, defaults to 0
                Translates the matrix on the y axis.
        r   )r   r   r   )rL   rX   rZ   r   r"   r"   r#   get_window_matrix  s    

zWidget.get_window_matrixd   c                 C   s   | j | j S r   rX   r   rT   r"   r"   r#   	get_right  s    zWidget.get_rightc                 C   s   || j  | _d S r   r   rX   rL   valuer"   r"   r#   	set_right  s    zWidget.set_rightr   )rK   cachewatch_before_usec                 C   s   | j | j S r   rZ   r   rT   r"   r"   r#   get_top  s    zWidget.get_topc                 C   s   || j  | _d S r   r   rZ   r   r"   r"   r#   set_top  s    zWidget.set_topr   c                 C   s   | j | jd  S Ng       @r   rT   r"   r"   r#   get_center_x  s    zWidget.get_center_xc                 C   s   || j d  | _d S r   r   r   r"   r"   r#   set_center_x  s    zWidget.set_center_xc                 C   s   | j | jd  S r   r   rT   r"   r"   r#   get_center_y  s    zWidget.get_center_yc                 C   s   || j d  | _d S r   r   r   r"   r"   r#   set_center_y  s    zWidget.set_center_y)	allownoneZrebindr^   )r   g      ?c                 C   s   | j }|d k	r||_d S r   )rH   r@   )rL   instancer   rH   r"   r"   r#   
on_opacity  s    zWidget.on_opacityc                 C   s
   | j dkS )Nr   )rG   rT   r"   r"   r#   get_disabled  s    zWidget.get_disabledc                 C   s6   t |}|| jkr2|| _|r&|   n|   dS d S )NT)boolrE   rs   r~   r   r"   r"   r#   set_disabled  s    

zWidget.set_disabledc                 C   sX   |  j |7  _ | j | d  k r*| j kr>n n| d|  | jD ]}|| qDd S )Nr^   r`   )rG   propertyrJ   rd   rs   rL   countcr"   r"   r#   rs   *  s
     
zWidget.inc_disabledc                 C   sX   |  j |8  _ | j d  kr*| j | k r>n n| d|  | jD ]}|| qDd S )Nr   r`   )rG   r   rJ   rd   r~   r   r"   r"   r#   r~   1  s
     
zWidget.dec_disabled)r   )r   N)N)N)N)FFN)FF)FF)F)F)TF)F)F)N)r   r   )r^   )r^   )[r%   r&   r'   r(   r)   __metaclass__Z
__events__rP   r,   r   rR   rU   setrI   r\   r]   r5   r6   r7   r8   r9   r{   r   r   ry   r   rx   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r	   rX   rZ   r   r   r   ri   r   r   r   r   rY   r   r   r[   r   r   Zcenter_xr   r   Zcenter_ycenterr   r*   rd   r   rr   Zsize_hint_xZsize_hint_yZ	size_hintZpos_hintZsize_hint_min_xZsize_hint_min_yZsize_hint_minZsize_hint_max_xZsize_hint_max_yZsize_hint_maxr   idsr@   r   rH   r   r   rs   r~   r`   rb   r3   r"   r"   r1   r#   r   '  s   $'
  
K!(
M


"

8
!
7







 	 	 	 	
	

	
	
	6

r   N)0r(   __all__Z
kivy.eventr   Zkivy.eventmanagerr   r   r   Zkivy.factoryr   Zkivy.propertiesr	   r
   r   r   r   r   r   r   Zkivy.graphicsr   r   r   r   r   r   Zkivy.graphics.transformationr   Z	kivy.baser   Z	kivy.langr   Zkivy.contextr   Zkivy.weakproxyr   	functoolsr   	itertoolsr   r   r$   	Exceptionr   typer)   r4   r   r"   r"   r"   r#   <module>   s(    m( 