Commit graph

11 commits

Author SHA1 Message Date
Derick M
0ac495f7f4
Remove accesskit re-export from bevy_a11y (#16257)
# Objective

- Fixes #16235 

## Solution

- Both Bevy and AccessKit export a `Node` struct, to reduce confusion
Bevy will no longer re-export `AccessKit` from `bevy_a11y`

## Testing

- Tested locally

## Migration Guide

```diff
# main.rs
--    use bevy_a11y::{
--        accesskit::{Node, Rect, Role},
--        AccessibilityNode,
--    };
++    use bevy_a11y::AccessibilityNode;
++    use accesskit::{Node, Rect, Role};

# Cargo.toml
++    accesskit = "0.17"
```

- Users will need to add `accesskit = "0.17"` to the dependencies
section of their `Cargo.toml` file and update their `accesskit` use
statements to come directly from the external crate instead of
`bevy_a11y`.
- Make sure to keep the versions of `accesskit` aligned with the
versions Bevy uses.
2024-11-08 21:01:16 +00:00
Nolan Darilek
817f160d35
Bump accesskit and accesskit_winit. (#16234)
# Objective

- Bumps accesskit and accesskit_winit dependencies

## Solution

- Fixes several breaking API changes introduced in accesskit 0.23.

## Testing

- Tested with the ui example and seems to work comparably
2024-11-04 20:07:38 +00:00
Carter Anderson
015f2c69ca
Merge Style properties into Node. Use ComputedNode for computed properties. (#15975)
# Objective

Continue improving the user experience of our UI Node API in the
direction specified by [Bevy's Next Generation Scene / UI
System](https://github.com/bevyengine/bevy/discussions/14437)

## Solution

As specified in the document above, merge `Style` fields into `Node`,
and move "computed Node fields" into `ComputedNode` (I chose this name
over something like `ComputedNodeLayout` because it currently contains
more than just layout info. If we want to break this up / rename these
concepts, lets do that in a separate PR). `Style` has been removed.

This accomplishes a number of goals:

## Ergonomics wins

Specifying both `Node` and `Style` is now no longer required for
non-default styles

Before:
```rust
commands.spawn((
    Node::default(),
    Style {
        width:  Val::Px(100.),
        ..default()
    },
));
```

After:

```rust
commands.spawn(Node {
    width:  Val::Px(100.),
    ..default()
});
```

## Conceptual clarity

`Style` was never a comprehensive "style sheet". It only defined "core"
style properties that all `Nodes` shared. Any "styled property" that
couldn't fit that mold had to be in a separate component. A "real" style
system would style properties _across_ components (`Node`, `Button`,
etc). We have plans to build a true style system (see the doc linked
above).

By moving the `Style` fields to `Node`, we fully embrace `Node` as the
driving concept and remove the "style system" confusion.

## Next Steps

* Consider identifying and splitting out "style properties that aren't
core to Node". This should not happen for Bevy 0.15.

---

## Migration Guide

Move any fields set on `Style` into `Node` and replace all `Style`
component usage with `Node`.

Before:
```rust
commands.spawn((
    Node::default(),
    Style {
        width:  Val::Px(100.),
        ..default()
    },
));
```

After:

```rust
commands.spawn(Node {
    width:  Val::Px(100.),
    ..default()
});
```

For any usage of the "computed node properties" that used to live on
`Node`, use `ComputedNode` instead:

Before:
```rust
fn system(nodes: Query<&Node>) {
    for node in &nodes {
        let computed_size = node.size();
    }
}
```

After:
```rust
fn system(computed_nodes: Query<&ComputedNode>) {
    for computed_node in &computed_nodes {
        let computed_size = computed_node.size();
    }
}
```
2024-10-18 22:25:33 +00:00
VitalyR
eb19a9ea0b
Migrate UI bundles to required components (#15898)
# Objective

- Migrate UI bundles to required components, fixes #15889

## Solution

- deprecate `NodeBundle` in favor of `Node`
- deprecate `ImageBundle` in favor of `UiImage`
- deprecate `ButtonBundle` in favor of `Button`

## Testing

CI.

## Migration Guide

- Replace all uses of `NodeBundle` with `Node`. e.g.
```diff
     commands
-        .spawn(NodeBundle {
-            style: Style {
+        .spawn((
+            Node::default(),
+            Style {
                 width: Val::Percent(100.),
                 align_items: AlignItems::Center,
                 justify_content: JustifyContent::Center,
                 ..default()
             },
-            ..default()
-        })
+        ))
``` 
- Replace all uses of `ButtonBundle` with `Button`. e.g.
```diff
                     .spawn((
-                        ButtonBundle {
-                            style: Style {
-                                width: Val::Px(w),
-                                height: Val::Px(h),
-                                // horizontally center child text
-                                justify_content: JustifyContent::Center,
-                                // vertically center child text
-                                align_items: AlignItems::Center,
-                                margin: UiRect::all(Val::Px(20.0)),
-                                ..default()
-                            },
-                            image: image.clone().into(),
+                        Button,
+                        Style {
+                            width: Val::Px(w),
+                            height: Val::Px(h),
+                            // horizontally center child text
+                            justify_content: JustifyContent::Center,
+                            // vertically center child text
+                            align_items: AlignItems::Center,
+                            margin: UiRect::all(Val::Px(20.0)),
                             ..default()
                         },
+                        UiImage::from(image.clone()),
                         ImageScaleMode::Sliced(slicer.clone()),
                     ))
```
- Replace all uses of `ImageBundle` with `UiImage`. e.g.
```diff
-    commands.spawn(ImageBundle {
-        image: UiImage {
+    commands.spawn((
+        UiImage {
             texture: metering_mask,
             ..default()
         },
-        style: Style {
+        Style {
             width: Val::Percent(100.0),
             height: Val::Percent(100.0),
             ..default()
         },
-        ..default()
-    });
+    ));
 ```

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-10-17 21:11:02 +00:00
ickshonpe
6f7d0e5725
split up TextStyle (#15857)
# Objective

Currently text is recomputed unnecessarily on any changes to its color,
which is extremely expensive.

## Solution
Split up `TextStyle` into two separate components `TextFont` and
`TextColor`.

## Testing

I added this system to `many_buttons`:
```rust
fn set_text_colors_changed(mut colors: Query<&mut TextColor>) {
    for mut text_color in colors.iter_mut() {
        text_color.set_changed();
    }
}
```

reports ~4fps on main, ~50fps with this PR.

## Migration Guide
`TextStyle` has been renamed to `TextFont` and its `color` field has
been moved to a separate component named `TextColor` which newtypes
`Color`.
2024-10-13 17:06:22 +00:00
UkoeHB
c2c19e5ae4
Text rework (#15591)
**Ready for review. Examples migration progress: 100%.**

# Objective

- Implement https://github.com/bevyengine/bevy/discussions/15014

## Solution

This implements [cart's
proposal](https://github.com/bevyengine/bevy/discussions/15014#discussioncomment-10574459)
faithfully except for one change. I separated `TextSpan` from
`TextSpan2d` because `TextSpan` needs to require the `GhostNode`
component, which is a `bevy_ui` component only usable by UI.

Extra changes:
- Added `EntityCommands::commands_mut` that returns a mutable reference.
This is a blocker for extension methods that return something other than
`self`. Note that `sickle_ui`'s `UiBuilder::commands` returns a mutable
reference for this reason.

## Testing

- [x] Text examples all work.

---

## Showcase

TODO: showcase-worthy

## Migration Guide

TODO: very breaking

### Accessing text spans by index

Text sections are now text sections on different entities in a
hierarchy, Use the new `TextReader` and `TextWriter` system parameters
to access spans by index.

Before:
```rust
fn refresh_text(mut query: Query<&mut Text, With<TimeText>>, time: Res<Time>) {
    let text = query.single_mut();
    text.sections[1].value = format_time(time.elapsed());
}
```

After:
```rust
fn refresh_text(
    query: Query<Entity, With<TimeText>>,
    mut writer: UiTextWriter,
    time: Res<Time>
) {
    let entity = query.single();
    *writer.text(entity, 1) = format_time(time.elapsed());
}
```

### Iterating text spans

Text spans are now entities in a hierarchy, so the new `UiTextReader`
and `UiTextWriter` system parameters provide ways to iterate that
hierarchy. The `UiTextReader::iter` method will give you a normal
iterator over spans, and `UiTextWriter::for_each` lets you visit each of
the spans.

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-10-09 18:35:36 +00:00
Tim
d454db8e58
Rename the Pickable component and fix incorrect documentation (#15707)
# Objective

- Rename `Pickable` to `PickingBehavior` to counter the easily-made
assumption that the component is required. It is optional
- Fix and clarify documentation
- The docs in `crates/bevy_ui/src/picking_backend.rs` were incorrect
about the necessity of `Pickable`
- Plus two minor code quality changes in this commit
(7c2e75f48d)

Closes #15632
2024-10-07 17:09:57 +00:00
Joona Aalto
25bfa80e60
Migrate cameras to required components (#15641)
# Objective

Yet another PR for migrating stuff to required components. This time,
cameras!

## Solution

As per the [selected
proposal](https://hackmd.io/tsYID4CGRiWxzsgawzxG_g#Combined-Proposal-1-Selected),
deprecate `Camera2dBundle` and `Camera3dBundle` in favor of `Camera2d`
and `Camera3d`.

Adding a `Camera` without `Camera2d` or `Camera3d` now logs a warning,
as suggested by Cart [on
Discord](https://discord.com/channels/691052431525675048/1264881140007702558/1291506402832945273).
I would personally like cameras to work a bit differently and be split
into a few more components, to avoid some footguns and confusing
semantics, but that is more controversial, and shouldn't block this core
migration.

## Testing

I ran a few 2D and 3D examples, and tried cameras with and without
render graphs.

---

## Migration Guide

`Camera2dBundle` and `Camera3dBundle` have been deprecated in favor of
`Camera2d` and `Camera3d`. Inserting them will now also insert the other
components required by them automatically.
2024-10-05 01:59:52 +00:00
Clar Fon
efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00
Piefayth
1d9ee56457
Fix horizontal scrolling in scroll example for macOS (#15407)
# Objective
Fixes #15401

## Solution
Changes the scroll inversion hotkey in the example from Shift to
Control.

Shift is idiomatic for this. Since we cannot use Shift per #15401, I
picked another modifier arbitrarily. A production app would handle this
in a platform specific way until the platform behaviors are unified
upstream, but no point here.

## Testing
I don't have a mac readily available for testing, if someone wouldn't
mind testing. I would also appreciate confirmation that trackpad is
working nicely.
2024-09-24 11:40:54 +00:00
Piefayth
55dddaf72e
UI Scrolling (#15291)
# Objective

- Fixes #8074 
- Adopts / Supersedes #8104

## Solution

Adapted from #8104 and affords the same benefits.

**Additions**
- [x] Update scrolling on relayout (height of node or contents may have
changed)
- [x] Make ScrollPosition component optional for ui nodes to avoid
checking every node on scroll
- [x] Nested scrollviews

**Omissions**
- Removed input handling for scrolling from `bevy_ui`. Users should
update `ScrollPosition` directly.

### Implementation

Adds a new `ScrollPosition` component. Updating this component on a
`Node` with an overflow axis set to `OverflowAxis::Scroll` will
reposition its children by that amount when calculating node transforms.
As before, no impact on the underlying Taffy layout.

Calculating this correctly is trickier than it was in #8104 due to
`"Update scrolling on relayout"`.

**Background**

When `ScrollPosition` is updated directly by the user, it can be
trivially handled in-engine by adding the parent's scroll position to
the final location of each child node. However, _other layout actions_
may result in a situation where `ScrollPosition` needs to be updated.
Consider a 1000 pixel tall vertically scrolling list of 100 elements,
each 100 pixels tall. Scrolled to the bottom, the
`ScrollPosition.offset_y` is 9000, just enough to display the last
element in the list. When removing an element from that list, the new
desired `ScrollPosition.offset_y` is 8900, but, critically, that is not
known until after the sizes and positions of the children of the
scrollable node are resolved.

All user scrolling code today handles this by delaying the resolution by
one frame. One notable disadvantage of this is the inability to support
`WinitSettings::desktop_app()`, since there would need to be an input
AFTER the layout change that caused the scroll position to update for
the results of the scroll position update to render visually.

I propose the alternative in this PR, which allows for same-frame
resolution of scrolling layout.

**Resolution**

_Edit: Below resolution is outdated, and replaced with the simpler usage
of taffy's `Layout::content_size`._

When recursively iterating the children of a node, each child now
returns a `Vec2` representing the location of their own bottom right
corner. Then, `[[0,0, [x,y]]` represents a bounding box containing the
scrollable area filled by that child. Scrollable parents aggregate those
areas into the bounding box of _all_ children, then consider that result
against `ScrollPosition` to ensure its validity.

In the event that resolution of the layout of the children invalidates
the `ScrollPosition` (e.g. scrolled further than there were children to
scroll to), _all_ children of that node must be recursively
repositioned. The position of each child must change as a result of the
change in scroll position.

Therefore, this implementation takes care to only spend the cost of the
"second layout pass" when a specific node actually had a
`ScrollPosition` forcibly updated by the layout of its children.


## Testing

Examples in `ui/scroll.rs`. There may be more complex node/style
interactions that were unconsidered.

---

## Showcase



![scroll](https://github.com/user-attachments/assets/1331138f-93aa-4a8f-959c-6be18a04ff03)

## Alternatives

- `bevy_ui` doesn't support scrolling.
- `bevy_ui` implements scrolling with a one-frame delay on reactions to
layout changes.
2024-09-23 17:17:58 +00:00