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

Kivy image manipulations with Mesh and Textures

If you want to give a little life to interactive (or not) elements, it’s always nice to have more tricks to manipulate images for nifty effects.

One of such ways is mapping a Texture on a special canvas instruction, that will distort your texture based on the position of its points.

[kivy.graphics.Mesh](http://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Mesh) is such an instruction, and it has a simple interface, if not 100% straightforward, you basically call it this way.

Mesh:
vertices: (x1, y1, s1, v1, x2, y2, s2, v2, x3, y3, s3, v3...)
indices: (1, 2, 3...)
texture: some_texture
mode: some_mode

where all: x mean the horizontal coordinate of a point y mean the vertical coordinate of a point s mean the horizontal position of the texture attached to this point (between 0 and 1) v mean the vertical position of the texture attached to this point (between 0 and 1)

indices is useful if, for some (very good) reason, you don’t want to give the points in the order you’ll use them, or if you want to refer to a point multiple time (this won’t be demonstrated in this blog post, but try to think about a grid mapping, for example), now we will use it in the most simple way, just give the range of your number of points.

the texture needs to be a texture object, you can get such an object by getting the texture property of a [CoreImage](http://kivy.org/docs/api-kivy.core.image.html#kivy.core.image.Image) or an Image (or even a Label, if you want to).

Let’s say we have an image, for example, kivy logo.

from kivy.core.image import Image as CoreImage

texture = CoreImage('data/logo/kivy-icon-512.png').texture

(this will work wherever you are, because kivy look at his images anyway :))

This image is a circle, lets use that to cut it into a virtual pie and assign a part of the texture to each part, we’ll be using the triangle_fan mode of Mesh, that is a perfect fit for such an operation.

# the central point
points = [Window.width / 2, Window.height / 2, .5, .5]

# now go around
    i = 0
    while i < 2 * pi:
        i += 0.01 * pi
        points.extend([
    Window.width / 2 + cos(i) * 100,
    Window.height / 2 + sin(i) * 100,
    .5 + sin(i),
    .5 + cos(i)])

put that in a more complete program, and you get this:

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
Widget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Mesh:
            vertices: app.mesh_points
            indices: range(len(app.mesh_points) / 4)
            texture: app.mesh_texture
            mode: 'triangle_fan'
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * 100,
                Window.height / 2 + sin(i) * 100,
                .5 + cos(i),
                .5 + sin(i)])

        self.mesh_points = points

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

Now, this is not very impressive, we just have an image, there were much simpler ways to do that!

But now, we can tweek the rendering a lot, lets add some offseting of the texture, some radius change, and some wobbling, with sliders to control all this.

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty, NumericProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
BoxLayout:
    Widget:
        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Mesh:
                vertices: app.mesh_points
                indices: range(len(app.mesh_points) / 4)
                texture: app.mesh_texture
                mode: 'triangle_fan'
    BoxLayout:
        orientation: 'vertical'
        size_hint_x: None
        width: 100
        Slider:
            value: app.offset_x
            on_value: app.offset_x = args[1]
            min: -1
            max: 1
        Slider:
            value: app.offset_y
            on_value: app.offset_y = args[1]
            min: -1
            max: 1
        Slider:
            value: app.radius
            on_value: app.radius = args[1]
            min: 10
            max: 1000
        Slider:
            value: app.sin_wobble
            on_value: app.sin_wobble = args[1]
            min: -50
            max: 50
        Slider:
            value: app.sin_wobble_speed
            on_value: app.sin_wobble_speed = args[1]
            min: 0
            max: 50
            step: 1
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)
    radius = NumericProperty(500)
    offset_x = NumericProperty(.5)
    offset_y = NumericProperty(.5)
    sin_wobble = NumericProperty(0)
    sin_wobble_speed = NumericProperty(0)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                Window.height / 2 + sin(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                self.offset_x + sin(i),
                self.offset_y + cos(i)])

        self.mesh_points = points

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

which gives us:

Kivy image manipulations with Mesh and Text

Now we are talking!

Kivy image manipulations with Mesh and Textures

If you want to give a little life to interactive (or not) elements, it’s always nice to have more tricks to manipulate images for nifty effects.

One of such ways is mapping a Texture on a special canvas instruction, that will distort your texture based on the position of its points.

[kivy.graphics.Mesh](http://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Mesh) is such an instruction, and it has a simple interface, if not 100% straightforward, you basically call it this way.

Mesh:
vertices: (x1, y1, s1, v1, x2, y2, s2, v2, x3, y3, s3, v3...)
indices: (1, 2, 3...)
texture: some_texture
mode: some_mode

where all: x mean the horizontal coordinate of a point y mean the vertical coordinate of a point s mean the horizontal position of the texture attached to this point (between 0 and 1) v mean the vertical position of the texture attached to this point (between 0 and 1)

indices is useful if, for some (very good) reason, you don’t want to give the points in the order you’ll use them, or if you want to refer to a point multiple time (this won’t be demonstrated in this blog post, but try to think about a grid mapping, for example), now we will use it in the most simple way, just give the range of your number of points.

the texture needs to be a texture object, you can get such an object by getting the texture property of a [CoreImage](http://kivy.org/docs/api-kivy.core.image.html#kivy.core.image.Image) or an Image (or even a Label, if you want to).

Let’s say we have an image, for example, kivy logo.

from kivy.core.image import Image as CoreImage

texture = CoreImage('data/logo/kivy-icon-512.png').texture

(this will work wherever you are, because kivy look at his images anyway :))

This image is a circle, lets use that to cut it into a virtual pie and assign a part of the texture to each part, we’ll be using the triangle_fan mode of Mesh, that is a perfect fit for such an operation.

# the central point
points = [Window.width / 2, Window.height / 2, .5, .5]

# now go around
    i = 0
    while i < 2 * pi:
        i += 0.01 * pi
        points.extend([
    Window.width / 2 + cos(i) * 100,
    Window.height / 2 + sin(i) * 100,
    .5 + sin(i),
    .5 + cos(i)])

put that in a more complete program, and you get this:

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
Widget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Mesh:
            vertices: app.mesh_points
            indices: range(len(app.mesh_points) / 4)
            texture: app.mesh_texture
            mode: 'triangle_fan'
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * 100,
                Window.height / 2 + sin(i) * 100,
                .5 + cos(i),
                .5 + sin(i)])

        self.mesh_points = points

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

Now, this is not very impressive, we just have an image, there were much simpler ways to do that!

But now, we can tweek the rendering a lot, lets add some offseting of the texture, some radius change, and some wobbling, with sliders to control all this.

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty, NumericProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
BoxLayout:
    Widget:
        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Mesh:
                vertices: app.mesh_points
                indices: range(len(app.mesh_points) / 4)
                texture: app.mesh_texture
                mode: 'triangle_fan'
    BoxLayout:
        orientation: 'vertical'
        size_hint_x: None
        width: 100
        Slider:
            value: app.offset_x
            on_value: app.offset_x = args[1]
            min: -1
            max: 1
        Slider:
            value: app.offset_y
            on_value: app.offset_y = args[1]
            min: -1
            max: 1
        Slider:
            value: app.radius
            on_value: app.radius = args[1]
            min: 10
            max: 1000
        Slider:
            value: app.sin_wobble
            on_value: app.sin_wobble = args[1]
            min: -50
            max: 50
        Slider:
            value: app.sin_wobble_speed
            on_value: app.sin_wobble_speed = args[1]
            min: 0
            max: 50
            step: 1
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)
    radius = NumericProperty(500)
    offset_x = NumericProperty(.5)
    offset_y = NumericProperty(.5)
    sin_wobble = NumericProperty(0)
    sin_wobble_speed = NumericProperty(0)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                Window.height / 2 + sin(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                self.offset_x + sin(i),
                self.offset_y + cos(i)])

        self.mesh_points = points

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

which gives us:

Kivy image manipulations with Mesh and Text

Now we are talking!

Creating a Kivy layout: the SparseGridLayout

I thought for a change I’d try for a shorter post on a single quick subject, so I’m going to quickly explain a simple Kivy layout I created, the SparseGridLayout. The post is standalone, but would go well with ideas from my Kivy Crash Course, especially the recent videos trying to draw ideas together to make widgets or specifically focusing on layouts.

The point here is that Kivy has a built in GridLayout, but it doesn’t cover all use cases for widgets in a grid, which is sometimes confusing to users who’ve seen grid widgets in other places and expected a slightly different behaviour. The problem is that the GridLayout fills widgets in from the top. That means for instance if there are 3 columns, you can’t place a widget in the third row without first adding 6 widgets to fill the first two rows. That’s just inefficient and wasteful if all you wanted was a small number of widgets in a grid.

So, my SparseGridLayout is a very simple layout that has a number of rows or columns, and checks its children for a row and column property. It then resizes them automatically to be placed in the right grid cell. That means we don’t need any extra widgets, which is much more efficient if we want a grid with not many entries, hence sparse grid layout.

We can start with a FloatLayout base, then all we need to do is set our grid children’s size_hint and pos_hint properties appropriately for the grid and call the FloatLayout‘s normal layout method to actually place them in the grid positions/shapes for us.

We can start by making our layout class:

from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ReferenceListProperty

class SparseGridLayout(FloatLayout):
    rows = NumericProperty(1)
    columns = NumericProperty(1)
    shape = ReferenceListProperty(rows, columns)

That creates a basic class that doesn’t have any more actual behavior than the FloatLayout alone, but has a few new properties. It’ll hopefully all make sense if you’ve used Kivy a little or followed my crash course, though the ReferenceListProperty may be new - this takes multiple other properties and lets us access them as a list, so for instance referencing or setting shape[0] really updates the rows property, including calling all its associated events etc.. At the same time, the shape is also a real property, with its own events. Do experiment with this if the explanation is not clear.

Now, to make our layout actually rearrange its children to the grid, we need to override its do_layout method, which is what’s called whenever it or its children are updated.

def do_layout(self, *args):
    shape_hint = (1. / self.columns, 1. / self.rows)
    for child in self.children:
        child.size_hint = shape_hint
        if not hasattr(child, 'row'):
            child.row = 0
        if not hasattr(child, 'column'):
            child.column = 0

        child.pos_hint = {'x': shape_hint[0] * child.row,
                          'y': shape_hint[1] * child.column}
    super(SparseGridLayout, self).do_layout(*args)

This iterates over all the SparseGridLayout‘s children, setting their size_hint so that they’ll fit exactly in a grid cell (as per the rows and columns properties we set above). It then checks if they have a row or column property, setting it to 0 if not - I’ve chosen that my rows and columns should be zero-indexed, you could modify that if you like. After that, it sets their pos_hint such that they’re placed in the right place. I’ve deliberately let this work with floats, so for instance they could be in column 2.5 to be halfway between the integer columns, so the layout is extra flexible.

The final step is calling the original do_layout method of the FloatLayout. The magic is that all we did is set the child widgets size_hint and pos_hint so that the widgets align to a grid - the FloatLayout itself already knows how to actually set their positions and sizes based on this information. By making use of Kivy’s existing layout abilities, we’ve saved ourself a lot of work.

Finally, I also added a class to represent entries in the grid:

class GridEntry(EventDispatcher):
    row = NumericProperty(0)
    column = NumericProperty(0)

This is very simple, but it means you can do for example:

class GridLabel(Label, GridEntry):
    pass

The GridLabel is thereby a Label that already has row and column properties, so it will behave properly in our SparseGridLayout. We don’t strictly need to do this, we could add the row and column any other way, but this is neat and makes it totally clear what we’re using our widgets for.

That’s everything! With just a few simple modifications we’ve made a whole new Layout widget that can place its children in rows and columns of a grid. Maybe you’ll find that useful, but more generally I hope this demonstrates the general principles of thinking about Layouts and using Kivy’s existing mechanisms to do most of the work.

You can find all this code at my sparsegridlayout github repository, which also includes a simple demonstration App so you can test the new layout if you like.

Creating a Kivy layout: the SparseGridLayout

I thought for a change I’d try for a shorter post on a single quick subject, so I’m going to quickly explain a simple Kivy layout I created, the SparseGridLayout. The post is standalone, but would go well with ideas from my Kivy Crash Course, especially the recent videos trying to draw ideas together to make widgets or specifically focusing on layouts.

The point here is that Kivy has a built in GridLayout, but it doesn’t cover all use cases for widgets in a grid, which is sometimes confusing to users who’ve seen grid widgets in other places and expected a slightly different behaviour. The problem is that the GridLayout fills widgets in from the top. That means for instance if there are 3 columns, you can’t place a widget in the third row without first adding 6 widgets to fill the first two rows. That’s just inefficient and wasteful if all you wanted was a small number of widgets in a grid.

So, my SparseGridLayout is a very simple layout that has a number of rows or columns, and checks its children for a row and column property. It then resizes them automatically to be placed in the right grid cell. That means we don’t need any extra widgets, which is much more efficient if we want a grid with not many entries, hence sparse grid layout.

We can start with a FloatLayout base, then all we need to do is set our grid children’s size_hint and pos_hint properties appropriately for the grid and call the FloatLayout‘s normal layout method to actually place them in the grid positions/shapes for us.

We can start by making our layout class:

from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ReferenceListProperty

class SparseGridLayout(FloatLayout):
    rows = NumericProperty(1)
    columns = NumericProperty(1)
    shape = ReferenceListProperty(rows, columns)

That creates a basic class that doesn’t have any more actual behavior than the FloatLayout alone, but has a few new properties. It’ll hopefully all make sense if you’ve used Kivy a little or followed my crash course, though the ReferenceListProperty may be new - this takes multiple other properties and lets us access them as a list, so for instance referencing or setting shape[0] really updates the rows property, including calling all its associated events etc.. At the same time, the shape is also a real property, with its own events. Do experiment with this if the explanation is not clear.

Now, to make our layout actually rearrange its children to the grid, we need to override its do_layout method, which is what’s called whenever it or its children are updated.

def do_layout(self, *args):
    shape_hint = (1. / self.columns, 1. / self.rows)
    for child in self.children:
        child.size_hint = shape_hint
        if not hasattr(child, 'row'):
            child.row = 0
        if not hasattr(child, 'column'):
            child.column = 0

        child.pos_hint = {'x': shape_hint[0] * child.row,
                          'y': shape_hint[1] * child.column}
    super(SparseGridLayout, self).do_layout(*args)

This iterates over all the SparseGridLayout‘s children, setting their size_hint so that they’ll fit exactly in a grid cell (as per the rows and columns properties we set above). It then checks if they have a row or column property, setting it to 0 if not - I’ve chosen that my rows and columns should be zero-indexed, you could modify that if you like. After that, it sets their pos_hint such that they’re placed in the right place. I’ve deliberately let this work with floats, so for instance they could be in column 2.5 to be halfway between the integer columns, so the layout is extra flexible.

The final step is calling the original do_layout method of the FloatLayout. The magic is that all we did is set the child widgets size_hint and pos_hint so that the widgets align to a grid - the FloatLayout itself already knows how to actually set their positions and sizes based on this information. By making use of Kivy’s existing layout abilities, we’ve saved ourself a lot of work.

Finally, I also added a class to represent entries in the grid:

class GridEntry(EventDispatcher):
    row = NumericProperty(0)
    column = NumericProperty(0)

This is very simple, but it means you can do for example:

class GridLabel(Label, GridEntry):
    pass

The GridLabel is thereby a Label that already has row and column properties, so it will behave properly in our SparseGridLayout. We don’t strictly need to do this, we could add the row and column any other way, but this is neat and makes it totally clear what we’re using our widgets for.

That’s everything! With just a few simple modifications we’ve made a whole new Layout widget that can place its children in rows and columns of a grid. Maybe you’ll find that useful, but more generally I hope this demonstrates the general principles of thinking about Layouts and using Kivy’s existing mechanisms to do most of the work.

You can find all this code at my sparsegridlayout github repository, which also includes a simple demonstration App so you can test the new layout if you like.

Creating a Kivy layout: the SparseGridLayout

I thought for a change I’d try for a shorter post on a single quick subject, so I’m going to quickly explain a simple Kivy layout I created, the SparseGridLayout. The post is standalone, but would go well with ideas from my Kivy Crash Course, especially the recent videos trying to draw ideas together to make widgets or specifically focusing on layouts.

The point here is that Kivy has a built in GridLayout, but it doesn’t cover all use cases for widgets in a grid, which is sometimes confusing to users who’ve seen grid widgets in other places and expected a slightly different behaviour. The problem is that the GridLayout fills widgets in from the top. That means for instance if there are 3 columns, you can’t place a widget in the third row without first adding 6 widgets to fill the first two rows. That’s just inefficient and wasteful if all you wanted was a small number of widgets in a grid.

So, my SparseGridLayout is a very simple layout that has a number of rows or columns, and checks its children for a row and column property. It then resizes them automatically to be placed in the right grid cell. That means we don’t need any extra widgets, which is much more efficient if we want a grid with not many entries, hence sparse grid layout.

We can start with a FloatLayout base, then all we need to do is set our grid children’s size_hint and pos_hint properties appropriately for the grid and call the FloatLayout‘s normal layout method to actually place them in the grid positions/shapes for us.

We can start by making our layout class:

from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ReferenceListProperty

class SparseGridLayout(FloatLayout):
    rows = NumericProperty(1)
    columns = NumericProperty(1)
    shape = ReferenceListProperty(rows, columns)

That creates a basic class that doesn’t have any more actual behavior than the FloatLayout alone, but has a few new properties. It’ll hopefully all make sense if you’ve used Kivy a little or followed my crash course, though the ReferenceListProperty may be new - this takes multiple other properties and lets us access them as a list, so for instance referencing or setting shape[0] really updates the rows property, including calling all its associated events etc.. At the same time, the shape is also a real property, with its own events. Do experiment with this if the explanation is not clear.

Now, to make our layout actually rearrange its children to the grid, we need to override its do_layout method, which is what’s called whenever it or its children are updated.

def do_layout(self, *args):
    shape_hint = (1. / self.columns, 1. / self.rows)
    for child in self.children:
        child.size_hint = shape_hint
        if not hasattr(child, 'row'):
            child.row = 0
        if not hasattr(child, 'column'):
            child.column = 0

        child.pos_hint = {'x': shape_hint[0] * child.row,
                          'y': shape_hint[1] * child.column}
    super(SparseGridLayout, self).do_layout(*args)

This iterates over all the SparseGridLayout‘s children, setting their size_hint so that they’ll fit exactly in a grid cell (as per the rows and columns properties we set above). It then checks if they have a row or column property, setting it to 0 if not - I’ve chosen that my rows and columns should be zero-indexed, you could modify that if you like. After that, it sets their pos_hint such that they’re placed in the right place. I’ve deliberately let this work with floats, so for instance they could be in column 2.5 to be halfway between the integer columns, so the layout is extra flexible.

The final step is calling the original do_layout method of the FloatLayout. The magic is that all we did is set the child widgets size_hint and pos_hint so that the widgets align to a grid - the FloatLayout itself already knows how to actually set their positions and sizes based on this information. By making use of Kivy’s existing layout abilities, we’ve saved ourself a lot of work.

Finally, I also added a class to represent entries in the grid:

class GridEntry(EventDispatcher):
    row = NumericProperty(0)
    column = NumericProperty(0)

This is very simple, but it means you can do for example:

class GridLabel(Label, GridEntry):
    pass

The GridLabel is thereby a Label that already has row and column properties, so it will behave properly in our SparseGridLayout. We don’t strictly need to do this, we could add the row and column any other way, but this is neat and makes it totally clear what we’re using our widgets for.

That’s everything! With just a few simple modifications we’ve made a whole new Layout widget that can place its children in rows and columns of a grid. Maybe you’ll find that useful, but more generally I hope this demonstrates the general principles of thinking about Layouts and using Kivy’s existing mechanisms to do most of the work.

You can find all this code at my sparsegridlayout github repository, which also includes a simple demonstration App so you can test the new layout if you like.

Kivy – Mouse cursor on Rapsberry Pi

It’s no news that kivy have been ported to Rapsberry Pi, it happened nearly a year ago, and works quite well, especially if you start the app without an X server, since kivy draw directly to EGL (don’t ask me :)), it doesn’t need it.

However, there is a little issue about it if you don’t have a touch screen, you can use your mouse, but you don’t see any cursor, whever you are in X or not, because in X, kivy display is actually on top of the X cursor, and without X, nothing even try to draw a mouse cursor.

A few months ago, i wrote a quick hack, adding a few graphic instructions to the egl window provider, and made the probsys driver used on rpi directly update the position of this instruction. It worked, but it wasn’t really a general solution.

So after procrastinating a proper solution for a long time, i finally got my act together and added the cursor display as an option to the touchring module of kivy, along with options of what image to use, offsets and so on, and added the code that made the mouse driver dispatch pos to window’s mouse_pos property.

So here it is, you can find it here until the PR is merged.

Kivy – Mouse cursor on Rapsberry Pi

It’s no news that kivy have been ported to Rapsberry Pi, it happened nearly a year ago, and works quite well, especially if you start the app without an X server, since kivy draw directly to EGL (don’t ask me :)), it doesn’t need it.

However, there is a little issue about it if you don’t have a touch screen, you can use your mouse, but you don’t see any cursor, whever you are in X or not, because in X, kivy display is actually on top of the X cursor, and without X, nothing even try to draw a mouse cursor.

A few months ago, i wrote a quick hack, adding a few graphic instructions to the egl window provider, and made the probsys driver used on rpi directly update the position of this instruction. It worked, but it wasn’t really a general solution.

So after procrastinating a proper solution for a long time, i finally got my act together and added the cursor display as an option to the touchring module of kivy, along with options of what image to use, offsets and so on, and added the code that made the mouse driver dispatch pos to window’s mouse_pos property.

So here it is, you can find it here until the PR is merged.