guido 0.12.0

A reactive Rust GUI library using wgpu for Wayland layer shell widgets
Documentation
# Transform Basics

Learn the fundamental transform operations: translate, rotate, and scale.

## Translation

Move a widget by offset values:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .translate((20.0, 10.0))  // Move 20px right, 10px down
# ;
# }
```

Negative values move in the opposite direction:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .translate((-10.0, 0.0))  // Move 10px left
# ;
# }
```

### By Its Own Size

`Translate::relative` moves a widget by fractions of its own size — CSS's
`translateX(-100%)`. `-1.0` is one of its own widths:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .translate(Translate::relative(-1.0, 0.0))  // exactly its own width left
# ;
# }
```

The fraction is resolved against the size the container is laid out at, every
time it is painted, so it stays one width at any width — including one that
changes, and including the first frame, before anything has been measured.
Pixels and a fraction add, like CSS's `calc(8px - 100%)`:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .translate(Translate { x: 8.0, ..Translate::relative(-1.0, 0.0) })
# ;
# }
```

Reading the width back through a [`WidgetRef`](../advanced/widget-ref.md) and
translating by it is the other way to spell this, and the wrong one for a
slide: the width is still zero when an `entering_from` plays, and a width
change under a `transition` animates an offset that never changed. See
[animated transforms](animated.md#sliding-by-its-own-width).

## Rotation

Rotate a widget around its center (default):

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .rotate(45.0)  // Rotate 45 degrees clockwise
# ;
# }
```

Degrees, always, and the number is kept as written. A full turn is `360.0` and
not `0.0`, two turns are `720.0`, and nothing is normalised behind your back:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container().rotate(360.0);   // one full turn — animates as one
container().rotate(-90.0)   // a quarter turn anticlockwise
# ;
# }
```

That matters as soon as the angle is animated. See
[animated transforms](animated.md).

## Scale

### Uniform Scale

Scale equally in both dimensions:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container().scale(1.5);   // 150% size
container().scale(0.8)   // 80% size
# ;
# }
```

### Non-Uniform Scale

Scale differently on each axis:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container().scale((2.0, 0.5))  // 200% width, 50% height
# ;
# }
```

## Combining Them

Declare as many as you need on the same container. They apply in one fixed
order — **translate, then rotate, then scale** — whatever order you write them
in:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
    .rotate(30.0)
    .translate((50.0, 0.0))
    .scale(1.2)
# ;
# }
```

The order is fixed rather than taken from the call site so that two containers
that declare the same three values are the same shape. It is the order CSS uses
for its `translate` / `rotate` / `scale` properties, for the same reason.

Rotation and scale both happen about the [pivot](origins.md), which is the
centre of the container unless you say otherwise — so rotating about a corner is
`.pivot(Pivot::TOP_LEFT)`, not a translate-rotate-translate sandwich.

## Reactive Transforms

Transforms can use signals for dynamic updates:

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
let rotation = create_signal(0.0f32);

container()
    .rotate(rotation)
    .on_click(move || rotation.update(|r| *r += 45.0))
# ;
# }
```

When the signal changes, the container repaints. Nothing re-runs layout: all
three are paint-only, so the space the container was given does not move and
neither does anything around it.

## Complete Example

```rust
# extern crate guido;
# use guido::prelude::*;
fn transform_demo() -> impl Widget {
    let rotation = create_signal(0.0f32);
    let scale_factor = create_signal(1.0f32);

    container()
        .layout(Flex::row().spacing(20.0))
        .children([
            // Static rotation
            container()
                .width(60.0)
                .height(60.0)
                .background(Color::rgb(0.8, 0.3, 0.3))
                .corners(8.0)
                .rotate(45.0)
                .child(container().child(text("45°").color(Color::WHITE))),

            // Click to rotate
            container()
                .width(60.0)
                .height(60.0)
                .background(Color::rgb(0.3, 0.6, 0.8))
                .corners(8.0)
                .rotate(rotation)
                .when_hovered(|s| s.lighter(0.1))
                .on_click(move || rotation.update(|r| *r += 45.0))
                .child(container().child(text("Click").color(Color::WHITE))),

            // Click to scale
            container()
                .width(60.0)
                .height(60.0)
                .background(Color::rgb(0.3, 0.8, 0.4))
                .corners(8.0)
                .scale(scale_factor)
                .when_hovered(|s| s.lighter(0.1))
                .on_click(move || {
                    let new = if scale_factor.get() > 1.0 { 1.0 } else { 1.3 };
                    scale_factor.set(new);
                })
                .child(container().child(text("Scale").color(Color::WHITE))),
        ])
}
# fn main() {}
```

## API Reference

### Container Methods

All transform properties accept static values, signals, or closures. Integers also work (e.g., `.rotate(45)`, `.scale(2)`).

```rust,ignore
# // not compiled: a signature listing — these declarations have no bodies.
impl Container {
    pub fn translate<M>(self, t: impl IntoSignal<Translate, M>) -> Self;
    pub fn rotate<M>(self, degrees: impl IntoSignal<f32, M>) -> Self;
    pub fn scale<M>(self, factor: impl IntoSignal<Scale, M>) -> Self;
    pub fn pivot<M>(self, pivot: impl IntoSignal<Pivot, M>) -> Self;
}
```

### The Value Types

A pair builds either one; a bare number builds a uniform `Scale`.

```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
Translate::NONE;                  // no displacement
Translate::new(20.0, 10.0);       // or just (20.0, 10.0)
Translate::relative(-1.0, 0.0);   // one of its own widths left

Scale::NONE;                      // unscaled — 1.0 on both axes
Scale::uniform(1.5);              // or just 1.5
Scale::new(2.0, 0.5)             // or just (2.0, 0.5)
# ;
# }
```

There is no matrix in the application-facing API. The three components are what
an application declares, and a matrix is what they compose into on the way to
the renderer — a widget written outside the crate reaches it through
`guido::widget_prelude`.