# Anchor layout

> Free positions like a form designer, with anchors that follow resizes. A Pyzed component for Python desktop GUIs, with examples and its API.

Source: https://albakore.github.io/pyzed/library/anchor-layout/

:::tip[In plain words]
Places things exactly where you put them, and says which corner each one sticks to when the window grows.
:::

Places children at exact positions, the way a visual form designer does, and says how each one follows a resize: `pz.anchor(child, x=, y=, width=, height=, anchor=)` keeps the distance to the edges it is anchored to, stretches between opposite edges and stays centered otherwise. Presets such as `"top_right"`, `"bottom_wide"`, `"center"` or `"full"` cover the usual cases. `pyzed.anchors.place` is the math behind it, for your own layouts.

`pz.anchor_layout` · Category: [Layout](https://albakore.github.io/pyzed/library/#layout) · [Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor_layout)

**Code:**

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([
    pz.anchor(ui.heading("Report", level=3), x=16, y=12, width=200, height=28, anchor="top_left"),
    pz.anchor(ui.icon_button("x", on_close), x=356, y=12, width=28, height=28, anchor="top_right"),
    pz.anchor(ui.input("", on_input, placeholder="Search…"), x=16, y=56, width=368, height=30,
              anchor="top_wide"),
    pz.anchor(ui.button("Close", on_close, variant="solid"), x=284, y=172, width=100, height=30,
              anchor="bottom_right"),
], design=(400, 216)), width=400, height=216, bg=t.panel, border_color=t.border, border_width=1, radius=8)
```

:::note[New]
This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues).
:::

## When to use

- For forms drawn in Pyzed Design (it is what the Form view generates) or ported from Visual Basic, Qt Designer or WinForms.
- For game HUDs and overlays where things stick to corners.
- For forms that grow and shrink with the window, prefer `row`, `column` and `grid`.

## Usage

```python
import pyzed as pz
from pyzed import ui

class Report(pz.App):
    def view(self):
        return pz.anchor_layout([
            pz.anchor(ui.heading("Report"), x=16, y=12, width=368, height=28, anchor="top_wide"),
            pz.anchor(self.table(), x=16, y=48, width=368, height=196, anchor="full"),
            pz.anchor(ui.button("Close", self.close), x=284, y=252, width=100, height=32,
                      anchor="bottom_right"),
        ], design=(400, 300))
```

## Variants

:::note[About these captures]
Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks.
:::

### Presets

Each layout was designed at 110 × 44 and drawn at 260 × 110: the badge keeps its distance to the edges it is anchored to.

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(ui.badge("top_left"), x=10, y=10, width=90, height=24,
                                         anchor="top_left")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(ui.badge("top_right"), x=10, y=10, width=90, height=24,
                                         anchor="top_right")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(ui.badge("bottom_left"), x=10, y=10, width=90, height=24,
                                         anchor="bottom_left")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(ui.badge("bottom_right"), x=10, y=10, width=90, height=24,
                                         anchor="bottom_right")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(ui.badge("center"), x=10, y=10, width=90, height=24,
                                         anchor="center")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

### Stretching

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4),
                                         x=10, y=10, width=90, height=24, anchor="top_wide")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4),
                                         x=10, y=10, width=90, height=24, anchor="bottom_wide")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4),
                                         x=10, y=10, width=90, height=24, anchor="left_tall")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4),
                                         x=10, y=10, width=90, height=24, anchor="center_wide")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

```python
t = pz.theme.current()
pz.container(pz.anchor_layout([pz.anchor(pz.container(width="fill", height="fill", bg=t.accent, radius=4),
                                         x=10, y=10, width=90, height=24, anchor="full")], design=(110, 44)),
             width=260, height=110, border_color=t.border, border_width=1, radius=8)
```

## Events

Anchor layout has no events of its own: it shows what you give it. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/).

## Tips

:::tip
`design` is the size the positions were measured in; when the layout gets more or less room, each child moves or stretches from there. Try it live: drag the window corner of a form in Pyzed Design.
:::

## Properties and API

### `pz.anchor_layout`

```python
anchor_layout(children, *, design=None, width='fill', height='fill')
```

Places children made with `pz.anchor` freely, like a designed form: when it is resized, each child keeps its distance to the edges it is anchored to, stretches between opposite ones and stays centered otherwise. Later children are drawn on top. See [Anchored layouts](https://albakore.github.io/pyzed/guides/layout/#anchored-layouts).

| Property | Default | Description |
| --- | --- | --- |
| `children` | *required* | Children made with `pz.anchor(...)` (`None` is skipped). |
| `design` | `None` | `(width, height)` the children were laid out in; by default the smallest size that holds them. |
| `width` | `"fill"` | Width. |
| `height` | `"fill"` | Height. |

[Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor_layout)

### `pz.anchor`

```python
anchor(
    content,
    *,
    x=0,
    y=0,
    width=100,
    height=28,
    anchor='top_left',
    min_width=0,
    min_height=0,
    max_width=0,
    max_height=0,
    pivot=(0.5, 0.5),
    rotate=0,
)
```

Places a child of `pz.anchor_layout` at `x`, `y` with `width` and `height` (in the layout's design size) and says how it follows a resize.

| Property | Default | Description |
| --- | --- | --- |
| `content` | *required* | The widget. |
| `x` | `0` | Left edge in the design size. |
| `y` | `0` | Top edge in the design size. |
| `width` | `100` | Width in the design size. |
| `height` | `28` | Height in the design size. |
| `anchor` | `"top_left"` | A preset of `pyzed.anchors.PRESETS` (`"top_right"`, `"bottom_wide"`, `"center"`, `"full"`...), words (`"left right bottom"`) or a tuple of edges. |
| `min_width` | `0` | Smallest width when it stretches (`0`: no limit). |
| `min_height` | `0` | Smallest height when it stretches. |
| `max_width` | `0` | Largest width when it stretches (`0`: no limit). |
| `max_height` | `0` | Largest height when it stretches. |
| `pivot` | `(0.5, 0.5)` | `(x, y)` from `0` to `1`: the point that stays put when a limit stops it, and that `rotate` turns around. |
| `rotate` | `0` | Degrees clockwise. |

[Full reference →](https://albakore.github.io/pyzed/reference/widgets/#anchor)

### `pz.anchors.place`

```python
place(
    rect,
    anchor,
    design,
    actual,
    *,
    min_size=(0, 0),
    max_size=(0, 0),
    pivot=(0.5, 0.5),
)
```

Where a box designed in a parent of size `design` goes in a parent of size `actual`, following its anchor, with size limits and a pivot. The math behind `pz.anchor_layout` and designed forms.

| Property | Default | Description |
| --- | --- | --- |
| `rect` | *required* | `(x, y, width, height)` in the design size. |
| `anchor` | *required* | A preset, words or edges. |
| `design` | *required* | The parent's design size. |
| `actual` | *required* | The parent's current size. |
| `min_size` | `(0, 0)` | `(width, height)` lower limits (`0`: none). |
| `max_size` | `(0, 0)` | `(width, height)` upper limits (`0`: none). |
| `pivot` | `(0.5, 0.5)` | The point that stays put when a limit stops the box from stretching. |

[Full reference →](https://albakore.github.io/pyzed/reference/widgets/#place)

## Related

- [Stack](https://albakore.github.io/pyzed/library/stack/): Layers children on top of each other; `pin` places one at x, y.
- [Grid](https://albakore.github.io/pyzed/library/grid/): Equal columns, or CSS-like tracks with spans.
- [Container](https://albakore.github.io/pyzed/library/container/): Size, padding, alignment, background, border and shadow for one child.
