Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The position function

Most widgets such as gtk::Box don’t use the position function because they are one-dimensional and place widgets relative to each other. However, a few widgets such as gtk::Grid use fixed positions and need the position function to work inside a factory.

The task of the position function is mainly to map the index to a certain position/area (x, y, width and height) of a factory widget within the parent widget (view).

The code we will use in this chapter is based on the grid_factory example here. Run cargo run --example grid_factory from the example directory if you want to see the code in action.

How it works

Let’s take a grid as an example. For a grid, there are many possibilities to place your widgets. You can, for example, place three, four or five widgets per row or you could place a certain amount of widgets per column. You can even create patterns like a chess grid if you want to.

However, we want to use a factory for generating our widgets, which means we only have the index to calculate the desired two-dimensional position. In the simplest case, we create a layout that places a certain amount of widgets per row or per column.

To place three elements per row from left to right in a gtk::Grid we could use the following position function.

    fn position(&self, index: &usize) -> GridPosition {
        let index = *index as i32;

        let row = index / 3;
        let column = index % 3;

        GridPosition {
            column,
            row,
            width: 1,
            height: 1,
        }
    }

And indeed, it works as expected.

A chess grid

Let’s have a look at a more complex layout. It’s unlikely that this would be used in a real application, but it’s still interesting to have a look at it.

To create a chess grid layout, we need to place our widgets only on fields of one color and leave the other fields empty.

Actually, the code isn’t too complicated.

    fn position(&self, index: &usize) -> GridPosition {
        let index = *index as i32;

        // add a new row for every 5 elements
        let row = index / 5;
        // use every second column and move columns in uneven rows by 1
        let column = (index % 5) * 2 + row % 2;

        GridPosition {
            column,
            row,
            width: 1,
            height: 1,
        }
    }

And as you can see, it works!