Commit Graph

26 Commits

Author SHA1 Message Date
Vic
f57c7a43c4
reexport entity set collections in entity module (#18413)
# Objective

Unlike for their helper typers, the import paths for
`unique_array::UniqueEntityArray`, `unique_slice::UniqueEntitySlice`,
`unique_vec::UniqueEntityVec`, `hash_set::EntityHashSet`,
`hash_map::EntityHashMap`, `index_set::EntityIndexSet`,
`index_map::EntityIndexMap` are quite redundant.

When looking at the structure of `hashbrown`, we can also see that while
both `HashSet` and `HashMap` have their own modules, the main types
themselves are re-exported to the crate level.

## Solution

Re-export the types in their shared `entity` parent module, and simplify
the imports where they're used.
2025-03-30 03:51:14 +00:00
ickshonpe
300fe4db4d
Store UI render target info locally per node (#17579)
# Objective

It's difficult to understand or make changes to the UI systems because
of how each system needs to individually track changes to scale factor,
windows and camera targets in local hashmaps, particularly for new
contributors. Any major change inevitably introduces new scale factor
bugs.

Instead of per-system resolution we can resolve the camera target info
for all UI nodes in a system at the start of `PostUpdate` and then store
it per-node in components that can be queried with change detection.

Fixes #17578
Fixes #15143

## Solution

Store the UI render target's data locally per node in a component that
is updated in `PostUpdate` before any other UI systems run.

This component can be then be queried with change detection so that UI
systems no longer need to have knowledge of cameras and windows and
don't require fragile custom change detection solutions using local
hashmaps.

## Showcase
Compare `measure_text_system` from main (which has a bug the causes it
to use the wrong scale factor when a node's camera target changes):
```
pub fn measure_text_system(
    mut scale_factors_buffer: Local<EntityHashMap<f32>>,
    mut last_scale_factors: Local<EntityHashMap<f32>>,
    fonts: Res<Assets<Font>>,
    camera_query: Query<(Entity, &Camera)>,
    default_ui_camera: DefaultUiCamera,
    ui_scale: Res<UiScale>,
    mut text_query: Query<
        (
            Entity,
            Ref<TextLayout>,
            &mut ContentSize,
            &mut TextNodeFlags,
            &mut ComputedTextBlock,
            Option<&UiTargetCamera>,
        ),
        With<Node>,
    >,
    mut text_reader: TextUiReader,
    mut text_pipeline: ResMut<TextPipeline>,
    mut font_system: ResMut<CosmicFontSystem>,
) {
    scale_factors_buffer.clear();

    let default_camera_entity = default_ui_camera.get();

    for (entity, block, content_size, text_flags, computed, maybe_camera) in &mut text_query {
        let Some(camera_entity) = maybe_camera
            .map(UiTargetCamera::entity)
            .or(default_camera_entity)
        else {
            continue;
        };
        let scale_factor = match scale_factors_buffer.entry(camera_entity) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => *entry.insert(
                camera_query
                    .get(camera_entity)
                    .ok()
                    .and_then(|(_, c)| c.target_scaling_factor())
                    .unwrap_or(1.0)
                    * ui_scale.0,
            ),
        };

        if last_scale_factors.get(&camera_entity) != Some(&scale_factor)
            || computed.needs_rerender()
            || text_flags.needs_measure_fn
            || content_size.is_added()
        {
            create_text_measure(
                entity,
                &fonts,
                scale_factor.into(),
                text_reader.iter(entity),
                block,
                &mut text_pipeline,
                content_size,
                text_flags,
                computed,
                &mut font_system,
            );
        }
    }
    core::mem::swap(&mut *last_scale_factors, &mut *scale_factors_buffer);
}
```

with `measure_text_system` from this PR (which always uses the correct
scale factor):
```
pub fn measure_text_system(
    fonts: Res<Assets<Font>>,
    mut text_query: Query<
        (
            Entity,
            Ref<TextLayout>,
            &mut ContentSize,
            &mut TextNodeFlags,
            &mut ComputedTextBlock,
            Ref<ComputedNodeTarget>,
        ),
        With<Node>,
    >,
    mut text_reader: TextUiReader,
    mut text_pipeline: ResMut<TextPipeline>,
    mut font_system: ResMut<CosmicFontSystem>,
) {
    for (entity, block, content_size, text_flags, computed, computed_target) in &mut text_query {
        // Note: the ComputedTextBlock::needs_rerender bool is cleared in create_text_measure().
        if computed_target.is_changed()
            || computed.needs_rerender()
            || text_flags.needs_measure_fn
            || content_size.is_added()
        {
            create_text_measure(
                entity,
                &fonts,
                computed_target.scale_factor.into(),
                text_reader.iter(entity),
                block,
                &mut text_pipeline,
                content_size,
                text_flags,
                computed,
                &mut font_system,
            );
        }
    }
}
```

## Testing

I removed an alarming number of tests from the `layout` module but they
were mostly to do with the deleted camera synchronisation logic. The
remaining tests should all pass now.

The most relevant examples are `multiple_windows` and `split_screen`,
the behaviour of both should be unchanged from main.

---------

Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-02-10 07:27:58 +00:00
ickshonpe
89a1c49377
Fix Taffy viewport node leaks (#17596)
# Objective

For most UI node entities there's a 1-to-1 mapping from the entity to
its associated Taffy node. Root UI nodes are an exception though, their
corresponding Taffy node in the Taffy tree is also given a parent that
represents the viewport. These viewport Taffy nodes are not removed when
a root UI node is despawned.

Parenting of an existing root UI node with an associated viewport Taffy
node also results in the leak of the viewport node.

These tests fail if added to the `layout` module's tests on the main
branch:

```rust
    #[test]
    fn no_viewport_node_leak_on_root_despawned() {
        let (mut world, mut ui_schedule) = setup_ui_test_world();

        let ui_root_entity = world.spawn(Node::default()).id();

        // The UI schedule synchronizes Bevy UI's internal `TaffyTree` with the
        // main world's tree of `Node` entities.
        ui_schedule.run(&mut world);

        // Two taffy nodes are added to the internal `TaffyTree` for each root UI entity.
        // An implicit taffy node representing the viewport and a taffy node corresponding to the
        // root UI entity which is parented to the viewport taffy node.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            2
        );

        world.despawn(ui_root_entity);

        // The UI schedule removes both the taffy node corresponding to `ui_root_entity` and its
        // parent viewport node.
        ui_schedule.run(&mut world);

        // Both taffy nodes should now be removed from the internal `TaffyTree`
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            0
        );
    }

    #[test]
    fn no_viewport_node_leak_on_parented_root() {
        let (mut world, mut ui_schedule) = setup_ui_test_world();

        let ui_root_entity_1 = world.spawn(Node::default()).id();
        let ui_root_entity_2 = world.spawn(Node::default()).id();

        ui_schedule.run(&mut world);

        // There are two UI root entities. Each root taffy node is given it's own viewport node parent,
        // so a total of four taffy nodes are added to the `TaffyTree` by the UI schedule.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            4
        );

        // Parent `ui_root_entity_2` onto `ui_root_entity_1` so now only `ui_root_entity_1` is a
        // UI root entity.
        world
            .entity_mut(ui_root_entity_1)
            .add_child(ui_root_entity_2);

        // Now there is only one root node so the second viewport node is removed by
        // the UI schedule.
        ui_schedule.run(&mut world);

        // There is only one viewport node now, so the `TaffyTree` contains 3 nodes in total.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            3
        );
    }
```

Fixes #17594

## Solution

Change the `UiSurface::entity_to_taffy` to map to `LayoutNode`s. A
`LayoutNode` has a `viewport_id: Option<taffy::NodeId>` field which is
the id of the corresponding implicit "viewport" node if the node is a
root UI node, otherwise it is `None`. When removing or parenting nodes
this field is checked and the implicit viewport node is removed if
present.

## Testing

There are two new tests in `bevy_ui::layout::tests` included with this
PR:
* `no_viewport_node_leak_on_root_despawned`
* `no_viewport_node_leak_on_parented_root`
2025-02-02 15:03:10 +00:00
ickshonpe
d4356062bf
UiSurface::upsert_node refactor (#8831)
# Objective

Simplify the `UiSurface::upsert_node` method by directly matching on
HashMap entry states.
2025-01-28 18:05:59 +00:00
Alice Cecile
5a9bc28502
Support non-Vec data structures in relations (#17447)
# Objective

The existing `RelationshipSourceCollection` uses `Vec` as the only
possible backing for our relationships. While a reasonable choice,
benchmarking use cases might reveal that a different data type is better
or faster.

For example:

- Not all relationships require a stable ordering between the
relationship sources (i.e. children). In cases where we a) have many
such relations and b) don't care about the ordering between them, a hash
set is likely a better datastructure than a `Vec`.
- The number of children-like entities may be small on average, and a
`smallvec` may be faster

## Solution

- Implement `RelationshipSourceCollection` for `EntityHashSet`, our
custom entity-optimized `HashSet`.
-~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things
compile.~~
   -  This implementation was cursed and very surprising.
- Instead, by moving the iterator type on `RelationshipSourceCollection`
from an erased RPTIT to an explicit associated type we can add a trait
bound on the offending methods!
- Implement `RelationshipSourceCollection` for `SmallVec`

## Testing

I've added a pair of new tests to make sure this pattern compiles
successfully in practice!

## Migration Guide

`EntityHashSet` and `EntityHashMap` are no longer re-exported in
`bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s
`prelude`, you can access them through their now-public modules,
`hash_set` and `hash_map` instead.

## Notes to reviewers

The `EntityHashSet::Iter` type needs to be public for this impl to be
allowed. I initially renamed it to something that wasn't ambiguous and
re-exported it, but as @Victoronz pointed out, that was somewhat
unidiomatic.

In
1a8564898f,
I instead made the `entity_hash_set` public (and its `entity_hash_set`)
sister public, and removed the re-export. I prefer this design (give me
module docs please), but it leads to a lot of churn in this PR.

Let me know which you'd prefer, and if you'd like me to split that
change out into its own micro PR.
2025-01-20 21:26:08 +00:00
MichiRecRoom
8b4c25ad5f
bevy_ui: Apply #![deny(clippy::allow_attributes, clippy::allow_attributes_without_reason)] (#17229)
# Objective
- https://github.com/bevyengine/bevy/issues/17111

## Solution
Set the `clippy::allow_attributes` and
`clippy::allow_attributes_without_reason` lints to `deny`, and bring
`bevy_ui` in line with the new restrictions.

## Testing
`cargo clippy --tests` and `cargo test --package bevy_ui` were run, and
no errors were encountered.
2025-01-08 19:30:19 +00:00
ickshonpe
bfc2a88f94
Toggleable UI layout rounding (#16841)
# Objective

Allow users to enable or disable layout rounding for specific UI nodes
and their descendants.

Fixes #16731

## Solution

New component `LayoutConfig` that can be added to any UiNode entity.
Setting the `use_rounding` field of `LayoutConfig` determines if the
Node and its descendants should be given rounded or unrounded
coordinates.

## Testing

Not tested this extensively but it seems to work and it's not very
complicated.
This really basic test app returns fractional coords:

```rust
use bevy::prelude::*;

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

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d);
    commands.spawn((
        Node {
            left: Val::Px(0.1),
            width: Val::Px(100.1),
            height: Val::Px(100.1),
            ..Default::default()
        },
        LayoutConfig { use_rounding: false },
    ));
}

fn report(node: Query<(Ref<ComputedNode>, &GlobalTransform)>) {
    for (c, g) in node.iter() {
        if c.is_changed() {
            println!("{:#?}", c);
            println!("position = {:?}", g.to_scale_rotation_translation().2);
        }
    }
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-12-24 02:41:46 +00:00
homersimpsons
0707c0717b
✏️ Fix typos across bevy (#16702)
# Objective

Fixes typos in bevy project, following suggestion in
https://github.com/bevyengine/bevy-website/pull/1912#pullrequestreview-2483499337

## Solution

I used https://github.com/crate-ci/typos to find them.

I included only the ones that feel undebatable too me, but I am not in
game engine so maybe some terms are expected.

I left out the following typos:
- `reparametrize` => `reparameterize`: There are a lot of occurences, I
believe this was expected
- `semicircles` => `hemicircles`: 2 occurences, may mean something
specific in geometry
- `invertation` => `inversion`: may mean something specific
- `unparented` => `parentless`: may mean something specific
- `metalness` => `metallicity`: may mean something specific

## Testing

- Did you test these changes? If so, how? I did not test the changes,
most changes are related to raw text. I expect the others to be tested
by the CI.
- Are there any parts that need more testing? I do not think
- How can other people (reviewers) test your changes? Is there anything
specific they need to know? To me there is nothing to test
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

---

## Migration Guide

> This section is optional. If there are no breaking changes, you can
delete this section.

(kept in case I include the `reparameterize` change here)

- If this PR is a breaking change (relative to the last release of
Bevy), describe how a user might need to migrate their code to support
these changes
- Simply adding new functionality is not a breaking change.
- Fixing behavior that was definitely a bug, rather than a questionable
design choice is not a breaking change.

## Questions

- [x] Should I include the above typos? No
(https://github.com/bevyengine/bevy/pull/16702#issuecomment-2525271152)
- [ ] Should I add `typos` to the CI? (I will check how to configure it
properly)

This project looks awesome, I really enjoy reading the progress made,
thanks to everyone involved.
2024-12-08 01:18:39 +00:00
ickshonpe
05d90686fc
Remove custom rounding (#16097)
# Objective

Taffy added layout rounding a while ago but it had a couple of bugs and
caused some problems with the fussy `ab_glyph` text implementation. So I
disabled Taffy's builtin rounding and added some hacks ad hoc that fixed
(some) of those issues. Since then though Taffy's rounding algorithm has
improved while we've changed layout a lot and migrated to `cosmic-text`
so those hacks don't help any more and in some cases cause significant
problems.

Also our rounding implementation only rounds to the nearest logical
pixel, whereas Taffy rounds to the nearest physical pixel meaning it's
much more accurate with high dpi displays.

fixes #15197

## Some examples of layout rounding errors visible in the UI examples

These errors are much more obvious at high scale factor, you might not
see any problems at a scale factor of 1.

`cargo run --example text_wrap_debug`

<img width="1000" alt="text_debug_gaps"
src="https://github.com/user-attachments/assets/5a584016-b8e2-487b-8842-f0f359077391">

The narrow horizontal and vertical lines are gaps in the layout caused
by errors in the coordinate rounding.

`cargo run --example text_debug`

<img width="1000" alt="text_debug"
src="https://github.com/user-attachments/assets/a4b37c02-a2fd-441c-a7bd-cd7a1a72e7dd">

The two text blocks here are aligned right to the same boundary but in
this screen shot you can see that the lower block is one pixel off to
the left. Because the size of this text node changes between frames with
the reported framerate the rounding errors cause it to jump left and
right.

## Solution

Remove all our custom rounding hacks and reenable Taffy's layout
rounding.

The gaps in the `text_wrap_debug` example are gone:
<img width="1000" alt="text_wrap_debug_fix"
src="https://github.com/user-attachments/assets/92d2dd97-30c6-4ac8-99f1-6d65358995a7">

This doesn't fix some of the gaps that occur between borders and content
but they seem appear to be a rendering problem as they disappear with
`UiAntiAlias::Off` set.

## Testing

Run the examples as described above in the `Objective` section. With
this PR the problems mentioned shouldn't appear.

Also added an example in a separate PR #16096 `layout_rounding_debug`
for identifying these issues.

## Migration Guide

`UiSurface::get_layout` now also returns the final sizes before
rounding. Call `.0` on the `Ok` result to get the previously returned
`taffy::Layout` value.

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
2024-10-28 22:20:50 +00:00
Carter Anderson
7577895d0c
Use CosmicFontSystem in public bevy_text APIs and remove cosmic_text re-export (#16063)
# Objective

Fixes #16006

## Solution

We currently re-export `cosmic_text`, which is seemingly motivated by
the desire to use `cosmic_text::FontSystem` in `bevy_text` public APIs
instead of our `CosmicFontSystem` resource wrapper type.

This change makes `bevy_text` a "true" abstraction over `cosmic_text`
(it in fact, was already built to be that way generally and has this one
"leak").

This allows us to remove the `cosmic_text` re-export, which helps clean
up the Rust Analyzer imports and generally makes this a "cleaner" API.
2024-10-23 20:05:28 +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
ickshonpe
396aff906e
Remove bevy_ui's "bevy_text" feature (#15951)
# Objective

Remove `bevy-ui`'s non-functional "bevy_text" feature.

Fixes #15900

## Solution

Remove all the "bevy_text" cfg gates.

I tried to fix it at first but couldn't figure it out. I'll happily
withdraw this in favour of another PR that gets the feature gate
working.
2024-10-16 16:43:57 +00:00
Brett Striker
de08fb2afa
[bevy_ui/layout] Add tests, missing asserts, and missing debug fields for UiSurface (#12803)
This is 3 of 5 iterative PR's that affect bevy_ui/layout

- [x] Blocked by https://github.com/bevyengine/bevy/pull/12801
- [x] Blocked by https://github.com/bevyengine/bevy/pull/12802

---

# Objective

- Add tests to `UiSurface`
- Add missing asserts in `_assert_send_sync_ui_surface_impl_safe`
- Add missing Debug field print for `camera_entity_to_taffy`

## Solution

- Adds tests to `UiSurface`
- Adds missing asserts in `_assert_send_sync_ui_surface_impl_safe`
- Adds missing impl Debug field print for `camera_entity_to_taffy`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-10-15 14:06:17 +00:00
Viktor Gustavsson
5989a845f0
Filter UI traversal to only Node and GhostNode (#15746)
# Objective

With the warning removed in
https://github.com/bevyengine/bevy/pull/15736, the rules for the UI tree
changes.
We no longer need to traverse non `Node`/`GhostNode` entities.

## Solution

- Added a filter `Or<(With<Node>, With<GhostNode>)>` to the child
traversal query so we don't unnecessarily traverse nodes that are not
part of the UI tree (like text nodes).
- Also moved the warning for NoUI->UI entities so it is actually
triggered (see comments)

## Testing

- Ran unit tests (still passing)
- Ran the ghost_nodes and ui examples, still works and looks fine 👍 
- Tested the warning by spawning a Node under an empty entity.

---

---------

Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-10-13 17:25:15 +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
Alice Cecile
2f63ebc9c9
Remove warning for children in UI hierarchies without Style (#15736)
# Objective

As discussed in #15591, this warning prevents us from storing leaf nodes
without a `Style` component. Because text sections (as distinct
entities) should not be laid out using `taffy`, this warning is
incorrect.

Users may also have other uses for doing this, and this should generally
increase flexibility without posing particularly serious correctness
concerns.

## Solution

- removed warning about non-UI children with UI parents
- improved the warning about UI parents with non-UI parents
- this warning should stay, for now, as it results in a genuine failure
to perform `taffy` layout
- that said, we should be clearer about the cause and potentially
harmful results of this!
   
## Testing

I inserted an empty entity into the hierarchy in the `button` example as
a leaf node, and it ran with no warnings.
2024-10-08 19:51:47 +00:00
Viktor Gustavsson
f86ee32576
Add UI GhostNode (#15341)
# Objective

- Fixes #14826 
- For context, see #15238

## Solution
Add a `GhostNode` component to `bevy_ui` and update all the relevant
systems to use it to traverse for UI children.

- [x] `ghost_hierarchy` module
  - [x] Add `GhostNode`
- [x] Add `UiRootNodes` system param for iterating (ghost-aware) UI root
nodes
- [x] Add `UiChildren` system param for iterating (ghost-aware) UI
children
- [x] Update `layout::ui_layout_system`
  - [x] Use ghost-aware root nodes for camera updates
  - [x] Update and remove children in taffy
    - [x] Initial spawn
    - [x] Detect changes on nested UI children
- [x] Use ghost-aware children traversal in
`update_uinode_geometry_recursive`
- [x] Update the rest of the UI systems to use the ghost hierarchy
  - [x] `stack::ui_stack_system`
  - [x] `update::`
    - [x] `update_clipping_system`
    - [x] `update_target_camera_system`
  - [x] `accessibility::calc_name`

## Testing
- [x] Added a new example `ghost_nodes` that can be used as a testbed.
- [x] Added unit tests for _some_ of the traversal utilities in
`ghost_hierarchy`
- [x] Ensure this fulfills the needs for currently known use cases
  - [x] Reactivity libraries (test with `bevy_reactor`)
- [ ] Text spans (mentioned by koe [on
discord](https://discord.com/channels/691052431525675048/1285371432460881991/1285377442998915246))
  
---
## Performance
[See comment
below](https://github.com/bevyengine/bevy/pull/15341#issuecomment-2385456820)

## Migration guide
Any code that previously relied on `Parent`/`Children` to iterate UI
children may now want to use `bevy_ui::UiChildren` to ensure ghost nodes
are skipped, and their first descendant Nodes included.

UI root nodes may now be children of ghost nodes, which means
`Without<Parent>` might not query all root nodes. Use
`bevy_ui::UiRootNodes` where needed to iterate root nodes instead.

## Potential future work
- Benchmarking/optimizations of hierarchies containing lots of ghost
nodes
- Further exploration of UI hierarchies and markers for root nodes/leaf
nodes to create better ergonomics for things like `UiLayer` (world-space
ui)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-10-02 00:24:28 +00:00
Zachary Harrold
d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +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
UkoeHB
41474226c3
Optimize UI text measurement (#15003)
# Objective

- Avoid cloning the `CosmicBuffer` every time you create a new text
measurement.

## Solution

- Inject a buffer query when calculating layout so existing buffers can
be reused.

## Testing

- I tested the `text`, `text_debug`, and `text_wrap_debug` examples.
- I did not do a performance test.
2024-09-01 11:50:54 +00:00
BD103
cd497152bb
Fix error in bevy_ui when building without bevy_text (#14430)
# Objective

- `bevy_ui` does not build without the `bevy_text` feature due to
improper feature gating.
- Specifically, `MeasureArgs<'a>` had an unused lifetime `'a` without
`bevy_text` enabled. This is because it stores a reference to a
`cosmic_text::FontSystem`.
- This was caught by `flag-frenzy` in [this
run](https://github.com/TheBevyFlock/flag-frenzy/actions/runs/10024258523/job/27706132250).

## Solution

- Add a `PhantomData` to `MeasureArgs<'a>` in order to maintain its
lifetime argument.
- I also named it `font_system`, after the feature-gated argument that
actually needs a lifetime, for usability. Please comment if you have a
better solution!
- Move some unused imports to be behind the `bevy_text` feature gate.

## Testing

```bash
# Fails on main.
cargo check -p bevy_ui --no-default-features
# Succeeds on main.
cargo check -p bevy_ui --no-default-features -F bevy_text
```

---

## Migration Guide

**This is not a breaking change for users migrating from 0.14, since
`MeasureArgs` did not exist then.**

When the `bevy_text` feature is disabled for `bevy_ui`, the type of the
`MeasureArgs::font_system` field is now a `PhantomData` instead of being
removed entirely. This is in order to keep the lifetime parameter, even
though it is unused without text being enabled.
2024-07-22 19:19:10 +00:00
Mike
91dd7e6f0f
add entity to error message (#14163)
# Objective

- There was a new warning added about having an unstyled child in the ui
hierarchy. Debugging the new error is pretty hard without any info about
which entity is.

## Solution

- Add the entity id to the warning.

```text
// Before
2024-07-05T19:40:59.904014Z  WARN bevy_ui::layout::ui_surface: Unstyled child in a UI entity hierarchy. You are using an entity without UI components as a child of an entity with UI components, results may be unexpected.

//After
2024-07-05T19:40:59.904014Z  WARN bevy_ui::layout::ui_surface: Unstyled child `3v1` in a UI entity hierarchy. You are using an entity without UI components as a child of an entity with UI components, results may be unexpected.
```

## Changelog

- add entity id to ui surface warning
2024-07-08 01:01:47 +00:00
TotalKrill
5986d5d309
Cosmic text (#10193)
# Replace ab_glyph with the more capable cosmic-text

Fixes #7616.

Cosmic-text is a more mature text-rendering library that handles scripts
and ligatures better than ab_glyph, it can also handle system fonts
which can be implemented in bevy in the future

Rebase of https://github.com/bevyengine/bevy/pull/8808

## Changelog

Replaces text renderer ab_glyph with cosmic-text

The definition of the font size has changed with the migration to cosmic
text. The behavior is now consistent with other platforms (e.g. the
web), where the font size in pixels measures the height of the font (the
distance between the top of the highest ascender and the bottom of the
lowest descender). Font sizes in your app need to be rescaled to
approximately 1.2x smaller; for example, if you were using a font size
of 60.0, you should now use a font size of 50.0.

## Migration guide

- `Text2dBounds` has been replaced with `TextBounds`, and it now accepts
`Option`s to the bounds, instead of using `f32::INFINITY` to inidicate
lack of bounds
- Textsizes should be changed, dividing the current size with 1.2 will
result in the same size as before.
- `TextSettings` struct is removed
- Feature `subpixel_alignment` has been removed since cosmic-text
already does this automatically
- TextBundles and things rendering texts requires the `CosmicBuffer`
Component on them as well

## Suggested followups:

- TextPipeline: reconstruct byte indices for keeping track of eventual
cursors in text input
- TextPipeline: (future work) split text entities into section entities
- TextPipeline: (future work) text editing
- Support line height as an option. Unitless `1.2` is the default used
in browsers (1.2x font size).
- Support System Fonts and font families
- Example showing of animated text styles. Eg. throbbing hyperlinks

---------

Co-authored-by: tigregalis <anak.harimau@gmail.com>
Co-authored-by: Nico Burns <nico@nicoburns.com>
Co-authored-by: sam edelsten <samedelsten1@gmail.com>
Co-authored-by: Dimchikkk <velo.app1@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
2024-07-04 20:41:08 +00:00
Nico Burns
a3e60d39b7
Fix image measure function to apply inherent aspect ratio to style sizes (#13555)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/13155
- fixes https://github.com/bevyengine/bevy/issues/13517
- Supercedes https://github.com/bevyengine/bevy/pull/13381
- Requires https://github.com/DioxusLabs/taffy/pull/661

## Solution

- Taffy has been updated to:
    - Apply size styles to absolutely positioned children
    - Pass the node's `Style` through to the measure function
- Bevy's image measure function has been updated to make use of this
style information

## Notes

- This is currently using a git version of Taffy. If this is tested as
fixing the issue then we can turn that into a Taffy 0.5 release (this
would be the only change between Taffy 0.4 and Taffy 0.5 so upgrading is
not expected to be an issue)
- This implementation may not be completely correct. I would have
preferred to extend Taffy's gentest infrastructure to handle images and
used that to nail down the correct behaviour. But I don't have time for
that atm so we'll have to iterate on this in future. This PR at least
puts that under Bevy's control.

## Testing

- I manually tested the game_menu_example (from
https://github.com/bevyengine/bevy/issues/13155)
- More testing is probably merited

---

## Changelog

No changelog should be required as it fixes a regression on `main` that
was not present in bevy 0.13. The changelog for "Taffy upgrade" may want
to be changed from 0.4 to 0.5 if this change gets merged.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-05-30 18:37:39 +00:00
Nico Burns
96b9d0a7e2
Upgrade to Taffy 0.4 (#10690)
# Objective

- Enables support for `Display::Block`
- Enables support for `Overflow::Hidden`
- Allows for cleaner integration with text, image and other content
layout.
- Unblocks https://github.com/bevyengine/bevy/pull/8104
- Unlocks the possibility of Bevy creating a custom layout tree over
which Taffy operates.
- Enables #8808 / #10193 to remove a Mutex around the font system.

## Todo

- [x] ~Fix rendering of text/images to account for padding/border on
nodes (should size/position to content box rather than border box)~ In
order get this into a mergeable state this PR instead zeroes out
padding/border when syncing leaf node styles into Taffy to preserve the
existing behaviour. https://github.com/bevyengine/bevy/issues/6879 can
be fixed in a followup PR.

## Solution

- Update the version of Taffy
- Update code to work with the new version

Note: Taffy 0.4 has not yet been released. This PR is being created in
advance of the release to ensure that there are no blockers to upgrading
once the release occurs.

---

## Changelog

- Bevy now supports the `Display::Block` and `Overflow::Hidden` styles.
2024-04-30 14:13:17 +00:00
Brett Striker
cf092d45f9
[bevy_ui/layout] Extract UiSurface to its own file (#12801)
This is 1 of 5 iterative PR's that affect bevy_ui/layout

---

# Objective

- Extract `UiSurface` into its own file to make diffs in future PR's
easier to digest

## Solution

- Moved `UiSurface` to its own file
2024-04-01 22:47:34 +00:00