Kivy’s bind method

One of the most common problems for new Kivy users is misunderstanding how the bind method works, especially amongst newer Python users who haven’t fully formed their intuition about function calls. For instance, a user will write code like:

some_screenmanager.bind(current=a_function(arg1, arg2))

Here, the idea is that when the current property changes, it will call a_function with the arguments arg1 and arg2.

The problem is that Python itself doesn’t work like this; the bind method doesn’t know about the existence of a_function or its arguments, it only receives the result of this function call. This often leads to confusion when a user doesn’t understand why the binding is only called once, during the declaration of the binding.

Stepping back, our real goal is to call a_function with the given arguments, but bind needs to be passed a function if it is to work correctly. That means we can solve our problem by creating a new function with these arguments already passed (and discarding the extra arguments automatically passed by bind).

It’s usually convenient to do this with the partial function from the functools module:

from functools import partial
some_screenmanager.bind(current=partial(a_function,arg1, arg2))

partial returns a new function that will automatically be passed arg1 and arg2, exactly as we want. You can also pass kwargs this way.

This isn’t the only way to solve the problem, we could have created a lambda function (though the syntax is longer and can have scope problems) or an entire new function with def syntax, but both of these are more complicated than the simple use of partial. So if you need to do a binding in Python, look at this way first!

Kpritz

Just because it seemed not to hard, i spent the evening (actually about 2 hours) making a Spritz clone using kivy.

Code is a bit crude and all, but here it is for your enjoyment:

https://gist.github.com/9316552

Here is an apk if you want to actually try it.

Only flat text files are supported, opening the option window is a bit slow (because of ColorPickers), but it’s functionnal, progression is saved, all the options i though were needed are there, and it seems usable.

You can find a lot of free book in the .txt format over at project gutenberg.

Kpritz

Just because it seemed not to hard, i spent the evening (actually about 2 hours) making a Spritz clone using kivy.

Code is a bit crude and all, but here it is for your enjoyment:

https://gist.github.com/9316552

Here is an apk if you want to actually try it.

Only flat text files are supported, opening the option window is a bit slow (because of ColorPickers), but it’s functionnal, progression is saved, all the options i though were needed are there, and it seems usable.

You can find a lot of free book in the .txt format over at project gutenberg.

Using tex_coords in kivy for fun and profit

Your gpu is an awesome thing, it can do all kind of calculations, very fast. For example, instead of telling it exactly how you want each pixels to be, you can throw textures and vertices at it, and have it correctly deduce how this things will have to look.

To do this, though, you must tell it what part of the texture will be stuck to each vertice. This is usually denoted using texture coordinates.

Texture coordinates, like usual coordinates, indicate the place of something. Instead of noting them x and y, they are often called u and v, which allows to clearly note what parts of an equation relate to each.

While kivy offers you high level canvas instructions, it gives you a pretty good access to lower level features, and you can actually manipulate the texture coordinates of your Rectangle instructions. This allow for cheap zooming, repeat-scrolling, and other image manipulations, since your gpu is doing all the actual work.

tex_coords = u, v, u + w, v, u + w, v + h, u, v + h

which is better understood as:

tex_coords = [
    u,     v,
    u + w, v,
    u + w, v + h,
    u,     v + h
]

considering a default tex_coords value, where u and v = 0, and w and h = 1 (all values are relatives, so usually between 0 and 1).

u, v + h-------u + w, v + h
|              |
u, v-----------u + w, v

which means the 4 angles of your texture, will be on the 4 angles of your rectangle, how dull!

One way to play with different values, is to create a little app showing you the effect of deformations.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty
from kivy.core.image import Image as CoreImage

kv = '''
#:import chain itertools.chain
RootWidget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: root.pos
            size: root.size
            texture: app.texture
            # here is our usage of the calculated texture coordinates
            # we devide by 100 because we took the input with a 100x100
            # rectangle as default value
            tex_coords: [x / 100. for x in chain(*root.points)]

        PushMatrix
        # translate the rectangle to make it easier to play with
        Translate:
            xy: root.width / 2, root.height / 2

        Color:
            rgba: 1, 0, 0, .5
        Line:
            points: chain(*root.points + root.points[:1])
            width: 2
        PopMatrix
'''


def dist(point, pos):
    return ((point[0] - pos[0]) ** 2 + (point[1] - pos[1]) ** 2)
    # ** .5 # who cares about square root here? it doesn't change the order


class RootWidget(Widget):
    # the default values, a 100x100 square, displayed around the middle of the screen
    points = ListProperty([[0, 0], [100, 0], [100, 100], [0, 100]])

    def on_touch_down(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2

        touch.ud['point'] = min(
            range(4), key=lambda x: dist(self.points[x], pos))

    def on_touch_move(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2
        # update the point
        self.points[touch.ud['point']] = pos


class TexCoordsApp(App):
    texture = ObjectProperty(None)

    def build(self):
        self.root = Builder.load_string(kv)
        self.texture = CoreImage.load(
            'GrassGreenTexture0002.jpg').texture
        self.texture.wrap = 'repeat'
        return self.root


if __name__ == '__main__':
    TexCoordsApp().run()

The texture have been scrapped on the web and is not very interesting, but you can find it here.

Of course, this is much more a learning device (helful because these transformation are not quite straighforward for our brains) than a practical application, but a lot more can be done.

Here is, for example, a little infinite scroll app uting this concept.

edit: Ben Rousch kindly created apks out of the two examples, if you want to try them on android: TexCoordsExample ScrollExample

Using tex_coords in kivy for fun and profit

Your gpu is an awesome thing, it can do all kind of calculations, very fast. For example, instead of telling it exactly how you want each pixels to be, you can throw textures and vertices at it, and have it correctly deduce how this things will have to look.

To do this, though, you must tell it what part of the texture will be stuck to each vertice. This is usually denoted using texture coordinates.

Texture coordinates, like usual coordinates, indicate the place of something. Instead of noting them x and y, they are often called u and v, which allows to clearly note what parts of an equation relate to each.

While kivy offers you high level canvas instructions, it gives you a pretty good access to lower level features, and you can actually manipulate the texture coordinates of your Rectangle instructions. This allow for cheap zooming, repeat-scrolling, and other image manipulations, since your gpu is doing all the actual work.

tex_coords = u, v, u + w, v, u + w, v + h, u, v + h

which is better understood as:

tex_coords = [
    u,     v,
    u + w, v,
    u + w, v + h,
    u,     v + h
]

considering a default tex_coords value, where u and v = 0, and w and h = 1 (all values are relatives, so usually between 0 and 1).

u, v + h-------u + w, v + h
|              |
u, v-----------u + w, v

which means the 4 angles of your texture, will be on the 4 angles of your rectangle, how dull!

One way to play with different values, is to create a little app showing you the effect of deformations.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty
from kivy.core.image import Image as CoreImage

kv = '''
#:import chain itertools.chain
RootWidget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: root.pos
            size: root.size
            texture: app.texture
            # here is our usage of the calculated texture coordinates
            # we devide by 100 because we took the input with a 100x100
            # rectangle as default value
            tex_coords: [x / 100. for x in chain(*root.points)]

        PushMatrix
        # translate the rectangle to make it easier to play with
        Translate:
            xy: root.width / 2, root.height / 2

        Color:
            rgba: 1, 0, 0, .5
        Line:
            points: chain(*root.points + root.points[:1])
            width: 2
        PopMatrix
'''


def dist(point, pos):
    return ((point[0] - pos[0]) ** 2 + (point[1] - pos[1]) ** 2)
    # ** .5 # who cares about square root here? it doesn't change the order


class RootWidget(Widget):
    # the default values, a 100x100 square, displayed around the middle of the screen
    points = ListProperty([[0, 0], [100, 0], [100, 100], [0, 100]])

    def on_touch_down(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2

        touch.ud['point'] = min(
            range(4), key=lambda x: dist(self.points[x], pos))

    def on_touch_move(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2
        # update the point
        self.points[touch.ud['point']] = pos


class TexCoordsApp(App):
    texture = ObjectProperty(None)

    def build(self):
        self.root = Builder.load_string(kv)
        self.texture = CoreImage.load(
            'GrassGreenTexture0002.jpg').texture
        self.texture.wrap = 'repeat'
        return self.root


if __name__ == '__main__':
    TexCoordsApp().run()

The texture have been scrapped on the web and is not very interesting, but you can find it here.

Of course, this is much more a learning device (helful because these transformation are not quite straighforward for our brains) than a practical application, but a lot more can be done.

Here is, for example, a little infinite scroll app uting this concept.

edit: Ben Rousch kindly created apks out of the two examples, if you want to try them on android: TexCoordsExample ScrollExample

Magnet: a widget to easily make your interface more lively

Kivy has a very nice Animation class, that allows you to move move widgets around (or other things), by updating any numeric property to a target value, just by setting a time and a transition function. Still, when you are building a complex interface, it can still be a bit cumbersome to manually trigger animations for all the elements, and to keep track of them.

After being frustrated about this issue for some time, i tried my luck some time ago, at doing a nicer, “90% use cases” interface, and the Magnet garden widget was born.

Its usage is simple, you simply use it to wrap your target widget, and give it rules about how to transition when the magnet is moved. As the magnet is moved or resized by the usual kivy logic, instead of making the wrapped widget immediately follow such constraints, it’ll create and keep track of animations to achieve a smooth transition to the new values for you.

As any garden “flower”, to install it, you need to install and use the garden project.

python setup.py install

(either in a virtualenv or system-wide)

then do:

garden install magnet

you can now import it a kivy application:

from kivy.garden.magnet import Magnet

Garden Magnet video

Magnet: a widget to easily make your interface more lively

Kivy has a very nice Animation class, that allows you to move move widgets around (or other things), by updating any numeric property to a target value, just by setting a time and a transition function. Still, when you are building a complex interface, it can still be a bit cumbersome to manually trigger animations for all the elements, and to keep track of them.

After being frustrated about this issue for some time, i tried my luck some time ago, at doing a nicer, “90% use cases” interface, and the Magnet garden widget was born.

Its usage is simple, you simply use it to wrap your target widget, and give it rules about how to transition when the magnet is moved. As the magnet is moved or resized by the usual kivy logic, instead of making the wrapped widget immediately follow such constraints, it’ll create and keep track of animations to achieve a smooth transition to the new values for you.

As any garden “flower”, to install it, you need to install and use the garden project.

python setup.py install

(either in a virtualenv or system-wide)

then do:

garden install magnet

you can now import it a kivy application:

from kivy.garden.magnet import Magnet

Garden Magnet video