bevyengine / bevyengine/bevy

`ScrollPositions` does not work on `Node` with `flex_direction` set to `RowReverse`

Open
#17,129 1 comment 0 reactions 0 assignees View on GitHub
A-UI C-Bug D-Straightforward S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version

v0.15

## \[Optional\] Relevant system information

```
2025-01-03T20:16:22.418810Z INFO bevy_diagnostic::system_information_diagnostics_plugin::internal: SystemInfo { os: "Linux 24.11 NixOS", kernel: "6.6.63", cpu: "Intel(R) Core(TM) i7-14700KF", core_count: "20", memory: "31.2 GiB" }
2025-01-03T20:16:22.566379Z INFO bevy_render::renderer: AdapterInfo { name: "NVIDIA GeForce RTX 4060 Ti", vendor: 4318, device: 10243, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "560.35.03", backend: Vulkan }
```

## What you did

Created a `Node` with `flex_direction` set to `RowReverse` or `ColumnReverse` and scrolling enabled, updated the value of the offset in `ScrollPosition`.

## What went wrong

Offsets of `ScrollPosition` are clamped to `0, 0` as if already scrolled to the end, when trying to scroll either way.

## Additional information

```rust
use bevy::{
app::{App, Startup, Update},
color::{palettes, Color},
prelude::{
BuildChildren, Camera2d, ChildBuild, ChildBuilder, Commands, Component, Local, Query, Text,
With, Without,
},
text::TextColor,
ui::{BackgroundColor, FlexDirection, Node, Overflow, ScrollPosition, Val},
DefaultPlugins,
};

#[derive(Component)]
struct Row;
#[derive(Component)]
struct Column;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (scroll_x, scroll_y))
.run();
}

fn setup(mut commands: Commands) {
commands.spawn(Camera2d);

let colors: &[Color] = &[
palettes::tailwind::BLUE_100.into(),
palettes::tailwind::GREEN_100.into(),
];

let row_spawner = |parent: &mut ChildBuilder, flex_direction, max_width| {
parent
.spawn((
Row,
Node {
max_width,
flex_direction,
overflow: Overflow::scroll_x(),
..Default::default()
},
))
.with_children(|parent| {
for i in 0..50 {
parent
.spawn((
Node {
min_width: Val::Px(50.),
min_height: Val::Px(50.),
justify_content: bevy::ui::JustifyContent::SpaceEvenly,
align_content: bevy::ui::AlignContent::SpaceEvenly,
..Default::default()
},
BackgroundColor(colors[i % 2]),
))
.with_child((Text::new(i.to_string()), TextColor(Color::BLACK)));
}
});
};
let col_spawner = |parent: &mut ChildBuilder, flex_direction, max_height| {
parent
.spawn((
Column,
Node {
max_height,
flex_direction,
overflow: Overflow::scroll_y(),
..Default::default()
},
))
.with_children(|parent| {
for i in 0..50 {
parent
.spawn((
Node {
min_width: Val::Px(50.),
min_height: Val::Px(50.),
justify_content: bevy::ui::JustifyContent::SpaceEvenly,
align_content: bevy::ui::AlignContent::SpaceEvenly,
..Default::default()
},
BackgroundColor(colors[i % 2]),
))
.with_child((Text::new(i.to_string()), TextColor(Color::BLACK)));
}
});
};
commands
.spawn(Node {
flex_direction: FlexDirection::Column,
..Default::default()
})
.with_children(|parent| {
row_spawner(parent, FlexDirection::Row, Val::Vw(50.));
row_spawner(parent, FlexDirection::RowReverse, Val::Vw(50.));
parent.spawn(Node::default()).with_children(|parent| {
col_spawner(parent, FlexDirection::Column, Val::Vh(50.));
col_spawner(parent, FlexDirection::ColumnReverse, Val::Vh(50.));
});
});
}

fn scroll_x(
mut rows: Query<&mut ScrollPosition, (With, Without)>,
mut local: Local,
) {
let f: fn(&mut f32) = if *local & 0x100 != 0 {
|x| *x -= 2.
} else {
|x| *x += 2.
};
for mut row in rows.iter_mut() {
f(&mut row.offset_x);
}
*local += 1;
}

fn scroll_y(
mut columns: Query<&mut ScrollPosition, (With, Without)>,
mut local: Local,
) {
let f: fn(&mut f32) = if *local & 0x100 != 0 {
|x| *x -= 2.
} else {
|x| *x += 2.
};
for mut column in columns.iter_mut() {
f(&mut column.offset_y);
}
*local += 1;
}
```

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.