bevyengine / bevyengine/bevy

Grid alignment ergonomics pitfall

Open
#19,272 2 comments 0 reactions 0 assignees View on GitHub
A-UI C-Feature S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

I want to spawn a grid with two columns, one right-aligned and one left-aligned. This is a very common use case, e.g. for a [credits screen](https://github.com/TheBevyFlock/bevy_new_2d/blob/d5c50ea75d712d9b5f91de061d634f399723d841/src/screens/credits.rs#L48) or [settings menu](https://github.com/TheBevyFlock/bevy_new_2d/blob/d5c50ea75d712d9b5f91de061d634f399723d841/src/screens/settings.rs#L31). The recommended approach in CSS is to use selectors and style cascading to overwrite _only_ the `justify-self` property on the appropriate grid items:

```css
.grid > :nth-child(2) {
justify-self: end;
}
```

However, this does not translate to Bevy, where properties live in a monolithic `Node` component with no support for selectors or style cascading. You have to set the properties manually on spawn instead:

```rust
fn grid() -> impl Bundle {
(
Node { display: Display::Grid, ..default() },
children![
(Node { justify-self: JustifySelf::End, ..default() }, ...),
(Node { justify-self: JustifySelf::Start, ..default() }, ...),
(Node { justify-self: JustifySelf::End, ..default() }, ...),
(Node { justify-self: JustifySelf::Start, ..default() }, ...),
],
)
}
```

Unfortunately, this approach destroys reusability, because there's no way to do something like this:

```rust
fn grid() -> impl Bundle {
(
Node { display: Display::Grid, ..default() },
children![
widget::label(...).with_justify_self(JustifySelf::End),
widget::button(...).with_justify_self(JustifySelf::Start),
widget::container(...).with_justify_self(JustifySelf::End),
widget::color_picker(...).with_justify_self(JustifySelf::Start),
],
)
}
```

And even if you could, this type of code is a major pain to tweak (e.g. add a column, change a column's alignment, rearrange grid items, etc.). Plus, if you make changes like spawning or despawning grid items after the initial spawn, the column alignment will break.

To fix these issues, you could define a custom `GridAlignment { rows: Vec, columns: Vec }` component and a system to keep grid items in sync.

However, this leads to another problem: Between template tracks and explicit grid placement, how can you determine which rows/columns a grid item spans? Luckily this is already solved internally by `taffy`, and the computed information is [provided](https://github.com/DioxusLabs/taffy/pull/772) -- but Bevy doesn't expose this yet.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.