Events
======

You have 2 types of events living in Kivy:

- Clock events: if you want to call a function X times per seconds, or if you
  want to call a function later.
- Widget events: if you want to call a function where something change in the
  widget, or attach a function to a widget specific event.


Clock events
------------

Before we discuss events, you need to know that Kivy has a main loop, and that
it's important that you avoid breaking it. The main loop is responsible for
reading from inputs, loading images asynchronously, drawing to the frame, etc.
If you are looping or sleeping, you'll break the main loop. As an example, the
following code does both::

    while True:
        animate_something()
        time.sleep(.10)

When you run this, the program will never exit your loop, preventing Kivy from
doing all of the other things that need doing. As a result, all you'll see is a
black window which you won't be able to interact with. You need to "schedule"
your ``animate_something()`` function call over time. You can do this in 2 ways:
a repetitive call or one-time call.

Scheduling a repetitive event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can call a function or a method every X times per seconds using
:meth:`~kivy.clock.Clock.schedule_interval`. Here is an example of calling a
function named my_callback 30 times per seconds::

    def my_callback(dt):
        print 'My callback is called', dt
    Clock.schedule_interval(my_callback, 1 / 30.)

You have 2 ways of unscheduling a previously scheduled event. The first would be
to use :meth:`~kivy.clock.Clock.unschedule`::

    Clock.unschedule(my_callback)

Or, you can return False in your callback, and your event will be automatically
unscheduled::

    count = 0
    def my_callback(dt):
        global count
        count += 1
        if count == 10:
            print 'Last call of my callback, bye bye !'
            return False
        print 'My callback is called'
    Clock.schedule_interval(my_callback, 1 / 30.)


Scheduling a one-time event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Using :meth:`~kivy.clock.Clock.schedule_once`, you can call a function "later",
like in the next frame, or in X seconds::

    def my_callback(dt):
        print 'My callback is called !'
    Clock.schedule_once(my_callback, 1)

This will call ``my_calback`` in one second. The second argument is the amount
of time to wait before calling the function, in seconds. However, you can
achieve some other results with special values for the second argument:

- If X is greater than 0, the callback will be called in X seconds
- If X is 0, the callback will be called after the next frame
- If X is -1, the callback will be called before the next frame

The -1 is mostly used when you are already in a scheduled event, and if you
want to schedule a call BEFORE the next frame is happening.


Trigger events
~~~~~~~~~~~~~~

If you want to schedule a function to be called only once for the next frame,
like a trigger, you can achieve that like so::

    Clock.unschedule(my_callback)
    Clock.schedule_once(my_callback, 0)

This way of programming a trigger is expensive, since you'll always call
unschedule, whether or not you've even scheduled it. In addition, unschedule
needs to iterate the weakref list of the Clock in order to find your callback
and remove it. Use a trigger instead::

    trigger = Clock.create_trigger(my_callback)
    # later
    trigger()

Each time you call trigger, it will schedule a single call of your callback. If
it was already scheduled, it will not be rescheduled.




Widget events
-------------

A widget has 2 types of events:

- Property event: if your widget changes its position or size, an event is fired.
- Widget-defined event: an event will be fired for a Button when it's pressed or
  released.


Property event
~~~~~~~~~~~~~~

A widget has many properties. You'll find in the doc that every property has a
type like :class:`~kivy.properties.NumericProperty`,
:class:`~kivy.properties.StringProperty`,
:class:`~kivy.properties.ListProperty`.

Usualy, when you want to create a Python class with properties, you do something like this::

    class MyClass(object):
        def __init__(self):
            super(MyClass, self).__init__()
            self.prop1 = 'bleh'

Using this code though, you do not have a good way to know when ``prop1`` is
changed, except by rewriting the class and adding a hook in
``__getattribute__``. The Kivy way to do this is::

    class MyClass(Widget):
        prop1 = StringProperty('bleh')

You can connect a function to this property if you want to be called when the
value of the property changes::

    def my_callback(instance, value):
        print 'the widget', instance, 'prop1 changed to', value

    # create an instance of MyClass
    obj = MyClass()
    # and connect my_callback to prop1
    obj.bind(prop1=my_callback)
    # now change prop1 => it will call your callback !
    obj.prop1 = 'hello world'

If you want to stop receiving events from the ``prop1`` property, call unbind::

    obj.unbind(prop1=my_callback)


Widget-defined event
~~~~~~~~~~~~~~~~~~~~

Sometimes the property event is not enough to hook onto. For example, a Button
could have a state property that indicates whether the Button is currently
pressed or not. We made the choice to add additional events for this: the
:meth:`~kivy.uix.button.Button.on_press` and
:meth:`~kivy.uix.button.Button.on_release` events::

    def my_callback_press(instance):
        print 'The button', instance, 'is pressed'
    button = Button(text='Hello world')
    button.bind(on_press=my_callback_press)

Every event defined by a widget is in the documentation, at the start of the
class. You can find a list of widget-defined events that the widget supports.

If you are designing your own widget, you can create a widget event by using
:meth:`~kivy.event.register_event_type`::

    class MyClass(Widget):

        def __init__(self, **kwargs):
            self.register_event_type('on_custom_event')
            super(MyClass, self).__init__(**kwargs)

        def on_custom_event(self):
            # empty handler needed
            pass

Then, the user can hook to it, same as the Button.on_press event. In this
example,  the event is never dispatched. Let's just add a function demonstrating
how to dispatch a widget-defined event::

    class MyClass(Widget):

        # ... __init__ + on_custom_event

        def do_something(self):
            self.dispatch('on_custom_event')

Now, everytime you call the ``do_something()`` method, it will dispatch
``on_custom_event``, and call every function attached to this event.
