# State Layer API
The state layer system provides declarative style overrides based on widget interaction state.
## Overview
State layers let containers define how they should look when:
- **Hovered** - Mouse cursor is over the widget
- **Pressed** - Mouse button is held down on the widget
- **Focused** - The keyboard focus is inside the widget
- **Disabled** - The widget, or something above it, was declared `enabled(false)` — see [Disabling a Subtree](disabled.md)
Changes are defined declaratively, and the framework handles state transitions, animations, and rendering.
## Basic Usage
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
.background(Color::rgb(0.2, 0.2, 0.3))
.corners(8.0)
.when_hovered(|s| s.lighter(0.1)) // Style when hovered
.when_pressed(|s| s.ripple()) // Style when pressed
.child(text("Click me"))
# ;
# }
```
## Available Overrides
State layers can override these properties:
### Background
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
# container()
// Explicit color
.when_hovered(|s| s.background(Color::rgb(0.4, 0.6, 0.9)))
// Relative to base
.when_hovered(|s| s.lighter(0.1)) // 10% lighter
.when_pressed(|s| s.darker(0.1)) // 10% darker
# ;
# }
```
On a container with a gradient, `lighter`, `darker` and `alpha` apply to both
of its ends, and an explicit `background` replaces the gradient while the state
is active.
### Border
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
# container()
.when_hovered(|s| s.border(2.0, Color::WHITE)) // both halves, always
# ;
# }
```
### Transform
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
# container()
.when_pressed(|s| s.scale(0.98))
# ;
# }
```
### Corner Radius
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
# container()
.when_hovered(|s| s.corners(12.0))
# ;
# }
```
### Shadow
```rust
# extern crate guido;
# use guido::prelude::*;
# const LOW: Shadow = Shadow::simple((0.0, 1.0), 3.0, Color::rgba(0.0, 0.0, 0.0, 0.12));
# const HIGH: Shadow = Shadow::simple((0.0, 6.0), 10.0, Color::rgba(0.0, 0.0, 0.0, 0.22));
# fn main() {
# container()
.when_hovered(|s| s.shadow(HIGH))
.when_pressed(|s| s.shadow(LOW))
# ;
# }
```
### Ripple
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
# container()
.when_pressed(|s| s.ripple())
.when_pressed(|s| s.ripple_with_color(Color::rgba(1.0, 0.8, 0.0, 0.4)))
# ;
# }
```
## Combining Overrides
Chain multiple overrides in a single state:
```rust
# extern crate guido;
# use guido::prelude::*;
# const RAISED: Shadow = Shadow::simple((0.0, 3.0), 6.0, Color::rgba(0.0, 0.0, 0.0, 0.19));
# fn main() {
# container()
.when_hovered(|s| s
.lighter(0.1)
.border(2.0, Color::WHITE)
.shadow(RAISED)
)
.when_pressed(|s| s
.ripple()
.darker(0.05)
.scale(0.98)
)
# ;
# }
```
## With Animations
The motion belongs to the property, declared once beside its base value. A
layer supplies a value for a property somebody else owns, and carries no timing
of its own — so a hover eases under whatever the base declared:
```rust
# extern crate guido;
# use guido::prelude::*;
# fn main() {
container()
.background(Color::rgb(0.3, 0.5, 0.8).transition(200.0))
.when_hovered(|s| s.lighter(0.15))
.when_pressed(|s| s.darker(0.1))
# ;
# }
```
Writing a timing on the override does not compile. It would be a declaration
that is legal and does nothing:
```rust,ignore
# // not compiled: the line is the mistake the paragraph above names.
.when_hovered(|s| s.background(HOT.transition(900.0))) // error
```
## Complete Example
```rust
# extern crate guido;
# use guido::prelude::*;
fn interactive_button(label: &str) -> Container {
container()
.padding(16.0)
// Each property carries its own motion
.background(Color::rgb(0.3, 0.5, 0.8).transition(200.0))
.corners(8.0)
.border(1.0.transition(150.0), Color::rgb(0.4, 0.6, 0.9))
.scale(Scale::NONE.transition(Transition::spring(SpringConfig::GENTLE)))
// State layers
.when_hovered(|s| s
.lighter(0.1)
.border(2.0, Color::rgb(0.5, 0.7, 1.0))
)
.when_pressed(|s| s
.ripple()
.darker(0.05)
.scale(0.98)
)
.child(container().child(text(label).color(Color::WHITE)))
}
# fn main() {}
```
## How It Works
Internally, `StateStyle` holds all possible overrides:
```rust,ignore
# // not compiled: a field listing of the real struct, whose halves
# // (`BackgroundOverride`, `BorderOverride`) are named without being built.
pub struct StateStyle {
pub background: Option<BackgroundOverride>,
// Both halves or neither: half a border is no border.
pub border: Option<BorderOverride>,
pub corners: Prop<Corners>,
pub translate: Prop<Translate>,
pub rotate: Prop<f32>,
pub scale: Prop<Scale>,
pub shadow: Prop<Shadow>,
pub alpha: Prop<f32>,
pub ripple: Option<RippleConfig>,
}
```
`RippleConfig` is in the prelude, because `ripple_config` takes one.
`BackgroundOverride` and `BorderOverride` are not: nothing asks you to build
either — `background`, `lighter`, `darker` and `border` take a colour and a
number and build them for you — so they stay in `guido::widgets`, for the rare
caller that reads a `StateStyle` back.
When the container paints, it checks the current state and applies overrides accordingly, blending with animations when configured.