Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text rework #15591

Merged
merged 41 commits into from
Oct 9, 2024
Merged

Text rework #15591

merged 41 commits into from
Oct 9, 2024

Conversation

UkoeHB
Copy link
Contributor

@UkoeHB UkoeHB commented Oct 2, 2024

Ready for review. Examples migration progress: 100%.

Objective

Solution

This implements cart's proposal faithfully.

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

  • 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:

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:

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.

@viridia
Copy link
Contributor

viridia commented Oct 2, 2024

Note that my original conception of ghost nodes is that they would work in all rendering contexts, not just UI, however this is somewhat controversial.

@Jondolf Jondolf added C-Feature A new feature, making something new possible A-Text Rendering and layout for characters labels Oct 2, 2024
@alice-i-cecile alice-i-cecile added this to the 0.15 milestone Oct 2, 2024
@alice-i-cecile alice-i-cecile added the S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged label Oct 2, 2024
@UkoeHB UkoeHB force-pushed the text_rework branch 2 times, most recently from b391283 to 99b9678 Compare October 3, 2024 03:41
@UkoeHB UkoeHB marked this pull request as ready for review October 3, 2024 07:36
crates/bevy_ui/src/widget/text.rs Outdated Show resolved Hide resolved
/// The text's sections
pub sections: Vec<TextSection>,
#[require(ComputedTextBlock, TextLayoutInfo)]
pub struct TextBlock {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name TextBlock doesn't seem very intuitive, the name implies to me it would be the primary text component holding the string, not the arrangment settings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not great but this is what we have in the rework discussion so I will leave it as-is unless something better is proposed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the defining component for a "text block", which is a UI entity that "receives and lays out text". ComputedTextBlock is where that text is received / that is what holds the final string. Given that there are multiple top-level text types which actually the hold string, we can't really call any of those TextBlock, as we need a central unopinionated reusable component, and the top-level text types are all opinionated.

Open to alternative names, but I don't see TextBlock as a particularly bad name for "the UI component that indicates that an enitty recieves text to be laid out".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextBlock is pretty awkward in practice, from my experience migrating examples. TextLayout would make a lot more sense. You don't actually add TextBlock to an entity and get a text block... you get a partial text block that needs a root text component and text style to function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you get a partial text block that needs a root text component and text style to function.

Not super important, but when I pitched this design I intended for TextBlock to be the "source of truth text span receiver component" that served its function independently of specific "root text" components. Of course I didn't explicitly call that out and I think the current impl is totally fine. But if we went that route, it would make TextBlock make sense (and would also probably make building future TextBlock types easier). Plenty of open questions there though in terms of implementation / I don't think we need to go down that road in this PR.

/// The text's internal alignment.
/// Should not affect its position within a container.
pub justify: JustifyText,
/// How the text should linebreak when running out of the bounds determined by `max_size`
/// How the text should linebreak when running out of the bounds determined by `max_size`.
pub linebreak: LineBreak,
/// The antialiasing method to use when rendering text.
pub font_smoothing: FontSmoothing,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think don't think the font smoothing setting belongs here, it doesn't affect the arrangement of the text. It would be better stored in an elidable component of its own or in TextStyle.

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to TextStyle since smoothing is applied per-font.

/// the font face, the font size, and the color.
#[derive(Component, Clone, Debug, Reflect)]
#[reflect(Component, Default, Debug)]
pub struct TextStyle {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The color should be in a separate component TextColor, so that changes to the color don't trigger change detection and a relayout of the text.

Copy link
Contributor

@ickshonpe ickshonpe Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe TextStyle should be renamed as well to TextFont or something. It might be more consistant maybe with the UI Style component if TextBlock took over the name TextStyle.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this makes sense to me. I'm cool with TextFont and TextColor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine with me but can we do it in a separate PR? This one is already quite huge. The migration from TextStyle to TextFont/TextColor will by itself be a big chore and I call 'not it'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup thats fine by me.

Copy link
Contributor

@ickshonpe ickshonpe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance seems improved over main slightly overall, maybe ~5% in the stress tests on recomputations. Without recomputation it seems to be just slightly slower but that's to be expected because of the overhead of the extra nodes in the tree.

Copy link
Contributor

@Olle-Lukowski Olle-Lukowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the fact that I don't think TextNEW is a good name (I don't think this was intended even), this LGTM!

crates/bevy_ui/src/widget/text.rs Show resolved Hide resolved
crates/bevy_ui/src/widget/text.rs Outdated Show resolved Hide resolved
crates/bevy_text/src/text2d.rs Outdated Show resolved Hide resolved
crates/bevy_ui/src/widget/text.rs Outdated Show resolved Hide resolved
Visibility, // TODO: Remove when Node uses required components.
Transform // TODO: Remove when Node uses required components.
)]
pub struct TextNEW(pub String);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really dislike how the first span is a different type. I'd prefer if it just required the first text span to be a child too.
Could we do something like put the require on a marker component and have a constructor that returns a tuple (Marker, TextSpan)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original proposal had a universal span component but cart wanted to consolidate: #15014 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really dislike how the first span is a different type. I'd prefer if it just required the first text span to be a child too.

Text from my perspective exists to be the "standalone single span of text". A huge percentage of text cases receive no benefit from the added flexibility of TextBlock->TextSpan nesting. People won't want to pay that cost unless they have to.

The suggested "constructor that returns two components" pattern feels really nasty to me, especially in the context of the scene system. People don't expect constructors to behave that way, and I'd prefer it if we didn't embrace that pattern in Bevy, especially for something as fundamental as text. The init dataflow should be as simple as spawning the components you want explicitly.

If we aren't already doing it, we could make text.0 for the default empty string behave as "no span", so the first child of Text::default() -> TextSpan is at index 0.

It wasn't a part of my examples, but we could implement support for (Node, TextBlock) [ TextSpan ] as an option (and/or a new TextBlockNode type (which could require Node)) . Functionally TextBlock was intended to be the "arbitrary TextSpan collector" that worked across contexts. My thought when writing the proposal was that it would all be backed by the same fundamental system, and that system could be applied anywhere TextBlock and TextSpan are nested. That isn't how the impl ended up (which is fine given that I didn't explicitly express that need). I don't think changing to make that possible is necessary, as Text::default() -> TextSpan feels totally fine to me logically. But we can discuss it!

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we aren't already doing it, we could make text.0 for the default empty string behave as "no span", so the first child of Text::default() -> TextSpan is at index 0.

I disagree with this, it creates ambiguity and conceptual branching. Note that it's common to set a default-empty span and then later write text to it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with this, it creates ambiguity and conceptual branching. Note that it's common to set a default-empty span and then later write text to it.

I don't have strong opinions on that. Just pitching an alternative path that allows Text::default()->TextSpan to behave as if the first TextSpan child is actually the first span. I do agree that it makes the "empty Text to non-empty" change harder to reason about, as it would behave differently than an empty child TextSpan.

Visibility, // TODO: Remove when Node uses required components.
Transform // TODO: Remove when Node uses required components.
)]
pub struct TextNEW(pub String);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing would be to call it TextRootSpan. it's uglier but less confusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here: https://github.com/bevyengine/bevy/pull/15591/files#r1786443025. Giving this a "bad name" would fundamentally conflict with the goal of making single-span text easy and ergonomic to define.

crates/bevy_ui/src/widget/text.rs Outdated Show resolved Hide resolved
*/
#[derive(Component, Debug, Default, Clone, Deref, DerefMut, Reflect)]
#[reflect(Component, Default, Debug)]
#[require(TextStyle, GhostNode, Visibility(hidden_visibility))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer if TextStyle were elidable and if missing it just uses the TextStyle of its parent or the root text span.

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea but want to see what @cart has to say. There's also some added complexity for editing text spans to consider.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its worth considering adding inheritance, but I think we should spec that out separately / give it its own PR rather than hold this one up with more design work. There are some implications to consider, such as using enums (ex: TextStyle::Inherit) vs component presence.

examples/ui/text_debug.rs Outdated Show resolved Hide resolved
crates/bevy_text/src/text.rs Outdated Show resolved Hide resolved
crates/bevy_text/src/text.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@ickshonpe ickshonpe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a warning or error if we encounter orphaned/misparented TextSpan entities. It seems like it would be very easy to spawn a text node, but add the child text span to the wrong parent.

crates/bevy_dev_tools/src/fps_overlay.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/system/commands/mod.rs Show resolved Hide resolved
/// The text's sections
pub sections: Vec<TextSection>,
#[require(ComputedTextBlock, TextLayoutInfo)]
pub struct TextBlock {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the defining component for a "text block", which is a UI entity that "receives and lays out text". ComputedTextBlock is where that text is received / that is what holds the final string. Given that there are multiple top-level text types which actually the hold string, we can't really call any of those TextBlock, as we need a central unopinionated reusable component, and the top-level text types are all opinionated.

Open to alternative names, but I don't see TextBlock as a particularly bad name for "the UI component that indicates that an enitty recieves text to be laid out".

/// the font face, the font size, and the color.
#[derive(Component, Clone, Debug, Reflect)]
#[reflect(Component, Default, Debug)]
pub struct TextStyle {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this makes sense to me. I'm cool with TextFont and TextColor.

crates/bevy_text/src/text.rs Show resolved Hide resolved
crates/bevy_text/src/text2d.rs Outdated Show resolved Hide resolved
Visibility, // TODO: Remove when Node uses required components.
Transform // TODO: Remove when Node uses required components.
)]
pub struct TextNEW(pub String);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here: https://github.com/bevyengine/bevy/pull/15591/files#r1786443025. Giving this a "bad name" would fundamentally conflict with the goal of making single-span text easy and ergonomic to define.

Visibility, // TODO: Remove when Node uses required components.
Transform // TODO: Remove when Node uses required components.
)]
pub struct TextNEW(pub String);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really dislike how the first span is a different type. I'd prefer if it just required the first text span to be a child too.

Text from my perspective exists to be the "standalone single span of text". A huge percentage of text cases receive no benefit from the added flexibility of TextBlock->TextSpan nesting. People won't want to pay that cost unless they have to.

The suggested "constructor that returns two components" pattern feels really nasty to me, especially in the context of the scene system. People don't expect constructors to behave that way, and I'd prefer it if we didn't embrace that pattern in Bevy, especially for something as fundamental as text. The init dataflow should be as simple as spawning the components you want explicitly.

If we aren't already doing it, we could make text.0 for the default empty string behave as "no span", so the first child of Text::default() -> TextSpan is at index 0.

It wasn't a part of my examples, but we could implement support for (Node, TextBlock) [ TextSpan ] as an option (and/or a new TextBlockNode type (which could require Node)) . Functionally TextBlock was intended to be the "arbitrary TextSpan collector" that worked across contexts. My thought when writing the proposal was that it would all be backed by the same fundamental system, and that system could be applied anywhere TextBlock and TextSpan are nested. That isn't how the impl ended up (which is fine given that I didn't explicitly express that need). I don't think changing to make that possible is necessary, as Text::default() -> TextSpan feels totally fine to me logically. But we can discuss it!

*/
#[derive(Component, Debug, Default, Clone, Deref, DerefMut, Reflect)]
#[reflect(Component, Default, Debug)]
#[require(TextStyle, GhostNode, Visibility(hidden_visibility))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its worth considering adding inheritance, but I think we should spec that out separately / give it its own PR rather than hold this one up with more design work. There are some implications to consider, such as using enums (ex: TextStyle::Inherit) vs component presence.

*/
#[derive(Component, Debug, Default, Clone, Deref, DerefMut, Reflect)]
#[reflect(Component, Default, Debug)]
#[require(TextStyle, GhostNode, Visibility(hidden_visibility))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we discuss why GhostNode is here? My theory is that this is to support scenarios like Text -> TextSpan -> Node -> TextSpan.

  1. It feels like TextSpan should always be a "leaf" from a UI perspective, other than having other child TextSpans. I can't think of a scenario where arbitrary hierarchy like this makes sense.
  2. GhostNode is still a bit contentious / we're considering it experimental. I'd prefer it if we didn't take a dependency on it for "real things" yet.
  3. By removing the GhostNode requirement, we can go back to having a single TextSpan type that works across contexts, which seems much nicer to me.

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we discuss why GhostNode is here?

We need text spans to not participate in layout. The alternative is Display::None but then you start lugging around useless Node and Style components. GhostNode is currently the most well-suited to the task.

By removing the GhostNode requirement, we can go back to having a single TextSpan type that works across contexts, which seems much nicer to me.

Not without some serious design analysis, since we need a good way to skip entities during layout. See my comment on the GhostNode PR.

I can't think of a scenario where arbitrary hierarchy like this makes sense.

In the distant future we may have 'in-line UI' in text blocks. But there is no design around that now (it may not be in-tree, or may use different relations) so I agree text spans can be considered simple leafs.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need text spans to not participate in layout.

Why wouldn't you want them to participate in UI layout? The main text node defines the available / desired space for text, which communicates sizes both upwards and downwards the tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why wouldn't you want them to participate in UI layout? The main text node defines the available / desired space for text, which communicates sizes both upwards and downwards the tree.

I lied a little, they do participate in layout, but not directly. Spans are collected into a cosmic-text buffer which knows how to manage text, and then the buffer is 'measured' when doing taffy layout (taffy needs to ignore spans).

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I'm leaning toward the idea that text spans as individual entities is not worth the trouble. Perhaps they can just be consolidated into a component and then the whole question of ghost nodes becomes moot. Need to avoid landing back on TextSection ugliness...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it is the reason I also researched and PoC-d a text create, and yes, that PR is the proper solution instead of ghost nodes. Except that is mile-stoned for 0.16.0. so maybe next year

Also, I think text measurement should be provided with a bounding box which should be coming from the node constraints. The only issue here is that the constraints don't exist before text is measured so to me the problem really is that calcs are done late and only once.

I would also like to point out that the entity per span is not the entire solution for text, as you cannot make a GPU renderer for it if its chopped up in entities (not without a render texture rendering an entire UI block - but that prevents splatting text on any part of the UV). However, if text is chopped up and has its own hierarchy, GPU rendering is much easier once you grab the entire text tree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need text spans to not participate in layout. The alternative is Display::None but then you start lugging around useless Node and Style components. GhostNode is currently the most well-suited to the task.

TextSpans aren't UI Nodes (or at least, have no reason to be as they are "metadata" / not rendered directly). Why would they participate in layout?

In the distant future we may have 'in-line UI' in text blocks. But there is no design around that now (it may not be in-tree, or may use different relations) so I agree text spans can be considered simple leafs.

Even in those cases, I think it probably could serve as an independent UI root. Id prefer to punt that scenario down the road until we actually choose to implement it, in favor of the simpler design here.

I think for this PR we should:

  1. Remove the GhostNode require
  2. Remove the "arbitrary propagation of TextSpan" up the hierarchy. TextSpans only propagate up other TextSpans until they either hit a TextBlock (success) or hit a parent without a TextSpan or TextBlock (invalid).
  3. Remove TextSpan2d and embrace TextSpan as the "one context-free span type".

If you're burnt out on changes let me know. Happy to hop in.

Copy link
Contributor Author

@UkoeHB UkoeHB Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextSpans aren't UI Nodes (or at least, have no reason to be as they are "metadata" / not rendered directly). Why would they participate in layout?

They are not, but they are in-tree and the layout algorithm walks the tree. Currently we issue a warning (or panic?) if any in-tree entity is missing Node. Whether or not to 'ignore' entities without Node is part of the discussion around ghost nodes. I'm leaning toward EidLoi's position that hierarchies should be self-contained structures and that non-uniform entities should be attached with tailored relationships. So, text spans should be attached as an ancillary hierarchy that doesn't use Parent/Child (maybe ParentSpan/ChildSpan).

Remove the "arbitrary propagation of TextSpan" up the hierarchy.

This was already fixed, it was a bug.

Remove TextSpan2d and embrace TextSpan as the "one context-free span type".

Only possible if changes are maybe to UI layout to make ghost nodes implicit instead of/in addition to explicit. Or if we introduce a different relationship structure.

If you're burnt out on changes let me know. Happy to hop in.

Not quite yet but I probably only make big changes that I'm confident are improving the situation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we issue a warning (or panic?) if any in-tree entity is missing Node.

I think UI nodes having non UI children should probably be valid. Its when a UI node has non-UI children who then have UI nodes where we have problems.

Whether or not to 'ignore' entities without Node is part of the discussion around ghost nodes. I'm leaning toward EidLoi's position that hierarchies should be self-contained structures and that non-uniform entities should be attached with tailored relationships. So, text spans should be attached as an ancillary hierarchy that doesn't use Parent/Child (maybe ParentSpan/ChildSpan).

I agree that this is a path worth exploring. But it feels pretty non-viable without both relations and scene construction tools that make multi-hierarchy management (aka multi-relation construction) easier. The current Bevy paradigm is "one hierarchy" and we should design under that constraint until that changes.

This was already fixed, it was a bug.

Excellent.

Only possible if changes are maybe to UI layout to make ghost nodes implicit instead of/in addition to explicit. Or if we introduce a different relationship structure.

Having thought on this, I think the path forward is removing GhostNode and making replacing the no UI->NonUI layout constraint with a no UI->NonUi->UI constraint. Then we unify on a single TextSpan type as it can be a non-ui contextless component.

Not a fan of using GhostNode to enable these "leaf-like" cases because we're heavily considering reverting that changeset (it is still experimental), and I think these "leaf-like" cases should be valid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having thought on this, I think the path forward is removing GhostNode and making replacing the no UI->NonUI layout constraint with a no UI->NonUi->UI constraint. Then we unify on a single TextSpan type as it can be a non-ui contextless component.

This is fine with me, but changing the layout algorithm should not be part of this PR. Can you open a new PR supporting the changes you want? Then I will rebase once that's merged and consolidate the span types.

@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide and removed C-Feature A new feature, making something new possible labels Oct 8, 2024
github-merge-queue bot pushed a commit that referenced this pull request Oct 8, 2024
…pper (#15740)

# Objective

- Closes #15720

## Solution

Wrap the handle in a new wrapper component: `UiMaterialHandle`
It's not possible to match the naming convention of `MeshMaterial3d/2d`
here with the trait already being called `UiMaterial`

Should we consider renaming to `Material3d/2dHandle` and `Mesh3d/2d` to
`Mesh3d/2dHandle`?

- This shouldn't have any merge conflicts with #15591

## Testing

Tested the `ui_material` example

## Migration Guide

Let's defer the migration guide to the required component port. I just
want to yeet the `Component` impl on `Handle` in the meantime :)
github-merge-queue bot pushed a commit that referenced this pull request Oct 8, 2024
# 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.
@UkoeHB
Copy link
Contributor Author

UkoeHB commented Oct 9, 2024

Instead of TextBlock add TextJustification and LineBreak to Style, then layout child text nodes according to their parent's TextJustifcation and LineBreak properties.

Blocks of text are implicitly created from any adjacent sibling text nodes. Each Text node in the block of text has an identical copy of the same Node component so they overlap.

I'd prefer to keep the current design, which is much more explicit and does not further increase the complexity of Style.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Oct 9, 2024
Merged via the queue into bevyengine:main with commit c2c19e5 Oct 9, 2024
30 checks passed
@UkoeHB UkoeHB deleted the text_rework branch October 9, 2024 19:02
github-merge-queue bot pushed a commit that referenced this pull request Oct 9, 2024
# Objective

- Improve clarity when spawning a text block. See [this
discussion](#15591).

## Solution

- Rename `TextBlock` to `TextLayout`.
github-merge-queue bot pushed a commit that referenced this pull request Oct 11, 2024
# Objective

Fixes a mistake in the migration done in #15591.

## Solution

Restore a line of instructions that was accidentally dropped.

## Testing

`cargo run --example motion_blur`

Tested that instructions make sense and text updates correctly when keys
are pressed.
github-merge-queue bot pushed a commit that referenced this pull request Oct 11, 2024
# Objective

Fixes #15832

## Solution

It seems that this was just a transliteration mistake during #15591.

Update the correct text span index.

## Testing

I tested on macos with:

`cargo run --example gamepad_viewer`
- without gamepad connected
- with gamepad connected
- disconnecting and reconnecting gamepad while running
@MiniaczQ MiniaczQ mentioned this pull request Oct 13, 2024
github-merge-queue bot pushed a commit that referenced this pull request Oct 15, 2024
# Objective

Cleanup naming and docs, add missing migration guide after #15591 

All text root nodes now use `Text` (UI) / `Text2d`.
All text readers/writers use `Text<Type>Reader`/`Text<Type>Writer`
convention.

---

## Migration Guide

Doubles as #15591 migration guide.

Text bundles (`TextBundle` and `Text2dBundle`) were removed in favor of
`Text` and `Text2d`.
Shared configuration fields were replaced with `TextLayout`, `TextFont`
and `TextColor` components.
Just `TextBundle`'s additional field turned into `TextNodeFlags`
component,
while `Text2dBundle`'s additional fields turned into `TextBounds` and
`Anchor` components.

Text sections were removed in favor of hierarchy-based approach.
For root text entities with `Text` or `Text2d` components, child
entities with `TextSpan` will act as additional text sections.
To still access text spans by index, use the new `TextUiReader`,
`Text2dReader` and `TextUiWriter`, `Text2dWriter` system parameters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Text Rendering and layout for characters C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants